diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,10 @@
 version bound format to use is `h-raylib >=x.y.z.w && <x.y.(z+1)` (instead of
 the usual `^>=` bound).
 
+## Version 6.1.0.0 _10 September 2026_
+
+- **BREAKING CHANGE** Updated raylib to the master branch
+
 ## Version 5.6.0.0 _19 January 2026_
 
 - \[[#61](https://github.com/Anut-py/h-raylib/issues/61)\] Fixed a bug where
diff --git a/default.nix b/default.nix
--- a/default.nix
+++ b/default.nix
@@ -3,7 +3,7 @@
 }:
 mkDerivation {
   pname = "h-raylib";
-  version = "5.6.0.0";
+  version = "6.1.0.0";
   src = ./.;
   isLibrary = true;
   isExecutable = buildExamples;
diff --git a/examples/basic-animations/assets/robot.glb b/examples/basic-animations/assets/robot.glb
new file mode 100644
Binary files /dev/null and b/examples/basic-animations/assets/robot.glb differ
diff --git a/examples/basic-animations/src/Main.hs b/examples/basic-animations/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/examples/basic-animations/src/Main.hs
@@ -0,0 +1,53 @@
+-- adapted from https://github.com/futu2/h-raylib-examples/blob/master/src/ModelsLoadingGltf.hs
+{-# LANGUAGE PatternSynonyms #-}
+module Main where
+
+import Paths_h_raylib (getDataFileName)
+import Raylib.Core (isMouseButtonPressed, clearBackground)
+import Raylib.Core.Models (loadModel, loadModelAnimations, drawModel, updateModelAnimation, drawGrid)
+import Raylib.Core.Text (drawText)
+import Raylib.Types (Camera3D (..), MouseButton (..), CameraProjection (..), pattern Vector3)
+import Raylib.Util (withWindow, managed, whileWindowOpen_, mode3D, drawing)
+import Raylib.Util.Colors (rayWhite, white, gray)
+
+modelPath :: String
+modelPath = "examples/basic-animations/assets/robot.glb"
+
+main :: IO ()
+main = do
+  withWindow
+    800
+    450
+    "raylib [models] example - basic animations"
+    60
+    ( \window -> do
+
+        model <- managed window $ loadModel =<< getDataFileName modelPath
+        animations <- loadModelAnimations =<< getDataFileName modelPath
+
+        let camera = Camera3D (Vector3 6 6 6) (Vector3 0 2 0) (Vector3 0 1 0) 45 CameraPerspective
+
+        let anims = length animations
+        whileWindowOpen_
+          ( \(frame, anim) -> do
+            leftPressed <- isMouseButtonPressed MouseButtonLeft
+            rightPressed <- isMouseButtonPressed MouseButtonRight
+            let anim' = if leftPressed then (anim - 1 + anims) `mod` anims
+                else if rightPressed then (anim + 1) `mod` anims
+                else anim
+            drawing
+              ( do
+                  clearBackground rayWhite
+                  mode3D
+                    camera
+                    ( do
+                        drawModel model (Vector3 0 0 0) 1 white
+                        drawGrid 10 1
+                        updateModelAnimation model (animations !! anim') frame
+                    )
+                  drawText "Use the LEFT/RIGHT mouse buttons to switch animation" 10 10 20 gray
+              )
+            return ((frame + 1), anim')
+          )
+          (0, 0)
+    )
diff --git a/examples/raygui-suite/src/Main.hs b/examples/raygui-suite/src/Main.hs
--- a/examples/raygui-suite/src/Main.hs
+++ b/examples/raygui-suite/src/Main.hs
@@ -298,7 +298,7 @@
 
       oldState <- guiGetState
       unless custom' guiDisable
-      color' <- guiColorPicker (Rectangle 20 (height - 470) 374 360) (customBackground ps)
+      color' <- guiColorPicker (Rectangle 20 (height - 470) 374 360) Nothing (customBackground ps)
       unless (oldState == StateDisabled) guiEnable
 
       when (theme' /= theme ps) (themes !! (fromMaybe 0 theme'))
diff --git a/flake.nix b/flake.nix
--- a/flake.nix
+++ b/flake.nix
@@ -9,10 +9,10 @@
       forAllSystems' = nixpkgs.lib.genAttrs;
       forAllSystems = forAllSystems' supportedSystems;
 
-      raylibRev = "29896a24039fb687d6ede44c63a78dd3b5829f8b";
-      raylibHash = "sha256-eKquM7Dumd++eIYXBNKi8lhyGGgGt+PO0QPxcSux+/o=";
-      rayguiRev = "9a1c183d8539e2470635b22f92bdaefaf5218aaa";
-      rayguiHash = "sha256-eRcF41quNwlEn5lHVaoyn1wmppZ5Ou+M8c908qFvLek=";
+      raylibRev = "f25c8241f393a81368a99a8d2e6babbc208e7d4b";
+      raylibHash = "sha256-ncWYlyAwrRzWWQRa9dA9JjYKbl80uixf3OPSRZTJLEE=";
+      rayguiRev = "30e303400781d3ef6e81f01e1b95cdf3b19386df";
+      rayguiHash = "sha256-BX0GavFQp4iAKhrmRAeWyTLD2PrEFWP9JhObdMlRAxk=";
 
       pkgsForSystem =
         system:
@@ -22,13 +22,19 @@
             (self: super: {
               raylib = super.raylib.overrideAttrs (old: {
                 patches = [];
-                version = "5.0.0";
+                version = "6.1.0";
                 src = self.fetchFromGitHub {
                   owner = "raysan5";
                   repo = "raylib";
                   rev = raylibRev;
                   sha256 = raylibHash;
                 };
+
+                cmakeFlags = (old.cmakeFlags or [])
+                    ++ (if self.stdenv.hostPlatform.isLinux then
+                        [ "-DCMAKE_EXE_LINKER_FLAGS=-lGL" ]
+                        else []);
+
                 postFixup = "cp ../src/*.h $out/include/";
               });
               raygui = super.stdenv.mkDerivation { # A bit of a hack to get raygui working
@@ -51,8 +57,8 @@
         pkgs:
         with pkgs; (
           [raylib raygui]
-          ++ lib.optionals stdenv.isLinux (with xorg; [libGL libX11 libXcursor libXext libXi libXinerama libXrandr])
-          ++ lib.optionals stdenv.isDarwin [apple-sdk]
+          ++ lib.optionals stdenv.hostPlatform.isLinux [libGL libx11 libxcursor libxi libxinerama libxrandr]
+          ++ lib.optionals stdenv.hostPlatform.isDarwin [apple-sdk]
         );
     in
       {
@@ -70,7 +76,7 @@
         );
         packages = forAllSystems (system: let
           pkgs = pkgsForSystem system;
-          baseInputs = pkgs // pkgs.xorg // pkgs.haskellPackages // rec { systemDeps = depsForSystem system pkgs; buildExamples = false; };
+          baseInputs = pkgs // pkgs.haskellPackages // rec { systemDeps = depsForSystem system pkgs; buildExamples = false; };
         in {
           default = import ./default.nix baseInputs;
           examples = import ./default.nix (baseInputs // rec { buildExamples = true; });
diff --git a/h-raylib.cabal b/h-raylib.cabal
--- a/h-raylib.cabal
+++ b/h-raylib.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               h-raylib
-version:            5.6.0.0
+version:            6.1.0.0
 synopsis:           Raylib bindings for Haskell
 category:           graphics
 description:
@@ -35,6 +35,7 @@
 
 data-files:
   examples/**/*.frag
+  examples/**/*.glb
   examples/**/*.mtl
   examples/**/*.obj
   examples/**/*.png
@@ -180,6 +181,12 @@
   hs-source-dirs: examples/basic-models/src
   main-is:        Main.hs
 
+-- animations
+executable basic-animations
+  import:         example-options
+  hs-source-dirs: examples/basic-animations/src
+  main-is:        Main.hs
+
 -- shaders
 executable basic-shaders
   import:         example-options
@@ -313,13 +320,12 @@
       Xcursor
       Xrandr
       Xi
-      Xext
 
     cc-options:
       -Wno-implicit-function-declaration -Wno-unused-result -Wno-ignored-qualifiers -D_GLFW_X11
 
   elif (flag(platform-mac) || (flag(detect-platform) && os(osx)))
-    frameworks: OpenGL Cocoa IOKit CoreVideo CoreAudio CoreFoundation
+    frameworks: OpenGL Cocoa IOKit CoreVideo CoreAudio CoreFoundation QuartzCore
 
   elif (flag(platform-bsd) || (flag(detect-platform) && ((os(freebsd) || os(netbsd)) || os(openbsd))))
     extra-libraries:
@@ -350,12 +356,29 @@
 
     if !flag(platform-nixos)
       include-dirs:
-        raylib/src raylib/src/external/glfw/src
-        raylib/src/external/glfw/include raygui/src raygui/styles/amber
-        raygui/styles/ashes raygui/styles/bluish raygui/styles/candy
-        raygui/styles/cherry raygui/styles/cyber raygui/styles/dark
-        raygui/styles/enefete raygui/styles/jungle raygui/styles/lavanda
-        raygui/styles/sunny raygui/styles/terminal
+        raylib/src
+        raylib/src/external/glfw/src
+        raylib/src/external/glfw/include
+        raygui/src
+        raygui/styles/advance
+        raygui/styles/amber
+        raygui/styles/ashes
+        raygui/styles/bluish
+        raygui/styles/brick
+        raygui/styles/candy
+        raygui/styles/cherry
+        raygui/styles/cyber
+        raygui/styles/dark
+        raygui/styles/enefete
+        raygui/styles/genesis
+        raygui/styles/jungle
+        raygui/styles/lavanda
+        raygui/styles/pocket
+        raygui/styles/rltech
+        raygui/styles/sunny
+        raygui/styles/terminal
+        raygui/styles/turbo
+        raygui/styles/wisteria
 
       c-sources:
         raylib/src/raudio.c
diff --git a/lib/rgui_bindings.c b/lib/rgui_bindings.c
--- a/lib/rgui_bindings.c
+++ b/lib/rgui_bindings.c
@@ -73,71 +73,111 @@
   return GuiLoadStyle(fileName);
 }
 
+RLBIND void GuiLoadStyleFromMemory_(const unsigned char *fileData, int dataSize)
+{
+  return GuiLoadStyleFromMemory(fileData, dataSize);
+}
+
 RLBIND void GuiLoadStyleDefault_(void)
 {
   return GuiLoadStyleDefault();
 }
 
+RLBIND void GuiLoadStyleAdvance_(void)
+{
+  return GuiLoadStyleAdvance();
+}
+
 RLBIND void GuiLoadStyleAmber_(void)
 {
-  GuiLoadStyleAmber();
+  return GuiLoadStyleAmber();
 }
 
 RLBIND void GuiLoadStyleAshes_(void)
 {
-  GuiLoadStyleAshes();
+  return GuiLoadStyleAshes();
 }
 
 RLBIND void GuiLoadStyleBluish_(void)
 {
-  GuiLoadStyleBluish();
+  return GuiLoadStyleBluish();
 }
 
+RLBIND void GuiLoadStyleBrick_(void)
+{
+  return GuiLoadStyleBrick();
+}
+
 RLBIND void GuiLoadStyleCandy_(void)
 {
-  GuiLoadStyleCandy();
+  return GuiLoadStyleCandy();
 }
 
 RLBIND void GuiLoadStyleCherry_(void)
 {
-  GuiLoadStyleCherry();
+  return GuiLoadStyleCherry();
 }
 
 RLBIND void GuiLoadStyleCyber_(void)
 {
-  GuiLoadStyleCyber();
+  return GuiLoadStyleCyber();
 }
 
 RLBIND void GuiLoadStyleDark_(void)
 {
-  GuiLoadStyleDark();
+  return GuiLoadStyleDark();
 }
 
 RLBIND void GuiLoadStyleEnefete_(void)
 {
-  GuiLoadStyleEnefete();
+  return GuiLoadStyleEnefete();
 }
 
+RLBIND void GuiLoadStyleGenesis_(void)
+{
+  return GuiLoadStyleGenesis();
+}
+
 RLBIND void GuiLoadStyleJungle_(void)
 {
-  GuiLoadStyleJungle();
+  return GuiLoadStyleJungle();
 }
 
 RLBIND void GuiLoadStyleLavanda_(void)
 {
-  GuiLoadStyleLavanda();
+  return GuiLoadStyleLavanda();
 }
 
+RLBIND void GuiLoadStylePocket_(void)
+{
+  return GuiLoadStylePocket();
+}
+
+RLBIND void GuiLoadStyleRLTech_(void)
+{
+  return GuiLoadStyleRLTech();
+}
+
 RLBIND void GuiLoadStyleSunny_(void)
 {
-  GuiLoadStyleSunny();
+  return GuiLoadStyleSunny();
 }
 
 RLBIND void GuiLoadStyleTerminal_(void)
 {
-  GuiLoadStyleTerminal();
+  return GuiLoadStyleTerminal();
 }
 
+RLBIND void GuiLoadStyleTurbo_(void)
+{
+  return GuiLoadStyleTurbo();
+}
+
+RLBIND void GuiLoadStyleWisteria_(void)
+{
+  return GuiLoadStyleWisteria();
+}
+
 RLBIND void GuiEnableTooltip_(void)
 {
   return GuiEnableTooltip();
@@ -173,6 +213,11 @@
   return GuiLoadIcons(fileName, loadIconsName);
 }
 
+RLBIND char **GuiLoadIconsFromMemory_(const unsigned char *fileData, int dataSize, bool loadIconsName)
+{
+  return GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName);
+}
+
 RLBIND void GuiDrawIcon_(int iconId, int posX, int posY, int pixelSize, Color *color)
 {
   return GuiDrawIcon(iconId, posX, posY, pixelSize, *color);
@@ -203,11 +248,6 @@
   return GuiPanel(*bounds, text);
 }
 
-RLBIND int GuiTabBar_(Rectangle *bounds, const char **text, int count, int *active)
-{
-  return GuiTabBar(*bounds, text, count, active);
-}
-
 RLBIND int GuiScrollPanel_(Rectangle *bounds, const char *text, Rectangle *content, Vector2 *scroll, Rectangle *view)
 {
   return GuiScrollPanel(*bounds, text, *content, scroll, view);
@@ -312,19 +352,29 @@
   return GuiListView(*bounds, text, scrollIndex, active);
 }
 
-RLBIND int GuiListViewEx_(Rectangle *bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
+RLBIND int GuiListViewEx_(Rectangle *bounds, char **text, int count, int *scrollIndex, int *active, int *focus)
 {
   return GuiListViewEx(*bounds, text, count, scrollIndex, active, focus);
 }
 
-RLBIND int GuiMessageBox_(Rectangle *bounds, const char *title, const char *message, const char *buttons)
+RLBIND int GuiTabBar_(Rectangle *bounds, const char *text, int *hscroll, int *active)
 {
-  return GuiMessageBox(*bounds, title, message, buttons);
+  return GuiTabBar(*bounds, text, hscroll, active);
 }
 
-RLBIND int GuiTextInputBox_(Rectangle *bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive)
+int GuiTabBarEx_(Rectangle *bounds, char **text, int count, int *hscroll, int *active, int *focus)
 {
-  return GuiTextInputBox(*bounds, title, message, buttons, text, textMaxSize, secretViewActive);
+  return GuiTabBarEx(*bounds, text, count, hscroll, active, focus);
+}
+
+RLBIND int GuiMessageBox_(Rectangle *bounds, const char *title, const char *message, const char *btnText, int *btnActive)
+{
+  return GuiMessageBox(*bounds, title, message, btnText, btnActive);
+}
+
+RLBIND int GuiTextInputBox_(Rectangle *bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive)
+{
+  return GuiTextInputBox(*bounds, title, message, text, textSize, btnText, btnActive, secretViewActive);
 }
 
 RLBIND int GuiColorPicker_(Rectangle *bounds, const char *text, Color *color)
diff --git a/lib/rgui_bindings.h b/lib/rgui_bindings.h
--- a/lib/rgui_bindings.h
+++ b/lib/rgui_bindings.h
@@ -5,18 +5,25 @@
  */
 
 #include "rl_common.h"
+#include <style_advance.h>
 #include <style_amber.h>
 #include <style_ashes.h>
 #include <style_bluish.h>
+#include <style_brick.h>
 #include <style_candy.h>
 #include <style_cherry.h>
 #include <style_cyber.h>
 #include <style_dark.h>
 #include <style_enefete.h>
+#include <style_genesis.h>
 #include <style_jungle.h>
 #include <style_lavanda.h>
+#include <style_pocket.h>
+#include <style_rltech.h>
 #include <style_sunny.h>
 #include <style_terminal.h>
+#include <style_turbo.h>
+#include <style_wisteria.h>
 
 void GuiEnable_(void);
 
@@ -44,14 +51,20 @@
 
 void GuiLoadStyle_(const char *fileName);
 
+void GuiLoadStyleFromMemory_(const unsigned char *fileData, int dataSize);
+
 void GuiLoadStyleDefault_(void);
 
+void GuiLoadStyleAdvance_(void);
+
 void GuiLoadStyleAmber_(void);
 
 void GuiLoadStyleAshes_(void);
 
 void GuiLoadStyleBluish_(void);
 
+void GuiLoadStyleBrick_(void);
+
 void GuiLoadStyleCandy_(void);
 
 void GuiLoadStyleCherry_(void);
@@ -62,14 +75,24 @@
 
 void GuiLoadStyleEnefete_(void);
 
+void GuiLoadStyleGenesis_(void);
+
 void GuiLoadStyleJungle_(void);
 
 void GuiLoadStyleLavanda_(void);
 
+void GuiLoadStylePocket_(void);
+
+void GuiLoadStyleRLTech_(void);
+
 void GuiLoadStyleSunny_(void);
 
 void GuiLoadStyleTerminal_(void);
 
+void GuiLoadStyleTurbo_(void);
+
+void GuiLoadStyleWisteria_(void);
+
 void GuiEnableTooltip_(void);
 
 void GuiDisableTooltip_(void);
@@ -84,6 +107,8 @@
 
 char **GuiLoadIcons_(const char *fileName, bool loadIconsName);
 
+char **GuiLoadIconsFromMemory_(const unsigned char *fileData, int dataSize, bool loadIconsName);
+
 void GuiDrawIcon_(int iconId, int posX, int posY, int pixelSize, Color *color);
 
 int GuiGetTextWidth_(char *a);
@@ -96,8 +121,6 @@
 
 int GuiPanel_(Rectangle *bounds, const char *text);
 
-int GuiTabBar_(Rectangle *bounds, const char **text, int count, int *active);
-
 int GuiScrollPanel_(Rectangle *bounds, const char *text, Rectangle *content, Vector2 *scroll, Rectangle *view);
 
 int GuiLabel_(Rectangle *bounds, const char *text);
@@ -140,11 +163,15 @@
 
 int GuiListView_(Rectangle *bounds, const char *text, int *scrollIndex, int *active);
 
-int GuiListViewEx_(Rectangle *bounds, const char **text, int count, int *scrollIndex, int *active, int *focus);
+int GuiListViewEx_(Rectangle *bounds, char **text, int count, int *scrollIndex, int *active, int *focus);
 
-int GuiMessageBox_(Rectangle *bounds, const char *title, const char *message, const char *buttons);
+int GuiTabBar_(Rectangle *bounds, const char *text, int *hscroll, int *active);
 
-int GuiTextInputBox_(Rectangle *bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive);
+int GuiTabBarEx_(Rectangle *bounds, char **text, int count, int *hscroll, int *active, int *focus);
+
+int GuiMessageBox_(Rectangle *bounds, const char *title, const char *message, const char *btnText, int *btnActive);
+
+int GuiTextInputBox_(Rectangle *bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive);
 
 int GuiColorPicker_(Rectangle *bounds, const char *text, Color *color);
 
diff --git a/lib/rl_bindings.c b/lib/rl_bindings.c
--- a/lib/rl_bindings.c
+++ b/lib/rl_bindings.c
@@ -215,6 +215,16 @@
     UnloadDroppedFiles(*a);
 }
 
+RLBIND unsigned int GetDirectoryFileCount_(const char *a)
+{
+    return GetDirectoryFileCount(a);
+}
+
+RLBIND unsigned int GetDirectoryFileCountEx_(const char *a, const char *b, bool c)
+{
+    return GetDirectoryFileCountEx(a, b, c);
+}
+
 RLBIND AutomationEventList *LoadAutomationEventList_(char *a)
 {
     AutomationEventList *ptr = (AutomationEventList *)malloc(sizeof(AutomationEventList));
@@ -358,11 +368,16 @@
     DrawCircleSectorLines(*a, b, c, d, e, *f);
 }
 
-RLBIND void DrawCircleGradient_(int a, int b, float c, Color *d, Color *e)
+RLBIND void DrawCircleSectorLinesEx_(Vector2 *a, float b, float c, float d, int e, float f, Color *g)
 {
-    DrawCircleGradient(a, b, c, *d, *e);
+    DrawCircleSectorLinesEx(*a, b, c, d, e, f, *g);
 }
 
+RLBIND void DrawCircleGradient_(Vector2 *a, float b, Color *c, Color *d)
+{
+    DrawCircleGradient(*a, b, *c, *d);
+}
+
 RLBIND void DrawCircleV_(Vector2 *a, float b, Color *c)
 {
     DrawCircleV(*a, b, *c);
@@ -378,6 +393,11 @@
     DrawCircleLinesV(*a, b, *c);
 }
 
+RLBIND void DrawCircleLinesEx_(Vector2 *a, float b, float c, Color *d)
+{
+    DrawCircleLinesEx(*a, b, c, *d);
+}
+
 RLBIND void DrawEllipse_(int a, int b, float c, float d, Color *e)
 {
     DrawEllipse(a, b, c, d, *e);
@@ -408,6 +428,11 @@
     DrawRingLines(*a, b, c, d, e, f, *g);
 }
 
+RLBIND void DrawRingLinesEx_(Vector2 *a, float b, float c, float d, float e, int f, float g, Color *h)
+{
+    DrawRingLinesEx(*a, b, c, d, e, f, g, *h);
+}
+
 RLBIND void DrawRectangle_(int a, int b, int c, int d, Color *e)
 {
     DrawRectangle(a, b, c, d, *e);
@@ -473,11 +498,21 @@
     DrawTriangle(*a, *b, *c, *d);
 }
 
+RLBIND void DrawTriangleGradient_(Vector2 *a, Vector2 *b, Vector2 *c, Color *d, Color *e, Color *f)
+{
+    DrawTriangleGradient(*a, *b, *c, *d, *e, *f);
+}
+
 RLBIND void DrawTriangleLines_(Vector2 *a, Vector2 *b, Vector2 *c, Color *d)
 {
     DrawTriangleLines(*a, *b, *c, *d);
 }
 
+RLBIND void DrawTriangleLinesEx_(Vector2 *a, Vector2 *b, Vector2 *c, float d, Color *e)
+{
+    DrawTriangleLinesEx(*a, *b, *c, d, *e);
+}
+
 RLBIND void DrawTriangleFan_(const Vector2 *a, int b, Color *c)
 {
     DrawTriangleFan(a, b, *c);
@@ -574,10 +609,10 @@
     return ptr;
 }
 
-RLBIND Vector2 *GetSplinePointBezierQuad_(Vector2 *a, Vector2 *b, Vector2 *c, float d)
+RLBIND Vector2 *GetSplinePointBezierQuadratic_(Vector2 *a, Vector2 *b, Vector2 *c, float d)
 {
     Vector2 *ptr = (Vector2 *)malloc(sizeof(Vector2));
-    *ptr = GetSplinePointBezierQuad(*a, *b, *c, d);
+    *ptr = GetSplinePointBezierQuadratic(*a, *b, *c, d);
     return ptr;
 }
 
@@ -704,7 +739,7 @@
     UnloadImage(*a);
 }
 
-RLBIND int ExportImage_(Image *a, char *b)
+RLBIND bool ExportImage_(Image *a, char *b)
 {
     return ExportImage(*a, b);
 }
@@ -714,7 +749,7 @@
     return ExportImageToMemory(*a, fileType, fileSize);
 }
 
-RLBIND int ExportImageAsCode_(Image *a, char *b)
+RLBIND bool ExportImageAsCode_(Image *a, char *b)
 {
     return ExportImageAsCode(*a, b);
 }
@@ -901,6 +936,16 @@
     ImageDrawLineV(a, *b, *c, *d);
 }
 
+RLBIND void ImageDrawLineEx_(Image *a, Vector2 *b, Vector2 *c, int d, Color *e)
+{
+    ImageDrawLineEx(a, *b, *c, d, *e);
+}
+
+RLBIND void ImageDrawLineStrip_(Image *a, Vector2 *b, int c, Color *d)
+{
+    ImageDrawLineStrip(a, b, c, *d);
+}
+
 RLBIND void ImageDrawCircle_(Image *a, int b, int c, int d, Color *e)
 {
     ImageDrawCircle(a, b, c, d, *e);
@@ -921,6 +966,31 @@
     ImageDrawCircleLinesV(a, *b, c, *d);
 }
 
+RLBIND void ImageDrawCircleGradient_(Image *a, Vector2 *b, float c, Color *d, Color *e)
+{
+    ImageDrawCircleGradient(a, *b, c, *d, *e);
+}
+
+RLBIND void ImageDrawImage_(Image *a, Image *b, int c, int d, Color *e)
+{
+    ImageDrawImage(a, *b, c, d, *e);
+}
+
+RLBIND void ImageDrawImageEx_(Image *a, Image *b, Vector2 *c, float d, float e, Color *f)
+{
+    ImageDrawImageEx(a, *b, *c, d, e, *f);
+}
+
+RLBIND void ImageDrawImageRec_(Image *a, Image *b, Rectangle *c, Vector2 *d, Color *e)
+{
+    ImageDrawImageRec(a, *b, *c, *d, *e);
+}
+
+RLBIND void ImageDrawImagePro_(Image *a, Image *b, Rectangle *c, Rectangle *d, Vector2 *e, float f, Color *g)
+{
+    ImageDrawImagePro(a, *b, *c, *d, *e, f, *g);
+}
+
 RLBIND void ImageDrawRectangle_(Image *a, int b, int c, int d, int e, Color *f)
 {
     ImageDrawRectangle(a, b, c, d, e, *f);
@@ -936,19 +1006,34 @@
     ImageDrawRectangleRec(a, *b, *c);
 }
 
-RLBIND void ImageDrawRectangleLines_(Image *a, Rectangle *b, int c, Color *d)
+RLBIND void ImageDrawRectanglePro_(Image *a, Rectangle *b, Vector2 *c, float d, Color *e)
 {
-    ImageDrawRectangleLines(a, *b, c, *d);
+    ImageDrawRectanglePro(a, *b, *c, d, *e);
 }
 
+RLBIND void ImageDrawRectangleLines_(Image *a, int b, int c, int d, int e, Color *f)
+{
+    ImageDrawRectangleLines(a, b, c, d, e, *f);
+}
+
+RLBIND void ImageDrawRectangleLinesEx_(Image *a, Rectangle *b, int c, Color *d)
+{
+    ImageDrawRectangleLinesEx(a, *b, c, *d);
+}
+
+RLBIND void ImageDrawRectangleGradientEx_(Image *a, Rectangle *b, Color *c, Color *d, Color *e, Color *f)
+{
+    ImageDrawRectangleGradientEx(a, *b, *c, *d, *e, *f);
+}
+
 RLBIND void ImageDrawTriangle_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e)
 {
     ImageDrawTriangle(a, *b, *c, *d, *e);
 }
 
-RLBIND void ImageDrawTriangleEx_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e, Color *f, Color *g)
+RLBIND void ImageDrawTriangleGradient_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e, Color *f, Color *g)
 {
-    ImageDrawTriangleEx(a, *b, *c, *d, *e, *f, *g);
+    ImageDrawTriangleGradient(a, *b, *c, *d, *e, *f, *g);
 }
 
 RLBIND void ImageDrawTriangleLines_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e)
@@ -966,11 +1051,6 @@
     ImageDrawTriangleStrip(a, b, c, *d);
 }
 
-RLBIND void ImageDraw_(Image *a, Image *b, Rectangle *c, Rectangle *d, Color *e)
-{
-    ImageDraw(a, *b, *c, *d, *e);
-}
-
 RLBIND void ImageDrawText_(Image *a, char *b, int c, int d, int e, Color *f)
 {
     ImageDrawText(a, b, c, d, e, *f);
@@ -981,6 +1061,11 @@
     ImageDrawTextEx(a, *b, c, *d, e, f, *g);
 }
 
+RLBIND void ImageDrawTextPro_(Image *a, Font *b, char *c, Vector2 *d, Vector2 *e, float f, float g, float h, Color *i)
+{
+    ImageDrawTextPro(a, *b, c, *d, *e, f, g, h, *i);
+}
+
 RLBIND Texture *LoadTexture_(char *a)
 {
     Texture *ptr = (Texture *)malloc(sizeof(Texture));
@@ -1009,6 +1094,13 @@
     return ptr;
 }
 
+RLBIND RenderTexture *LoadRenderTextureEx_(int a, int b, int c)
+{
+    RenderTexture *ptr = (RenderTexture *)malloc(sizeof(RenderTexture));
+    *ptr = LoadRenderTextureEx(a, b, c);
+    return ptr;
+}
+
 RLBIND bool IsTextureValid_(Texture *a)
 {
     return IsTextureValid(*a);
@@ -1253,7 +1345,7 @@
     UnloadFont(*a);
 }
 
-RLBIND int ExportFontAsCode_(Font *a, char *b)
+RLBIND bool ExportFontAsCode_(Font *a, char *b)
 {
     return ExportFontAsCode(*a, b);
 }
@@ -1290,6 +1382,13 @@
     return ptr;
 }
 
+RLBIND Vector2 *MeasureTextCodepoints_(Font *a, int *b, int c, float d, float e)
+{
+    Vector2 *ptr = (Vector2 *)malloc(sizeof(Vector2));
+    *ptr = MeasureTextCodepoints(*a, b, c, d, e);
+    return ptr;
+}
+
 RLBIND int GetGlyphIndex_(Font *a, int b)
 {
     return GetGlyphIndex(*a, b);
@@ -1460,16 +1559,6 @@
     DrawModelWiresEx(*a, *b, *c, d, *e, *f);
 }
 
-RLBIND void DrawModelPoints_(Model *a, Vector3 *b, float c, Color *d)
-{
-    DrawModelPoints(*a, *b, c, *d);
-}
-
-RLBIND void DrawModelPointsEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f)
-{
-    DrawModelPointsEx(*a, *b, *c, d, *e, *f);
-}
-
 RLBIND void DrawBoundingBox_(BoundingBox *a, Color *b)
 {
     DrawBoundingBox(*a, *b);
@@ -1626,14 +1715,14 @@
     SetMaterialTexture(a, b, *c);
 }
 
-RLBIND void UpdateModelAnimation_(Model *a, ModelAnimation *b, int c)
+RLBIND void UpdateModelAnimation_(Model *a, ModelAnimation *b, float c)
 {
     UpdateModelAnimation(*a, *b, c);
 }
 
-RLBIND void UnloadModelAnimation_(ModelAnimation *a)
+RLBIND void UpdateModelAnimationEx_(Model *a, ModelAnimation *b, float c, ModelAnimation *d, float e, float f)
 {
-    UnloadModelAnimation(*a);
+    UpdateModelAnimationEx(*a, *b, c, *d, e, f);
 }
 
 RLBIND bool IsModelAnimationValid_(Model *a, ModelAnimation *b)
@@ -1641,11 +1730,6 @@
     return IsModelAnimationValid(*a, *b);
 }
 
-RLBIND void UpdateModelAnimationBones_(Model *a, ModelAnimation *b, int c)
-{
-    UpdateModelAnimationBones(*a, *b, c);
-}
-
 RLBIND bool CheckCollisionSpheres_(Vector3 *a, float b, Vector3 *c, float d)
 {
     return CheckCollisionSpheres(*a, b, *c, d);
@@ -1761,12 +1845,12 @@
     UnloadSoundAlias(*a);
 }
 
-RLBIND int ExportWave_(Wave *a, char *b)
+RLBIND bool ExportWave_(Wave *a, char *b)
 {
     return ExportWave(*a, b);
 }
 
-RLBIND int ExportWaveAsCode_(Wave *a, char *b)
+RLBIND bool ExportWaveAsCode_(Wave *a, char *b)
 {
     return ExportWaveAsCode(*a, b);
 }
@@ -1791,7 +1875,7 @@
     ResumeSound(*a);
 }
 
-RLBIND int IsSoundPlaying_(Sound *a)
+RLBIND bool IsSoundPlaying_(Sound *a)
 {
     return IsSoundPlaying(*a);
 }
@@ -1852,7 +1936,7 @@
     PlayMusicStream(*a);
 }
 
-RLBIND int IsMusicStreamPlaying_(Music *a)
+RLBIND bool IsMusicStreamPlaying_(Music *a)
 {
     return IsMusicStreamPlaying(*a);
 }
@@ -1929,7 +2013,7 @@
     UpdateAudioStream(*a, b, c);
 }
 
-RLBIND int IsAudioStreamProcessed_(AudioStream *a)
+RLBIND bool IsAudioStreamProcessed_(AudioStream *a)
 {
     return IsAudioStreamProcessed(*a);
 }
@@ -1949,7 +2033,7 @@
     ResumeAudioStream(*a);
 }
 
-RLBIND int IsAudioStreamPlaying_(AudioStream *a)
+RLBIND bool IsAudioStreamPlaying_(AudioStream *a)
 {
     return IsAudioStreamPlaying(*a);
 }
@@ -2527,11 +2611,21 @@
     return IsFileExtension(a, b);
 }
 
+RLBIND bool IsFileHidden_(const char *a)
+{
+    return IsFileHidden(a);
+}
+
 RLBIND int GetFileLength_(const char *a)
 {
     return GetFileLength(a);
 }
 
+RLBIND long GetFileModTime_(const char *a)
+{
+    return GetFileModTime(a);
+}
+
 RLBIND const char *GetFileExtension_(const char *a)
 {
     return GetFileExtension(a);
@@ -2572,7 +2666,7 @@
     return MakeDirectory(a);
 }
 
-RLBIND bool ChangeDirectory_(const char *a)
+RLBIND int ChangeDirectory_(const char *a)
 {
     return ChangeDirectory(a);
 }
@@ -2592,11 +2686,6 @@
     return IsFileDropped();
 }
 
-RLBIND long GetFileModTime_(const char *a)
-{
-    return GetFileModTime(a);
-}
-
 RLBIND unsigned char *CompressData_(const unsigned char *a, int b, int *c)
 {
     return CompressData(a, b, c);
@@ -2617,21 +2706,26 @@
     return DecodeDataBase64(a, b);
 }
 
-RLBIND unsigned int ComputeCRC32_(unsigned char *a, int b)
+RLBIND unsigned int ComputeCRC32_(const unsigned char *a, int b)
 {
     return ComputeCRC32(a, b);
 }
 
-RLBIND unsigned int *ComputeMD5_(unsigned char *a, int b)
+RLBIND unsigned int *ComputeMD5_(const unsigned char *a, int b)
 {
     return ComputeMD5(a, b);
 }
 
-RLBIND unsigned int *ComputeSHA1_(unsigned char *a, int b)
+RLBIND unsigned int *ComputeSHA1_(const unsigned char *a, int b)
 {
     return ComputeSHA1(a, b);
 }
 
+RLBIND unsigned int *ComputeSHA256_(const unsigned char *a, int b)
+{
+    return ComputeSHA256(a, b);
+}
+
 RLBIND void SetAutomationEventList_(AutomationEventList *a)
 {
     SetAutomationEventList(a);
@@ -2937,7 +3031,7 @@
     ImageColorGrayscale(a);
 }
 
-RLBIND void ImageColorContrast_(Image *a, float b)
+RLBIND void ImageColorContrast_(Image *a, int b)
 {
     ImageColorContrast(a, b);
 }
diff --git a/lib/rl_bindings.h b/lib/rl_bindings.h
--- a/lib/rl_bindings.h
+++ b/lib/rl_bindings.h
@@ -82,6 +82,10 @@
 
 void UnloadDroppedFiles_(FilePathList *a);
 
+unsigned int GetDirectoryFileCount_(const char *a);
+
+unsigned int GetDirectoryFileCountEx_(const char *a, const char *b, bool c);
+
 AutomationEventList *LoadAutomationEventList_(char *a);
 
 void UnloadAutomationEventList_(AutomationEventList *a);
@@ -132,14 +136,18 @@
 
 void DrawCircleSectorLines_(Vector2 *a, float b, float c, float d, int e, Color *f);
 
-void DrawCircleGradient_(int a, int b, float c, Color *d, Color *e);
+void DrawCircleSectorLinesEx_(Vector2 *a, float b, float c, float d, int e, float f, Color *g);
 
+void DrawCircleGradient_(Vector2 *a, float b, Color *c, Color *d);
+
 void DrawCircleV_(Vector2 *a, float b, Color *c);
 
 void DrawCircleLines_(int a, int b, float c, Color *d);
 
 void DrawCircleLinesV_(Vector2 *a, float b, Color *c);
 
+void DrawCircleLinesEx_(Vector2 *a, float b, float c, Color *d);
+
 void DrawEllipse_(int a, int b, float c, float d, Color *e);
 
 void DrawEllipseV_(Vector2 *a, float b, float c, Color *d);
@@ -152,6 +160,8 @@
 
 void DrawRingLines_(Vector2 *a, float b, float c, float d, float e, int f, Color *g);
 
+void DrawRingLinesEx_(Vector2 *a, float b, float c, float d, float e, int f, float g, Color *h);
+
 void DrawRectangle_(int a, int b, int c, int d, Color *e);
 
 void DrawRectangleV_(Vector2 *a, Vector2 *b, Color *c);
@@ -178,8 +188,12 @@
 
 void DrawTriangle_(Vector2 *a, Vector2 *b, Vector2 *c, Color *d);
 
+void DrawTriangleGradient_(Vector2 *a, Vector2 *b, Vector2 *c, Color *d, Color *e, Color *f);
+
 void DrawTriangleLines_(Vector2 *a, Vector2 *b, Vector2 *c, Color *d);
 
+void DrawTriangleLinesEx_(Vector2 *a, Vector2 *b, Vector2 *c, float d, Color *e);
+
 void DrawTriangleFan_(const Vector2 *a, int b, Color *c);
 
 void DrawTriangleStrip_(const Vector2 *a, int b, Color *c);
@@ -216,7 +230,7 @@
 
 Vector2 *GetSplinePointCatmullRom_(Vector2 *a, Vector2 *b, Vector2 *c, Vector2 *d, float e);
 
-Vector2 *GetSplinePointBezierQuad_(Vector2 *a, Vector2 *b, Vector2 *c, float d);
+Vector2 *GetSplinePointBezierQuadratic_(Vector2 *a, Vector2 *b, Vector2 *c, float d);
 
 Vector2 *GetSplinePointBezierCubic_(Vector2 *a, Vector2 *b, Vector2 *c, Vector2 *d, float e);
 
@@ -260,11 +274,11 @@
 
 void UnloadImage_(Image *a);
 
-int ExportImage_(Image *a, char *b);
+bool ExportImage_(Image *a, char *b);
 
 unsigned char *ExportImageToMemory_(Image *a, char *fileType, int *fileSize);
 
-int ExportImageAsCode_(Image *a, char *b);
+bool ExportImageAsCode_(Image *a, char *b);
 
 Image *GenImageColor_(int a, int b, Color *c);
 
@@ -326,6 +340,10 @@
 
 void ImageDrawLineV_(Image *a, Vector2 *b, Vector2 *c, Color *d);
 
+void ImageDrawLineEx_(Image *a, Vector2 *b, Vector2 *c, int d, Color *e);
+
+void ImageDrawLineStrip_(Image *a, Vector2 *b, int c, Color *d);
+
 void ImageDrawCircle_(Image *a, int b, int c, int d, Color *e);
 
 void ImageDrawCircleV_(Image *a, Vector2 *b, int c, Color *d);
@@ -334,17 +352,33 @@
 
 void ImageDrawCircleLinesV_(Image *a, Vector2 *b, int c, Color *d);
 
+void ImageDrawCircleGradient_(Image *a, Vector2 *b, float c, Color *d, Color *e);
+
+void ImageDrawImage_(Image *a, Image *b, int c, int d, Color *e);
+
+void ImageDrawImageEx_(Image *a, Image *b, Vector2 *c, float d, float e, Color *f);
+
+void ImageDrawImageRec_(Image *a, Image *b, Rectangle *c, Vector2 *d, Color *e);
+
+void ImageDrawImagePro_(Image *a, Image *b, Rectangle *c, Rectangle *d, Vector2 *e, float f, Color *g);
+
 void ImageDrawRectangle_(Image *a, int b, int c, int d, int e, Color *f);
 
 void ImageDrawRectangleV_(Image *a, Vector2 *b, Vector2 *c, Color *d);
 
 void ImageDrawRectangleRec_(Image *a, Rectangle *b, Color *c);
 
-void ImageDrawRectangleLines_(Image *a, Rectangle *b, int c, Color *d);
+void ImageDrawRectanglePro_(Image *a, Rectangle *b, Vector2 *c, float d, Color *e);
 
+void ImageDrawRectangleLines_(Image *a, int b, int c, int d, int e, Color *f);
+
+void ImageDrawRectangleLinesEx_(Image *a, Rectangle *b, int c, Color *d);
+
+void ImageDrawRectangleGradientEx_(Image *a, Rectangle *b, Color *c, Color *d, Color *e, Color *f);
+
 void ImageDrawTriangle_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e);
 
-void ImageDrawTriangleEx_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e, Color *f, Color *g);
+void ImageDrawTriangleGradient_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e, Color *f, Color *g);
 
 void ImageDrawTriangleLines_(Image *a, Vector2 *b, Vector2 *c, Vector2 *d, Color *e);
 
@@ -352,12 +386,12 @@
 
 void ImageDrawTriangleStrip_(Image *a, Vector2 *b, int c, Color *d);
 
-void ImageDraw_(Image *a, Image *b, Rectangle *c, Rectangle *d, Color *e);
-
 void ImageDrawText_(Image *a, char *b, int c, int d, int e, Color *f);
 
 void ImageDrawTextEx_(Image *a, Font *b, char *c, Vector2 *d, float e, float f, Color *g);
 
+void ImageDrawTextPro_(Image *a, Font *b, char *c, Vector2 *d, Vector2 *e, float f, float g, float h, Color *i);
+
 Texture *LoadTexture_(char *a);
 
 Texture *LoadTextureFromImage_(Image *a);
@@ -366,6 +400,8 @@
 
 RenderTexture *LoadRenderTexture_(int a, int b);
 
+RenderTexture *LoadRenderTextureEx_(int a, int b, int c);
+
 bool IsTextureValid_(Texture *a);
 
 void UnloadTexture_(Texture *a);
@@ -406,6 +442,12 @@
 
 Color *ColorFromHSV_(float a, float b, float c);
 
+Color *ColorTint_(Color *a, Color *b);
+
+Color *ColorBrightness_(Color *a, float b);
+
+Color *ColorContrast_(Color *a, float b);
+
 Color *ColorAlpha_(Color *a, float b);
 
 Color *ColorAlphaBlend_(Color *a, Color *b, Color *c);
@@ -436,7 +478,7 @@
 
 void UnloadFont_(Font *a);
 
-int ExportFontAsCode_(Font *a, char *b);
+bool ExportFontAsCode_(Font *a, char *b);
 
 void DrawText_(char *a, int b, int c, int d, Color *e);
 
@@ -450,6 +492,8 @@
 
 Vector2 *MeasureTextEx_(Font *a, char *b, float c, float d);
 
+Vector2 *MeasureTextCodepoints_(Font *a, int *b, int c, float d, float e);
+
 int GetGlyphIndex_(Font *a, int b);
 
 GlyphInfo *GetGlyphInfo_(Font *a, int b);
@@ -474,10 +518,6 @@
 
 void DrawCubeWiresV_(Vector3 *a, Vector3 *b, Color *c);
 
-void DrawCubeTexture_(Texture *a, Vector3 *b, float c, float d, float e, Color *f);
-
-void DrawCubeTextureRec_(Texture *a, Rectangle *b, Vector3 *c, float d, float e, float f, Color *g);
-
 void DrawSphere_(Vector3 *a, float b, Color *c);
 
 void DrawSphereEx_(Vector3 *a, float b, int c, int d, Color *e);
@@ -494,8 +534,6 @@
 
 void DrawCapsule_(Vector3 *a, Vector3 *b, float c, int d, int e, Color *f);
 
-void DrawCapsuleEx_(Vector3 *a, Vector3 *b, float c, int d, int e, Color *f);
-
 void DrawPlane_(Vector3 *a, Vector2 *b, Color *c);
 
 void DrawRay_(Ray *a, Color *b);
@@ -518,10 +556,6 @@
 
 void DrawModelWiresEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f);
 
-void DrawModelPoints_(Model *a, Vector3 *b, float c, Color *d);
-
-void DrawModelPointsEx_(Model *a, Vector3 *b, Vector3 *c, float d, Vector3 *e, Color *f);
-
 void DrawBoundingBox_(BoundingBox *a, Color *b);
 
 void DrawBillboard_(Camera3D *a, Texture *b, Vector3 *c, float d, Color *e);
@@ -574,14 +608,12 @@
 
 void SetMaterialTexture_(Material *a, int b, Texture *c);
 
-void UpdateModelAnimation_(Model *a, ModelAnimation *b, int c);
+void UpdateModelAnimation_(Model *a, ModelAnimation *b, float c);
 
-void UnloadModelAnimation_(ModelAnimation *a);
+void UpdateModelAnimationEx_(Model *a, ModelAnimation *b, float c, ModelAnimation *d, float e, float f);
 
 bool IsModelAnimationValid_(Model *a, ModelAnimation *b);
 
-void UpdateModelAnimationBones_(Model *a, ModelAnimation *b, int c);
-
 bool CheckCollisionSpheres_(Vector3 *a, float b, Vector3 *c, float d);
 
 bool CheckCollisionBoxes_(BoundingBox *a, BoundingBox *b);
@@ -620,9 +652,9 @@
 
 void UnloadSoundAlias_(Sound *a);
 
-int ExportWave_(Wave *a, char *b);
+bool ExportWave_(Wave *a, char *b);
 
-int ExportWaveAsCode_(Wave *a, char *b);
+bool ExportWaveAsCode_(Wave *a, char *b);
 
 void PlaySound_(Sound *a);
 
@@ -632,7 +664,7 @@
 
 void ResumeSound_(Sound *a);
 
-int IsSoundPlaying_(Sound *a);
+bool IsSoundPlaying_(Sound *a);
 
 void SetSoundVolume_(Sound *a, float b);
 
@@ -654,7 +686,7 @@
 
 void PlayMusicStream_(Music *a);
 
-int IsMusicStreamPlaying_(Music *a);
+bool IsMusicStreamPlaying_(Music *a);
 
 void UpdateMusicStream_(Music *a);
 
@@ -684,7 +716,7 @@
 
 void UpdateAudioStream_(AudioStream *a, const void *b, int c);
 
-int IsAudioStreamProcessed_(AudioStream *a);
+bool IsAudioStreamProcessed_(AudioStream *a);
 
 void PlayAudioStream_(AudioStream *a);
 
@@ -692,7 +724,7 @@
 
 void ResumeAudioStream_(AudioStream *a);
 
-int IsAudioStreamPlaying_(AudioStream *a);
+bool IsAudioStreamPlaying_(AudioStream *a);
 
 void StopAudioStream_(AudioStream *a);
 
@@ -910,10 +942,16 @@
 
 int FileTextFindIndex_(const char *a, const char *b);
 
+bool DirectoryExists_(const char *a);
+
 bool IsFileExtension_(const char *a, const char *b);
 
+bool IsFileHidden_(const char *a);
+
 int GetFileLength_(const char *a);
 
+long GetFileModTime_(const char *a);
+
 const char *GetFileExtension_(const char *a);
 
 const char *GetFileName_(const char *a);
@@ -930,7 +968,7 @@
 
 int MakeDirectory_(const char *a);
 
-bool ChangeDirectory_(const char *a);
+int ChangeDirectory_(const char *a);
 
 bool IsPathFile_(const char *a);
 
@@ -938,8 +976,6 @@
 
 bool IsFileDropped_();
 
-long GetFileModTime_(const char *a);
-
 unsigned char *CompressData_(const unsigned char *a, int b, int *c);
 
 unsigned char *DecompressData_(const unsigned char *a, int b, int *c);
@@ -948,12 +984,14 @@
 
 unsigned char *DecodeDataBase64_(const char *a, int *b);
 
-unsigned int ComputeCRC32_(unsigned char *a, int b);
+unsigned int ComputeCRC32_(const unsigned char *a, int b);
 
-unsigned int *ComputeMD5_(unsigned char *a, int b);
+unsigned int *ComputeMD5_(const unsigned char *a, int b);
 
-unsigned int *ComputeSHA1_(unsigned char *a, int b);
+unsigned int *ComputeSHA1_(const unsigned char *a, int b);
 
+unsigned int *ComputeSHA256_(const unsigned char *a, int b);
+
 void SetAutomationEventList_(AutomationEventList *a);
 
 void SetAutomationEventBaseFrame_(int a);
@@ -1076,7 +1114,7 @@
 
 void ImageColorGrayscale_(Image *a);
 
-void ImageColorContrast_(Image *a, float b);
+void ImageColorContrast_(Image *a, int b);
 
 void ImageColorBrightness_(Image *a, int b);
 
diff --git a/lib/rlgl_bindings.c b/lib/rlgl_bindings.c
--- a/lib/rlgl_bindings.c
+++ b/lib/rlgl_bindings.c
@@ -529,21 +529,31 @@
   rlUnloadFramebuffer(a);
 }
 
-RLBIND unsigned int rlLoadShaderCode_(const char *a, const char *b)
+RLBIND unsigned int rlLoadShader_(const char *a, int b)
 {
-  return rlLoadShaderCode(a, b);
+  return rlLoadShader(a, b);
 }
 
-RLBIND unsigned int rlCompileShader_(const char *a, int b)
+RLBIND unsigned int rlLoadShaderProgram_(const char *a, const char *b)
 {
-  return rlCompileShader(a, b);
+  return rlLoadShaderProgram(a, b);
 }
 
-RLBIND unsigned int rlLoadShaderProgram_(unsigned int a, unsigned int b)
+RLBIND unsigned int rlLoadShaderProgramEx_(unsigned int a, unsigned int b)
 {
-  return rlLoadShaderProgram(a, b);
+  return rlLoadShaderProgramEx(a, b);
 }
 
+RLBIND unsigned int rlLoadShaderProgramCompute_(unsigned int a)
+{
+  return rlLoadShaderProgramCompute(a);
+}
+
+RLBIND void rlUnloadShader_(unsigned int a)
+{
+  rlUnloadShader(a);
+}
+
 RLBIND void rlUnloadShaderProgram_(unsigned int a)
 {
   rlUnloadShaderProgram(a);
@@ -572,11 +582,6 @@
 RLBIND void rlSetShader_(unsigned int a, int *b)
 {
   rlSetShader(a, b);
-}
-
-RLBIND unsigned int rlLoadComputeShaderProgram_(unsigned int a)
-{
-  return rlLoadComputeShaderProgram(a);
 }
 
 RLBIND void rlComputeShaderDispatch_(unsigned int a, unsigned int b, unsigned int c)
diff --git a/lib/rlgl_bindings.h b/lib/rlgl_bindings.h
--- a/lib/rlgl_bindings.h
+++ b/lib/rlgl_bindings.h
@@ -212,12 +212,16 @@
 
 void rlUnloadFramebuffer_(unsigned int a);
 
-unsigned int rlLoadShaderCode_(const char *a, const char *b);
+unsigned int rlLoadShader_(const char *a, int b);
 
-unsigned int rlCompileShader_(const char *a, int b);
+unsigned int rlLoadShaderProgram_(const char *a, const char *b);
 
-unsigned int rlLoadShaderProgram_(unsigned int a, unsigned int b);
+unsigned int rlLoadShaderProgramEx_(unsigned int a, unsigned int b);
 
+unsigned int rlLoadShaderProgramCompute_(unsigned int a);
+
+void rlUnloadShader_(unsigned int a);
+
 void rlUnloadShaderProgram_(unsigned int a);
 
 int rlGetLocationUniform_(unsigned int a, const char *b);
@@ -229,8 +233,6 @@
 void rlSetUniformSampler_(int a, unsigned int b);
 
 void rlSetShader_(unsigned int a, int *b);
-
-unsigned int rlLoadComputeShaderProgram_(unsigned int a);
 
 void rlComputeShaderDispatch_(unsigned int a, unsigned int b, unsigned int c);
 
diff --git a/raygui/src/raygui.h b/raygui/src/raygui.h
--- a/raygui/src/raygui.h
+++ b/raygui/src/raygui.h
@@ -1,5949 +1,6425 @@
 /*******************************************************************************************
 *
-*   raygui v4.5-dev - 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        --> 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 set we have the EXTENDED properties (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_DEBUG_RECS_BOUNDS
-*           Draw control bounds rectangles for debug
-*
-*       #define RAYGUI_DEBUG_TEXT_BOUNDS
-*           Draw text bounds rectangles for debug
-*
-*   VERSIONS HISTORY:
-*       5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
-*                         ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
-*                         ADDED: GuiValueBoxFloat()
-*                         ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
-*                         ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
-*                         ADDED: GuiLoadIconsFromMemory()
-*                         ADDED: Multiple new icons
-*                         REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
-*                         REMOVED: GuiSliderPro(), functionality was redundant
-*                         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
-*                         REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
-*
-*       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 5.6-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 4
-#define RAYGUI_VERSION_MINOR 5
-#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION  "5.0-dev"
-
-#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)     // We are building the library as a Win32 shared library (.dll)
-    #elif defined(USE_LIBTYPE_SHARED)
-        #define RAYGUIAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
-    #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
-
-//----------------------------------------------------------------------------------
-// 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;
-
-    // Rectangle type
-    typedef struct Rectangle {
-        float x;
-        float y;
-        float width;
-        float height;
-    } Rectangle;
-
-    // TODO: 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;
-
-    // TODO: 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 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
-typedef enum {
-    // Default -> populates to all controls when set
-    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
-} GuiControl;
-
-// Gui base properties for every control
-// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
-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
-} 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)
-//----------------------------------------------------------------------------------
-// DEFAULT extended properties
-// NOTE: Those properties are common to all controls or global
-// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
-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
-} GuiDefaultProperty;
-
-// Other possible text properties:
-// TEXT_WEIGHT                  // Normal, Italic, Bold -> Requires specific font change
-// TEXT_INDENT                  // Text indentation -> Now using TEXT_PADDING...
-
-// Label
-//typedef enum { } GuiLabelProperty;
-
-// Button/Spinner
-//typedef enum { } GuiButtonProperty;
-
-// Toggle/ToggleGroup
-typedef enum {
-    GROUP_PADDING = 16,         // ToggleGroup separation between toggles
-} 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
-} 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 (default rolls down)
-} GuiDropdownBoxProperty;
-
-// TextBox/TextBoxMulti/ValueBox/Spinner
-typedef enum {
-    TEXT_READONLY = 16,         // TextBox in read-only mode: 0-text editable, 1-text no-editable
-} GuiTextBoxProperty;
-
-// ValueBox/Spinner
-typedef enum {
-    SPINNER_BUTTON_WIDTH = 16,  // Spinner left/right buttons width
-    SPINNER_BUTTON_SPACING,     // Spinner buttons separation
-} GuiValueBoxProperty;
-
-// Control11
-//typedef enum { } GuiControl11Property;
-
-// ListView
-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)
-    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,
-    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
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// 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 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 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 GuiTabBar(Rectangle bounds, const 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
-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, const 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 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()
-//----------------------------------------------------------------------------------------------------------
-
-#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_250                      = 250,
-    ICON_251                      = 251,
-    ICON_252                      = 252,
-    ICON_253                      = 253,
-    ICON_254                      = 254,
-    ICON_255                      = 255
-} GuiIconName;
-#endif
-
-#endif
-
-#if defined(__cplusplus)
-}            // Prevents name mangling of functions
-#endif
-
-#endif // RAYGUI_H
-
-/***********************************************************************************
-*
-*   RAYGUI IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RAYGUI_IMPLEMENTATION)
-
-#include <ctype.h>              // required for: isspace() [GuiTextBox()]
-#include <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
-#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
-#include <math.h>               // Required for: roundf() [GuiColorPicker()]
-
-// 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 <stdlib.h>             // 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         256          // Maximum number of icons
-#define RAYGUI_ICON_MAX_NAME_LENGTH    32          // Maximum length of icon name id
-
-// 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: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 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
-    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
-};
-
-// 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 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 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()
-//-------------------------------------------------------------------------------
-
-// raylib functions already implemented in raygui
-//-------------------------------------------------------------------------------
-static Color GetColor(int hexValue);                // Returns a Color struct from hexadecimal value
-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 const 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
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize);    // Load style from memory (binary only)
-
-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 const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow);   // 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 Color GuiFade(Color color, float alpha);         // Fade color by an alpha factor
-
-//----------------------------------------------------------------------------------
-// Gui Setup Functions Definition
-//----------------------------------------------------------------------------------
-// Enable gui global state
-// NOTE: We check 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: We check 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 we try to setup a font but default style has not been
-        // lazily loaded before, it will be overwritten, so we need to force
-        // default style loading 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 = 0;
-    //GuiState state = guiState;
-
-    int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
-
-    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 - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
-    Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 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
-    //--------------------------------------------------------------------
-    GuiStatusBar(statusBar, title); // Draw window header as status bar
-    GuiPanel(windowPanel, NULL);    // Draw window base
-
-    // Draw window close button
-    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)
-    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;      // Window close button clicked: result = 1
-}
-
-// 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 = 0;
-    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 = 0;
-    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 = 0;
-    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) 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;
-}
-
-// Tab Bar control
-// NOTE: Using GuiToggle() for the TABS
-int GuiTabBar(Rectangle bounds, const 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(GetMousePosition(), 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)
-{
-    #define RAYGUI_MIN_SCROLLBAR_WIDTH     40
-    #define RAYGUI_MIN_SCROLLBAR_HEIGHT    40
-    #define RAYGUI_MIN_MOUSE_WHEEL_SPEED   20
-
-    int result = 0;
-    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 = hasVerticalScrollBar? 0.0f : -1.0f;
-    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 = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
-            if (hasHorizontalScrollBar)
-            {
-                if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-
-            if (hasVerticalScrollBar)
-            {
-                if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-#endif
-            float wheelMove = GetMouseWheelMove();
-
-            // Set scrolling speed with mouse wheel based on ratio between bounds and content
-            Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
-            if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-            if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-
-            // Horizontal and vertical scrolling with mouse wheel
-            if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
-            else scrollPos.y += wheelMove*mouseWheelSpeed.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) 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Button pressed: result = 1
-}
-
-// Label button control
-int GuiLabelButton(Rectangle bounds, const char *text)
-{
-    GuiState state = guiState;
-    bool pressed = false;
-
-    // NOTE: We 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 = GetMousePosition();
-
-        // Check checkbox state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
-    //--------------------------------------------------------------------
-
-    return pressed;
-}
-
-// Toggle Button control
-int GuiToggle(Rectangle bounds, const char *text, bool *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    bool temp = false;
-    if (active == NULL) active = &temp;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check toggle button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                state = STATE_NORMAL;
-                *active = !(*active);
-            }
-            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)
-{
-    #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
-        #define RAYGUI_TOGGLEGROUP_MAX_ITEMS    32
-    #endif
-
-    int result = 0;
-    float initBoundsX = bounds.x;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, rows);
-
-    int prevRow = rows[0];
-
-    for (int i = 0; i < itemCount; i++)
-    {
-        if (prevRow != rows[i])
-        {
-            bounds.x = initBoundsX;
-            bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
-            prevRow = rows[i];
-        }
-
-        if (i == (*active))
-        {
-            toggle = true;
-            GuiToggle(bounds, items[i], &toggle);
-        }
-        else
-        {
-            toggle = false;
-            GuiToggle(bounds, items[i], &toggle);
-            if (toggle) *active = i;
-        }
-
-        bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
-    }
-
-    return result;
-}
-
-// Toggle Slider control extended
-int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    if (active == NULL) active = &temp;
-
-    //bool toggle = false;    // Required for individual toggles
-
-    // Get substrings items from text (items pointers)
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = GetMousePosition();
-
-        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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                *checked = !(*checked);
-                result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds) ||
-            CheckCollisionPointRec(mousePoint, selector))
-        {
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                *active += 1;
-                if (*active >= itemCount) *active = 0;      // Cyclic combobox
-            }
-
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            // Check if mouse has been pressed or released outside limits
-            if (!CheckCollisionPointRec(mousePoint, boundsOpen))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-
-            // Check if already selected item has been pressed again
-            if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) 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 (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-                    {
-                        itemSelected = i;
-                        result = 1;         // Item selected
-                    }
-                    break;
-                }
-            }
-
-            itemBounds = bounds;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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? "#121#" : "#120#", 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;
-
-    // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
-    return result;   // Mouse click: result = 1
-}
-
-// 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 = 0;
-    GuiState state = guiState;
-
-    bool multiline = false; // TODO: Consider multiline text input
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            // GLOBAL: Auto-cursor movement logic
-            // NOTE: Keystrokes are handled repeatedly when button is held down for some time
-            if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(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,
-            // we add 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 = GetCharPressed();       // Get Unicode codepoint
-            if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
-
-            // Encode codepoint as UTF-8
-            int codepointSize = 0;
-            const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
-
-            // Handle text paste action
-            if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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';
-                    }
-                }
-            }
-            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';
-            }
-
-            // Move cursor to start
-            if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
-
-            // Move cursor to end
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
-
-            // Delete related codepoints from text, after current cursor position
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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;
-            }
-
-            else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(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;
-            }
-
-            // Delete related codepoints from text, before current cursor position
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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;
-            }
-
-            else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(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;
-            }
-
-            // Move cursor position with keys
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
-            {
-                int prevCodepointSize = 0;
-                GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
-
-                textBoxCursorIndex -= prevCodepointSize;
-            }
-            else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
-            {
-                int nextCodepointSize = 0;
-                GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
-                textBoxCursorIndex += nextCodepointSize;
-            }
-
-            // Move cursor position with mouse
-            if (CheckCollisionPointRec(mousePosition, textBounds))     // Mouse hover text
-            {
-                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 (GetMousePosition().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) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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 && IsKeyPressed(KEY_ENTER)) ||
-                (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                textBoxCursorIndex = 0;     // GLOBAL: Reset the shared cursor index
-                autoCursorCounter = 0;      // GLOBAL: Reset counter for repeated keystrokes
-                result = 1;
-            }
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePosition, bounds))
-            {
-                state = STATE_FOCUSED;
-
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    textBoxCursorIndex = textLength;   // GLOBAL: Place cursor index to the end of current text
-                    autoCursorCounter = 0;             // GLOBAL: Reset counter for repeated keystrokes
-                    result = 1;
-                }
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Mouse button pressed: result = 1
-}
-
-/*
-// 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 = GetMousePosition();
-
-        // Check spinner state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) 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))));
-    //--------------------------------------------------------------------
-
-    *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;
-    GuiState state = guiState;
-
-    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 = GetMousePosition();
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-
-                // Only allow keys in range [48..57]
-                if ((key >= 48) && (key <= 57))
-                {
-                    textValue[keyCount] = (char)key;
-                    keyCount++;
-                    valueHasChanged = true;
-                }
-            }
-
-            // Delete text
-            if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
-            {
-                keyCount--;
-                textValue[keyCount] = '\0';
-                valueHasChanged = true;
-            }
-
-            if (valueHasChanged) *value = TextToInteger(textValue);
-
-            // NOTE: We are not clamp values until user input finishes
-            //if (*value > maxValue) *value = maxValue;
-            //else if (*value < minValue) *value = minValue;
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                if (*value > maxValue) *value = maxValue;
-                else if (*value < minValue) *value = minValue;
-
-                result = 1;
-            }
-        }
-        else
-        {
-            if (*value > maxValue) *value = maxValue;
-            else if (*value < minValue) *value = minValue;
-
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-// 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;
-    GuiState state = guiState;
-
-    //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
-    //snprintf(textValue, sizeof(textValue), "%2.2f", *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 = GetMousePosition();
-
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                    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 (IsKeyPressed(KEY_BACKSPACE))
-            {
-                if (keyCount > 0)
-                {
-                    keyCount--;
-                    textValue[keyCount] = '\0';
-                    valueHasChanged = true;
-                }
-            }
-
-            if (valueHasChanged) *value = TextToFloat(textValue);
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-    float oldValue = *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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    }
-
-    // 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
-    {
-        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);
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-
-    // 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));
-    //--------------------------------------------------------------------
-
-    // 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)
-        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 = 0;
-    GuiState state = guiState;
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
-
-    return result;
-}
-
-// List View control with extended parameters
-int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int itemFocused = (focus == NULL)? -1 : *focus;
-    int itemSelected = (active == NULL)? -1 : *active;
-
-    // Check if we need a scroll bar
-    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 = GetMousePosition();
-
-        // 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 (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                    {
-                        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)
-            {
-                int wheelMove = (int)GetMouseWheelMove();
-                startIndex -= wheelMove;
-
-                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(DEFAULT, 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
-            }
-            else if (((startIndex + i) == itemFocused)) // && (focus != NULL))  // NOTE: We want 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
-            }
-            else
-            {
-                // Draw item normal (no rectangle)
-                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, 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;
-
-    return result;
-}
-
-// Color Panel control - Color (RGBA) variant
-int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
-{
-    int result = 0;
-
-    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
-
-    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)
-    {
-        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 };
-    }
-    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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_UP))
-            {
-                hue -= 2.0f;
-                if (hue <= 0.0f) hue = 0.0f;
-            }
-            else if (IsKeyDown(KEY_DOWN))
-            {
-                hue += 2.0f;
-                if (hue >= 360.0f) hue = 360.0f;
-            }*/
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    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));
-    }
-    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);
-
-    // 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 = 0;
-
-    Color temp = { 200, 0, 0, 255 };
-    if (color == NULL) color = &temp;
-
-    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 });
-
-    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 = 0;
-
-    Vector3 tempHsv = { 0 };
-
-    if (colorHsv == NULL)
-    {
-        const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
-        tempHsv = ConvertRGBtoHSV(tempColor);
-        colorHsv = &tempHsv;
-    }
-
-    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 };
-
-    GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
-
-    return result;
-}
-
-// Color Panel control - HSV variant
-int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
-{
-    int result = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
-{
-    #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 = -1;    // Returns clicked button from buttons list, 0 refers to closed window button
-
-    int buttonCount = 0;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    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, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
-    //--------------------------------------------------------------------
-
-    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)
-{
-    #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
-
-    // 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;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    // 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);
-    }
-
-    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, textMaxSize, textEditMode)) 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);
-    }
-    else
-    {
-        if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
-    }
-
-    int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
-
-    for (int i = 0; i < buttonCount; i++)
-    {
-        if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    if (result >= 0) textEditMode = false;
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
-    //--------------------------------------------------------------------
-
-    return result;      // Result is the pressed button index
-}
-
-// 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 = 0;
-    GuiState state = guiState;
-
-    Vector2 mousePoint = GetMousePosition();
-    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);
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;
-
-            while (!feof(rgsFile))
-            {
-                switch (buffer[0])
-                {
-                    case 'p':
-                    {
-                        // Style property: p <control_id> <property_id> <property_value> <property_name>
-
-                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
-                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
-
-                    } break;
-                    case 'f':
-                    {
-                        // Style font: f <gen_font_size> <charmap_file> <font_file>
-
-                        int fontSize = 0;
-                        char charmapFileName[256] = { 0 };
-                        char fontFileName[256] = { 0 };
-                        sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, 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));
-                fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
-
-                GuiLoadStyleFromMemory(fileData, fileDataSize);
-
-                RAYGUI_FREE(fileData);
-            }
-
-            fclose(rgsFile);
-        }
-    }
-}
-
-// Load style default over global style
-void GuiLoadStyleDefault(void)
-{
-    // We set this variable 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, 15);        // DEFAULT, 15 pixels between lines
-    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);
-
-    // 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: We set 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 });
-    }
-}
-
-// 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)
-// 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;
-
-        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);
-
-        if ((signature[0] == 'r') &&
-            (signature[1] == 'G') &&
-            (signature[2] == 'I') &&
-            (signature[3] == ' '))
-        {
-            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);
-
-            // Read icons data directly over internal icons array
-            fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
-        }
-
-        fclose(rgiFile);
-    }
-
-    return guiIconsName;
-}
-
-// Load icons from memory
-// WARNING: Binary files only
-char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
-{
-    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)
-        {
-            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));
-                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)
-{
-    #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))
-            {
-            #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
-            }
-
-            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)
-int GuiGetTextWidth(const char *text)
-{
-    #if !defined(ICON_TEXT_PADDING)
-        #define ICON_TEXT_PADDING   4
-    #endif
-
-    Vector2 textSize = { 0 };
-    int textIconOffset = 0;
-
-    if ((text != NULL) && (text[0] != '\0'))
-    {
-        if (text[0] == '#')
-        {
-            for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
-            {
-                if (text[i] == '#')
-                {
-                    textIconOffset = i;
-                    break;
-                }
-            }
-        }
-
-        text += textIconOffset;
-
-        // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
-        float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
-        // Custom MeasureText() implementation
-        if ((guiFont.texture.id > 0) && (text != NULL))
-        {
-            // Get size in bytes of text, 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 + 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)
-{
-    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 CONTROL11:
-            // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
-        default:
-        {
-            // TODO: 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: We support up to 999 values for iconId
-static const char *GetTextIcon(const char *text, int *iconId)
-{
-#if !defined(RAYGUI_NO_ICONS)
-    *iconId = -1;
-    if (text[0] == '#')     // Maybe we have an icon!
-    {
-        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] == '#')
-        {
-            *iconId = TextToInteger(iconValue);
-
-            // 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, k = 0; (i < textLength) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
-    {
-        if (text[i] == '\n')
-        {
-            k++;
-            lines[k] = &text[i + 1]; // WARNING: next value is valid?
-            *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(ICON_TEXT_PADDING)
-        #define 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: We can't use GuiTextSplit() function because it can be already 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_SIZE)/2);
-    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: We get text size after icon has been processed
-        // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
-        int textSizeX = GuiGetTextWidth(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 += 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 we get pixel-perfect coordinates,
-        // In case of decimals we got weird text positioning
-        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: We consider 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);
-        }
-#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 we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
-            // but we need to draw all of the bad bytes using the '?' symbol moving one byte
-            if (codepoint == 0x3f) codepointSize = 1; // TODO: Review 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_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_LINE_SPACING);
-                }
-            }
-
-            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,
-                // 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_LINE_SPACING);
-        else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
-        //---------------------------------------------------------------------------------
-    }
-
-#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(GuiGetFont(), 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);
-
-        GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, 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, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
-        GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
-        GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
-    }
-}
-
-// Split controls text into multiple strings
-// Also check for multiple columns (required by GuiToggleGroup())
-static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
-{
-    // 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
-
-    // 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
-    #endif
-
-    static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };   // 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;
-
-    // Count how many substrings we have on text and point to every one
-    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'))
-        {
-            result[counter] = buffer + i + 1;
-
-            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;
-        }
-    }
-
-    *count = counter;
-
-    return result;
-}
-
-// 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;
-}
-
-// 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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
-                !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
-            int wheel = (int)GetMouseWheelMove();
-            if (wheel != 0) value += wheel;
-
-            // Handle mouse button down
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_DOWN)) value += 5;
-                else if (IsKeyDown(KEY_UP)) value -= 5;
-            }
-            else
-            {
-                if (IsKeyDown(KEY_RIGHT)) value += 5;
-                else if (IsKeyDown(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
-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;
-}
-
-// 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];
-
-    va_list args;
-    va_start(args, text);
-    vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
-    va_end(args);
-
-    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
-const 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 we have on text and point to every one
-        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)
-{
-    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 we exit as soon as possible and a '?'(0x3f) codepoint is returned
-// Total number of bytes processed are returned as a parameter
-// NOTE: the standard says U+FFFD should be returned in case of errors
+*   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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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
+
+static void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
+//-------------------------------------------------------------------------------
+
+// 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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)
+    {
+        // TODO: Remove MeasureTextEx(), implement logic directly or add custom GuiMeasureText()
+        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)
 {
diff --git a/raygui/styles/advance/style_advance.h b/raygui/styles/advance/style_advance.h
new file mode 100644
--- /dev/null
+++ b/raygui/styles/advance/style_advance.h
@@ -0,0 +1,587 @@
+//////////////////////////////////////////////////////////////////////////////////
+//                                                                              //
+// StyleAsCode exporter v2.0 - Style data exported as a values array            //
+//                                                                              //
+// USAGE: On init call: GuiLoadStyleAdvance();                                   //
+//                                                                              //
+// more info and bugs-report:  github.com/raysan5/raygui                        //
+// feedback and support:       ray[at]raylibtech.com                            //
+//                                                                              //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
+//                                                                              //
+//////////////////////////////////////////////////////////////////////////////////
+
+#define ADVANCE_STYLE_PROPS_COUNT  26
+
+// Custom style name: Advance
+static const GuiStyleProp advanceStyleProps[ADVANCE_STYLE_PROPS_COUNT] = {
+    { 0, 0, (int)0x575757ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xdbdbdbff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x575757ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x94b6e9ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x917de2ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xedebf9ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xf98751ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xffb033ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xf2f289ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0xc6c6c6ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xd9d8d8ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0xc6c6c6ff },    // DEFAULT_TEXT_COLOR_DISABLED
+    { 0, 16, (int)0x0000000c },    // DEFAULT_TEXT_SIZE 
+    { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
+    { 0, 18, (int)0x9eadd0ff },    // DEFAULT_LINE_COLOR 
+    { 0, 19, (int)0xe6e6e6ff },    // DEFAULT_BACKGROUND_COLOR 
+    { 0, 20, (int)0x00000006 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 5, (int)0x917de2ff },    // LABEL_TEXT_COLOR_FOCUSED
+    { 1, 8, (int)0xffb033ff },    // LABEL_TEXT_COLOR_PRESSED
+    { 4, 5, (int)0xb0b0e1ff },    // SLIDER_TEXT_COLOR_FOCUSED
+    { 4, 8, (int)0xffb033ff },    // SLIDER_TEXT_COLOR_PRESSED
+    { 5, 3, (int)0xf98751ff },    // PROGRESSBAR_BORDER_COLOR_FOCUSED
+    { 6, 5, (int)0xc0bcdbff },    // CHECKBOX_TEXT_COLOR_FOCUSED
+    { 6, 8, (int)0xffb033ff },    // CHECKBOX_TEXT_COLOR_PRESSED
+    { 9, 5, (int)0x917de2ff },    // TEXTBOX_TEXT_COLOR_FOCUSED
+    { 10, 5, (int)0x917de2ff },    // VALUEBOX_TEXT_COLOR_FOCUSED
+};
+
+// WARNING: This style uses a custom font: "Fairfax.ttf" (size: 12, spacing: 0)
+
+#define ADVANCE_STYLE_FONT_ATLAS_COMP_SIZE 1809
+
+// Font atlas image pixels data: DEFLATE compressed
+static unsigned char advanceFontData[ADVANCE_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
+    0xdd, 0x4b, 0x96, 0xe2, 0x30, 0x10, 0x44, 0x51, 0xed, 0x7f, 0xd3, 0xd1, 0xa3, 0x9e, 0x15, 0x92, 0x33, 0x14, 0xfa, 0x18,
+    0xde, 0xb9, 0x33, 0x68, 0xdc, 0xe0, 0xb4, 0x65, 0x53, 0x0a, 0x52, 0x6a, 0x00, 0x00, 0x00, 0x7f, 0xd0, 0x9f, 0x8f, 0xe8,
+    0xc3, 0xbf, 0xd4, 0xe3, 0xad, 0xf4, 0x1f, 0xef, 0x3d, 0xf3, 0xe9, 0x39, 0x45, 0xb6, 0xfe, 0x69, 0xdb, 0xfa, 0xf3, 0x31,
+    0x7d, 0x7c, 0xa6, 0xb2, 0x7d, 0x75, 0x5e, 0xf1, 0xf9, 0x71, 0x75, 0xde, 0xab, 0xb6, 0xd7, 0xff, 0xf3, 0xde, 0x68, 0x9d,
+    0xc7, 0x3f, 0x6f, 0xad, 0x7a, 0xcc, 0xa8, 0xb0, 0xb7, 0x7b, 0xdb, 0x7f, 0x5e, 0xff, 0xde, 0x3e, 0x53, 0x71, 0x7f, 0xb6,
+    0xce, 0x3e, 0xed, 0x6d, 0xa5, 0xb2, 0xb5, 0x53, 0xe7, 0xbf, 0x26, 0x5e, 0x33, 0x3b, 0x92, 0xd4, 0xce, 0x90, 0xfe, 0x31,
+    0xbc, 0x66, 0x6f, 0xfe, 0x7f, 0x4c, 0xc5, 0xcf, 0x3b, 0x33, 0x7e, 0xce, 0xbe, 0xe3, 0x56, 0xda, 0x77, 0xb2, 0xde, 0xa7,
+    0x42, 0xef, 0x52, 0xa1, 0xf3, 0xbf, 0x2d, 0xad, 0xbf, 0xac, 0xff, 0x59, 0xc6, 0xf8, 0xb3, 0xaa, 0xfe, 0xfd, 0xcf, 0xd0,
+    0x3b, 0xba, 0xeb, 0xfb, 0x24, 0x71, 0x3d, 0x5f, 0x7d, 0xde, 0xd4, 0xaf, 0x2d, 0xd9, 0x77, 0xaa, 0xeb, 0xee, 0x22, 0x55,
+    0xbc, 0xfe, 0x57, 0x8f, 0xbd, 0xdb, 0xf7, 0xc3, 0x68, 0xa4, 0x53, 0x64, 0x7c, 0xd4, 0xa1, 0xf1, 0x7f, 0x5c, 0x7b, 0x19,
+    0x67, 0x85, 0xa6, 0xcf, 0xad, 0x9b, 0xbf, 0x49, 0xf9, 0xf7, 0x23, 0xce, 0xdd, 0xf6, 0xc9, 0x4f, 0xbe, 0xfe, 0x1d, 0xdd,
+    0x5e, 0xff, 0xbb, 0x2a, 0xf2, 0x8d, 0x9f, 0x5e, 0x2f, 0x3d, 0xfb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8,
+    0xfd, 0x17, 0x6a, 0x2f, 0xd5, 0xe5, 0xcc, 0x4d, 0xf5, 0x5e, 0xf1, 0x3c, 0xdf, 0x90, 0xcc, 0xe9, 0xc9, 0x48, 0x33, 0xf4,
+    0xf7, 0x48, 0xe6, 0x35, 0xde, 0xac, 0xa0, 0x97, 0x59, 0x9b, 0x99, 0x57, 0x57, 0x24, 0xb5, 0xf6, 0xbc, 0x6e, 0x2b, 0x3e,
+    0xb7, 0x2e, 0x7e, 0x26, 0x39, 0xc7, 0xa4, 0xc1, 0xf9, 0x5f, 0x3b, 0xa6, 0xfb, 0x49, 0xb7, 0x35, 0xa9, 0x45, 0x19, 0xc9,
+    0xb4, 0x6c, 0x7a, 0x6c, 0x4d, 0x2d, 0x77, 0xd4, 0x5f, 0x46, 0xd2, 0x4c, 0x66, 0x1e, 0xb3, 0x7e, 0xbe, 0x9d, 0x38, 0xff,
+    0xc7, 0x59, 0x6d, 0x19, 0xe3, 0x72, 0x0b, 0xd5, 0x3f, 0x9d, 0xfc, 0x76, 0xce, 0x10, 0x4d, 0xa4, 0xb1, 0x2b, 0xe3, 0xc9,
+    0xfc, 0xf5, 0xdf, 0xab, 0x7d, 0xeb, 0x26, 0x16, 0xf5, 0x55, 0xe7, 0x7f, 0x7e, 0xc4, 0x96, 0x99, 0x4d, 0xd3, 0xf5, 0x69,
+    0x8a, 0x99, 0x8a, 0xdd, 0x7b, 0xfd, 0x6f, 0x56, 0x76, 0xf7, 0xd4, 0xaf, 0x56, 0x74, 0x38, 0xaf, 0xe9, 0x5c, 0xc3, 0xf6,
+    0xdc, 0xff, 0xf3, 0x2d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x73, 0x5a, 0xcf, 0xb7, 0xb5,
+    0x66, 0x0e, 0x5c, 0xc7, 0x52, 0x78, 0x6d, 0x62, 0x7e, 0xee, 0xdc, 0x33, 0xd9, 0xfd, 0x5c, 0x4f, 0x12, 0xa8, 0x9c, 0xdc,
+    0x6a, 0x97, 0xee, 0xc9, 0x6c, 0xfe, 0xe1, 0x8e, 0xfa, 0xb7, 0xc5, 0xf5, 0x77, 0x3a, 0x5c, 0xa9, 0x9b, 0x0a, 0xbb, 0x31,
+    0x85, 0xe9, 0xe6, 0x9f, 0xaa, 0x09, 0x9c, 0xd1, 0x3e, 0x55, 0x39, 0xff, 0x57, 0xed, 0x33, 0x54, 0xcd, 0xcd, 0xb5, 0x60,
+    0xfd, 0x9d, 0x14, 0xe6, 0x9e, 0xe4, 0x46, 0xbe, 0xfe, 0x5a, 0xdc, 0xc7, 0x6e, 0xd7, 0xf8, 0xaf, 0x70, 0xa2, 0x2a, 0x79,
+    0x9f, 0x51, 0xef, 0x43, 0x9b, 0xce, 0x3f, 0xe6, 0xba, 0xa7, 0x9e, 0xab, 0xbf, 0xc2, 0xd7, 0xff, 0x9d, 0xb9, 0x39, 0xef,
+    0x5d, 0xe7, 0xf2, 0x8f, 0x32, 0x8e, 0xcd, 0x16, 0xea, 0x7c, 0x96, 0xbb, 0xff, 0x77, 0x3a, 0x16, 0x27, 0xef, 0x97, 0x9b,
+    0xd5, 0xc1, 0x57, 0xc6, 0x3e, 0xce, 0xe6, 0x1f, 0xfb, 0x67, 0x72, 0xea, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xc0, 0xef, 0xa4, 0xff, 0xf4, 0x78, 0x96, 0xcf, 0xeb, 0x9a, 0xd7, 0x22, 0xbd, 0x2c, 0xdc, 0xd9, 0xbd, 0x6a,
+    0xa7, 0x1f, 0x95, 0xbb, 0x0c, 0x39, 0x5d, 0x39, 0x9e, 0xcf, 0x05, 0x8e, 0x52, 0x72, 0x4f, 0x67, 0x34, 0x6b, 0x59, 0x86,
+    0xd4, 0x9a, 0xa4, 0x32, 0x66, 0x24, 0x15, 0x78, 0xa7, 0xcd, 0xec, 0x3a, 0x54, 0xcf, 0xbd, 0xb8, 0x49, 0xb1, 0x35, 0x7b,
+    0xa3, 0xbe, 0x82, 0x66, 0x2d, 0x9b, 0x91, 0xed, 0x15, 0x57, 0x3f, 0x2f, 0x3f, 0x25, 0x75, 0xbc, 0x91, 0x41, 0xd3, 0x23,
+    0xe2, 0xa8, 0xfe, 0x9a, 0xce, 0xc4, 0x55, 0xd7, 0x08, 0xcd, 0xac, 0xa0, 0xaa, 0xd0, 0xd1, 0x98, 0xbb, 0x52, 0xf5, 0x52,
+    0x24, 0x6d, 0x43, 0x8f, 0xb5, 0xfe, 0x9e, 0x52, 0xe9, 0x9d, 0x55, 0xc7, 0x7f, 0x2d, 0x3b, 0xff, 0x93, 0xeb, 0xf3, 0x6b,
+    0xcb, 0xbd, 0x4a, 0x3d, 0xa9, 0x93, 0x4a, 0xf7, 0x28, 0x9a, 0x21, 0x7a, 0x5e, 0x7f, 0x2d, 0xab, 0xbf, 0x62, 0x57, 0x9d,
+    0x73, 0xc9, 0x23, 0xd9, 0xb9, 0x47, 0xc5, 0xd6, 0x1a, 0x6f, 0x4b, 0xeb, 0xbf, 0x2e, 0xeb, 0xa5, 0xc5, 0xf7, 0xae, 0x3b,
+    0xbf, 0xc3, 0xd4, 0x5f, 0x95, 0x5a, 0x6b, 0x3e, 0xfb, 0x1b, 0xaa, 0xc4, 0x56, 0xd6, 0xde, 0x75, 0x92, 0x3c, 0x5c, 0x3f,
+    0x9a, 0xdd, 0xfa, 0xbb, 0xc0, 0x13, 0xc7, 0xe2, 0x2f, 0xfd, 0x35, 0x86, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xc8, 0xcc, 0x36, 0xc8, 0x58, 0xb1, 0x51, 0x83, 0x54, 0x5f, 0xe2, 0x35, 0xf7, 0xf6, 0x52, 0xd3, 0xa0, 0x3b, 0x94,
+    0x9f, 0x59, 0x1b, 0x25, 0x09, 0x2a, 0x5b, 0xa9, 0xcc, 0x38, 0x28, 0x9a, 0xb7, 0xc9, 0x64, 0x74, 0xd2, 0xf5, 0x57, 0xb0,
+    0xff, 0x5a, 0x3d, 0x91, 0xf5, 0x3c, 0xb9, 0xa1, 0xc9, 0x19, 0x3a, 0x15, 0xe6, 0x11, 0x6f, 0xe8, 0x99, 0x57, 0x5f, 0x65,
+    0xbc, 0x9e, 0x36, 0x75, 0x7a, 0xa9, 0x29, 0x96, 0x8f, 0xd3, 0xf4, 0x3c, 0xaf, 0xd3, 0x07, 0xef, 0x54, 0xfd, 0xbd, 0xf5,
+    0x09, 0x15, 0xc8, 0xdb, 0x65, 0x7b, 0xa9, 0x8d, 0xfe, 0x9f, 0x3b, 0xea, 0xdf, 0xa6, 0x66, 0xe2, 0x57, 0x74, 0xd3, 0x6d,
+    0xc6, 0xef, 0x06, 0x32, 0x79, 0xbb, 0x16, 0xee, 0xa5, 0xe5, 0xac, 0xf7, 0xbc, 0x26, 0x2d, 0x53, 0xab, 0xff, 0xe9, 0x84,
+    0x8a, 0xbe, 0x2a, 0x0b, 0xa3, 0x40, 0x72, 0x7d, 0xcd, 0x56, 0xeb, 0xd9, 0xd6, 0x77, 0xd5, 0xff, 0x74, 0x22, 0xc6, 0xcb,
+    0x15, 0xee, 0xaa, 0x7f, 0x2b, 0x7f, 0x9f, 0xc2, 0x99, 0xd1, 0x42, 0x64, 0x25, 0x7f, 0xfa, 0x08, 0x60, 0xbd, 0x6e, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x2d, 0xbf, 0x3a, 0xf7, 0x56, 0x9f, 0x1c, 0xa5, 0x06, 0x6b, 0xe9, 0xbf, 0xda,
+    0x5c, 0xbe, 0x86, 0x3d, 0xbd, 0x5a, 0x29, 0xc9, 0x57, 0x5f, 0xe3, 0xb1, 0xba, 0x2a, 0x9a, 0xac, 0x44, 0x86, 0x0a, 0x15,
+    0x7c, 0x3a, 0x57, 0xab, 0x85, 0xe9, 0xa7, 0x67, 0x73, 0x1e, 0x2a, 0x1d, 0x99, 0xde, 0xff, 0xe3, 0x74, 0x08, 0x6a, 0x81,
+    0xf4, 0x4f, 0x6e, 0xa5, 0xe0, 0xfe, 0x9a, 0xb8, 0xce, 0x4c, 0xbd, 0xca, 0x89, 0x99, 0xfc, 0x8c, 0x79, 0x65, 0x05, 0x4e,
+    0x59, 0x7d, 0x98, 0x14, 0xab, 0xbf, 0xb3, 0x2e, 0x6e, 0x2e, 0x91, 0xa7, 0xf8, 0xdc, 0xa1, 0xd7, 0xe7, 0x49, 0xc1, 0xb1,
+    0x2b, 0x7d, 0xfe, 0xb7, 0xd0, 0x9e, 0x73, 0xc6, 0x7f, 0x15, 0xae, 0x0a, 0xbd, 0x7f, 0xaf, 0xe9, 0xfa, 0xeb, 0x51, 0x0e,
+    0x44, 0xc3, 0x54, 0xfe, 0xea, 0x15, 0x38, 0xdd, 0xee, 0x6d, 0x32, 0x2a, 0x79, 0x5f, 0x2e, 0xad, 0x9a, 0x54, 0xaf, 0x8e,
+    0xaf, 0x5a, 0x70, 0x9d, 0x93, 0x99, 0x55, 0xaa, 0x67, 0x46, 0x15, 0xec, 0xa0, 0xab, 0x0b, 0x53, 0x17, 0xb2, 0xee, 0x92,
+    0x14, 0x3e, 0x4e, 0x73, 0x6b, 0xd9, 0x3e, 0x19, 0x6f, 0x4e, 0x66, 0x3d, 0x15, 0xcb, 0x04, 0x26, 0x8e, 0x4c, 0xb7, 0xc3,
+    0xb6, 0x2e, 0x49, 0xcf, 0xca, 0xd8, 0x6b, 0x67, 0xd2, 0x8a, 0x37, 0x26, 0x22, 0xb5, 0x25, 0xbb, 0xba, 0xe2, 0x53, 0x8b,
+    0x0c, 0xdb, 0x97, 0x24, 0xdb, 0x77, 0xe6, 0xa2, 0xb1, 0xe7, 0xec, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfa,
+    0x2c, 0xd4, 0x38, 0xf5, 0x57, 0x7b, 0x95, 0x8c, 0xc4, 0x8c, 0x37, 0xbb, 0x58, 0xef, 0x23, 0x24, 0x73, 0x6b, 0x0a, 0xad,
+    0x28, 0xe8, 0x7e, 0x9e, 0x4c, 0xc6, 0x45, 0x66, 0x77, 0xb5, 0x1d, 0x33, 0xef, 0xb2, 0xf6, 0xd6, 0x7c, 0xb7, 0xbd, 0xb9,
+    0x7d, 0x90, 0xca, 0x12, 0xb6, 0x2d, 0xfb, 0xb3, 0x7a, 0xce, 0x8e, 0xfe, 0xbd, 0x62, 0xf9, 0xd2, 0x1b, 0x66, 0xb8, 0xaa,
+    0xa3, 0x99, 0x2e, 0x9e, 0x53, 0xaa, 0x77, 0x5e, 0xad, 0x9d, 0x49, 0xde, 0x59, 0x21, 0x3b, 0xaf, 0x96, 0x79, 0x26, 0xdb,
+    0x15, 0x4f, 0x46, 0xc5, 0xbc, 0x67, 0xd6, 0xdf, 0x29, 0x78, 0x57, 0x72, 0x59, 0x7d, 0x57, 0xab, 0xd9, 0xd8, 0xf3, 0xcf,
+    0x28, 0x96, 0x79, 0x3a, 0xbb, 0xfa, 0xb2, 0x93, 0x32, 0x54, 0xfc, 0xde, 0xf3, 0xc6, 0xfe, 0xce, 0x33, 0xf5, 0xd7, 0xf2,
+    0xfa, 0x9f, 0xcb, 0x13, 0x28, 0xd6, 0x2b, 0xef, 0xc9, 0x18, 0xab, 0x4d, 0x23, 0x69, 0xf5, 0x35, 0xf5, 0x4e, 0xc6, 0xd9,
+    0xab, 0xd9, 0xb7, 0xa7, 0xa0, 0x6e, 0x1e, 0xff, 0xb3, 0x59, 0xcf, 0xfb, 0x56, 0xdf, 0xa7, 0xfe, 0x7e, 0xfd, 0xb5, 0xe9,
+    0xfa, 0xff, 0xed, 0x99, 0xb2, 0xf3, 0xb5, 0xcc, 0x66, 0x5f, 0xb3, 0x57, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xf0, 0xff, 0xce, 0x5c, 0xef, 0xeb, 0x57, 0x4f, 0xdd, 0x9d, 0x4c, 0xf7, 0x39, 0x6b, 0x01, 0xee, 0xcd, 0xf0, 0xe5, 0x57,
+    0x92, 0xca, 0xe4, 0x3f, 0x3f, 0x6d, 0x41, 0xc5, 0xd4, 0xdd, 0xcd, 0xe9, 0xbe, 0xb6, 0xe1, 0x5d, 0x7b, 0xb5, 0x3a, 0x3f,
+    0xf3, 0x5f, 0xdd, 0x63, 0x6f, 0x4d, 0xf7, 0xe9, 0xd8, 0x0c, 0xd7, 0x9a, 0x39, 0xa9, 0xde, 0x1c, 0xd3, 0x4c, 0x56, 0x50,
+    0xc3, 0x95, 0x60, 0x75, 0x69, 0xba, 0xaf, 0xba, 0x7e, 0xf0, 0x7b, 0x33, 0x09, 0xf5, 0x64, 0x42, 0xfd, 0xd1, 0x77, 0xed,
+    0x2f, 0xaf, 0xf7, 0x2a, 0xf5, 0xaf, 0xd5, 0xff, 0xde, 0x23, 0xc3, 0xbd, 0x9f, 0xd9, 0xf3, 0xde, 0x72, 0x5d, 0x21, 0xf7,
+    0xd4, 0x5f, 0xaf, 0x1b, 0x49, 0x47, 0xf7, 0x85, 0x3a, 0x9c, 0x49, 0x59, 0x91, 0xfb, 0x5b, 0x55, 0xff, 0xd1, 0x79, 0xf4,
+    0xd6, 0xf1, 0xf2, 0xbe, 0xfa, 0xb7, 0xa3, 0xf5, 0x77, 0x3b, 0xd2, 0x9e, 0x1d, 0x49, 0x15, 0xef, 0x05, 0xbc, 0xe3, 0xbd,
+    0x69, 0xd3, 0x37, 0xa1, 0xda, 0xfd, 0x7f, 0xee, 0x1b, 0xce, 0x9e, 0xfb, 0xff, 0x7d, 0xdf, 0x26, 0xd3, 0xef, 0x8d, 0xcc,
+    0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd4, 0x5f, 0x2f, 0xcf, 0xa6, 0xf1, 0xbc, 0xfc, 0xd4, 0xe9, 0x5e, 0x7b,
+    0x6b, 0x13, 0x95, 0xd5, 0x67, 0xe6, 0xb2, 0x43, 0xb7, 0xa6, 0xf1, 0x9a, 0x31, 0x87, 0xbc, 0x2f, 0xa7, 0xb7, 0x2a, 0x51,
+    0xd9, 0xa2, 0xfb, 0x76, 0xc5, 0x5c, 0xe8, 0xae, 0x34, 0x5e, 0x3b, 0xd6, 0x03, 0x6d, 0xc7, 0xec, 0x52, 0x3d, 0x37, 0x3d,
+    0x37, 0x1b, 0xb7, 0x67, 0xce, 0x6d, 0xb4, 0xbf, 0x32, 0xfd, 0xc6, 0xb4, 0x69, 0x9e, 0xae, 0xdf, 0x21, 0xaa, 0x4d, 0x3d,
+    0xda, 0x4f, 0x20, 0x6b, 0xf3, 0xf9, 0xbf, 0xfe, 0x19, 0xd9, 0xfd, 0xb1, 0x32, 0xeb, 0x4c, 0x67, 0x3b, 0xc4, 0xad, 0x4a,
+    0xd4, 0x8c, 0x8f, 0x38, 0x2d, 0x99, 0x8d, 0x5f, 0xfd, 0xcc, 0xcc, 0x11, 0xe8, 0xa4, 0xe4, 0xd7, 0xf7, 0xda, 0xdc, 0x5f,
+    0xff, 0x36, 0x55, 0xff, 0xd3, 0xb9, 0xb6, 0xec, 0xda, 0xb0, 0x7b, 0x7a, 0x6d, 0xd5, 0xbf, 0x67, 0xcc, 0x27, 0xaa, 0x9c,
+    0x3c, 0xfb, 0xfc, 0x1d, 0xce, 0xfa, 0x91, 0x61, 0xd7, 0xbd, 0xe9, 0x9e, 0x9c, 0xce, 0x5d, 0x89, 0xaa, 0x6f, 0xf8, 0xdb,
+    0x04, 0xa9, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xbf, 0x29, 0x3e, 0xbf, 0xa2, 0xee, 0xfb, 0x7a,
+    0xee, 0xe9, 0x65, 0x73, 0x31, 0xa7, 0x53, 0x7e, 0xa3, 0x4e, 0x21, 0xed, 0x60, 0x96, 0xef, 0xd6, 0xf5, 0x69, 0xbf, 0x27,
+    0x67, 0x3c, 0x5a, 0x51, 0xef, 0xde, 0x9e, 0x7b, 0x7b, 0x67, 0xe3, 0xdf, 0xd1, 0xbd, 0x22, 0x9b, 0x51, 0xb8, 0xb9, 0x87,
+    0x9c, 0x16, 0xa4, 0x71, 0xce, 0x8d, 0xfd, 0x67, 0x7b, 0x2e, 0xe9, 0xd2, 0x6c, 0xd2, 0xf9, 0xee, 0x52, 0xbf, 0x51, 0xff,
+    0x1b, 0xde, 0xb5, 0x96, 0x6f, 0xed, 0x97, 0xeb, 0xbf, 0xa2, 0xe7, 0x96, 0x8c, 0x5a, 0xaa, 0xf4, 0xfb, 0x99, 0xde, 0xd6,
+    0xb4, 0x35, 0xa7, 0xff, 0xf6, 0xeb, 0xff, 0x9a, 0xdf, 0x48, 0xac, 0xff, 0x95, 0xd4, 0xa8, 0x8b, 0x71, 0x8b, 0xa5, 0x96,
+    0xf1, 0xa6, 0x6f, 0xc8, 0x3a, 0xf2, 0xcb, 0x20, 0xdc, 0xf4, 0xdb, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x2d, 0x58, 0xd1,
+    0x98, 0xfa, 0x53, 0xff, 0x1f, 0xaf, 0xff, 0x3f };
+
+// Font glyphs rectangles data (on atlas)
+static const Rectangle advanceFontRecs[189] = {
+    { 4, 4, 6 , 12 },
+    { 18, 4, 1 , 7 },
+    { 27, 4, 3 , 3 },
+    { 38, 4, 5 , 5 },
+    { 51, 4, 5 , 9 },
+    { 64, 4, 5 , 7 },
+    { 77, 4, 5 , 7 },
+    { 90, 4, 3 , 3 },
+    { 101, 4, 3 , 9 },
+    { 112, 4, 3 , 9 },
+    { 123, 4, 5 , 5 },
+    { 136, 4, 5 , 5 },
+    { 149, 4, 2 , 4 },
+    { 159, 4, 5 , 1 },
+    { 172, 4, 2 , 2 },
+    { 182, 4, 5 , 9 },
+    { 195, 4, 5 , 7 },
+    { 208, 4, 5 , 7 },
+    { 221, 4, 5 , 7 },
+    { 234, 4, 5 , 7 },
+    { 4, 24, 5 , 7 },
+    { 17, 24, 5 , 7 },
+    { 30, 24, 5 , 7 },
+    { 43, 24, 5 , 7 },
+    { 56, 24, 5 , 7 },
+    { 69, 24, 5 , 7 },
+    { 82, 24, 2 , 5 },
+    { 92, 24, 2 , 7 },
+    { 102, 24, 5 , 5 },
+    { 115, 24, 5 , 3 },
+    { 128, 24, 5 , 5 },
+    { 141, 24, 5 , 7 },
+    { 154, 24, 5 , 7 },
+    { 167, 24, 5 , 7 },
+    { 180, 24, 5 , 7 },
+    { 193, 24, 5 , 7 },
+    { 206, 24, 5 , 7 },
+    { 219, 24, 5 , 7 },
+    { 232, 24, 5 , 7 },
+    { 4, 44, 5 , 7 },
+    { 17, 44, 5 , 7 },
+    { 30, 44, 3 , 7 },
+    { 41, 44, 5 , 7 },
+    { 54, 44, 5 , 7 },
+    { 67, 44, 5 , 7 },
+    { 80, 44, 5 , 7 },
+    { 93, 44, 5 , 7 },
+    { 106, 44, 5 , 7 },
+    { 119, 44, 5 , 7 },
+    { 132, 44, 5 , 7 },
+    { 145, 44, 5 , 7 },
+    { 158, 44, 5 , 7 },
+    { 171, 44, 5 , 7 },
+    { 184, 44, 5 , 7 },
+    { 197, 44, 5 , 7 },
+    { 210, 44, 5 , 7 },
+    { 223, 44, 5 , 7 },
+    { 236, 44, 5 , 7 },
+    { 4, 64, 5 , 7 },
+    { 17, 64, 3 , 9 },
+    { 28, 64, 5 , 9 },
+    { 41, 64, 3 , 9 },
+    { 52, 64, 5 , 3 },
+    { 65, 64, 5 , 1 },
+    { 78, 64, 3 , 3 },
+    { 89, 64, 5 , 5 },
+    { 102, 64, 5 , 7 },
+    { 115, 64, 5 , 5 },
+    { 128, 64, 5 , 7 },
+    { 141, 64, 5 , 5 },
+    { 154, 64, 4 , 7 },
+    { 166, 64, 5 , 7 },
+    { 179, 64, 5 , 7 },
+    { 192, 64, 3 , 7 },
+    { 203, 64, 3 , 9 },
+    { 214, 64, 5 , 7 },
+    { 227, 64, 3 , 7 },
+    { 238, 64, 5 , 5 },
+    { 4, 84, 5 , 5 },
+    { 17, 84, 5 , 5 },
+    { 30, 84, 5 , 7 },
+    { 43, 84, 5 , 7 },
+    { 56, 84, 5 , 5 },
+    { 69, 84, 5 , 5 },
+    { 82, 84, 4 , 7 },
+    { 94, 84, 5 , 5 },
+    { 107, 84, 5 , 5 },
+    { 120, 84, 5 , 5 },
+    { 133, 84, 5 , 5 },
+    { 146, 84, 5 , 7 },
+    { 159, 84, 5 , 5 },
+    { 172, 84, 3 , 9 },
+    { 183, 84, 1 , 9 },
+    { 192, 84, 3 , 9 },
+    { 203, 84, 5 , 2 },
+    { 216, 84, 1 , 7 },
+    { 225, 84, 5 , 7 },
+    { 238, 84, 5 , 7 },
+    { 4, 104, 5 , 7 },
+    { 17, 104, 5 , 7 },
+    { 30, 104, 5 , 10 },
+    { 43, 104, 5 , 7 },
+    { 56, 104, 5 , 8 },
+    { 69, 104, 5 , 8 },
+    { 82, 104, 3 , 6 },
+    { 93, 104, 5 , 5 },
+    { 106, 104, 5 , 3 },
+    { 119, 104, 5 , 8 },
+    { 132, 104, 5 , 1 },
+    { 145, 104, 4 , 4 },
+    { 157, 104, 5 , 7 },
+    { 170, 104, 3 , 4 },
+    { 181, 104, 3 , 4 },
+    { 192, 104, 5 , 10 },
+    { 205, 104, 5 , 7 },
+    { 218, 104, 5 , 7 },
+    { 231, 104, 2 , 2 },
+    { 241, 104, 5 , 8 },
+    { 4, 124, 3 , 4 },
+    { 15, 124, 3 , 6 },
+    { 26, 124, 5 , 5 },
+    { 39, 124, 5 , 7 },
+    { 52, 124, 5 , 5 },
+    { 65, 124, 5 , 9 },
+    { 78, 124, 5 , 7 },
+    { 91, 124, 5 , 10 },
+    { 104, 124, 5 , 10 },
+    { 117, 124, 5 , 10 },
+    { 130, 124, 5 , 10 },
+    { 143, 124, 5 , 9 },
+    { 156, 124, 5 , 10 },
+    { 169, 124, 5 , 7 },
+    { 182, 124, 5 , 9 },
+    { 195, 124, 5 , 10 },
+    { 208, 124, 5 , 10 },
+    { 221, 124, 5 , 10 },
+    { 234, 124, 5 , 9 },
+    { 4, 144, 3 , 10 },
+    { 15, 144, 3 , 10 },
+    { 26, 144, 3 , 10 },
+    { 37, 144, 3 , 9 },
+    { 48, 144, 5 , 7 },
+    { 61, 144, 5 , 10 },
+    { 74, 144, 5 , 10 },
+    { 87, 144, 5 , 10 },
+    { 100, 144, 5 , 10 },
+    { 113, 144, 5 , 10 },
+    { 126, 144, 5 , 9 },
+    { 139, 144, 5 , 5 },
+    { 152, 144, 5 , 7 },
+    { 165, 144, 5 , 10 },
+    { 178, 144, 5 , 10 },
+    { 191, 144, 5 , 10 },
+    { 204, 144, 5 , 9 },
+    { 217, 144, 5 , 10 },
+    { 230, 144, 5 , 7 },
+    { 4, 164, 5 , 7 },
+    { 17, 164, 5 , 8 },
+    { 30, 164, 5 , 8 },
+    { 43, 164, 5 , 8 },
+    { 56, 164, 5 , 8 },
+    { 69, 164, 5 , 7 },
+    { 82, 164, 5 , 9 },
+    { 95, 164, 5 , 5 },
+    { 108, 164, 5 , 7 },
+    { 121, 164, 5 , 8 },
+    { 134, 164, 5 , 8 },
+    { 147, 164, 5 , 8 },
+    { 160, 164, 5 , 7 },
+    { 173, 164, 3 , 8 },
+    { 184, 164, 3 , 8 },
+    { 195, 164, 3 , 8 },
+    { 206, 164, 3 , 7 },
+    { 217, 164, 5 , 7 },
+    { 230, 164, 5 , 8 },
+    { 4, 184, 5 , 8 },
+    { 17, 184, 5 , 8 },
+    { 30, 184, 5 , 8 },
+    { 43, 184, 5 , 8 },
+    { 56, 184, 5 , 7 },
+    { 69, 184, 5 , 5 },
+    { 82, 184, 5 , 5 },
+    { 95, 184, 5 , 8 },
+    { 108, 184, 5 , 8 },
+    { 121, 184, 5 , 8 },
+    { 134, 184, 5 , 7 },
+    { 147, 184, 5 , 10 },
+    { 160, 184, 5 , 9 },
+    { 173, 184, 5 , 9 },
+};
+
+// Font glyphs info data
+// NOTE: No glyphs.image data provided
+static const GlyphInfo advanceFontGlyphs[189] = {
+    { 32, 0, 0, 6, { 0 }},
+    { 33, 2, 2, 6, { 0 }},
+    { 34, 1, 1, 6, { 0 }},
+    { 35, 0, 2, 6, { 0 }},
+    { 36, 0, 1, 6, { 0 }},
+    { 37, 0, 2, 6, { 0 }},
+    { 38, 0, 2, 6, { 0 }},
+    { 39, 1, 1, 6, { 0 }},
+    { 40, 1, 1, 6, { 0 }},
+    { 41, 1, 1, 6, { 0 }},
+    { 42, 0, 2, 6, { 0 }},
+    { 43, 0, 3, 6, { 0 }},
+    { 44, 1, 7, 6, { 0 }},
+    { 45, 0, 5, 6, { 0 }},
+    { 46, 1, 7, 6, { 0 }},
+    { 47, 0, 1, 6, { 0 }},
+    { 48, 0, 2, 6, { 0 }},
+    { 49, 0, 2, 6, { 0 }},
+    { 50, 0, 2, 6, { 0 }},
+    { 51, 0, 2, 6, { 0 }},
+    { 52, 0, 2, 6, { 0 }},
+    { 53, 0, 2, 6, { 0 }},
+    { 54, 0, 2, 6, { 0 }},
+    { 55, 0, 2, 6, { 0 }},
+    { 56, 0, 2, 6, { 0 }},
+    { 57, 0, 2, 6, { 0 }},
+    { 58, 1, 4, 6, { 0 }},
+    { 59, 1, 4, 6, { 0 }},
+    { 60, 0, 3, 6, { 0 }},
+    { 61, 0, 4, 6, { 0 }},
+    { 62, 0, 3, 6, { 0 }},
+    { 63, 0, 2, 6, { 0 }},
+    { 64, 0, 2, 6, { 0 }},
+    { 65, 0, 2, 6, { 0 }},
+    { 66, 0, 2, 6, { 0 }},
+    { 67, 0, 2, 6, { 0 }},
+    { 68, 0, 2, 6, { 0 }},
+    { 69, 0, 2, 6, { 0 }},
+    { 70, 0, 2, 6, { 0 }},
+    { 71, 0, 2, 6, { 0 }},
+    { 72, 0, 2, 6, { 0 }},
+    { 73, 1, 2, 6, { 0 }},
+    { 74, 0, 2, 6, { 0 }},
+    { 75, 0, 2, 6, { 0 }},
+    { 76, 0, 2, 6, { 0 }},
+    { 77, 0, 2, 6, { 0 }},
+    { 78, 0, 2, 6, { 0 }},
+    { 79, 0, 2, 6, { 0 }},
+    { 80, 0, 2, 6, { 0 }},
+    { 81, 0, 2, 6, { 0 }},
+    { 82, 0, 2, 6, { 0 }},
+    { 83, 0, 2, 6, { 0 }},
+    { 84, 0, 2, 6, { 0 }},
+    { 85, 0, 2, 6, { 0 }},
+    { 86, 0, 2, 6, { 0 }},
+    { 87, 0, 2, 6, { 0 }},
+    { 88, 0, 2, 6, { 0 }},
+    { 89, 0, 2, 6, { 0 }},
+    { 90, 0, 2, 6, { 0 }},
+    { 91, 1, 1, 6, { 0 }},
+    { 92, 0, 1, 6, { 0 }},
+    { 93, 1, 1, 6, { 0 }},
+    { 94, 0, 2, 6, { 0 }},
+    { 95, 0, 10, 6, { 0 }},
+    { 96, 1, 1, 6, { 0 }},
+    { 97, 0, 4, 6, { 0 }},
+    { 98, 0, 2, 6, { 0 }},
+    { 99, 0, 4, 6, { 0 }},
+    { 100, 0, 2, 6, { 0 }},
+    { 101, 0, 4, 6, { 0 }},
+    { 102, 1, 2, 6, { 0 }},
+    { 103, 0, 4, 6, { 0 }},
+    { 104, 0, 2, 6, { 0 }},
+    { 105, 1, 2, 6, { 0 }},
+    { 106, 0, 2, 6, { 0 }},
+    { 107, 0, 2, 6, { 0 }},
+    { 108, 1, 2, 6, { 0 }},
+    { 109, 0, 4, 6, { 0 }},
+    { 110, 0, 4, 6, { 0 }},
+    { 111, 0, 4, 6, { 0 }},
+    { 112, 0, 4, 6, { 0 }},
+    { 113, 0, 4, 6, { 0 }},
+    { 114, 0, 4, 6, { 0 }},
+    { 115, 0, 4, 6, { 0 }},
+    { 116, 1, 2, 6, { 0 }},
+    { 117, 0, 4, 6, { 0 }},
+    { 118, 0, 4, 6, { 0 }},
+    { 119, 0, 4, 6, { 0 }},
+    { 120, 0, 4, 6, { 0 }},
+    { 121, 0, 4, 6, { 0 }},
+    { 122, 0, 4, 6, { 0 }},
+    { 123, 1, 1, 6, { 0 }},
+    { 124, 2, 1, 6, { 0 }},
+    { 125, 1, 1, 6, { 0 }},
+    { 126, 0, 2, 6, { 0 }},
+    { 161, 2, 4, 6, { 0 }},
+    { 162, 0, 3, 6, { 0 }},
+    { 163, 0, 2, 6, { 0 }},
+    { 8364, 0, 2, 6, { 0 }},
+    { 165, 0, 2, 6, { 0 }},
+    { 352, 0, -1, 6, { 0 }},
+    { 167, 0, 2, 6, { 0 }},
+    { 353, 0, 1, 6, { 0 }},
+    { 169, 0, 2, 6, { 0 }},
+    { 170, 1, 1, 6, { 0 }},
+    { 171, 0, 3, 6, { 0 }},
+    { 172, 0, 5, 6, { 0 }},
+    { 174, 0, 2, 6, { 0 }},
+    { 175, 0, 2, 6, { 0 }},
+    { 176, 0, 1, 6, { 0 }},
+    { 177, 0, 2, 6, { 0 }},
+    { 178, 1, 1, 6, { 0 }},
+    { 179, 1, 1, 6, { 0 }},
+    { 381, 0, -1, 6, { 0 }},
+    { 181, 0, 4, 6, { 0 }},
+    { 182, 0, 2, 6, { 0 }},
+    { 183, 1, 4, 6, { 0 }},
+    { 382, 0, 1, 6, { 0 }},
+    { 185, 1, 1, 6, { 0 }},
+    { 186, 1, 1, 6, { 0 }},
+    { 187, 0, 3, 6, { 0 }},
+    { 338, 0, 2, 6, { 0 }},
+    { 339, 0, 4, 6, { 0 }},
+    { 376, 0, 0, 6, { 0 }},
+    { 191, 0, 4, 6, { 0 }},
+    { 192, 0, -1, 6, { 0 }},
+    { 193, 0, -1, 6, { 0 }},
+    { 194, 0, -1, 6, { 0 }},
+    { 195, 0, -1, 6, { 0 }},
+    { 196, 0, 0, 6, { 0 }},
+    { 197, 0, -1, 6, { 0 }},
+    { 198, 0, 2, 6, { 0 }},
+    { 199, 0, 2, 6, { 0 }},
+    { 200, 0, -1, 6, { 0 }},
+    { 201, 0, -1, 6, { 0 }},
+    { 202, 0, -1, 6, { 0 }},
+    { 203, 0, 0, 6, { 0 }},
+    { 204, 1, -1, 6, { 0 }},
+    { 205, 1, -1, 6, { 0 }},
+    { 206, 1, -1, 6, { 0 }},
+    { 207, 1, 0, 6, { 0 }},
+    { 208, 0, 2, 6, { 0 }},
+    { 209, 0, -1, 6, { 0 }},
+    { 210, 0, -1, 6, { 0 }},
+    { 211, 0, -1, 6, { 0 }},
+    { 212, 0, -1, 6, { 0 }},
+    { 213, 0, -1, 6, { 0 }},
+    { 214, 0, 0, 6, { 0 }},
+    { 215, 0, 3, 6, { 0 }},
+    { 216, 0, 2, 6, { 0 }},
+    { 217, 0, -1, 6, { 0 }},
+    { 218, 0, -1, 6, { 0 }},
+    { 219, 0, -1, 6, { 0 }},
+    { 220, 0, 0, 6, { 0 }},
+    { 221, 0, -1, 6, { 0 }},
+    { 222, 0, 2, 6, { 0 }},
+    { 223, 0, 2, 6, { 0 }},
+    { 224, 0, 1, 6, { 0 }},
+    { 225, 0, 1, 6, { 0 }},
+    { 226, 0, 1, 6, { 0 }},
+    { 227, 0, 1, 6, { 0 }},
+    { 228, 0, 2, 6, { 0 }},
+    { 229, 0, 0, 6, { 0 }},
+    { 230, 0, 4, 6, { 0 }},
+    { 231, 0, 4, 6, { 0 }},
+    { 232, 0, 1, 6, { 0 }},
+    { 233, 0, 1, 6, { 0 }},
+    { 234, 0, 1, 6, { 0 }},
+    { 235, 0, 2, 6, { 0 }},
+    { 236, 1, 1, 6, { 0 }},
+    { 237, 1, 1, 6, { 0 }},
+    { 238, 1, 1, 6, { 0 }},
+    { 239, 1, 2, 6, { 0 }},
+    { 240, 0, 2, 6, { 0 }},
+    { 241, 0, 1, 6, { 0 }},
+    { 242, 0, 1, 6, { 0 }},
+    { 243, 0, 1, 6, { 0 }},
+    { 244, 0, 1, 6, { 0 }},
+    { 245, 0, 1, 6, { 0 }},
+    { 246, 0, 2, 6, { 0 }},
+    { 247, 0, 3, 6, { 0 }},
+    { 248, 0, 4, 6, { 0 }},
+    { 249, 0, 1, 6, { 0 }},
+    { 250, 0, 1, 6, { 0 }},
+    { 251, 0, 1, 6, { 0 }},
+    { 252, 0, 2, 6, { 0 }},
+    { 253, 0, 1, 6, { 0 }},
+    { 254, 0, 2, 6, { 0 }},
+    { 255, 0, 2, 6, { 0 }},
+};
+
+// Style loading function: Advance
+static void GuiLoadStyleAdvance(void)
+{
+    // Load style properties provided
+    // NOTE: Default properties are propagated
+    for (int i = 0; i < ADVANCE_STYLE_PROPS_COUNT; i++)
+    {
+        GuiSetStyle(advanceStyleProps[i].controlId, advanceStyleProps[i].propertyId, advanceStyleProps[i].propertyValue);
+    }
+
+    // Custom font loading
+    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
+    int advanceFontDataSize = 0;
+    unsigned char *data = DecompressData(advanceFontData, ADVANCE_STYLE_FONT_ATLAS_COMP_SIZE, &advanceFontDataSize);
+    Image imFont = { data, 256, 256, 1, 2 };
+
+    Font font = { 0 };
+    font.baseSize = 12;
+    font.glyphCount = 189;
+
+    // Copy char recs data from global fontRecs
+    // NOTE: Required to avoid issues if trying to free font
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+    memcpy(font.recs, advanceFontRecs, font.glyphCount*sizeof(Rectangle));
+
+    // Copy font char info data from global fontChars
+    // NOTE: Required to avoid issues if trying to free font
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+    memcpy(font.glyphs, advanceFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
+
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
+    GuiSetFont(font);
+
+    // Setup a white rectangle on the font to be used on shapes drawing,
+    // it makes possible to draw shapes and text (full UI) in a single draw call
+    SetShapesTexture(font.texture, fontWhiteRec);
+
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "Fairfax.ttf");
+    //-----------------------------------------------------------------
+
+    // TODO: Custom user style setup: Set specific properties here (if required)
+    // i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
+}
diff --git a/raygui/styles/amber/style_amber.h b/raygui/styles/amber/style_amber.h
--- a/raygui/styles/amber/style_amber.h
+++ b/raygui/styles/amber/style_amber.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,24 +15,24 @@
 
 // Custom style name: Amber
 static const GuiStyleProp amberStyleProps[AMBER_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x898988ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x292929ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xd4d4d4ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xeb891dff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x292929ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xffffffff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xf1cf9dff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xf39333ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x191410ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x6a6a6aff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x818181ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x606060ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x898988ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x292929ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xd4d4d4ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xeb891dff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x292929ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xffffffff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xf1cf9dff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xf39333ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x191410ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x6a6a6aff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x818181ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x606060ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 18, (int)0xef922aff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x333333ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
-    { 1, 8, (int)0xe7e0d4ff },    // LABEL_TEXT_COLOR_PRESSED 
-    { 4, 8, (int)0xf1cf9dff },    // SLIDER_TEXT_COLOR_PRESSED 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 8, (int)0xe7e0d4ff },    // LABEL_TEXT_COLOR_PRESSED
+    { 4, 8, (int)0xf1cf9dff },    // SLIDER_TEXT_COLOR_PRESSED
 };
 
 // WARNING: This style uses a custom font: "hello-world.ttf" (size: 16, spacing: 1)
@@ -580,27 +580,38 @@
     font.baseSize = 16;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, amberFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, amberFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "hello-world.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/ashes/style_ashes.h b/raygui/styles/ashes/style_ashes.h
--- a/raygui/styles/ashes/style_ashes.h
+++ b/raygui/styles/ashes/style_ashes.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,22 +15,22 @@
 
 // Custom style name: Ashes
 static const GuiStyleProp ashesStyleProps[ASHES_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0xf0f0f0ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x868686ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xe6e6e6ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0x929999ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xeaeaeaff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0x98a1a8ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x3f3f3fff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xf6f6f6ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x414141ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x8b8b8bff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x777777ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x959595ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0xf0f0f0ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x868686ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xe6e6e6ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x929999ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xeaeaeaff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0x98a1a8ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x3f3f3fff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xf6f6f6ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x414141ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x8b8b8bff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x777777ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x959595ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 18, (int)0x9dadb1ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x6b6b6bff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "v5loxical.ttf" (size: 16, spacing: 1)
@@ -537,27 +537,38 @@
     font.baseSize = 16;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, ashesFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, ashesFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "v5loxical.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/bluish/style_bluish.h b/raygui/styles/bluish/style_bluish.h
--- a/raygui/styles/bluish/style_bluish.h
+++ b/raygui/styles/bluish/style_bluish.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,168 +15,166 @@
 
 // Custom style name: Bluish
 static const GuiStyleProp bluishStyleProps[BLUISH_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x5ca6a6ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0xb4e8f3ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x447e77ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0x5f8792ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xcdeff7ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0x4c6c74ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x3b5b5fff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xeaffffff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x275057ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x96aaacff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0xc8d7d9ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x8c9c9eff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x5ca6a6ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xb4e8f3ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x447e77ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x5f8792ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xcdeff7ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0x4c6c74ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x3b5b5fff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xeaffffff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x275057ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x96aaacff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xc8d7d9ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x8c9c9eff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 18, (int)0x84adb7ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0xe8eef1ff },    // DEFAULT_BACKGROUND_COLOR 
 };
 
 // WARNING: This style uses a custom font: "homespun.ttf" (size: 10, spacing: 1)
 
-#define BLUISH_STYLE_FONT_ATLAS_COMP_SIZE 2730
+#define BLUISH_STYLE_FONT_ATLAS_COMP_SIZE 2688
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char bluishFontData[BLUISH_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0x9d, 0xdb, 0x92, 0xdb, 0x38, 0x0c, 0x44, 0x45, 0xee, 0xff, 0xff, 0xf1, 0x90, 0xdc, 0xca, 0xc8, 0x33, 0xa9, 0x4d, 0xd4,
-    0x10, 0x01, 0x41, 0x17, 0xef, 0x9c, 0x9c, 0x4a, 0x1e, 0x44, 0x8b, 0x26, 0x09, 0x4a, 0x76, 0x84, 0x76, 0x63, 0x2c, 0x00,
-    0x00, 0x00, 0x00, 0x7f, 0x51, 0xc5, 0xb1, 0x2a, 0x5f, 0x5d, 0x1d, 0x3d, 0xad, 0xc7, 0xab, 0xd1, 0xee, 0xeb, 0xad, 0x3a,
-    0x7a, 0xb0, 0x5a, 0xec, 0xb6, 0x3f, 0x29, 0x2f, 0x32, 0x56, 0xb6, 0x7e, 0xaf, 0xc7, 0xf6, 0x2a, 0x79, 0x5e, 0x5f, 0x5d,
-    0xb3, 0xd8, 0x66, 0x88, 0x63, 0x7d, 0x73, 0xbe, 0x63, 0x14, 0xd1, 0x52, 0xc7, 0x10, 0xe3, 0x19, 0x9f, 0x67, 0x6d, 0xf7,
-    0x68, 0x9d, 0xb5, 0xf5, 0x1e, 0x6d, 0xa3, 0x8f, 0x26, 0x77, 0xc5, 0xaf, 0x77, 0x54, 0x2b, 0xd4, 0x45, 0x3c, 0xc7, 0xe6,
-    0x6b, 0x57, 0xca, 0xd4, 0xab, 0xad, 0x77, 0x18, 0xa3, 0x8d, 0xf6, 0x5a, 0x8f, 0x3f, 0x67, 0x31, 0x5c, 0xaf, 0xd7, 0x2d,
-    0xc7, 0xe3, 0xdf, 0x3f, 0xc7, 0x53, 0x36, 0xae, 0x83, 0x5f, 0xd1, 0xea, 0x22, 0x5e, 0x6a, 0x3c, 0xeb, 0xca, 0x95, 0xcd,
-    0x1e, 0xad, 0xb3, 0x96, 0xe9, 0xd5, 0xde, 0x3e, 0x7f, 0x1d, 0xe9, 0xf6, 0x3c, 0xca, 0x67, 0xdb, 0xd6, 0xda, 0xb5, 0xa4,
-    0xfb, 0xaa, 0x9a, 0xef, 0x62, 0x5e, 0x5b, 0xdb, 0xab, 0xd0, 0x5d, 0x2d, 0xc7, 0xe3, 0xaf, 0x77, 0xf4, 0x78, 0xfd, 0x55,
-    0x33, 0x6b, 0x62, 0x3c, 0x45, 0xb4, 0xd8, 0x67, 0x1d, 0x89, 0x7f, 0x79, 0x8d, 0xb4, 0x8a, 0xeb, 0x79, 0x88, 0x2b, 0xfa,
-    0xcc, 0xe8, 0xfb, 0xe3, 0x5f, 0x5e, 0x7b, 0xb5, 0x88, 0x4f, 0xa5, 0x6b, 0xe3, 0x5f, 0x5e, 0xf7, 0xff, 0x2a, 0x46, 0x5f,
-    0x64, 0xf4, 0xf5, 0xdd, 0xd6, 0xf3, 0xb9, 0xea, 0xbb, 0xfe, 0xd7, 0x75, 0x56, 0x7b, 0xeb, 0xbc, 0xd8, 0xdb, 0xf3, 0xf5,
-    0xc5, 0x7f, 0xc8, 0x4f, 0x9e, 0xaf, 0x5d, 0x7c, 0x74, 0x16, 0x3d, 0xe9, 0xfa, 0xef, 0x72, 0x3c, 0xe5, 0x75, 0xff, 0xdf,
-    0x9e, 0xb3, 0xe7, 0x2a, 0xf4, 0xc4, 0x7f, 0x2f, 0xc6, 0x67, 0x5e, 0xfb, 0xba, 0x6f, 0x7f, 0xfc, 0xd7, 0x1e, 0xb7, 0xde,
-    0xe5, 0xec, 0x5d, 0xbc, 0xb8, 0xbe, 0xff, 0x15, 0xe3, 0x3b, 0xcf, 0xd7, 0xde, 0xf1, 0xcc, 0x2f, 0x2b, 0xce, 0xd7, 0x33,
-    0x76, 0x67, 0xe0, 0x89, 0x7f, 0x91, 0xab, 0x5a, 0x2e, 0xff, 0xfc, 0xb7, 0xe2, 0x6f, 0x8d, 0xd4, 0x8a, 0xbf, 0x6f, 0x16,
-    0xc3, 0xf9, 0x1d, 0xfc, 0x79, 0xf1, 0x1f, 0xdf, 0xff, 0x1f, 0x9a, 0x9b, 0x9b, 0x7a, 0xbd, 0xd5, 0xd3, 0x3d, 0xb3, 0x8e,
-    0x8c, 0xe7, 0x69, 0xb3, 0x80, 0x23, 0x7c, 0x04, 0xe2, 0xf8, 0x41, 0xec, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xd2, 0x54, 0x3e, 0x59, 0x0a, 0x93, 0xec, 0x96, 0x63, 0xaa, 0x20, 0xad, 0xce, 0xb1, 0x14, 0x49, 0xf6, 0x28, 0xaf, 0x5a,
-    0x8f, 0xe5, 0x22, 0xcd, 0xcf, 0x08, 0x28, 0x52, 0xae, 0x6a, 0x69, 0xd3, 0x2a, 0x8c, 0xed, 0x6c, 0xae, 0x56, 0xe7, 0x74,
-    0xb1, 0x56, 0x7b, 0xa3, 0xbc, 0x6e, 0x3d, 0x6a, 0x60, 0x74, 0x91, 0xa7, 0xe5, 0x63, 0x27, 0x3b, 0xd7, 0x5c, 0x2d, 0x7d,
-    0x37, 0xd7, 0xe7, 0x53, 0xbe, 0x1c, 0xcb, 0xab, 0x5a, 0xea, 0x3c, 0xa5, 0xff, 0xb0, 0x46, 0xa9, 0x74, 0x15, 0x23, 0x3c,
-    0xeb, 0x96, 0x7a, 0x4e, 0x0b, 0xc5, 0x5f, 0xcf, 0x4a, 0xe7, 0xe6, 0x6d, 0xd5, 0xa3, 0xee, 0xcd, 0xd7, 0x32, 0xaf, 0x3e,
-    0x50, 0x31, 0xd6, 0x1a, 0x09, 0xaf, 0x76, 0x66, 0x18, 0xba, 0x8a, 0xbd, 0xb9, 0x35, 0x57, 0x6e, 0x72, 0xec, 0xac, 0xe1,
-    0x71, 0xb5, 0xcc, 0x9c, 0x3a, 0xa3, 0x1b, 0xf3, 0xb5, 0x15, 0x26, 0xdd, 0x75, 0x4e, 0x4f, 0xd0, 0xab, 0x78, 0x77, 0x8f,
-    0xa5, 0xc3, 0xe9, 0x46, 0xfc, 0xab, 0x73, 0x6e, 0x6b, 0x4b, 0x75, 0xe5, 0x82, 0xc7, 0xce, 0x1a, 0x1e, 0x57, 0xcb, 0xcc,
-    0xad, 0x5f, 0x09, 0xdf, 0xb1, 0xb3, 0xce, 0x39, 0x6f, 0x07, 0x0c, 0x77, 0x3f, 0xe3, 0x7b, 0xa7, 0x66, 0xde, 0xff, 0x4b,
-    0xe0, 0x13, 0xb9, 0x1c, 0xd6, 0x6a, 0xcc, 0xdf, 0xb1, 0x63, 0x0a, 0x93, 0xac, 0x73, 0x9e, 0xa5, 0xdd, 0x28, 0xc1, 0x3b,
-    0xf6, 0x35, 0x2d, 0x67, 0xc4, 0x3f, 0xaa, 0x30, 0xe9, 0x69, 0xe7, 0x2c, 0x97, 0x6b, 0x7a, 0x86, 0xbc, 0xfe, 0xad, 0xf5,
-    0xc8, 0x5c, 0x43, 0x4b, 0x07, 0x64, 0x8f, 0xe0, 0x27, 0xd0, 0x78, 0x66, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xe0, 0xd0, 0xff, 0xd8, 0xea, 0x1b, 0x9f, 0x42, 0xc5, 0x56, 0xed, 0x78, 0x3d, 0x7a, 0xea, 0xe5, 0xaa, 0x9b, 0xec,
-    0x96, 0xc8, 0x5a, 0xec, 0xb5, 0xf8, 0xce, 0xdc, 0x7f, 0xde, 0xad, 0x35, 0x25, 0xea, 0xa9, 0x76, 0xfb, 0x3c, 0x2b, 0x27,
-    0xfb, 0x37, 0x76, 0x47, 0xb6, 0xfe, 0x5b, 0x1f, 0xa8, 0x4f, 0xb2, 0x94, 0x4b, 0x5f, 0x23, 0xcf, 0xcc, 0x16, 0xae, 0x2d,
-    0x6d, 0x73, 0x2d, 0xa2, 0x39, 0xb4, 0x88, 0x0e, 0xc5, 0xce, 0x86, 0xe5, 0xc5, 0x3f, 0x3a, 0xe7, 0x6b, 0x5b, 0xbc, 0x3e,
-    0x22, 0xcf, 0x8b, 0xbf, 0xa5, 0xf2, 0xc9, 0x8a, 0xff, 0x31, 0x1d, 0x4c, 0x5e, 0xfc, 0x23, 0x1a, 0x2e, 0x3d, 0x76, 0x4b,
-    0x07, 0x75, 0x65, 0xfc, 0xb5, 0x8f, 0xd6, 0x4c, 0xfc, 0xfd, 0x2a, 0x1f, 0x7f, 0xfc, 0x8f, 0xe9, 0x60, 0xf2, 0xe2, 0x1f,
-    0xd1, 0x70, 0x74, 0xc3, 0x2d, 0xaa, 0xbb, 0xbd, 0x47, 0xc6, 0x8e, 0xc6, 0xb0, 0x05, 0xe2, 0x5f, 0xe4, 0x18, 0x8f, 0xea,
-    0x3f, 0x3d, 0xd7, 0x7f, 0x39, 0x4d, 0x07, 0x93, 0x7b, 0xff, 0xcf, 0x5a, 0x87, 0xb2, 0xa3, 0x3e, 0x2c, 0x01, 0xb5, 0x48,
-    0x4f, 0x5e, 0x8b, 0x39, 0xbd, 0x43, 0x4e, 0xfc, 0x23, 0x7d, 0xcd, 0x9d, 0xe3, 0x8d, 0x7f, 0x09, 0xc4, 0x3f, 0x73, 0xec,
-    0x76, 0xfc, 0x8b, 0xa1, 0x16, 0xd9, 0x3f, 0x27, 0x3b, 0xfe, 0x51, 0x55, 0x4b, 0x49, 0xec, 0x6b, 0x24, 0xc7, 0xdf, 0xaf,
-    0x93, 0xc9, 0x1d, 0xbb, 0x1d, 0xff, 0xf8, 0xe8, 0xd6, 0x3f, 0xf5, 0x04, 0x0d, 0x3d, 0xe0, 0x38, 0x03, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x2c, 0x46, 0x45, 0x2a, 0x5b, 0x65, 0x34, 0xaf, 0x16, 0xfa, 0x52, 0x50, 0x6c,
-    0xeb, 0x27, 0x72, 0x9c, 0x7e, 0xf6, 0x6b, 0x77, 0x79, 0xdf, 0x47, 0xad, 0x56, 0x64, 0x6c, 0x67, 0xd7, 0x38, 0x9b, 0x53,
-    0xf9, 0x58, 0xba, 0x17, 0xdf, 0x6f, 0x50, 0x95, 0x37, 0x4d, 0x15, 0x4e, 0x37, 0xde, 0xdf, 0xee, 0x5b, 0x5e, 0x15, 0xba,
-    0x9f, 0x4c, 0x17, 0x8b, 0x21, 0xf7, 0xeb, 0x08, 0x8c, 0xad, 0x89, 0xa3, 0xaa, 0x8f, 0x1a, 0xfe, 0xa5, 0x74, 0xdc, 0xcb,
-    0x61, 0xd6, 0x53, 0x49, 0x67, 0x0c, 0xd7, 0x5c, 0xb7, 0x77, 0x07, 0x74, 0x79, 0x8d, 0x6d, 0x8f, 0xb5, 0x4a, 0x7d, 0xcb,
-    0x22, 0xab, 0x99, 0xf9, 0xbd, 0x6a, 0x86, 0xa8, 0x1a, 0x66, 0xe7, 0x8f, 0xd4, 0xd8, 0x54, 0xb5, 0xa4, 0x45, 0xf4, 0xd1,
-    0xc2, 0xbf, 0x09, 0x1f, 0x3b, 0x75, 0xa4, 0x3c, 0x3d, 0x5b, 0x3b, 0xc0, 0xaa, 0xe4, 0xd6, 0x12, 0x6a, 0x95, 0xf8, 0xbd,
-    0x6a, 0x2c, 0xe5, 0x81, 0xdd, 0x9b, 0xd7, 0x9b, 0x45, 0xef, 0x19, 0xdf, 0x9d, 0x21, 0xcb, 0x61, 0x66, 0xee, 0xce, 0x59,
-    0x8c, 0x19, 0x2d, 0xee, 0x1d, 0x70, 0x6e, 0x25, 0x8f, 0xf3, 0x94, 0x07, 0xb3, 0xb3, 0xc8, 0xce, 0x2c, 0xcf, 0xc7, 0x7f,
-    0x39, 0xe4, 0x09, 0x52, 0xc2, 0x5a, 0x19, 0xdf, 0x0e, 0x38, 0x3b, 0xfe, 0x67, 0x29, 0x0f, 0xb2, 0x1c, 0x38, 0xfa, 0x43,
-    0xe3, 0xbf, 0xe7, 0x36, 0xe3, 0x8f, 0xa5, 0x5f, 0x31, 0xba, 0xdc, 0x72, 0x67, 0xc8, 0x3e, 0x67, 0x71, 0xff, 0x4f, 0xe6,
-    0x19, 0xf1, 0x8f, 0x39, 0xd4, 0x14, 0xb7, 0x97, 0xd0, 0x5d, 0xf1, 0xf7, 0xd7, 0x91, 0x8a, 0x9d, 0x93, 0xaf, 0xbd, 0xbc,
-    0x22, 0xfe, 0xf0, 0x3e, 0xce, 0x47, 0x0d, 0x7d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x29, 0xff,
-    0xc1, 0xa3, 0x5e, 0xb9, 0xbf, 0xa5, 0xee, 0x64, 0xb5, 0x4a, 0xb8, 0xa5, 0xa4, 0xf5, 0x69, 0x69, 0x8c, 0x8e, 0xd6, 0x3c,
-    0xfb, 0xea, 0xbb, 0x84, 0xd5, 0x3f, 0xbf, 0x73, 0xd0, 0xeb, 0xbf, 0x35, 0x29, 0xb3, 0x9e, 0xdf, 0x72, 0xfe, 0xaf, 0xf9,
-    0xcf, 0xf0, 0x1b, 0xb0, 0x1c, 0x22, 0xea, 0xb4, 0xb6, 0xa2, 0xc9, 0x9c, 0x6a, 0x97, 0x9e, 0x01, 0x2d, 0x90, 0x83, 0xb8,
-    0xdf, 0x65, 0xa7, 0x39, 0xeb, 0x50, 0xd5, 0x0b, 0x3d, 0x36, 0xfa, 0x8e, 0x1e, 0xc6, 0xa7, 0xa1, 0xd1, 0x1e, 0x0a, 0x8b,
-    0xeb, 0xb5, 0xaa, 0x26, 0x51, 0x79, 0xcb, 0xf8, 0x2f, 0x4e, 0x6d, 0x5f, 0x9f, 0xf0, 0xcb, 0xc8, 0xf2, 0xd8, 0x28, 0x01,
-    0x85, 0x4f, 0x31, 0xea, 0x8f, 0xf9, 0xe2, 0xaf, 0xaa, 0xd5, 0xf9, 0xef, 0x8d, 0x57, 0xb8, 0x6c, 0xe4, 0x57, 0xb0, 0xc9,
-    0x73, 0xf3, 0xc8, 0xf7, 0xd8, 0xb0, 0x32, 0xe5, 0x5a, 0x57, 0xe9, 0x8b, 0xbf, 0xd7, 0xdb, 0xe1, 0x8a, 0xf8, 0x47, 0x6b,
-    0xdb, 0xe4, 0x3a, 0x73, 0x94, 0x87, 0x78, 0x6c, 0x78, 0x1d, 0x42, 0x8e, 0xdf, 0xff, 0xb3, 0xf5, 0x08, 0x79, 0x99, 0xea,
-    0x6b, 0x7c, 0x36, 0x22, 0x3a, 0x9d, 0xb3, 0x32, 0xf3, 0xfe, 0xec, 0xbc, 0x47, 0x5b, 0xd9, 0xdf, 0x2a, 0xfe, 0x4f, 0xd6,
-    0xf6, 0x3c, 0x89, 0x33, 0x6b, 0x9e, 0xa1, 0xfe, 0x79, 0xd7, 0x3d, 0xcd, 0x1a, 0xfc, 0x6c, 0x95, 0x17, 0x6b, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x38, 0x00, 0x2d, 0xd2, 0xd3, 0x66, 0xbe, 0x87, 0x9a, 0xe6, 0x2f, 0xb4, 0x77,
-    0x4e, 0x75, 0xd6, 0x25, 0x2b, 0x6e, 0x7d, 0xce, 0xb1, 0xda, 0x63, 0xbe, 0x95, 0x8e, 0xf4, 0x35, 0xb7, 0x5e, 0x33, 0xfa,
-    0x2f, 0x4b, 0x45, 0xd1, 0xa6, 0x9e, 0xae, 0x0f, 0xe3, 0x79, 0x76, 0xfb, 0x9c, 0xc3, 0x87, 0xb3, 0x7a, 0x96, 0x7d, 0x8e,
-    0xaa, 0x08, 0xa6, 0xfa, 0x2b, 0x9f, 0x2a, 0x89, 0xe6, 0xd2, 0xe7, 0xec, 0xbf, 0x93, 0xfa, 0x4d, 0x77, 0x73, 0x57, 0x04,
-    0xb0, 0xab, 0x88, 0x95, 0xc3, 0x1e, 0x3e, 0x31, 0xe7, 0x94, 0x35, 0xbf, 0xd6, 0xa6, 0xde, 0xbf, 0x1a, 0x2e, 0x32, 0x4d,
-    0xea, 0x5f, 0xb4, 0xf7, 0x8b, 0x75, 0x4e, 0x79, 0x65, 0xfd, 0xea, 0xe6, 0xf5, 0xb2, 0xad, 0xc2, 0x2a, 0xa6, 0x37, 0x8d,
-    0xd6, 0x09, 0x95, 0x5d, 0x5f, 0xa3, 0xad, 0xb5, 0xe8, 0xc2, 0x53, 0xa8, 0x8b, 0x2b, 0x4d, 0x8d, 0x5b, 0x1d, 0xcf, 0x8d,
-    0xbf, 0x76, 0x41, 0x1a, 0x93, 0x33, 0xff, 0xad, 0x20, 0x2c, 0x8e, 0x3b, 0xa5, 0xe5, 0x7e, 0x54, 0x0c, 0xcf, 0xa6, 0x2e,
-    0xe3, 0xa9, 0xaf, 0xbd, 0x2e, 0x77, 0xa7, 0xb5, 0x2e, 0x7d, 0x77, 0xe7, 0xa8, 0x5c, 0x70, 0x71, 0xad, 0x91, 0xaa, 0x14,
-    0x78, 0xcd, 0xf5, 0xaf, 0x34, 0x14, 0x7d, 0x5a, 0x75, 0x62, 0xed, 0xed, 0x3d, 0xc7, 0x24, 0xbf, 0xe2, 0x73, 0x8d, 0xc7,
-    0x76, 0xfc, 0x6b, 0x9a, 0x1a, 0x60, 0x7c, 0xaf, 0x68, 0x0f, 0x7e, 0xb2, 0xce, 0xdf, 0xff, 0xd5, 0x27, 0x70, 0x99, 0xdc,
-    0xb5, 0xc7, 0xe2, 0x5f, 0x4c, 0xcf, 0x96, 0x72, 0xf0, 0xfa, 0xb7, 0xd4, 0x9b, 0xb6, 0xcb, 0x9a, 0xff, 0xfa, 0xef, 0x52,
-    0x6d, 0xf7, 0xec, 0xf8, 0xab, 0x71, 0xcf, 0xce, 0xe7, 0x58, 0xfc, 0x6d, 0x85, 0xd2, 0x6c, 0xaf, 0xf6, 0xdc, 0x86, 0xeb,
-    0xbb, 0x97, 0xf5, 0xad, 0xac, 0x7c, 0xbf, 0xa6, 0x5e, 0xe0, 0x1b, 0x74, 0xc5, 0x3b, 0xdd, 0xad, 0x83, 0xfa, 0x70, 0xd7,
-    0xa9, 0xd2, 0xca, 0x39, 0x6f, 0x8d, 0xbc, 0xa8, 0x9e, 0x6e, 0x4c, 0x7f, 0x37, 0x39, 0xaa, 0x2d, 0xca, 0x7a, 0xa7, 0x71,
-    0xa2, 0x5a, 0xe9, 0xc9, 0x3a, 0xa8, 0x98, 0xcb, 0xde, 0x7b, 0xeb, 0xba, 0xd0, 0x8c, 0xcc, 0xc4, 0x32, 0xa6, 0x9a, 0x04,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xfa, 0xc7, 0xaa, 0x5c, 0x35, 0x77, 0xfe, 0xbc, 0x72, 0xa5, 0xc8,
-    0x5e, 0xeb, 0x44, 0x05, 0xad, 0xe2, 0xd6, 0xbe, 0x54, 0xb7, 0xe6, 0xc9, 0x56, 0xe9, 0xe8, 0xe3, 0x79, 0xda, 0xa7, 0x88,
-    0xea, 0x68, 0x09, 0x3f, 0xa3, 0x5e, 0xff, 0x34, 0xb3, 0x3e, 0x8f, 0xfd, 0xec, 0x71, 0x38, 0x54, 0x30, 0x5d, 0xd6, 0x7b,
-    0x5a, 0xcf, 0x68, 0x32, 0x1f, 0x3c, 0x44, 0x46, 0xa8, 0x99, 0x39, 0x8c, 0x26, 0x8f, 0xff, 0x23, 0xa3, 0xfc, 0x21, 0xdd,
-    0x7a, 0xb6, 0xcf, 0x1a, 0x9f, 0xc7, 0xbb, 0x6b, 0x6c, 0xc3, 0xac, 0xad, 0x36, 0x8c, 0x36, 0xa5, 0x08, 0xd0, 0x33, 0x9a,
-    0x89, 0x7f, 0x39, 0x90, 0x37, 0x1d, 0x32, 0x4f, 0xbf, 0xad, 0xc4, 0xd2, 0x1e, 0x3a, 0x76, 0x9b, 0xd2, 0xc8, 0x2c, 0xa6,
-    0x43, 0x96, 0xde, 0xb7, 0xde, 0x1d, 0xa3, 0x62, 0xd9, 0xa4, 0x5e, 0xc9, 0xd6, 0xbe, 0x54, 0x43, 0xe1, 0x60, 0xf9, 0x0c,
-    0x79, 0x47, 0xfe, 0xa4, 0xf8, 0x77, 0xd3, 0xf7, 0x40, 0x6b, 0x48, 0xf6, 0x7c, 0x6e, 0xb4, 0xe2, 0xaa, 0x84, 0xee, 0xbe,
-    0x39, 0x2d, 0xf6, 0x55, 0xde, 0x64, 0x86, 0xdb, 0x5a, 0x07, 0xfb, 0x53, 0x3c, 0xa2, 0x49, 0xe8, 0xa7, 0xc4, 0xbf, 0x06,
-    0xf5, 0x56, 0x3e, 0xcf, 0x26, 0x3b, 0x8b, 0xa8, 0xfd, 0x9a, 0xae, 0x72, 0xae, 0x5b, 0x02, 0xb9, 0x4f, 0x4b, 0x4b, 0xb3,
-    0x98, 0x15, 0xeb, 0xa2, 0x31, 0xec, 0x87, 0xe2, 0x7f, 0x44, 0xb9, 0xf2, 0xf7, 0x1d, 0xa3, 0x38, 0x73, 0xe7, 0x96, 0x8a,
-    0x48, 0xaf, 0x56, 0xa4, 0xbe, 0xe3, 0x55, 0x2d, 0xd6, 0x3a, 0xd8, 0xfd, 0x1d, 0xd1, 0x25, 0xdd, 0xed, 0xa2, 0xf3, 0x75,
-    0x8d, 0x77, 0xb7, 0x8b, 0x8e, 0xad, 0x15, 0xea, 0xb7, 0x3b, 0x57, 0xfa, 0xef, 0x19, 0x5d, 0x46, 0x59, 0x5f, 0x05, 0xfd,
-    0xe0, 0x15, 0x7c, 0x7f, 0xfc, 0x63, 0xaa, 0x8f, 0x12, 0x50, 0x91, 0x5c, 0xeb, 0x69, 0xe8, 0x6f, 0xe9, 0xc6, 0x3a, 0x58,
-    0xae, 0x51, 0x3f, 0x51, 0x49, 0x11, 0xaf, 0xd5, 0xf7, 0xcc, 0xf8, 0xef, 0x69, 0xf5, 0x2c, 0x2f, 0xd1, 0xfb, 0x9d, 0xd0,
-    0x9e, 0xa4, 0x2f, 0xfa, 0x3f, 0xc6, 0xff, 0x1d, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x64, 0x07,
-    0x20, 0x5b, 0x6b, 0x52, 0x53, 0x74, 0x35, 0xfa, 0x68, 0x75, 0x7a, 0x12, 0x55, 0xf3, 0xac, 0x7b, 0xf5, 0x3e, 0xc5, 0x7c,
-    0x3a, 0x7b, 0xfe, 0x98, 0xed, 0xe8, 0x7b, 0x15, 0x2f, 0x96, 0x16, 0xa2, 0xba, 0xde, 0xa5, 0x1a, 0xef, 0xf0, 0x21, 0x9e,
-    0x74, 0xfa, 0x75, 0x38, 0xf7, 0xeb, 0x7d, 0x94, 0xa2, 0xa3, 0x1a, 0x1e, 0x2f, 0x99, 0x63, 0xb6, 0x15, 0x5c, 0x5e, 0xc5,
-    0x8b, 0xa5, 0x36, 0xf0, 0xa9, 0x53, 0x9a, 0x68, 0xd1, 0xfd, 0xeb, 0x27, 0xdd, 0xcd, 0xf0, 0x0d, 0xba, 0x5b, 0xef, 0xa3,
-    0x6b, 0x4e, 0x29, 0x1d, 0x48, 0x95, 0x3b, 0x60, 0x75, 0xb2, 0xaa, 0xae, 0x31, 0x2f, 0x01, 0xe5, 0x48, 0x44, 0xd7, 0xe2,
-    0x75, 0x32, 0x53, 0xc7, 0x57, 0x0d, 0x9c, 0xf6, 0x24, 0xf2, 0x39, 0x0d, 0xdd, 0xaf, 0xf7, 0xe9, 0xa6, 0xcb, 0x54, 0x56,
-    0xee, 0x20, 0xe2, 0x03, 0xb7, 0xe7, 0xcf, 0xe3, 0xab, 0xd5, 0xa7, 0x3c, 0x83, 0xbc, 0xc7, 0x17, 0xe9, 0xe3, 0x34, 0x8c,
-    0xec, 0xf8, 0x13, 0x72, 0xf7, 0xbe, 0xac, 0xce, 0xaa, 0x7a, 0x18, 0x37, 0x66, 0x95, 0xb4, 0x72, 0x24, 0xd2, 0xb2, 0xec,
-    0x54, 0x57, 0xcb, 0x3a, 0xfe, 0xdc, 0xdc, 0xbd, 0x37, 0xfe, 0xe3, 0xf6, 0xf8, 0xdb, 0x2a, 0x39, 0x5f, 0x0b, 0xf1, 0xf7,
-    0xc6, 0xbf, 0x27, 0xde, 0xff, 0x63, 0xf1, 0xd7, 0x2a, 0x39, 0x7f, 0xcb, 0x15, 0xf1, 0x1f, 0x66, 0xe5, 0xbc, 0x77, 0x8b,
-    0x7f, 0xb9, 0x59, 0x55, 0x90, 0x5b, 0xc5, 0xf3, 0xfc, 0xf8, 0xc7, 0x54, 0x1d, 0xe5, 0xe6, 0x16, 0xbf, 0x6e, 0xe3, 0x9a,
-    0xf7, 0xcf, 0xaf, 0xe2, 0x79, 0xee, 0xf1, 0x68, 0xfc, 0xf3, 0xe7, 0x38, 0x52, 0x7c, 0xab, 0xda, 0x45, 0x71, 0x01, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x3f, 0x35, 0x49, 0x99, 0x12, 0x75, 0xa8, 0xb9, 0xd7, 0x73, 0xc7, 0xf2, 0x17,
-    0xd2, 0x2d, 0xd9, 0x33, 0xf2, 0x6a, 0xaa, 0x72, 0x7c, 0x80, 0x2c, 0xcd, 0x40, 0x95, 0x1a, 0x1c, 0x7f, 0x06, 0xdc, 0xd6,
-    0x06, 0xb5, 0x80, 0x06, 0xa7, 0x1a, 0x1a, 0x9c, 0xe6, 0xf2, 0xdc, 0xe8, 0x86, 0xbf, 0x90, 0xe5, 0xac, 0x90, 0x39, 0x23,
-    0x3d, 0xee, 0x26, 0x76, 0x45, 0x13, 0x7a, 0xaa, 0x9a, 0x74, 0xfd, 0x6b, 0x9d, 0x49, 0x34, 0x03, 0x1e, 0xd3, 0xe0, 0x34,
-    0x97, 0x06, 0xc7, 0xaa, 0x1d, 0x55, 0x77, 0x6a, 0x73, 0xe9, 0x9c, 0x4a, 0xae, 0x8b, 0x90, 0x6f, 0xdc, 0x7a, 0x05, 0xe6,
-    0xf5, 0x54, 0xd7, 0xfd, 0x16, 0xb6, 0x08, 0xa5, 0x5b, 0xe4, 0x0e, 0x1b, 0x69, 0xd1, 0x7e, 0x10, 0x56, 0xcd, 0xbe, 0x48,
-    0xfd, 0xa2, 0xdc, 0x71, 0x5b, 0x75, 0xf8, 0x8a, 0xc3, 0xd9, 0x2a, 0x33, 0x6b, 0x16, 0x73, 0xaf, 0xd9, 0xae, 0x97, 0x93,
-    0x5b, 0x07, 0x48, 0xb7, 0x14, 0xe9, 0x91, 0x52, 0xcc, 0x4a, 0x54, 0xdd, 0x5d, 0x05, 0x27, 0x5b, 0x3b, 0x54, 0x0c, 0x95,
-    0xe0, 0xfc, 0x7d, 0x29, 0x33, 0x6b, 0x16, 0x73, 0xaf, 0x59, 0x8c, 0xd5, 0x3f, 0xbf, 0x65, 0x84, 0xaa, 0x4a, 0xd9, 0x99,
-    0xb3, 0x7e, 0x89, 0x8b, 0x50, 0x37, 0xf4, 0x36, 0x77, 0xc4, 0x7f, 0x7f, 0xbd, 0xfc, 0x77, 0x86, 0x6b, 0xae, 0x23, 0xef,
-    0x0e, 0x8c, 0x7a, 0x6e, 0x44, 0x94, 0x93, 0x96, 0xc7, 0x99, 0xcf, 0x61, 0xed, 0xec, 0xf8, 0x97, 0x9d, 0xfb, 0xbf, 0x76,
-    0xf1, 0x1a, 0xb7, 0x6a, 0x30, 0xfc, 0xf7, 0xeb, 0x3c, 0xdf, 0xbb, 0x23, 0x2d, 0x76, 0x1d, 0xbe, 0xf3, 0xe2, 0x9f, 0xa9,
-    0x26, 0xb9, 0x56, 0x67, 0x32, 0x92, 0x94, 0x4e, 0x4f, 0x98, 0x91, 0x77, 0xa7, 0xe5, 0xc5, 0xff, 0xa7, 0xa8, 0x49, 0x50,
-    0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xcf, 0xd5, 0xff, 0xf8, 0x3c, 0x78, 0x9e, 0xec, 0xb3, 0x93, 0xe7,
-    0x40, 0x94, 0xad, 0xe2, 0x89, 0xa9, 0xa9, 0x96, 0x03, 0x95, 0xbd, 0xe6, 0xf5, 0x3f, 0x4d, 0xaa, 0x5b, 0x54, 0xed, 0xaa,
-    0x7a, 0x81, 0x22, 0x26, 0xa2, 0xf1, 0x51, 0x47, 0xad, 0xdc, 0xcf, 0x35, 0x2a, 0x1e, 0xdd, 0xdb, 0xd8, 0xd1, 0x66, 0xb5,
-    0x93, 0x9f, 0x58, 0x16, 0x63, 0xf6, 0x55, 0xee, 0x98, 0xf6, 0x48, 0x8d, 0x4f, 0x44, 0x5d, 0x91, 0xab, 0xe2, 0xd1, 0x2b,
-    0xda, 0xa4, 0xc2, 0xc0, 0xae, 0xbf, 0x58, 0x4e, 0x7f, 0x2e, 0xae, 0xc7, 0xdb, 0x6f, 0x54, 0xf2, 0x44, 0xb4, 0x32, 0xdd,
-    0x54, 0xf1, 0x74, 0x57, 0xc4, 0x22, 0x2d, 0x7b, 0xd9, 0xd4, 0x92, 0xa8, 0xa6, 0x3b, 0x37, 0xfe, 0x11, 0x85, 0xc5, 0x13,
-    0x7c, 0x76, 0x8a, 0xe1, 0x72, 0xf2, 0x8e, 0xb5, 0x60, 0xee, 0x8a, 0xff, 0x7b, 0xae, 0x98, 0xed, 0x4a, 0xf1, 0x6e, 0x51,
-    0x1e, 0x41, 0xc5, 0x4a, 0x4e, 0xfc, 0x9f, 0xbd, 0x2e, 0x79, 0x3e, 0x1b, 0xd7, 0x8c, 0x2c, 0xa6, 0x09, 0xbb, 0x22, 0x63,
-    0x3d, 0x12, 0xaf, 0x98, 0xbb, 0x35, 0x3e, 0x11, 0x9f, 0x8d, 0xab, 0xd4, 0x47, 0x51, 0x9d, 0xc5, 0x3d, 0x55, 0x9d, 0x62,
-    0x57, 0xcc, 0xdd, 0x1a, 0x9f, 0x27, 0xab, 0x78, 0xfc, 0x6a, 0x3a, 0xad, 0x58, 0x87, 0x77, 0x43, 0xc7, 0xb2, 0xb1, 0x3a,
+    0x9d, 0xed, 0x76, 0xdb, 0x38, 0x0c, 0x44, 0x45, 0xee, 0xfb, 0xbf, 0x71, 0x48, 0xee, 0x69, 0xe4, 0xa4, 0x67, 0xbb, 0x1a,
+    0x50, 0x80, 0xa0, 0x0f, 0x37, 0xb7, 0xf7, 0xb4, 0x3f, 0xc4, 0x88, 0x26, 0x09, 0x8a, 0x4e, 0x8d, 0xf1, 0x60, 0x2c, 0x00,
+    0x00, 0x00, 0x00, 0xff, 0xa3, 0x8a, 0x6b, 0x55, 0xfe, 0x74, 0x75, 0xf4, 0xb4, 0x5e, 0xaf, 0x46, 0xbb, 0xaf, 0xb7, 0xea,
+    0xe8, 0xc1, 0x6a, 0xb1, 0xdb, 0xfe, 0xa4, 0xbc, 0xc8, 0x58, 0xd9, 0xfa, 0xbd, 0x1e, 0xdb, 0xab, 0xe4, 0xf9, 0xf9, 0xea,
+    0x9a, 0xc5, 0x36, 0x43, 0x5c, 0xeb, 0x9b, 0xf3, 0x1d, 0xa3, 0x88, 0x96, 0x3a, 0x86, 0x18, 0xcf, 0xf8, 0xbc, 0x6b, 0xbb,
+    0x47, 0xeb, 0xae, 0xad, 0xd7, 0x68, 0x1b, 0x7d, 0x34, 0xb9, 0x2b, 0x7e, 0xbd, 0xa2, 0x5a, 0xa1, 0x2e, 0xe2, 0x39, 0x36,
+    0x7f, 0x76, 0xa5, 0xec, 0xfa, 0x69, 0xeb, 0x15, 0xc6, 0x68, 0xa3, 0xbd, 0xd6, 0xe3, 0xcf, 0x59, 0x0c, 0xd7, 0xcf, 0xeb,
+    0x96, 0xe3, 0xf1, 0xef, 0x9f, 0xe3, 0x29, 0x1b, 0xcf, 0xc1, 0xaf, 0x68, 0x75, 0x11, 0x2f, 0x35, 0x9e, 0x75, 0xe5, 0xca,
+    0x66, 0x8f, 0xd6, 0x5d, 0xcb, 0xee, 0xd5, 0xde, 0xbe, 0x7f, 0x1d, 0xe9, 0xf6, 0x3c, 0xca, 0x67, 0xdb, 0xd6, 0xda, 0xb5,
+    0xa4, 0x73, 0x55, 0xcd, 0x77, 0x31, 0x9f, 0xad, 0xed, 0x55, 0xe8, 0xae, 0x96, 0xe3, 0xf1, 0xd7, 0x3b, 0x7a, 0xbc, 0xfe,
+    0xaa, 0x99, 0x35, 0x31, 0x9e, 0x22, 0x5a, 0xec, 0xbb, 0x8e, 0xc4, 0xbf, 0xbc, 0x46, 0x5a, 0xc5, 0xf3, 0x3c, 0xc4, 0x13,
+    0x7d, 0x66, 0xf4, 0xfd, 0xf1, 0x2f, 0xaf, 0xbd, 0x5a, 0xc4, 0xbb, 0xd2, 0xb5, 0xf1, 0x2f, 0xaf, 0xf3, 0xbf, 0x8a, 0xd1,
+    0x17, 0x19, 0x7d, 0x7d, 0xda, 0x7a, 0xde, 0x57, 0x7d, 0xcf, 0xff, 0xba, 0xce, 0x6a, 0x6f, 0x9d, 0x17, 0x7b, 0x7b, 0xbe,
+    0xbe, 0xf8, 0x0f, 0xf9, 0xce, 0xf3, 0xb5, 0x8b, 0x8f, 0xce, 0xa2, 0x27, 0x3d, 0xff, 0x5d, 0x8e, 0xa7, 0xbc, 0xce, 0xff,
+    0xed, 0x39, 0x7b, 0x9e, 0x42, 0x4f, 0xfc, 0x67, 0x31, 0x3e, 0xf3, 0xd9, 0xd7, 0x7d, 0xfb, 0xe3, 0xbf, 0xf6, 0xb8, 0xf5,
+    0x2a, 0x67, 0xef, 0xe2, 0xc5, 0xf5, 0xfb, 0x5f, 0x31, 0x7e, 0xe7, 0xf9, 0xda, 0x3b, 0x9e, 0xf9, 0x65, 0xc5, 0xf9, 0x7a,
+    0xc6, 0x74, 0x06, 0x9e, 0xf8, 0x17, 0xb9, 0xaa, 0xe5, 0xf2, 0xf7, 0x7f, 0x2b, 0xfe, 0xd6, 0x48, 0xad, 0xf8, 0xfb, 0x66,
+    0x31, 0x9c, 0xbf, 0x83, 0x3f, 0x2f, 0xfe, 0xe3, 0xfb, 0xff, 0x43, 0xfb, 0xe6, 0xa6, 0x7e, 0xde, 0xea, 0xe9, 0x9e, 0x59,
+    0x47, 0xc6, 0xf3, 0xb4, 0x59, 0xc0, 0x11, 0x3e, 0x02, 0x71, 0xfc, 0x20, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x69, 0x2a, 0x9f, 0x2c, 0x85, 0x49, 0x76, 0xcb, 0x31, 0x55, 0x90, 0x56, 0xe7, 0x58, 0x8a, 0x24, 0x7b, 0x94, 0x57,
+    0xad, 0xc7, 0x72, 0x91, 0xe6, 0x67, 0x04, 0x14, 0x29, 0x57, 0xb5, 0xb4, 0xdd, 0x2a, 0x8c, 0xed, 0x6c, 0xae, 0x56, 0xe7,
+    0x74, 0xb1, 0x56, 0xb3, 0x51, 0x5e, 0xb7, 0x1e, 0x35, 0x30, 0xba, 0xc8, 0xa7, 0xe5, 0x63, 0x92, 0x9d, 0x6b, 0xae, 0x96,
+    0x3e, 0xcd, 0xf5, 0xf9, 0x94, 0x2f, 0xc7, 0xf2, 0xaa, 0x96, 0x3a, 0x4f, 0xe9, 0x3f, 0xac, 0x51, 0x2a, 0x5d, 0xc5, 0x08,
+    0xcf, 0xba, 0xa5, 0xde, 0xd3, 0x42, 0xf1, 0xd7, 0xb3, 0xd2, 0xb9, 0x79, 0x5b, 0xf5, 0xa8, 0x7b, 0xf3, 0xb5, 0xec, 0x57,
+    0x1f, 0xa8, 0x18, 0x6b, 0x8d, 0x84, 0x57, 0x3b, 0x33, 0x0c, 0x5d, 0xc5, 0x6c, 0x6e, 0xcd, 0x95, 0x9b, 0x1c, 0x93, 0x35,
+    0x3c, 0xae, 0x96, 0xd9, 0xa7, 0xce, 0xe8, 0xc6, 0x7c, 0x6d, 0x85, 0x49, 0x77, 0xdd, 0xd3, 0x13, 0xf4, 0x2a, 0xde, 0xdd,
+    0x63, 0xe9, 0x70, 0xba, 0x11, 0xff, 0xea, 0x9c, 0xdb, 0xda, 0x52, 0x5d, 0xb9, 0xe0, 0x31, 0x59, 0xc3, 0xe3, 0x6a, 0x99,
+    0x7d, 0xeb, 0x57, 0xc2, 0x27, 0x76, 0xd6, 0x3d, 0xe7, 0xed, 0x80, 0xe1, 0xee, 0x67, 0x7c, 0xef, 0xd4, 0xcc, 0xf3, 0xbf,
+    0x04, 0xde, 0x91, 0xcb, 0x61, 0xad, 0xc6, 0xfe, 0x13, 0x3b, 0xa6, 0x30, 0xc9, 0xba, 0xe7, 0x59, 0xda, 0x8d, 0x12, 0x3c,
+    0xb1, 0xaf, 0x69, 0x39, 0x23, 0xfe, 0x51, 0x85, 0x49, 0x4f, 0xbb, 0x67, 0xb9, 0x5c, 0xd3, 0x33, 0xe4, 0xf3, 0x6f, 0xad,
+    0x47, 0xe6, 0x1a, 0x5a, 0x3a, 0x20, 0x7b, 0x04, 0x3f, 0x81, 0xc6, 0x67, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0e, 0xfd, 0x8f, 0xad, 0xbe, 0xf1, 0x29, 0x54, 0x6c, 0xd5, 0x8e, 0xd7, 0xa3, 0xa7, 0x5e, 0xae, 0xba, 0xc9,
+    0x6e, 0x89, 0xac, 0xc5, 0xac, 0xc5, 0x77, 0xe7, 0xfc, 0xf3, 0x6e, 0xad, 0x29, 0x51, 0x9f, 0x6a, 0xb7, 0xcf, 0xbb, 0x72,
+    0xb2, 0x7f, 0x63, 0x3a, 0xb2, 0xf5, 0xdf, 0xfa, 0x40, 0x7d, 0x92, 0xa5, 0x5c, 0xfa, 0x1a, 0x79, 0x66, 0xb6, 0x70, 0x6d,
+    0x69, 0x9b, 0x6b, 0x11, 0xcd, 0xa1, 0x45, 0x74, 0x28, 0x76, 0x36, 0x2c, 0x2f, 0xfe, 0xd1, 0x39, 0x5f, 0xdb, 0xe2, 0xf5,
+    0x11, 0x79, 0x5e, 0xfc, 0x2d, 0x95, 0x4f, 0x56, 0xfc, 0x8f, 0xe9, 0x60, 0xf2, 0xe2, 0x1f, 0xd1, 0x70, 0xe9, 0xb1, 0x5b,
+    0x3a, 0xa8, 0x2b, 0xe3, 0xaf, 0x7d, 0xb4, 0xf6, 0xc4, 0xdf, 0xaf, 0xf2, 0xf1, 0xc7, 0xff, 0x98, 0x0e, 0x26, 0x2f, 0xfe,
+    0x11, 0x0d, 0x47, 0x37, 0xdc, 0xa2, 0xba, 0xdb, 0x7b, 0x64, 0x4c, 0x34, 0x86, 0x2d, 0x10, 0xff, 0x22, 0xc7, 0x78, 0x54,
+    0xff, 0xe9, 0x79, 0xfe, 0xcb, 0x69, 0x3a, 0x98, 0xdc, 0xf3, 0x3f, 0x6b, 0x1d, 0xca, 0x44, 0x7d, 0x58, 0x02, 0x6a, 0x91,
+    0x9e, 0xbc, 0x16, 0xfb, 0xf4, 0x0e, 0x39, 0xf1, 0x8f, 0xf4, 0xb5, 0xef, 0x1e, 0x6f, 0xfc, 0x4b, 0x20, 0xfe, 0x99, 0x63,
+    0xb7, 0xe3, 0x5f, 0x0c, 0xb5, 0xc8, 0xfc, 0x9e, 0xec, 0xf8, 0x47, 0x55, 0x2d, 0x25, 0xb1, 0xaf, 0x91, 0x1c, 0x7f, 0xbf,
+    0x4e, 0x26, 0x77, 0xec, 0x76, 0xfc, 0xe3, 0xa3, 0x5b, 0xff, 0xd4, 0x13, 0x34, 0xf4, 0x80, 0xe3, 0x0c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xb3, 0x18, 0x15, 0xa9, 0x6c, 0x95, 0xd1, 0x7e, 0xb5, 0xd0, 0x97, 0x82, 0x62,
+    0x5b, 0x3f, 0x91, 0xe3, 0xf4, 0x33, 0xaf, 0xdd, 0xe5, 0x7d, 0x1d, 0xb5, 0x5a, 0x91, 0xb1, 0x9d, 0x5d, 0xe3, 0x6c, 0x9f,
+    0xca, 0xc7, 0xd2, 0xbd, 0xf8, 0xbe, 0x83, 0xaa, 0xbc, 0x69, 0xaa, 0x70, 0xba, 0xf1, 0x7e, 0x77, 0xdf, 0xf2, 0xaa, 0xd0,
+    0xfd, 0x64, 0xba, 0x58, 0x0c, 0xb9, 0x5f, 0x47, 0x60, 0x6c, 0x4d, 0x5c, 0x55, 0x7d, 0xd4, 0xf0, 0x37, 0xa5, 0xe3, 0x5e,
+    0x0e, 0x7b, 0x3d, 0x95, 0x74, 0xc6, 0x70, 0xcd, 0x75, 0x7b, 0x77, 0x40, 0x97, 0xcf, 0xd8, 0xf6, 0x58, 0xab, 0xd4, 0xb7,
+    0x2c, 0xb2, 0x9a, 0x99, 0xdf, 0xab, 0x66, 0x88, 0xaa, 0x61, 0x76, 0xfe, 0x48, 0x8d, 0x4d, 0x55, 0x4b, 0x5a, 0x44, 0x1f,
+    0x2d, 0xfc, 0x9d, 0xf0, 0x31, 0xa9, 0x23, 0xe5, 0xe9, 0xd9, 0xda, 0x01, 0x56, 0x25, 0xb7, 0x96, 0x50, 0xab, 0xc4, 0xef,
+    0x55, 0x63, 0x29, 0x0f, 0xec, 0xde, 0xbc, 0xde, 0x2c, 0x7a, 0xcf, 0xf8, 0x4e, 0x86, 0x2c, 0x87, 0x99, 0x7d, 0x27, 0x67,
+    0x31, 0x66, 0xb4, 0xb8, 0x77, 0xc0, 0xb9, 0x95, 0x3c, 0xce, 0x53, 0x1e, 0xec, 0x9d, 0x45, 0x76, 0x66, 0x79, 0x7f, 0xfc,
+    0x97, 0x43, 0x9e, 0x20, 0x25, 0xac, 0x95, 0xf1, 0xed, 0x80, 0xb3, 0xe3, 0x7f, 0x96, 0xf2, 0x20, 0xcb, 0x81, 0xa3, 0x3f,
+    0x34, 0xfe, 0x33, 0xb7, 0x19, 0x7f, 0x2c, 0xfd, 0x8a, 0xd1, 0xe5, 0x96, 0x93, 0x21, 0xfb, 0x9e, 0xc5, 0xfd, 0x3f, 0x99,
+    0x67, 0xc4, 0x3f, 0xe6, 0x50, 0x53, 0xdc, 0x5e, 0x42, 0x77, 0xc5, 0xdf, 0x5f, 0x47, 0x2a, 0x76, 0x4f, 0xbe, 0xf6, 0xf2,
+    0x8a, 0xf8, 0xc3, 0xfb, 0x38, 0x1f, 0x35, 0xf4, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa4, 0xfc,
+    0x07, 0x8f, 0x7a, 0xe5, 0xfe, 0x96, 0x3a, 0xc9, 0x6a, 0x95, 0x70, 0x4b, 0x49, 0xeb, 0xd3, 0xd2, 0x18, 0x1d, 0xad, 0x79,
+    0xf6, 0xd5, 0x77, 0x09, 0xab, 0x7f, 0x7e, 0xe7, 0xa0, 0xd7, 0x7f, 0x6b, 0x52, 0x66, 0x3d, 0xbf, 0xe5, 0xfc, 0x6f, 0xf3,
+    0x9f, 0xe1, 0x37, 0x60, 0x39, 0x44, 0xd4, 0xdd, 0xda, 0x8a, 0x26, 0x73, 0xaa, 0x5d, 0x7a, 0x06, 0xb4, 0x40, 0x0e, 0xe2,
+    0x7e, 0x97, 0x9d, 0xe6, 0xac, 0x43, 0x55, 0x2f, 0xf4, 0xd8, 0xe8, 0x13, 0x3d, 0x8c, 0x4f, 0x43, 0xa3, 0x3d, 0x14, 0x16,
+    0xd7, 0xcf, 0xaa, 0x9a, 0x44, 0xe5, 0x2d, 0xe3, 0xbf, 0x38, 0xb5, 0x7d, 0x7d, 0x87, 0x5f, 0x46, 0x96, 0xc7, 0x46, 0x09,
+    0x28, 0x7c, 0x8a, 0x51, 0x7f, 0xcc, 0x17, 0x7f, 0x55, 0xad, 0xce, 0x7f, 0x36, 0x5e, 0xe1, 0xb2, 0x91, 0x5f, 0xc1, 0x26,
+    0xcf, 0xcd, 0x23, 0xdf, 0x63, 0xc3, 0xca, 0x94, 0x6b, 0x5d, 0xa5, 0x2f, 0xfe, 0x5e, 0x6f, 0x87, 0x2b, 0xe2, 0x1f, 0xad,
+    0x6d, 0x93, 0xeb, 0xcc, 0x51, 0x1e, 0xe2, 0xb1, 0xe1, 0x75, 0x08, 0x39, 0x7e, 0xfe, 0x67, 0xeb, 0x11, 0xf2, 0x32, 0xd5,
+    0xd7, 0xf8, 0x6c, 0x44, 0x74, 0x3a, 0x67, 0x65, 0xe6, 0xfd, 0xd9, 0x79, 0x8f, 0xb6, 0xb2, 0xbf, 0x55, 0xfc, 0x9f, 0xac,
+    0xed, 0x79, 0x12, 0x67, 0xd6, 0x3c, 0x43, 0xfd, 0xf3, 0xae, 0x7b, 0x9a, 0x35, 0xf8, 0xd9, 0x2a, 0x2f, 0xd6, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x71, 0x00, 0x5a, 0xa4, 0xa7, 0x8d, 0xbe, 0xa3, 0xa6, 0xf9, 0x09, 0xcd, 0xee,
+    0xa9, 0xce, 0x3a, 0x64, 0xc5, 0xad, 0xc7, 0x39, 0x56, 0x6b, 0xcc, 0xb7, 0xb2, 0xde, 0xbe, 0xf6, 0xac, 0xcf, 0x12, 0x54,
+    0x00, 0x14, 0x53, 0x45, 0xd1, 0xcc, 0x1c, 0xda, 0xb6, 0xee, 0xe4, 0xd7, 0x68, 0x3e, 0x9c, 0xd5, 0xb2, 0xec, 0x7b, 0x54,
+    0x05, 0x30, 0xd5, 0x5f, 0xf9, 0x54, 0x45, 0x34, 0x97, 0x1e, 0x67, 0xfe, 0x4a, 0xea, 0x3b, 0xdc, 0xcd, 0x5d, 0x01, 0xc0,
+    0xae, 0x1a, 0xe6, 0xf7, 0x23, 0x68, 0xa6, 0xbb, 0x4a, 0xd4, 0x39, 0x65, 0xcd, 0xaf, 0x35, 0xc3, 0xb7, 0x66, 0x7b, 0x7e,
+    0x4d, 0xea, 0x5d, 0xb4, 0xd7, 0x8b, 0x75, 0x4f, 0x79, 0x65, 0xf9, 0xea, 0xe6, 0xee, 0xdf, 0x56, 0x5d, 0x15, 0xd3, 0x8b,
+    0x46, 0xeb, 0x82, 0xca, 0xd4, 0xc7, 0x68, 0x6b, 0x2d, 0xba, 0xf0, 0x10, 0xea, 0xe2, 0xc9, 0x52, 0xe3, 0x56, 0xd7, 0xe7,
+    0x95, 0x38, 0xe2, 0x39, 0x50, 0xcb, 0x05, 0x69, 0x88, 0x95, 0xf8, 0xad, 0x18, 0x2c, 0x8e, 0x93, 0xd2, 0x72, 0x3b, 0x2a,
+    0x86, 0x47, 0x53, 0x97, 0xf1, 0xd4, 0xcf, 0x5e, 0x77, 0xaf, 0x89, 0xfd, 0x4a, 0xb3, 0xdc, 0x6f, 0x71, 0xad, 0x91, 0xaa,
+    0x0c, 0x18, 0x7d, 0xfe, 0x8f, 0xc7, 0xbf, 0x08, 0x85, 0x8a, 0xd6, 0xb4, 0xa9, 0xbd, 0x3d, 0x73, 0x48, 0xf2, 0x2b, 0x3c,
+    0xd7, 0x78, 0x6c, 0xc7, 0xbf, 0xa6, 0x65, 0xff, 0xc7, 0xf7, 0x0a, 0xc7, 0xea, 0x68, 0x79, 0xce, 0x7f, 0xf5, 0x8e, 0xeb,
+    0xaf, 0x4d, 0xd7, 0x0d, 0x05, 0xe8, 0x71, 0x0d, 0xc5, 0x10, 0x4f, 0xa5, 0xbd, 0xb7, 0x8b, 0xbb, 0x9e, 0xe0, 0x08, 0x3e,
+    0xff, 0x5d, 0xaa, 0xeb, 0x9e, 0x1d, 0x7f, 0x35, 0x6e, 0x7f, 0x6d, 0xba, 0xd8, 0x59, 0xe7, 0x51, 0x28, 0x79, 0xab, 0x5b,
+    0xe9, 0xdf, 0xb0, 0x22, 0x2d, 0xbf, 0xaf, 0xe5, 0x45, 0x65, 0xe6, 0x69, 0x74, 0xf6, 0x2b, 0x65, 0xeb, 0x9c, 0x8e, 0xc5,
+    0x5f, 0xab, 0xb1, 0xe6, 0x2a, 0xbe, 0xe1, 0xae, 0x89, 0x17, 0xd5, 0xcf, 0x0d, 0xf9, 0xbb, 0x48, 0xb6, 0x96, 0x28, 0xeb,
+    0x95, 0x46, 0xa2, 0x3a, 0x69, 0x5e, 0x67, 0xec, 0x39, 0x95, 0xbf, 0x62, 0xae, 0x7a, 0xef, 0xad, 0xe3, 0x42, 0x13, 0xb2,
+    0x27, 0x96, 0x31, 0x95, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x55, 0xff, 0x78, 0x94, 0x28, 0x45,
+    0xea, 0x4a, 0xea, 0x8e, 0x0a, 0x58, 0xc5, 0xa5, 0x6d, 0x89, 0x5c, 0x9f, 0xa9, 0x6e, 0xf4, 0xf5, 0x3c, 0x2d, 0x53, 0x44,
+    0x45, 0x94, 0x3d, 0xa3, 0xfd, 0x0e, 0x40, 0xba, 0xc2, 0xd7, 0x10, 0xca, 0x8a, 0x26, 0xb2, 0xfb, 0xcd, 0xd0, 0x0b, 0xf5,
+    0x6f, 0xaf, 0x9a, 0xed, 0xcf, 0x36, 0x3f, 0xa4, 0x52, 0x46, 0x5d, 0xff, 0x47, 0xae, 0xc9, 0x87, 0x74, 0xdb, 0xd9, 0xbe,
+    0x6b, 0x7c, 0x5e, 0xef, 0xae, 0xb1, 0x0d, 0xb3, 0x36, 0xda, 0x30, 0xda, 0x94, 0x62, 0x21, 0x73, 0x46, 0xcd, 0xf5, 0x2d,
+    0xfb, 0x21, 0xf3, 0xee, 0xdb, 0xca, 0x2a, 0xed, 0x81, 0x63, 0xb7, 0x29, 0xcd, 0xcb, 0x62, 0x3a, 0x5c, 0xe9, 0x7d, 0xeb,
+    0xdd, 0x31, 0x6a, 0x4d, 0x9a, 0xd4, 0x1f, 0xd9, 0x5a, 0x96, 0x6a, 0x28, 0x16, 0x2c, 0x9f, 0x20, 0xff, 0xc8, 0xbd, 0x33,
+    0xaa, 0xa6, 0x2a, 0xf1, 0x48, 0xfc, 0xbb, 0xe9, 0x5b, 0xa0, 0x35, 0x21, 0x91, 0xdc, 0xb6, 0x56, 0x98, 0xc5, 0x75, 0x9a,
+    0xbe, 0x16, 0xfb, 0x29, 0x6f, 0x32, 0x63, 0x6d, 0xad, 0xc3, 0x62, 0xbe, 0x7b, 0x9e, 0x3d, 0xee, 0xfd, 0xf1, 0xaf, 0x41,
+    0xfd, 0x94, 0xcf, 0x73, 0xc9, 0xce, 0x0a, 0x6a, 0xbf, 0xa5, 0xab, 0x9c, 0xe7, 0x96, 0x40, 0x2e, 0xd3, 0xd2, 0xc6, 0x2c,
+    0x66, 0xc5, 0xb9, 0x1e, 0xa8, 0x38, 0xd7, 0xdd, 0xe7, 0xcc, 0x9e, 0xbc, 0xbb, 0x5f, 0x59, 0x33, 0xbe, 0x1d, 0xd2, 0x7c,
+    0xb9, 0xf0, 0x31, 0x51, 0x3d, 0x45, 0x94, 0x44, 0xf7, 0xb6, 0x58, 0xeb, 0x60, 0xf7, 0xb7, 0x38, 0x34, 0x58, 0xb1, 0x96,
+    0x73, 0xf3, 0xfe, 0x11, 0x25, 0xc2, 0x4c, 0xfb, 0xd3, 0x6f, 0x77, 0x9e, 0xf4, 0x9f, 0x19, 0x5d, 0x46, 0x59, 0x3f, 0x05,
+    0xf6, 0x59, 0x97, 0xd5, 0x72, 0x85, 0x7e, 0xc6, 0xf7, 0xba, 0x25, 0xa0, 0x0a, 0xb9, 0xd6, 0x93, 0xd0, 0xdf, 0xd2, 0x27,
+    0x6a, 0x9d, 0xc5, 0x75, 0xd6, 0x65, 0xb6, 0x3c, 0x51, 0x2f, 0x12, 0xad, 0xb5, 0xf7, 0xcc, 0xf8, 0xcf, 0xb4, 0x76, 0x96,
+    0x17, 0xe8, 0xf9, 0x2e, 0x8b, 0xef, 0xa4, 0x17, 0xfa, 0x1b, 0xe3, 0xef, 0x5f, 0x85, 0xdc, 0x16, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0xfd, 0x67, 0x4f, 0x9b, 0xbe, 0x5a, 0x5d, 0x6e, 0x37, 0x96, 0xf2, 0xe6, 0x7e, 0x85, 0x4f, 0x31,
+    0x3f, 0x41, 0xbd, 0x5b, 0xc3, 0xe3, 0x7f, 0x7d, 0xad, 0xa3, 0xa8, 0x2e, 0xdd, 0x49, 0x35, 0x34, 0x27, 0x1f, 0xe2, 0xb3,
+    0x4d, 0xbf, 0xf2, 0xe6, 0x7e, 0x85, 0x8f, 0xd2, 0x70, 0x54, 0xa9, 0xfc, 0xb8, 0x4e, 0xc3, 0x53, 0xe5, 0x4a, 0x7b, 0x74,
+    0x1f, 0x31, 0xdd, 0x49, 0x13, 0x2d, 0xfa, 0x95, 0xf5, 0xa7, 0xd1, 0xcd, 0x70, 0xfe, 0xb9, 0x5b, 0xe1, 0xa3, 0xab, 0x44,
+    0x29, 0x6d, 0x45, 0x95, 0x3b, 0x60, 0xf5, 0xa2, 0xaa, 0x4e, 0x0d, 0x8f, 0xd6, 0x1e, 0xaa, 0xde, 0x2c, 0x2f, 0xa7, 0x25,
+    0xcd, 0x8b, 0xac, 0x8a, 0x99, 0x0c, 0xd3, 0x45, 0xc8, 0xe7, 0x15, 0x74, 0xbf, 0xc2, 0xa7, 0x9b, 0x3e, 0x51, 0x59, 0xd9,
+    0x02, 0x1d, 0xe5, 0xab, 0xb2, 0x12, 0xca, 0xe5, 0xc7, 0x7b, 0x7d, 0x91, 0x4e, 0x4c, 0xc3, 0xc8, 0x87, 0x3f, 0x21, 0x5b,
+    0xef, 0x5b, 0xb1, 0x55, 0xe7, 0xf0, 0x6e, 0x59, 0x69, 0xaf, 0xfe, 0x2b, 0xff, 0xfa, 0x73, 0xb3, 0xf5, 0xde, 0xf8, 0x8f,
+    0xdb, 0xe3, 0xef, 0x57, 0x25, 0x11, 0xff, 0xbc, 0xf8, 0xf7, 0xc4, 0xf3, 0x3f, 0xb7, 0xa6, 0x6c, 0x2c, 0xef, 0x7b, 0x7e,
+    0xfc, 0x87, 0x59, 0xeb, 0xee, 0xdd, 0xe2, 0x7f, 0xf7, 0x6e, 0x2e, 0x93, 0x7b, 0xe2, 0xce, 0x57, 0xe7, 0x5c, 0x8f, 0xe9,
+    0x38, 0xca, 0xcd, 0x2d, 0x11, 0xa5, 0xc6, 0x53, 0xc7, 0x3c, 0x9f, 0x4f, 0x39, 0xed, 0x7a, 0x34, 0xfe, 0xd7, 0xe8, 0x61,
+    0xfc, 0x27, 0x66, 0xbb, 0x5d, 0xc3, 0x83, 0xba, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0x3f, 0xf5,
+    0xa1, 0x1a, 0x9c, 0x98, 0xa3, 0x90, 0x6e, 0xb9, 0x4a, 0xa1, 0x53, 0x4f, 0xd6, 0x53, 0xe9, 0xd5, 0xf2, 0x6b, 0x80, 0x6c,
+    0x4f, 0x1a, 0x3d, 0x93, 0x16, 0xd0, 0xe0, 0x54, 0x43, 0x83, 0xd3, 0x5c, 0x2e, 0x1b, 0xdd, 0x70, 0x14, 0x1a, 0x86, 0x7b,
+    0x41, 0xe6, 0x8c, 0xf4, 0xb8, 0x9b, 0xa1, 0xdb, 0xd8, 0xba, 0x5a, 0x1d, 0x3a, 0x9b, 0xb5, 0x77, 0xe5, 0x49, 0x54, 0x03,
+    0xd9, 0xbf, 0xc5, 0xac, 0x54, 0x16, 0xd1, 0xe0, 0x34, 0x97, 0x06, 0xc7, 0xaa, 0xfe, 0x54, 0x27, 0xd5, 0xb5, 0xfc, 0x59,
+    0x90, 0xbc, 0x19, 0x59, 0xe7, 0x4c, 0x93, 0xfb, 0x7c, 0x7f, 0x9c, 0x8b, 0xb1, 0x53, 0xf5, 0x8e, 0x69, 0x81, 0xec, 0x5f,
+    0x71, 0xce, 0x2f, 0xb7, 0x45, 0xe7, 0x33, 0xad, 0xaa, 0x7b, 0x91, 0x0a, 0x44, 0xb9, 0xe3, 0xb6, 0xd4, 0x56, 0x9e, 0x78,
+    0x16, 0x67, 0x5e, 0xae, 0x89, 0xfc, 0xb3, 0xb5, 0x1f, 0xed, 0x7c, 0xf6, 0x76, 0xc5, 0x9b, 0xdc, 0x4a, 0x3e, 0xba, 0xa5,
+    0x48, 0xd5, 0x42, 0x31, 0x6b, 0x49, 0xf5, 0x40, 0xdd, 0x9a, 0x5c, 0xed, 0x50, 0x31, 0x54, 0x82, 0xfb, 0xcf, 0x25, 0x5f,
+    0x3e, 0xb5, 0x18, 0xea, 0x0f, 0xbf, 0xfa, 0x6f, 0xe6, 0xbf, 0x55, 0x2e, 0x68, 0x19, 0xa1, 0xba, 0x50, 0xf3, 0x9a, 0x38,
+    0xe7, 0xfb, 0x06, 0x75, 0xc3, 0x81, 0xe5, 0xac, 0xf8, 0x67, 0x6a, 0xd9, 0xf6, 0xf8, 0x6f, 0x5d, 0xf3, 0x1c, 0x79, 0x77,
+    0x60, 0xd4, 0x65, 0x23, 0xd7, 0x65, 0xab, 0xb8, 0x3d, 0xf5, 0x32, 0xe2, 0x9f, 0xad, 0xfe, 0x5b, 0x02, 0xfe, 0x4b, 0xb9,
+    0x2d, 0xfe, 0xf3, 0x7a, 0x49, 0x55, 0xba, 0x44, 0x5b, 0xec, 0xca, 0x79, 0x67, 0xc5, 0xbf, 0xfc, 0x18, 0x4f, 0x92, 0x6c,
+    0x1f, 0x9b, 0xeb, 0xd4, 0x16, 0x19, 0xf1, 0xf7, 0xcf, 0x61, 0x79, 0x1b, 0xd7, 0x9f, 0xf3, 0xbc, 0x81, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x69, 0x2a, 0x9f, 0x3c, 0x0f, 0xa2, 0x27, 0x38, 0xed, 0xd4, 0xb0, 0x13, 0xcf, 0x5d,
+    0xdc, 0xad, 0xf2, 0xd1, 0xfa, 0x07, 0x9d, 0xfd, 0xb9, 0x46, 0xc7, 0xa3, 0x7b, 0x1b, 0x93, 0xef, 0x07, 0xb6, 0xb7, 0xfa,
+    0xcc, 0xf2, 0x5e, 0x95, 0x4f, 0x44, 0x5f, 0x91, 0xab, 0xe3, 0xd1, 0x2a, 0x8c, 0x26, 0x73, 0x33, 0x56, 0x85, 0xc4, 0x77,
+    0xa9, 0xbd, 0x70, 0xa5, 0xca, 0x67, 0x96, 0xe5, 0xf7, 0x64, 0xde, 0xcb, 0x44, 0x63, 0xe3, 0x6b, 0x99, 0x7d, 0xd3, 0xfe,
+    0x8a, 0x2c, 0xfc, 0x9d, 0x39, 0x96, 0xfb, 0x9d, 0x76, 0x8a, 0x7b, 0x64, 0xcf, 0xf5, 0x8d, 0x78, 0xbf, 0xf8, 0xdf, 0xbf,
+    0x2e, 0x3d, 0x2d, 0xd3, 0xfd, 0x84, 0x96, 0x98, 0x66, 0xe5, 0xef, 0x8f, 0x7f, 0xa6, 0xd3, 0xc6, 0x35, 0x23, 0x8b, 0xa9,
+    0xc2, 0xde, 0x2b, 0x67, 0x7d, 0xbf, 0xca, 0x27, 0xe2, 0xb4, 0x71, 0x95, 0xfe, 0x28, 0xaa, 0x0a, 0x79, 0xa7, 0xe7, 0xff,
+    0xfd, 0xbc, 0x49, 0xae, 0x1d, 0x99, 0xef, 0x3b, 0x06, 0x5a, 0xb3, 0x0e, 0xef, 0x86, 0x8e, 0x65, 0x63, 0x75, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xd6, 0x3f,
-    0xac, 0x03, 0xf1, 0x87, 0x1f, 0x1b, 0xff, 0x7f, 0x01 };
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc1, 0xfa, 0x87, 0x75,
+    0x20, 0xfe, 0xf0, 0x63, 0xe3, 0xff, 0x2f };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle bluishFontRecs[189] = {
+static const Rectangle bluishFontRecs[186] = {
     { 4, 4, 5 , 10 },
     { 17, 4, 2 , 8 },
     { 27, 4, 4 , 3 },
@@ -275,102 +273,99 @@
     { 240, 76, 2 , 8 },
     { 4, 94, 5 , 8 },
     { 17, 94, 5 , 8 },
-    { 30, 94, 0 , 0 },
-    { 38, 94, 6 , 8 },
-    { 52, 94, 5 , 10 },
-    { 65, 94, 5 , 10 },
-    { 78, 94, 5 , 9 },
-    { 91, 94, 7 , 8 },
-    { 106, 94, 4 , 6 },
-    { 118, 94, 5 , 4 },
-    { 131, 94, 5 , 3 },
-    { 144, 94, 7 , 8 },
-    { 159, 94, 5 , 2 },
-    { 172, 94, 4 , 4 },
-    { 184, 94, 6 , 8 },
-    { 198, 94, 4 , 6 },
-    { 210, 94, 4 , 6 },
-    { 222, 94, 0 , 0 },
-    { 230, 94, 5 , 9 },
-    { 4, 112, 6 , 8 },
-    { 18, 112, 2 , 2 },
-    { 28, 112, 0 , 0 },
-    { 36, 112, 3 , 6 },
-    { 47, 112, 4 , 6 },
-    { 59, 112, 5 , 4 },
-    { 72, 112, 6 , 8 },
-    { 86, 112, 6 , 6 },
-    { 100, 112, 5 , 10 },
-    { 113, 112, 5 , 8 },
-    { 126, 112, 5 , 10 },
-    { 139, 112, 5 , 10 },
-    { 152, 112, 5 , 10 },
-    { 165, 112, 5 , 10 },
-    { 178, 112, 5 , 10 },
-    { 191, 112, 5 , 10 },
-    { 204, 112, 6 , 8 },
-    { 218, 112, 5 , 9 },
-    { 231, 112, 5 , 10 },
-    { 4, 130, 5 , 10 },
-    { 17, 130, 5 , 10 },
-    { 30, 130, 5 , 10 },
-    { 43, 130, 4 , 10 },
-    { 55, 130, 4 , 10 },
-    { 67, 130, 4 , 10 },
-    { 79, 130, 4 , 10 },
-    { 91, 130, 6 , 8 },
+    { 30, 94, 6 , 8 },
+    { 44, 94, 5 , 10 },
+    { 57, 94, 5 , 10 },
+    { 70, 94, 5 , 9 },
+    { 83, 94, 7 , 8 },
+    { 98, 94, 4 , 6 },
+    { 110, 94, 5 , 4 },
+    { 123, 94, 5 , 3 },
+    { 136, 94, 7 , 8 },
+    { 151, 94, 5 , 2 },
+    { 164, 94, 4 , 4 },
+    { 176, 94, 6 , 8 },
+    { 190, 94, 4 , 6 },
+    { 202, 94, 4 , 6 },
+    { 214, 94, 5 , 9 },
+    { 227, 94, 6 , 8 },
+    { 241, 94, 2 , 2 },
+    { 4, 112, 3 , 6 },
+    { 15, 112, 4 , 6 },
+    { 27, 112, 5 , 4 },
+    { 40, 112, 6 , 8 },
+    { 54, 112, 6 , 6 },
+    { 68, 112, 5 , 10 },
+    { 81, 112, 5 , 8 },
+    { 94, 112, 5 , 10 },
+    { 107, 112, 5 , 10 },
+    { 120, 112, 5 , 10 },
+    { 133, 112, 5 , 10 },
+    { 146, 112, 5 , 10 },
+    { 159, 112, 5 , 10 },
+    { 172, 112, 6 , 8 },
+    { 186, 112, 5 , 9 },
+    { 199, 112, 5 , 10 },
+    { 212, 112, 5 , 10 },
+    { 225, 112, 5 , 10 },
+    { 238, 112, 5 , 10 },
+    { 4, 130, 4 , 10 },
+    { 16, 130, 4 , 10 },
+    { 28, 130, 4 , 10 },
+    { 40, 130, 4 , 10 },
+    { 52, 130, 6 , 8 },
+    { 66, 130, 5 , 10 },
+    { 79, 130, 5 , 10 },
+    { 92, 130, 5 , 10 },
     { 105, 130, 5 , 10 },
     { 118, 130, 5 , 10 },
     { 131, 130, 5 , 10 },
-    { 144, 130, 5 , 10 },
-    { 157, 130, 5 , 10 },
-    { 170, 130, 5 , 10 },
-    { 183, 130, 4 , 4 },
+    { 144, 130, 4 , 4 },
+    { 156, 130, 5 , 10 },
+    { 169, 130, 5 , 10 },
+    { 182, 130, 5 , 10 },
     { 195, 130, 5 , 10 },
     { 208, 130, 5 , 10 },
     { 221, 130, 5 , 10 },
-    { 234, 130, 5 , 10 },
-    { 4, 148, 5 , 10 },
-    { 17, 148, 5 , 10 },
-    { 30, 148, 5 , 8 },
-    { 43, 148, 5 , 8 },
+    { 234, 130, 5 , 8 },
+    { 4, 148, 5 , 8 },
+    { 17, 148, 5 , 9 },
+    { 30, 148, 5 , 9 },
+    { 43, 148, 5 , 9 },
     { 56, 148, 5 , 9 },
-    { 69, 148, 5 , 9 },
-    { 82, 148, 5 , 9 },
-    { 95, 148, 5 , 9 },
-    { 108, 148, 5 , 8 },
-    { 121, 148, 5 , 10 },
-    { 134, 148, 6 , 6 },
-    { 148, 148, 5 , 7 },
-    { 161, 148, 5 , 9 },
-    { 174, 148, 5 , 9 },
-    { 187, 148, 5 , 9 },
-    { 200, 148, 5 , 8 },
-    { 213, 148, 3 , 9 },
-    { 224, 148, 3 , 9 },
-    { 235, 148, 4 , 9 },
-    { 4, 166, 4 , 8 },
-    { 16, 166, 5 , 9 },
-    { 29, 166, 5 , 9 },
-    { 42, 166, 5 , 9 },
-    { 55, 166, 5 , 9 },
-    { 68, 166, 5 , 9 },
-    { 81, 166, 5 , 9 },
-    { 94, 166, 5 , 8 },
-    { 107, 166, 4 , 6 },
-    { 119, 166, 5 , 8 },
-    { 132, 166, 5 , 9 },
-    { 145, 166, 5 , 9 },
-    { 158, 166, 5 , 9 },
-    { 171, 166, 5 , 8 },
-    { 184, 166, 5 , 10 },
-    { 197, 166, 5 , 10 },
-    { 210, 166, 5 , 9 },
+    { 69, 148, 5 , 8 },
+    { 82, 148, 5 , 10 },
+    { 95, 148, 6 , 6 },
+    { 109, 148, 5 , 7 },
+    { 122, 148, 5 , 9 },
+    { 135, 148, 5 , 9 },
+    { 148, 148, 5 , 9 },
+    { 161, 148, 5 , 8 },
+    { 174, 148, 3 , 9 },
+    { 185, 148, 3 , 9 },
+    { 196, 148, 4 , 9 },
+    { 208, 148, 4 , 8 },
+    { 220, 148, 5 , 9 },
+    { 233, 148, 5 , 9 },
+    { 4, 166, 5 , 9 },
+    { 17, 166, 5 , 9 },
+    { 30, 166, 5 , 9 },
+    { 43, 166, 5 , 9 },
+    { 56, 166, 5 , 8 },
+    { 69, 166, 4 , 6 },
+    { 81, 166, 5 , 8 },
+    { 94, 166, 5 , 9 },
+    { 107, 166, 5 , 9 },
+    { 120, 166, 5 , 9 },
+    { 133, 166, 5 , 8 },
+    { 146, 166, 5 , 10 },
+    { 159, 166, 5 , 10 },
+    { 172, 166, 5 , 9 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo bluishFontGlyphs[189] = {
+static const GlyphInfo bluishFontGlyphs[186] = {
     { 32, 0, 0, 5, { 0 }},
     { 33, 0, 1, 2, { 0 }},
     { 34, 0, 1, 4, { 0 }},
@@ -469,7 +464,6 @@
     { 161, 0, 1, 2, { 0 }},
     { 162, 0, 2, 5, { 0 }},
     { 163, 0, 1, 5, { 0 }},
-    { 8364, 0, 0, 0, { 0 }},
     { 165, 0, 1, 6, { 0 }},
     { 352, 0, -1, 5, { 0 }},
     { 167, 0, 0, 5, { 0 }},
@@ -484,11 +478,9 @@
     { 177, 0, 1, 6, { 0 }},
     { 178, 0, -1, 4, { 0 }},
     { 179, 0, -1, 4, { 0 }},
-    { 381, 0, 0, 0, { 0 }},
     { 181, 0, 1, 5, { 0 }},
     { 182, 0, 1, 6, { 0 }},
     { 183, 0, 4, 2, { 0 }},
-    { 382, 0, 0, 0, { 0 }},
     { 185, 0, -1, 3, { 0 }},
     { 186, 0, -1, 4, { 0 }},
     { 187, 0, 3, 5, { 0 }},
@@ -580,29 +572,40 @@
 
     Font font = { 0 };
     font.baseSize = 10;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 186;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, bluishFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, bluishFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "homespun.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/brick/style_brick.h b/raygui/styles/brick/style_brick.h
new file mode 100644
--- /dev/null
+++ b/raygui/styles/brick/style_brick.h
@@ -0,0 +1,617 @@
+//////////////////////////////////////////////////////////////////////////////////
+//                                                                              //
+// StyleAsCode exporter v2.0 - Style data exported as a values array            //
+//                                                                              //
+// USAGE: On init call: GuiLoadStyleBrick();                                   //
+//                                                                              //
+// more info and bugs-report:  github.com/raysan5/raygui                        //
+// feedback and support:       ray[at]raylibtech.com                            //
+//                                                                              //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
+//                                                                              //
+//////////////////////////////////////////////////////////////////////////////////
+
+#define BRICK_STYLE_PROPS_COUNT  18
+
+// Custom style name: Brick
+static const GuiStyleProp brickStyleProps[BRICK_STYLE_PROPS_COUNT] = {
+    { 0, 0, (int)0x8c8e94ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xdedfe2ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x58585aff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x324c4fff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xa0a0a0ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xffffffff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xa1626aff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xc68f96ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x62374aff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x96aaacff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xc8d7d9ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x8c9c9eff },    // DEFAULT_TEXT_COLOR_DISABLED
+    { 0, 18, (int)0x71a8aeff },    // DEFAULT_LINE_COLOR 
+    { 0, 19, (int)0xeff0f3ff },    // DEFAULT_BACKGROUND_COLOR 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 5, (int)0x568a90ff },    // LABEL_TEXT_COLOR_FOCUSED
+    { 9, 5, (int)0x5e9095ff },    // TEXTBOX_TEXT_COLOR_FOCUSED
+    { 10, 5, (int)0x639196ff },    // VALUEBOX_TEXT_COLOR_FOCUSED
+};
+
+// WARNING: This style uses a custom font: "homespun.ttf" (size: 10, spacing: 1)
+
+#define BRICK_STYLE_FONT_ATLAS_COMP_SIZE 2688
+
+// Font atlas image pixels data: DEFLATE compressed
+static unsigned char brickFontData[BRICK_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
+    0x9d, 0xed, 0x76, 0xdb, 0x38, 0x0c, 0x44, 0x45, 0xee, 0xfb, 0xbf, 0x71, 0x48, 0xee, 0x69, 0xe4, 0xa4, 0x67, 0xbb, 0x1a,
+    0x50, 0x80, 0xa0, 0x0f, 0x37, 0xb7, 0xf7, 0xb4, 0x3f, 0xc4, 0x88, 0x26, 0x09, 0x8a, 0x4e, 0x8d, 0xf1, 0x60, 0x2c, 0x00,
+    0x00, 0x00, 0x00, 0xff, 0xa3, 0x8a, 0x6b, 0x55, 0xfe, 0x74, 0x75, 0xf4, 0xb4, 0x5e, 0xaf, 0x46, 0xbb, 0xaf, 0xb7, 0xea,
+    0xe8, 0xc1, 0x6a, 0xb1, 0xdb, 0xfe, 0xa4, 0xbc, 0xc8, 0x58, 0xd9, 0xfa, 0xbd, 0x1e, 0xdb, 0xab, 0xe4, 0xf9, 0xf9, 0xea,
+    0x9a, 0xc5, 0x36, 0x43, 0x5c, 0xeb, 0x9b, 0xf3, 0x1d, 0xa3, 0x88, 0x96, 0x3a, 0x86, 0x18, 0xcf, 0xf8, 0xbc, 0x6b, 0xbb,
+    0x47, 0xeb, 0xae, 0xad, 0xd7, 0x68, 0x1b, 0x7d, 0x34, 0xb9, 0x2b, 0x7e, 0xbd, 0xa2, 0x5a, 0xa1, 0x2e, 0xe2, 0x39, 0x36,
+    0x7f, 0x76, 0xa5, 0xec, 0xfa, 0x69, 0xeb, 0x15, 0xc6, 0x68, 0xa3, 0xbd, 0xd6, 0xe3, 0xcf, 0x59, 0x0c, 0xd7, 0xcf, 0xeb,
+    0x96, 0xe3, 0xf1, 0xef, 0x9f, 0xe3, 0x29, 0x1b, 0xcf, 0xc1, 0xaf, 0x68, 0x75, 0x11, 0x2f, 0x35, 0x9e, 0x75, 0xe5, 0xca,
+    0x66, 0x8f, 0xd6, 0x5d, 0xcb, 0xee, 0xd5, 0xde, 0xbe, 0x7f, 0x1d, 0xe9, 0xf6, 0x3c, 0xca, 0x67, 0xdb, 0xd6, 0xda, 0xb5,
+    0xa4, 0x73, 0x55, 0xcd, 0x77, 0x31, 0x9f, 0xad, 0xed, 0x55, 0xe8, 0xae, 0x96, 0xe3, 0xf1, 0xd7, 0x3b, 0x7a, 0xbc, 0xfe,
+    0xaa, 0x99, 0x35, 0x31, 0x9e, 0x22, 0x5a, 0xec, 0xbb, 0x8e, 0xc4, 0xbf, 0xbc, 0x46, 0x5a, 0xc5, 0xf3, 0x3c, 0xc4, 0x13,
+    0x7d, 0x66, 0xf4, 0xfd, 0xf1, 0x2f, 0xaf, 0xbd, 0x5a, 0xc4, 0xbb, 0xd2, 0xb5, 0xf1, 0x2f, 0xaf, 0xf3, 0xbf, 0x8a, 0xd1,
+    0x17, 0x19, 0x7d, 0x7d, 0xda, 0x7a, 0xde, 0x57, 0x7d, 0xcf, 0xff, 0xba, 0xce, 0x6a, 0x6f, 0x9d, 0x17, 0x7b, 0x7b, 0xbe,
+    0xbe, 0xf8, 0x0f, 0xf9, 0xce, 0xf3, 0xb5, 0x8b, 0x8f, 0xce, 0xa2, 0x27, 0x3d, 0xff, 0x5d, 0x8e, 0xa7, 0xbc, 0xce, 0xff,
+    0xed, 0x39, 0x7b, 0x9e, 0x42, 0x4f, 0xfc, 0x67, 0x31, 0x3e, 0xf3, 0xd9, 0xd7, 0x7d, 0xfb, 0xe3, 0xbf, 0xf6, 0xb8, 0xf5,
+    0x2a, 0x67, 0xef, 0xe2, 0xc5, 0xf5, 0xfb, 0x5f, 0x31, 0x7e, 0xe7, 0xf9, 0xda, 0x3b, 0x9e, 0xf9, 0x65, 0xc5, 0xf9, 0x7a,
+    0xc6, 0x74, 0x06, 0x9e, 0xf8, 0x17, 0xb9, 0xaa, 0xe5, 0xf2, 0xf7, 0x7f, 0x2b, 0xfe, 0xd6, 0x48, 0xad, 0xf8, 0xfb, 0x66,
+    0x31, 0x9c, 0xbf, 0x83, 0x3f, 0x2f, 0xfe, 0xe3, 0xfb, 0xff, 0x43, 0xfb, 0xe6, 0xa6, 0x7e, 0xde, 0xea, 0xe9, 0x9e, 0x59,
+    0x47, 0xc6, 0xf3, 0xb4, 0x59, 0xc0, 0x11, 0x3e, 0x02, 0x71, 0xfc, 0x20, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x69, 0x2a, 0x9f, 0x2c, 0x85, 0x49, 0x76, 0xcb, 0x31, 0x55, 0x90, 0x56, 0xe7, 0x58, 0x8a, 0x24, 0x7b, 0x94, 0x57,
+    0xad, 0xc7, 0x72, 0x91, 0xe6, 0x67, 0x04, 0x14, 0x29, 0x57, 0xb5, 0xb4, 0xdd, 0x2a, 0x8c, 0xed, 0x6c, 0xae, 0x56, 0xe7,
+    0x74, 0xb1, 0x56, 0xb3, 0x51, 0x5e, 0xb7, 0x1e, 0x35, 0x30, 0xba, 0xc8, 0xa7, 0xe5, 0x63, 0x92, 0x9d, 0x6b, 0xae, 0x96,
+    0x3e, 0xcd, 0xf5, 0xf9, 0x94, 0x2f, 0xc7, 0xf2, 0xaa, 0x96, 0x3a, 0x4f, 0xe9, 0x3f, 0xac, 0x51, 0x2a, 0x5d, 0xc5, 0x08,
+    0xcf, 0xba, 0xa5, 0xde, 0xd3, 0x42, 0xf1, 0xd7, 0xb3, 0xd2, 0xb9, 0x79, 0x5b, 0xf5, 0xa8, 0x7b, 0xf3, 0xb5, 0xec, 0x57,
+    0x1f, 0xa8, 0x18, 0x6b, 0x8d, 0x84, 0x57, 0x3b, 0x33, 0x0c, 0x5d, 0xc5, 0x6c, 0x6e, 0xcd, 0x95, 0x9b, 0x1c, 0x93, 0x35,
+    0x3c, 0xae, 0x96, 0xd9, 0xa7, 0xce, 0xe8, 0xc6, 0x7c, 0x6d, 0x85, 0x49, 0x77, 0xdd, 0xd3, 0x13, 0xf4, 0x2a, 0xde, 0xdd,
+    0x63, 0xe9, 0x70, 0xba, 0x11, 0xff, 0xea, 0x9c, 0xdb, 0xda, 0x52, 0x5d, 0xb9, 0xe0, 0x31, 0x59, 0xc3, 0xe3, 0x6a, 0x99,
+    0x7d, 0xeb, 0x57, 0xc2, 0x27, 0x76, 0xd6, 0x3d, 0xe7, 0xed, 0x80, 0xe1, 0xee, 0x67, 0x7c, 0xef, 0xd4, 0xcc, 0xf3, 0xbf,
+    0x04, 0xde, 0x91, 0xcb, 0x61, 0xad, 0xc6, 0xfe, 0x13, 0x3b, 0xa6, 0x30, 0xc9, 0xba, 0xe7, 0x59, 0xda, 0x8d, 0x12, 0x3c,
+    0xb1, 0xaf, 0x69, 0x39, 0x23, 0xfe, 0x51, 0x85, 0x49, 0x4f, 0xbb, 0x67, 0xb9, 0x5c, 0xd3, 0x33, 0xe4, 0xf3, 0x6f, 0xad,
+    0x47, 0xe6, 0x1a, 0x5a, 0x3a, 0x20, 0x7b, 0x04, 0x3f, 0x81, 0xc6, 0x67, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0e, 0xfd, 0x8f, 0xad, 0xbe, 0xf1, 0x29, 0x54, 0x6c, 0xd5, 0x8e, 0xd7, 0xa3, 0xa7, 0x5e, 0xae, 0xba, 0xc9,
+    0x6e, 0x89, 0xac, 0xc5, 0xac, 0xc5, 0x77, 0xe7, 0xfc, 0xf3, 0x6e, 0xad, 0x29, 0x51, 0x9f, 0x6a, 0xb7, 0xcf, 0xbb, 0x72,
+    0xb2, 0x7f, 0x63, 0x3a, 0xb2, 0xf5, 0xdf, 0xfa, 0x40, 0x7d, 0x92, 0xa5, 0x5c, 0xfa, 0x1a, 0x79, 0x66, 0xb6, 0x70, 0x6d,
+    0x69, 0x9b, 0x6b, 0x11, 0xcd, 0xa1, 0x45, 0x74, 0x28, 0x76, 0x36, 0x2c, 0x2f, 0xfe, 0xd1, 0x39, 0x5f, 0xdb, 0xe2, 0xf5,
+    0x11, 0x79, 0x5e, 0xfc, 0x2d, 0x95, 0x4f, 0x56, 0xfc, 0x8f, 0xe9, 0x60, 0xf2, 0xe2, 0x1f, 0xd1, 0x70, 0xe9, 0xb1, 0x5b,
+    0x3a, 0xa8, 0x2b, 0xe3, 0xaf, 0x7d, 0xb4, 0xf6, 0xc4, 0xdf, 0xaf, 0xf2, 0xf1, 0xc7, 0xff, 0x98, 0x0e, 0x26, 0x2f, 0xfe,
+    0x11, 0x0d, 0x47, 0x37, 0xdc, 0xa2, 0xba, 0xdb, 0x7b, 0x64, 0x4c, 0x34, 0x86, 0x2d, 0x10, 0xff, 0x22, 0xc7, 0x78, 0x54,
+    0xff, 0xe9, 0x79, 0xfe, 0xcb, 0x69, 0x3a, 0x98, 0xdc, 0xf3, 0x3f, 0x6b, 0x1d, 0xca, 0x44, 0x7d, 0x58, 0x02, 0x6a, 0x91,
+    0x9e, 0xbc, 0x16, 0xfb, 0xf4, 0x0e, 0x39, 0xf1, 0x8f, 0xf4, 0xb5, 0xef, 0x1e, 0x6f, 0xfc, 0x4b, 0x20, 0xfe, 0x99, 0x63,
+    0xb7, 0xe3, 0x5f, 0x0c, 0xb5, 0xc8, 0xfc, 0x9e, 0xec, 0xf8, 0x47, 0x55, 0x2d, 0x25, 0xb1, 0xaf, 0x91, 0x1c, 0x7f, 0xbf,
+    0x4e, 0x26, 0x77, 0xec, 0x76, 0xfc, 0xe3, 0xa3, 0x5b, 0xff, 0xd4, 0x13, 0x34, 0xf4, 0x80, 0xe3, 0x0c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xb3, 0x18, 0x15, 0xa9, 0x6c, 0x95, 0xd1, 0x7e, 0xb5, 0xd0, 0x97, 0x82, 0x62,
+    0x5b, 0x3f, 0x91, 0xe3, 0xf4, 0x33, 0xaf, 0xdd, 0xe5, 0x7d, 0x1d, 0xb5, 0x5a, 0x91, 0xb1, 0x9d, 0x5d, 0xe3, 0x6c, 0x9f,
+    0xca, 0xc7, 0xd2, 0xbd, 0xf8, 0xbe, 0x83, 0xaa, 0xbc, 0x69, 0xaa, 0x70, 0xba, 0xf1, 0x7e, 0x77, 0xdf, 0xf2, 0xaa, 0xd0,
+    0xfd, 0x64, 0xba, 0x58, 0x0c, 0xb9, 0x5f, 0x47, 0x60, 0x6c, 0x4d, 0x5c, 0x55, 0x7d, 0xd4, 0xf0, 0x37, 0xa5, 0xe3, 0x5e,
+    0x0e, 0x7b, 0x3d, 0x95, 0x74, 0xc6, 0x70, 0xcd, 0x75, 0x7b, 0x77, 0x40, 0x97, 0xcf, 0xd8, 0xf6, 0x58, 0xab, 0xd4, 0xb7,
+    0x2c, 0xb2, 0x9a, 0x99, 0xdf, 0xab, 0x66, 0x88, 0xaa, 0x61, 0x76, 0xfe, 0x48, 0x8d, 0x4d, 0x55, 0x4b, 0x5a, 0x44, 0x1f,
+    0x2d, 0xfc, 0x9d, 0xf0, 0x31, 0xa9, 0x23, 0xe5, 0xe9, 0xd9, 0xda, 0x01, 0x56, 0x25, 0xb7, 0x96, 0x50, 0xab, 0xc4, 0xef,
+    0x55, 0x63, 0x29, 0x0f, 0xec, 0xde, 0xbc, 0xde, 0x2c, 0x7a, 0xcf, 0xf8, 0x4e, 0x86, 0x2c, 0x87, 0x99, 0x7d, 0x27, 0x67,
+    0x31, 0x66, 0xb4, 0xb8, 0x77, 0xc0, 0xb9, 0x95, 0x3c, 0xce, 0x53, 0x1e, 0xec, 0x9d, 0x45, 0x76, 0x66, 0x79, 0x7f, 0xfc,
+    0x97, 0x43, 0x9e, 0x20, 0x25, 0xac, 0x95, 0xf1, 0xed, 0x80, 0xb3, 0xe3, 0x7f, 0x96, 0xf2, 0x20, 0xcb, 0x81, 0xa3, 0x3f,
+    0x34, 0xfe, 0x33, 0xb7, 0x19, 0x7f, 0x2c, 0xfd, 0x8a, 0xd1, 0xe5, 0x96, 0x93, 0x21, 0xfb, 0x9e, 0xc5, 0xfd, 0x3f, 0x99,
+    0x67, 0xc4, 0x3f, 0xe6, 0x50, 0x53, 0xdc, 0x5e, 0x42, 0x77, 0xc5, 0xdf, 0x5f, 0x47, 0x2a, 0x76, 0x4f, 0xbe, 0xf6, 0xf2,
+    0x8a, 0xf8, 0xc3, 0xfb, 0x38, 0x1f, 0x35, 0xf4, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa4, 0xfc,
+    0x07, 0x8f, 0x7a, 0xe5, 0xfe, 0x96, 0x3a, 0xc9, 0x6a, 0x95, 0x70, 0x4b, 0x49, 0xeb, 0xd3, 0xd2, 0x18, 0x1d, 0xad, 0x79,
+    0xf6, 0xd5, 0x77, 0x09, 0xab, 0x7f, 0x7e, 0xe7, 0xa0, 0xd7, 0x7f, 0x6b, 0x52, 0x66, 0x3d, 0xbf, 0xe5, 0xfc, 0x6f, 0xf3,
+    0x9f, 0xe1, 0x37, 0x60, 0x39, 0x44, 0xd4, 0xdd, 0xda, 0x8a, 0x26, 0x73, 0xaa, 0x5d, 0x7a, 0x06, 0xb4, 0x40, 0x0e, 0xe2,
+    0x7e, 0x97, 0x9d, 0xe6, 0xac, 0x43, 0x55, 0x2f, 0xf4, 0xd8, 0xe8, 0x13, 0x3d, 0x8c, 0x4f, 0x43, 0xa3, 0x3d, 0x14, 0x16,
+    0xd7, 0xcf, 0xaa, 0x9a, 0x44, 0xe5, 0x2d, 0xe3, 0xbf, 0x38, 0xb5, 0x7d, 0x7d, 0x87, 0x5f, 0x46, 0x96, 0xc7, 0x46, 0x09,
+    0x28, 0x7c, 0x8a, 0x51, 0x7f, 0xcc, 0x17, 0x7f, 0x55, 0xad, 0xce, 0x7f, 0x36, 0x5e, 0xe1, 0xb2, 0x91, 0x5f, 0xc1, 0x26,
+    0xcf, 0xcd, 0x23, 0xdf, 0x63, 0xc3, 0xca, 0x94, 0x6b, 0x5d, 0xa5, 0x2f, 0xfe, 0x5e, 0x6f, 0x87, 0x2b, 0xe2, 0x1f, 0xad,
+    0x6d, 0x93, 0xeb, 0xcc, 0x51, 0x1e, 0xe2, 0xb1, 0xe1, 0x75, 0x08, 0x39, 0x7e, 0xfe, 0x67, 0xeb, 0x11, 0xf2, 0x32, 0xd5,
+    0xd7, 0xf8, 0x6c, 0x44, 0x74, 0x3a, 0x67, 0x65, 0xe6, 0xfd, 0xd9, 0x79, 0x8f, 0xb6, 0xb2, 0xbf, 0x55, 0xfc, 0x9f, 0xac,
+    0xed, 0x79, 0x12, 0x67, 0xd6, 0x3c, 0x43, 0xfd, 0xf3, 0xae, 0x7b, 0x9a, 0x35, 0xf8, 0xd9, 0x2a, 0x2f, 0xd6, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x71, 0x00, 0x5a, 0xa4, 0xa7, 0x8d, 0xbe, 0xa3, 0xa6, 0xf9, 0x09, 0xcd, 0xee,
+    0xa9, 0xce, 0x3a, 0x64, 0xc5, 0xad, 0xc7, 0x39, 0x56, 0x6b, 0xcc, 0xb7, 0xb2, 0xde, 0xbe, 0xf6, 0xac, 0xcf, 0x12, 0x54,
+    0x00, 0x14, 0x53, 0x45, 0xd1, 0xcc, 0x1c, 0xda, 0xb6, 0xee, 0xe4, 0xd7, 0x68, 0x3e, 0x9c, 0xd5, 0xb2, 0xec, 0x7b, 0x54,
+    0x05, 0x30, 0xd5, 0x5f, 0xf9, 0x54, 0x45, 0x34, 0x97, 0x1e, 0x67, 0xfe, 0x4a, 0xea, 0x3b, 0xdc, 0xcd, 0x5d, 0x01, 0xc0,
+    0xae, 0x1a, 0xe6, 0xf7, 0x23, 0x68, 0xa6, 0xbb, 0x4a, 0xd4, 0x39, 0x65, 0xcd, 0xaf, 0x35, 0xc3, 0xb7, 0x66, 0x7b, 0x7e,
+    0x4d, 0xea, 0x5d, 0xb4, 0xd7, 0x8b, 0x75, 0x4f, 0x79, 0x65, 0xf9, 0xea, 0xe6, 0xee, 0xdf, 0x56, 0x5d, 0x15, 0xd3, 0x8b,
+    0x46, 0xeb, 0x82, 0xca, 0xd4, 0xc7, 0x68, 0x6b, 0x2d, 0xba, 0xf0, 0x10, 0xea, 0xe2, 0xc9, 0x52, 0xe3, 0x56, 0xd7, 0xe7,
+    0x95, 0x38, 0xe2, 0x39, 0x50, 0xcb, 0x05, 0x69, 0x88, 0x95, 0xf8, 0xad, 0x18, 0x2c, 0x8e, 0x93, 0xd2, 0x72, 0x3b, 0x2a,
+    0x86, 0x47, 0x53, 0x97, 0xf1, 0xd4, 0xcf, 0x5e, 0x77, 0xaf, 0x89, 0xfd, 0x4a, 0xb3, 0xdc, 0x6f, 0x71, 0xad, 0x91, 0xaa,
+    0x0c, 0x18, 0x7d, 0xfe, 0x8f, 0xc7, 0xbf, 0x08, 0x85, 0x8a, 0xd6, 0xb4, 0xa9, 0xbd, 0x3d, 0x73, 0x48, 0xf2, 0x2b, 0x3c,
+    0xd7, 0x78, 0x6c, 0xc7, 0xbf, 0xa6, 0x65, 0xff, 0xc7, 0xf7, 0x0a, 0xc7, 0xea, 0x68, 0x79, 0xce, 0x7f, 0xf5, 0x8e, 0xeb,
+    0xaf, 0x4d, 0xd7, 0x0d, 0x05, 0xe8, 0x71, 0x0d, 0xc5, 0x10, 0x4f, 0xa5, 0xbd, 0xb7, 0x8b, 0xbb, 0x9e, 0xe0, 0x08, 0x3e,
+    0xff, 0x5d, 0xaa, 0xeb, 0x9e, 0x1d, 0x7f, 0x35, 0x6e, 0x7f, 0x6d, 0xba, 0xd8, 0x59, 0xe7, 0x51, 0x28, 0x79, 0xab, 0x5b,
+    0xe9, 0xdf, 0xb0, 0x22, 0x2d, 0xbf, 0xaf, 0xe5, 0x45, 0x65, 0xe6, 0x69, 0x74, 0xf6, 0x2b, 0x65, 0xeb, 0x9c, 0x8e, 0xc5,
+    0x5f, 0xab, 0xb1, 0xe6, 0x2a, 0xbe, 0xe1, 0xae, 0x89, 0x17, 0xd5, 0xcf, 0x0d, 0xf9, 0xbb, 0x48, 0xb6, 0x96, 0x28, 0xeb,
+    0x95, 0x46, 0xa2, 0x3a, 0x69, 0x5e, 0x67, 0xec, 0x39, 0x95, 0xbf, 0x62, 0xae, 0x7a, 0xef, 0xad, 0xe3, 0x42, 0x13, 0xb2,
+    0x27, 0x96, 0x31, 0x95, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x55, 0xff, 0x78, 0x94, 0x28, 0x45,
+    0xea, 0x4a, 0xea, 0x8e, 0x0a, 0x58, 0xc5, 0xa5, 0x6d, 0x89, 0x5c, 0x9f, 0xa9, 0x6e, 0xf4, 0xf5, 0x3c, 0x2d, 0x53, 0x44,
+    0x45, 0x94, 0x3d, 0xa3, 0xfd, 0x0e, 0x40, 0xba, 0xc2, 0xd7, 0x10, 0xca, 0x8a, 0x26, 0xb2, 0xfb, 0xcd, 0xd0, 0x0b, 0xf5,
+    0x6f, 0xaf, 0x9a, 0xed, 0xcf, 0x36, 0x3f, 0xa4, 0x52, 0x46, 0x5d, 0xff, 0x47, 0xae, 0xc9, 0x87, 0x74, 0xdb, 0xd9, 0xbe,
+    0x6b, 0x7c, 0x5e, 0xef, 0xae, 0xb1, 0x0d, 0xb3, 0x36, 0xda, 0x30, 0xda, 0x94, 0x62, 0x21, 0x73, 0x46, 0xcd, 0xf5, 0x2d,
+    0xfb, 0x21, 0xf3, 0xee, 0xdb, 0xca, 0x2a, 0xed, 0x81, 0x63, 0xb7, 0x29, 0xcd, 0xcb, 0x62, 0x3a, 0x5c, 0xe9, 0x7d, 0xeb,
+    0xdd, 0x31, 0x6a, 0x4d, 0x9a, 0xd4, 0x1f, 0xd9, 0x5a, 0x96, 0x6a, 0x28, 0x16, 0x2c, 0x9f, 0x20, 0xff, 0xc8, 0xbd, 0x33,
+    0xaa, 0xa6, 0x2a, 0xf1, 0x48, 0xfc, 0xbb, 0xe9, 0x5b, 0xa0, 0x35, 0x21, 0x91, 0xdc, 0xb6, 0x56, 0x98, 0xc5, 0x75, 0x9a,
+    0xbe, 0x16, 0xfb, 0x29, 0x6f, 0x32, 0x63, 0x6d, 0xad, 0xc3, 0x62, 0xbe, 0x7b, 0x9e, 0x3d, 0xee, 0xfd, 0xf1, 0xaf, 0x41,
+    0xfd, 0x94, 0xcf, 0x73, 0xc9, 0xce, 0x0a, 0x6a, 0xbf, 0xa5, 0xab, 0x9c, 0xe7, 0x96, 0x40, 0x2e, 0xd3, 0xd2, 0xc6, 0x2c,
+    0x66, 0xc5, 0xb9, 0x1e, 0xa8, 0x38, 0xd7, 0xdd, 0xe7, 0xcc, 0x9e, 0xbc, 0xbb, 0x5f, 0x59, 0x33, 0xbe, 0x1d, 0xd2, 0x7c,
+    0xb9, 0xf0, 0x31, 0x51, 0x3d, 0x45, 0x94, 0x44, 0xf7, 0xb6, 0x58, 0xeb, 0x60, 0xf7, 0xb7, 0x38, 0x34, 0x58, 0xb1, 0x96,
+    0x73, 0xf3, 0xfe, 0x11, 0x25, 0xc2, 0x4c, 0xfb, 0xd3, 0x6f, 0x77, 0x9e, 0xf4, 0x9f, 0x19, 0x5d, 0x46, 0x59, 0x3f, 0x05,
+    0xf6, 0x59, 0x97, 0xd5, 0x72, 0x85, 0x7e, 0xc6, 0xf7, 0xba, 0x25, 0xa0, 0x0a, 0xb9, 0xd6, 0x93, 0xd0, 0xdf, 0xd2, 0x27,
+    0x6a, 0x9d, 0xc5, 0x75, 0xd6, 0x65, 0xb6, 0x3c, 0x51, 0x2f, 0x12, 0xad, 0xb5, 0xf7, 0xcc, 0xf8, 0xcf, 0xb4, 0x76, 0x96,
+    0x17, 0xe8, 0xf9, 0x2e, 0x8b, 0xef, 0xa4, 0x17, 0xfa, 0x1b, 0xe3, 0xef, 0x5f, 0x85, 0xdc, 0x16, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0xfd, 0x67, 0x4f, 0x9b, 0xbe, 0x5a, 0x5d, 0x6e, 0x37, 0x96, 0xf2, 0xe6, 0x7e, 0x85, 0x4f, 0x31,
+    0x3f, 0x41, 0xbd, 0x5b, 0xc3, 0xe3, 0x7f, 0x7d, 0xad, 0xa3, 0xa8, 0x2e, 0xdd, 0x49, 0x35, 0x34, 0x27, 0x1f, 0xe2, 0xb3,
+    0x4d, 0xbf, 0xf2, 0xe6, 0x7e, 0x85, 0x8f, 0xd2, 0x70, 0x54, 0xa9, 0xfc, 0xb8, 0x4e, 0xc3, 0x53, 0xe5, 0x4a, 0x7b, 0x74,
+    0x1f, 0x31, 0xdd, 0x49, 0x13, 0x2d, 0xfa, 0x95, 0xf5, 0xa7, 0xd1, 0xcd, 0x70, 0xfe, 0xb9, 0x5b, 0xe1, 0xa3, 0xab, 0x44,
+    0x29, 0x6d, 0x45, 0x95, 0x3b, 0x60, 0xf5, 0xa2, 0xaa, 0x4e, 0x0d, 0x8f, 0xd6, 0x1e, 0xaa, 0xde, 0x2c, 0x2f, 0xa7, 0x25,
+    0xcd, 0x8b, 0xac, 0x8a, 0x99, 0x0c, 0xd3, 0x45, 0xc8, 0xe7, 0x15, 0x74, 0xbf, 0xc2, 0xa7, 0x9b, 0x3e, 0x51, 0x59, 0xd9,
+    0x02, 0x1d, 0xe5, 0xab, 0xb2, 0x12, 0xca, 0xe5, 0xc7, 0x7b, 0x7d, 0x91, 0x4e, 0x4c, 0xc3, 0xc8, 0x87, 0x3f, 0x21, 0x5b,
+    0xef, 0x5b, 0xb1, 0x55, 0xe7, 0xf0, 0x6e, 0x59, 0x69, 0xaf, 0xfe, 0x2b, 0xff, 0xfa, 0x73, 0xb3, 0xf5, 0xde, 0xf8, 0x8f,
+    0xdb, 0xe3, 0xef, 0x57, 0x25, 0x11, 0xff, 0xbc, 0xf8, 0xf7, 0xc4, 0xf3, 0x3f, 0xb7, 0xa6, 0x6c, 0x2c, 0xef, 0x7b, 0x7e,
+    0xfc, 0x87, 0x59, 0xeb, 0xee, 0xdd, 0xe2, 0x7f, 0xf7, 0x6e, 0x2e, 0x93, 0x7b, 0xe2, 0xce, 0x57, 0xe7, 0x5c, 0x8f, 0xe9,
+    0x38, 0xca, 0xcd, 0x2d, 0x11, 0xa5, 0xc6, 0x53, 0xc7, 0x3c, 0x9f, 0x4f, 0x39, 0xed, 0x7a, 0x34, 0xfe, 0xd7, 0xe8, 0x61,
+    0xfc, 0x27, 0x66, 0xbb, 0x5d, 0xc3, 0x83, 0xba, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0x3f, 0xf5,
+    0xa1, 0x1a, 0x9c, 0x98, 0xa3, 0x90, 0x6e, 0xb9, 0x4a, 0xa1, 0x53, 0x4f, 0xd6, 0x53, 0xe9, 0xd5, 0xf2, 0x6b, 0x80, 0x6c,
+    0x4f, 0x1a, 0x3d, 0x93, 0x16, 0xd0, 0xe0, 0x54, 0x43, 0x83, 0xd3, 0x5c, 0x2e, 0x1b, 0xdd, 0x70, 0x14, 0x1a, 0x86, 0x7b,
+    0x41, 0xe6, 0x8c, 0xf4, 0xb8, 0x9b, 0xa1, 0xdb, 0xd8, 0xba, 0x5a, 0x1d, 0x3a, 0x9b, 0xb5, 0x77, 0xe5, 0x49, 0x54, 0x03,
+    0xd9, 0xbf, 0xc5, 0xac, 0x54, 0x16, 0xd1, 0xe0, 0x34, 0x97, 0x06, 0xc7, 0xaa, 0xfe, 0x54, 0x27, 0xd5, 0xb5, 0xfc, 0x59,
+    0x90, 0xbc, 0x19, 0x59, 0xe7, 0x4c, 0x93, 0xfb, 0x7c, 0x7f, 0x9c, 0x8b, 0xb1, 0x53, 0xf5, 0x8e, 0x69, 0x81, 0xec, 0x5f,
+    0x71, 0xce, 0x2f, 0xb7, 0x45, 0xe7, 0x33, 0xad, 0xaa, 0x7b, 0x91, 0x0a, 0x44, 0xb9, 0xe3, 0xb6, 0xd4, 0x56, 0x9e, 0x78,
+    0x16, 0x67, 0x5e, 0xae, 0x89, 0xfc, 0xb3, 0xb5, 0x1f, 0xed, 0x7c, 0xf6, 0x76, 0xc5, 0x9b, 0xdc, 0x4a, 0x3e, 0xba, 0xa5,
+    0x48, 0xd5, 0x42, 0x31, 0x6b, 0x49, 0xf5, 0x40, 0xdd, 0x9a, 0x5c, 0xed, 0x50, 0x31, 0x54, 0x82, 0xfb, 0xcf, 0x25, 0x5f,
+    0x3e, 0xb5, 0x18, 0xea, 0x0f, 0xbf, 0xfa, 0x6f, 0xe6, 0xbf, 0x55, 0x2e, 0x68, 0x19, 0xa1, 0xba, 0x50, 0xf3, 0x9a, 0x38,
+    0xe7, 0xfb, 0x06, 0x75, 0xc3, 0x81, 0xe5, 0xac, 0xf8, 0x67, 0x6a, 0xd9, 0xf6, 0xf8, 0x6f, 0x5d, 0xf3, 0x1c, 0x79, 0x77,
+    0x60, 0xd4, 0x65, 0x23, 0xd7, 0x65, 0xab, 0xb8, 0x3d, 0xf5, 0x32, 0xe2, 0x9f, 0xad, 0xfe, 0x5b, 0x02, 0xfe, 0x4b, 0xb9,
+    0x2d, 0xfe, 0xf3, 0x7a, 0x49, 0x55, 0xba, 0x44, 0x5b, 0xec, 0xca, 0x79, 0x67, 0xc5, 0xbf, 0xfc, 0x18, 0x4f, 0x92, 0x6c,
+    0x1f, 0x9b, 0xeb, 0xd4, 0x16, 0x19, 0xf1, 0xf7, 0xcf, 0x61, 0x79, 0x1b, 0xd7, 0x9f, 0xf3, 0xbc, 0x81, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x69, 0x2a, 0x9f, 0x3c, 0x0f, 0xa2, 0x27, 0x38, 0xed, 0xd4, 0xb0, 0x13, 0xcf, 0x5d,
+    0xdc, 0xad, 0xf2, 0xd1, 0xfa, 0x07, 0x9d, 0xfd, 0xb9, 0x46, 0xc7, 0xa3, 0x7b, 0x1b, 0x93, 0xef, 0x07, 0xb6, 0xb7, 0xfa,
+    0xcc, 0xf2, 0x5e, 0x95, 0x4f, 0x44, 0x5f, 0x91, 0xab, 0xe3, 0xd1, 0x2a, 0x8c, 0x26, 0x73, 0x33, 0x56, 0x85, 0xc4, 0x77,
+    0xa9, 0xbd, 0x70, 0xa5, 0xca, 0x67, 0x96, 0xe5, 0xf7, 0x64, 0xde, 0xcb, 0x44, 0x63, 0xe3, 0x6b, 0x99, 0x7d, 0xd3, 0xfe,
+    0x8a, 0x2c, 0xfc, 0x9d, 0x39, 0x96, 0xfb, 0x9d, 0x76, 0x8a, 0x7b, 0x64, 0xcf, 0xf5, 0x8d, 0x78, 0xbf, 0xf8, 0xdf, 0xbf,
+    0x2e, 0x3d, 0x2d, 0xd3, 0xfd, 0x84, 0x96, 0x98, 0x66, 0xe5, 0xef, 0x8f, 0x7f, 0xa6, 0xd3, 0xc6, 0x35, 0x23, 0x8b, 0xa9,
+    0xc2, 0xde, 0x2b, 0x67, 0x7d, 0xbf, 0xca, 0x27, 0xe2, 0xb4, 0x71, 0x95, 0xfe, 0x28, 0xaa, 0x0a, 0x79, 0xa7, 0xe7, 0xff,
+    0xfd, 0xbc, 0x49, 0xae, 0x1d, 0x99, 0xef, 0x3b, 0x06, 0x5a, 0xb3, 0x0e, 0xef, 0x86, 0x8e, 0x65, 0x63, 0x75, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc1, 0xfa, 0x87, 0x75,
+    0x20, 0xfe, 0xf0, 0x63, 0xe3, 0xff, 0x2f };
+
+// Font glyphs rectangles data (on atlas)
+static const Rectangle brickFontRecs[186] = {
+    { 4, 4, 5 , 10 },
+    { 17, 4, 2 , 8 },
+    { 27, 4, 4 , 3 },
+    { 39, 4, 6 , 8 },
+    { 53, 4, 5 , 10 },
+    { 66, 4, 6 , 8 },
+    { 80, 4, 5 , 10 },
+    { 93, 4, 2 , 3 },
+    { 103, 4, 3 , 8 },
+    { 114, 4, 3 , 8 },
+    { 125, 4, 6 , 6 },
+    { 139, 4, 6 , 6 },
+    { 153, 4, 2 , 3 },
+    { 163, 4, 5 , 2 },
+    { 176, 4, 2 , 2 },
+    { 186, 4, 6 , 8 },
+    { 200, 4, 5 , 8 },
+    { 213, 4, 3 , 8 },
+    { 224, 4, 5 , 8 },
+    { 237, 4, 5 , 8 },
+    { 4, 22, 5 , 8 },
+    { 17, 22, 5 , 8 },
+    { 30, 22, 5 , 8 },
+    { 43, 22, 5 , 8 },
+    { 56, 22, 5 , 8 },
+    { 69, 22, 5 , 8 },
+    { 82, 22, 2 , 8 },
+    { 92, 22, 2 , 9 },
+    { 102, 22, 4 , 6 },
+    { 114, 22, 5 , 4 },
+    { 127, 22, 4 , 6 },
+    { 139, 22, 5 , 8 },
+    { 152, 22, 6 , 8 },
+    { 166, 22, 5 , 8 },
+    { 179, 22, 5 , 8 },
+    { 192, 22, 5 , 8 },
+    { 205, 22, 5 , 8 },
+    { 218, 22, 5 , 8 },
+    { 231, 22, 5 , 8 },
+    { 4, 40, 5 , 8 },
+    { 17, 40, 5 , 8 },
+    { 30, 40, 4 , 8 },
+    { 42, 40, 5 , 8 },
+    { 55, 40, 5 , 8 },
+    { 68, 40, 5 , 8 },
+    { 81, 40, 8 , 8 },
+    { 97, 40, 5 , 8 },
+    { 110, 40, 5 , 8 },
+    { 123, 40, 5 , 8 },
+    { 136, 40, 5 , 9 },
+    { 149, 40, 5 , 8 },
+    { 162, 40, 5 , 8 },
+    { 175, 40, 6 , 8 },
+    { 189, 40, 5 , 8 },
+    { 202, 40, 5 , 8 },
+    { 215, 40, 8 , 8 },
+    { 231, 40, 5 , 8 },
+    { 4, 58, 5 , 8 },
+    { 17, 58, 5 , 8 },
+    { 30, 58, 3 , 8 },
+    { 41, 58, 6 , 8 },
+    { 55, 58, 3 , 8 },
+    { 66, 58, 6 , 4 },
+    { 80, 58, 5 , 1 },
+    { 93, 58, 2 , 3 },
+    { 103, 58, 5 , 6 },
+    { 116, 58, 5 , 8 },
+    { 129, 58, 5 , 6 },
+    { 142, 58, 5 , 8 },
+    { 155, 58, 5 , 6 },
+    { 168, 58, 5 , 8 },
+    { 181, 58, 5 , 7 },
+    { 194, 58, 5 , 8 },
+    { 207, 58, 2 , 8 },
+    { 217, 58, 3 , 9 },
+    { 228, 58, 5 , 8 },
+    { 241, 58, 2 , 8 },
+    { 4, 76, 8 , 6 },
+    { 20, 76, 5 , 6 },
+    { 33, 76, 5 , 6 },
+    { 46, 76, 5 , 7 },
+    { 59, 76, 5 , 7 },
+    { 72, 76, 5 , 6 },
+    { 85, 76, 5 , 6 },
+    { 98, 76, 5 , 8 },
+    { 111, 76, 5 , 6 },
+    { 124, 76, 5 , 6 },
+    { 137, 76, 8 , 6 },
+    { 153, 76, 5 , 6 },
+    { 166, 76, 5 , 7 },
+    { 179, 76, 5 , 6 },
+    { 192, 76, 4 , 8 },
+    { 204, 76, 2 , 10 },
+    { 214, 76, 4 , 8 },
+    { 226, 76, 6 , 4 },
+    { 240, 76, 2 , 8 },
+    { 4, 94, 5 , 8 },
+    { 17, 94, 5 , 8 },
+    { 30, 94, 6 , 8 },
+    { 44, 94, 5 , 10 },
+    { 57, 94, 5 , 10 },
+    { 70, 94, 5 , 9 },
+    { 83, 94, 7 , 8 },
+    { 98, 94, 4 , 6 },
+    { 110, 94, 5 , 4 },
+    { 123, 94, 5 , 3 },
+    { 136, 94, 7 , 8 },
+    { 151, 94, 5 , 2 },
+    { 164, 94, 4 , 4 },
+    { 176, 94, 6 , 8 },
+    { 190, 94, 4 , 6 },
+    { 202, 94, 4 , 6 },
+    { 214, 94, 5 , 9 },
+    { 227, 94, 6 , 8 },
+    { 241, 94, 2 , 2 },
+    { 4, 112, 3 , 6 },
+    { 15, 112, 4 , 6 },
+    { 27, 112, 5 , 4 },
+    { 40, 112, 6 , 8 },
+    { 54, 112, 6 , 6 },
+    { 68, 112, 5 , 10 },
+    { 81, 112, 5 , 8 },
+    { 94, 112, 5 , 10 },
+    { 107, 112, 5 , 10 },
+    { 120, 112, 5 , 10 },
+    { 133, 112, 5 , 10 },
+    { 146, 112, 5 , 10 },
+    { 159, 112, 5 , 10 },
+    { 172, 112, 6 , 8 },
+    { 186, 112, 5 , 9 },
+    { 199, 112, 5 , 10 },
+    { 212, 112, 5 , 10 },
+    { 225, 112, 5 , 10 },
+    { 238, 112, 5 , 10 },
+    { 4, 130, 4 , 10 },
+    { 16, 130, 4 , 10 },
+    { 28, 130, 4 , 10 },
+    { 40, 130, 4 , 10 },
+    { 52, 130, 6 , 8 },
+    { 66, 130, 5 , 10 },
+    { 79, 130, 5 , 10 },
+    { 92, 130, 5 , 10 },
+    { 105, 130, 5 , 10 },
+    { 118, 130, 5 , 10 },
+    { 131, 130, 5 , 10 },
+    { 144, 130, 4 , 4 },
+    { 156, 130, 5 , 10 },
+    { 169, 130, 5 , 10 },
+    { 182, 130, 5 , 10 },
+    { 195, 130, 5 , 10 },
+    { 208, 130, 5 , 10 },
+    { 221, 130, 5 , 10 },
+    { 234, 130, 5 , 8 },
+    { 4, 148, 5 , 8 },
+    { 17, 148, 5 , 9 },
+    { 30, 148, 5 , 9 },
+    { 43, 148, 5 , 9 },
+    { 56, 148, 5 , 9 },
+    { 69, 148, 5 , 8 },
+    { 82, 148, 5 , 10 },
+    { 95, 148, 6 , 6 },
+    { 109, 148, 5 , 7 },
+    { 122, 148, 5 , 9 },
+    { 135, 148, 5 , 9 },
+    { 148, 148, 5 , 9 },
+    { 161, 148, 5 , 8 },
+    { 174, 148, 3 , 9 },
+    { 185, 148, 3 , 9 },
+    { 196, 148, 4 , 9 },
+    { 208, 148, 4 , 8 },
+    { 220, 148, 5 , 9 },
+    { 233, 148, 5 , 9 },
+    { 4, 166, 5 , 9 },
+    { 17, 166, 5 , 9 },
+    { 30, 166, 5 , 9 },
+    { 43, 166, 5 , 9 },
+    { 56, 166, 5 , 8 },
+    { 69, 166, 4 , 6 },
+    { 81, 166, 5 , 8 },
+    { 94, 166, 5 , 9 },
+    { 107, 166, 5 , 9 },
+    { 120, 166, 5 , 9 },
+    { 133, 166, 5 , 8 },
+    { 146, 166, 5 , 10 },
+    { 159, 166, 5 , 10 },
+    { 172, 166, 5 , 9 },
+};
+
+// Font glyphs info data
+// NOTE: No glyphs.image data provided
+static const GlyphInfo brickFontGlyphs[186] = {
+    { 32, 0, 0, 5, { 0 }},
+    { 33, 0, 1, 2, { 0 }},
+    { 34, 0, 1, 4, { 0 }},
+    { 35, 0, 1, 6, { 0 }},
+    { 36, 0, 0, 5, { 0 }},
+    { 37, 0, 1, 6, { 0 }},
+    { 38, 0, 0, 5, { 0 }},
+    { 39, 0, 1, 2, { 0 }},
+    { 40, 0, 1, 3, { 0 }},
+    { 41, 0, 1, 3, { 0 }},
+    { 42, 0, 1, 6, { 0 }},
+    { 43, 0, 2, 6, { 0 }},
+    { 44, 0, 7, 2, { 0 }},
+    { 45, 0, 4, 5, { 0 }},
+    { 46, 0, 7, 2, { 0 }},
+    { 47, 0, 1, 6, { 0 }},
+    { 48, 0, 1, 5, { 0 }},
+    { 49, 0, 1, 3, { 0 }},
+    { 50, 0, 1, 5, { 0 }},
+    { 51, 0, 1, 5, { 0 }},
+    { 52, 0, 1, 5, { 0 }},
+    { 53, 0, 1, 5, { 0 }},
+    { 54, 0, 1, 5, { 0 }},
+    { 55, 0, 1, 5, { 0 }},
+    { 56, 0, 1, 5, { 0 }},
+    { 57, 0, 1, 5, { 0 }},
+    { 58, 0, 1, 2, { 0 }},
+    { 59, 0, 1, 2, { 0 }},
+    { 60, 0, 2, 4, { 0 }},
+    { 61, 0, 3, 5, { 0 }},
+    { 62, 0, 2, 4, { 0 }},
+    { 63, 0, 1, 5, { 0 }},
+    { 64, 0, 1, 6, { 0 }},
+    { 65, 0, 1, 5, { 0 }},
+    { 66, 0, 1, 5, { 0 }},
+    { 67, 0, 1, 5, { 0 }},
+    { 68, 0, 1, 5, { 0 }},
+    { 69, 0, 1, 5, { 0 }},
+    { 70, 0, 1, 5, { 0 }},
+    { 71, 0, 1, 5, { 0 }},
+    { 72, 0, 1, 5, { 0 }},
+    { 73, 0, 1, 4, { 0 }},
+    { 74, 0, 1, 5, { 0 }},
+    { 75, 0, 1, 5, { 0 }},
+    { 76, 0, 1, 5, { 0 }},
+    { 77, 0, 1, 8, { 0 }},
+    { 78, 0, 1, 5, { 0 }},
+    { 79, 0, 1, 5, { 0 }},
+    { 80, 0, 1, 5, { 0 }},
+    { 81, 0, 1, 5, { 0 }},
+    { 82, 0, 1, 5, { 0 }},
+    { 83, 0, 1, 5, { 0 }},
+    { 84, 0, 1, 6, { 0 }},
+    { 85, 0, 1, 5, { 0 }},
+    { 86, 0, 1, 5, { 0 }},
+    { 87, 0, 1, 8, { 0 }},
+    { 88, 0, 1, 5, { 0 }},
+    { 89, 0, 1, 5, { 0 }},
+    { 90, 0, 1, 5, { 0 }},
+    { 91, 0, 1, 3, { 0 }},
+    { 92, 0, 1, 6, { 0 }},
+    { 93, 0, 1, 3, { 0 }},
+    { 94, 0, 1, 6, { 0 }},
+    { 95, 0, 9, 5, { 0 }},
+    { 96, 0, 1, 2, { 0 }},
+    { 97, 0, 3, 5, { 0 }},
+    { 98, 0, 1, 5, { 0 }},
+    { 99, 0, 3, 5, { 0 }},
+    { 100, 0, 1, 5, { 0 }},
+    { 101, 0, 3, 5, { 0 }},
+    { 102, 0, 1, 5, { 0 }},
+    { 103, 0, 3, 5, { 0 }},
+    { 104, 0, 1, 5, { 0 }},
+    { 105, 0, 1, 2, { 0 }},
+    { 106, 0, 1, 3, { 0 }},
+    { 107, 0, 1, 5, { 0 }},
+    { 108, 0, 1, 2, { 0 }},
+    { 109, 0, 3, 8, { 0 }},
+    { 110, 0, 3, 5, { 0 }},
+    { 111, 0, 3, 5, { 0 }},
+    { 112, 0, 3, 5, { 0 }},
+    { 113, 0, 3, 5, { 0 }},
+    { 114, 0, 3, 5, { 0 }},
+    { 115, 0, 3, 5, { 0 }},
+    { 116, 0, 1, 5, { 0 }},
+    { 117, 0, 3, 5, { 0 }},
+    { 118, 0, 3, 5, { 0 }},
+    { 119, 0, 3, 8, { 0 }},
+    { 120, 0, 3, 5, { 0 }},
+    { 121, 0, 3, 5, { 0 }},
+    { 122, 0, 3, 5, { 0 }},
+    { 123, 0, 1, 4, { 0 }},
+    { 124, 0, 0, 2, { 0 }},
+    { 125, 0, 1, 4, { 0 }},
+    { 126, 0, 3, 6, { 0 }},
+    { 161, 0, 1, 2, { 0 }},
+    { 162, 0, 2, 5, { 0 }},
+    { 163, 0, 1, 5, { 0 }},
+    { 165, 0, 1, 6, { 0 }},
+    { 352, 0, -1, 5, { 0 }},
+    { 167, 0, 0, 5, { 0 }},
+    { 353, 0, 0, 5, { 0 }},
+    { 169, 0, 1, 7, { 0 }},
+    { 170, 0, -1, 4, { 0 }},
+    { 171, 0, 3, 5, { 0 }},
+    { 172, 0, 4, 5, { 0 }},
+    { 174, 0, 1, 7, { 0 }},
+    { 175, 0, -1, 5, { 0 }},
+    { 176, 0, -1, 4, { 0 }},
+    { 177, 0, 1, 6, { 0 }},
+    { 178, 0, -1, 4, { 0 }},
+    { 179, 0, -1, 4, { 0 }},
+    { 181, 0, 1, 5, { 0 }},
+    { 182, 0, 1, 6, { 0 }},
+    { 183, 0, 4, 2, { 0 }},
+    { 185, 0, -1, 3, { 0 }},
+    { 186, 0, -1, 4, { 0 }},
+    { 187, 0, 3, 5, { 0 }},
+    { 338, 0, 1, 6, { 0 }},
+    { 339, 0, 3, 6, { 0 }},
+    { 376, 0, -1, 5, { 0 }},
+    { 191, 0, 1, 5, { 0 }},
+    { 192, 0, -1, 5, { 0 }},
+    { 193, 0, -1, 5, { 0 }},
+    { 194, 0, -1, 5, { 0 }},
+    { 195, 0, -1, 5, { 0 }},
+    { 196, 0, -1, 5, { 0 }},
+    { 197, 0, -1, 5, { 0 }},
+    { 198, 0, 1, 6, { 0 }},
+    { 199, 0, 1, 5, { 0 }},
+    { 200, 0, -1, 5, { 0 }},
+    { 201, 0, -1, 5, { 0 }},
+    { 202, 0, -1, 5, { 0 }},
+    { 203, 0, -1, 5, { 0 }},
+    { 204, 0, -1, 4, { 0 }},
+    { 205, 0, -1, 4, { 0 }},
+    { 206, 0, -1, 4, { 0 }},
+    { 207, 0, -1, 4, { 0 }},
+    { 208, 0, 1, 6, { 0 }},
+    { 209, 0, -1, 5, { 0 }},
+    { 210, 0, -1, 5, { 0 }},
+    { 211, 0, -1, 5, { 0 }},
+    { 212, 0, -1, 5, { 0 }},
+    { 213, 0, -1, 5, { 0 }},
+    { 214, 0, -1, 5, { 0 }},
+    { 215, 0, 3, 4, { 0 }},
+    { 216, 0, 0, 5, { 0 }},
+    { 217, 0, -1, 5, { 0 }},
+    { 218, 0, -1, 5, { 0 }},
+    { 219, 0, -1, 5, { 0 }},
+    { 220, 0, -1, 5, { 0 }},
+    { 221, 0, -1, 5, { 0 }},
+    { 222, 0, 1, 5, { 0 }},
+    { 223, 0, 1, 5, { 0 }},
+    { 224, 0, 0, 5, { 0 }},
+    { 225, 0, 0, 5, { 0 }},
+    { 226, 0, 0, 5, { 0 }},
+    { 227, 0, 0, 5, { 0 }},
+    { 228, 0, 1, 5, { 0 }},
+    { 229, 0, -1, 5, { 0 }},
+    { 230, 0, 3, 6, { 0 }},
+    { 231, 0, 3, 5, { 0 }},
+    { 232, 0, 0, 5, { 0 }},
+    { 233, 0, 0, 5, { 0 }},
+    { 234, 0, 0, 5, { 0 }},
+    { 235, 0, 1, 5, { 0 }},
+    { 236, 0, 0, 3, { 0 }},
+    { 237, 0, 0, 2, { 0 }},
+    { 238, 0, 0, 3, { 0 }},
+    { 239, 0, 1, 3, { 0 }},
+    { 240, 0, 0, 5, { 0 }},
+    { 241, 0, 0, 5, { 0 }},
+    { 242, 0, 0, 5, { 0 }},
+    { 243, 0, 0, 5, { 0 }},
+    { 244, 0, 0, 5, { 0 }},
+    { 245, 0, 0, 5, { 0 }},
+    { 246, 0, 1, 5, { 0 }},
+    { 247, 0, 2, 4, { 0 }},
+    { 248, 0, 2, 5, { 0 }},
+    { 249, 0, 0, 5, { 0 }},
+    { 250, 0, 0, 5, { 0 }},
+    { 251, 0, 0, 5, { 0 }},
+    { 252, 0, 1, 5, { 0 }},
+    { 253, 0, 0, 5, { 0 }},
+    { 254, 0, 0, 5, { 0 }},
+    { 255, 0, 1, 5, { 0 }},
+};
+
+// Style loading function: Brick
+static void GuiLoadStyleBrick(void)
+{
+    // Load style properties provided
+    // NOTE: Default properties are propagated
+    for (int i = 0; i < BRICK_STYLE_PROPS_COUNT; i++)
+    {
+        GuiSetStyle(brickStyleProps[i].controlId, brickStyleProps[i].propertyId, brickStyleProps[i].propertyValue);
+    }
+
+    // Custom font loading
+    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
+    int brickFontDataSize = 0;
+    unsigned char *data = DecompressData(brickFontData, BRICK_STYLE_FONT_ATLAS_COMP_SIZE, &brickFontDataSize);
+    Image imFont = { data, 256, 256, 1, 2 };
+
+    Font font = { 0 };
+    font.baseSize = 10;
+    font.glyphCount = 186;
+
+    // Copy char recs data from global fontRecs
+    // NOTE: Required to avoid issues if trying to free font
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+    memcpy(font.recs, brickFontRecs, font.glyphCount*sizeof(Rectangle));
+
+    // Copy font char info data from global fontChars
+    // NOTE: Required to avoid issues if trying to free font
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+    memcpy(font.glyphs, brickFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
+
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
+    GuiSetFont(font);
+
+    // Setup a white rectangle on the font to be used on shapes drawing,
+    // it makes possible to draw shapes and text (full UI) in a single draw call
+    SetShapesTexture(font.texture, fontWhiteRec);
+
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "homespun.ttf");
+    //-----------------------------------------------------------------
+
+    // TODO: Custom user style setup: Set specific properties here (if required)
+    // i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
+}
diff --git a/raygui/styles/candy/style_candy.h b/raygui/styles/candy/style_candy.h
--- a/raygui/styles/candy/style_candy.h
+++ b/raygui/styles/candy/style_candy.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,140 +15,139 @@
 
 // Custom style name: Candy
 static const GuiStyleProp candyStyleProps[CANDY_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0xe58b68ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0xfeda96ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xe59b5fff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xee813fff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xfcd85bff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xfc6955ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xb34848ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xeb7272ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xbd4a4aff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x94795dff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0xc2a37aff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x9c8369ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0xe58b68ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xfeda96ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xe59b5fff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xee813fff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xfcd85bff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xfc6955ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xb34848ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xeb7272ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xbd4a4aff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x94795dff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xc2a37aff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x9c8369ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x0000000f },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0xd77575ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0xfff5e1ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000016 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000007 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "v5easter.ttf" (size: 15, spacing: 0)
 
-#define CANDY_STYLE_FONT_ATLAS_COMP_SIZE 2110
+#define CANDY_STYLE_FONT_ATLAS_COMP_SIZE 2097
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char candyFontData[CANDY_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0x5b, 0x76, 0xa4, 0x36, 0x10, 0x00, 0x50, 0xad, 0x2b, 0xfb, 0xdf, 0x97, 0x72, 0x92, 0x7c, 0xe4, 0xcc, 0x8c, 0x1b,
-    0x54, 0xa5, 0x12, 0x08, 0xfa, 0xfa, 0xfe, 0x19, 0xbb, 0x1b, 0x10, 0xa5, 0x07, 0xa0, 0x52, 0x6f, 0x00, 0x00, 0x00, 0xc0,
-    0x97, 0xfb, 0xe7, 0xe7, 0xcf, 0xdf, 0xb5, 0x1f, 0x7e, 0xfb, 0xff, 0xdf, 0xf6, 0x1f, 0xb7, 0x1e, 0x6d, 0xc9, 0xff, 0xe7,
-    0xf1, 0x9e, 0x8c, 0x7d, 0x42, 0x3b, 0xd8, 0x72, 0xbe, 0xcf, 0xbf, 0xff, 0xae, 0x97, 0x7c, 0xfb, 0xa7, 0xcf, 0x39, 0xdb,
-    0xa3, 0xcc, 0xb6, 0xa3, 0x4f, 0xed, 0x07, 0xc7, 0xd4, 0x06, 0xb6, 0xf4, 0xd4, 0xd1, 0xf5, 0xe9, 0x52, 0x8d, 0x95, 0xce,
-    0xf9, 0xf1, 0xb7, 0xf0, 0x31, 0xb6, 0x05, 0xdb, 0xfa, 0x64, 0x19, 0xaf, 0x8c, 0xff, 0xdf, 0x7f, 0x2a, 0xe3, 0xff, 0xf8,
-    0x33, 0x67, 0xae, 0x89, 0xff, 0x8f, 0xa6, 0x17, 0xc4, 0x7f, 0xbc, 0x16, 0x39, 0x3e, 0x82, 0xcf, 0x57, 0x71, 0x0b, 0xff,
-    0xcf, 0x79, 0xfd, 0x5a, 0xf9, 0xa9, 0x2b, 0xb7, 0x8d, 0x45, 0xed, 0xfc, 0x75, 0x7e, 0xb6, 0x37, 0x73, 0x65, 0x78, 0xe5,
-    0xb6, 0xda, 0xf8, 0x3f, 0xfb, 0xdb, 0x6c, 0xcd, 0x9e, 0xef, 0x1d, 0x8c, 0xb6, 0xe6, 0x3d, 0x74, 0xed, 0x9f, 0xb7, 0x62,
-    0x35, 0x67, 0x38, 0x7a, 0xc4, 0xc7, 0x75, 0xc9, 0xd9, 0xd6, 0xf9, 0x36, 0x37, 0x72, 0x6d, 0xdc, 0x71, 0x15, 0x9f, 0x97,
-    0x66, 0x45, 0xbb, 0xd4, 0x7f, 0x39, 0xdb, 0xe2, 0x7f, 0xf4, 0xaa, 0xed, 0x8b, 0x5b, 0xda, 0x16, 0x6e, 0x69, 0x73, 0x7d,
-    0x96, 0xba, 0x33, 0x5c, 0x15, 0xff, 0x7d, 0x22, 0xfa, 0x5b, 0xa2, 0xc7, 0x79, 0x5c, 0x6b, 0x9f, 0xed, 0x7f, 0xf6, 0x2a,
-    0xa9, 0xbd, 0x66, 0x67, 0xe3, 0xff, 0xb8, 0x3f, 0xdc, 0x0e, 0xeb, 0x9b, 0xeb, 0x7a, 0x5c, 0x3b, 0xc5, 0x7f, 0xb6, 0x87,
-    0x3c, 0x3e, 0xba, 0xa9, 0x6b, 0xff, 0xd7, 0xc7, 0xff, 0x59, 0x44, 0xf6, 0xe0, 0x48, 0xb5, 0xb6, 0x35, 0x1e, 0x19, 0x4f,
-    0x67, 0x6b, 0xf4, 0xf8, 0x18, 0xf7, 0xfa, 0xfe, 0xff, 0xf9, 0xb8, 0xb1, 0x2f, 0x1b, 0x39, 0xd5, 0x47, 0xd8, 0xbe, 0xfd,
-    0xff, 0xb1, 0x7e, 0xc1, 0x9a, 0xfe, 0xff, 0xd9, 0xf8, 0xbf, 0x5d, 0xde, 0xfa, 0x9f, 0x45, 0x56, 0xbe, 0xf4, 0x7b, 0xaa,
-    0x07, 0x34, 0x77, 0x57, 0x21, 0x57, 0x9e, 0x73, 0xf1, 0xbf, 0xa2, 0x0f, 0x10, 0x1d, 0xfd, 0xbd, 0xa3, 0xff, 0x9f, 0x39,
-    0x83, 0xd9, 0xfb, 0xcc, 0x55, 0x47, 0x16, 0xbf, 0xcf, 0x7f, 0xdf, 0x19, 0xab, 0xab, 0xe7, 0x67, 0xcf, 0x60, 0xfd, 0xa7,
-    0xe6, 0x7a, 0xd5, 0xd1, 0xab, 0xb8, 0xdf, 0xfa, 0x6c, 0xac, 0x3f, 0xe2, 0xce, 0xe9, 0x15, 0xed, 0xff, 0xd9, 0xfd, 0xff,
-    0x99, 0xbb, 0x03, 0xb1, 0x27, 0x1b, 0x7d, 0xc3, 0x6b, 0x45, 0xfc, 0x3f, 0xa5, 0x15, 0xab, 0xea, 0x55, 0xbb, 0xff, 0x97,
-    0x79, 0xa6, 0x5d, 0xd1, 0x9f, 0x7b, 0x4a, 0xfc, 0xf7, 0x81, 0xda, 0x74, 0x7c, 0x4b, 0xfe, 0x89, 0xfb, 0xaa, 0xb7, 0x0a,
-    0xce, 0x9e, 0x36, 0x5e, 0xf7, 0x14, 0x7b, 0xc7, 0xf8, 0x7f, 0xc6, 0xf3, 0xff, 0x3d, 0xce, 0xe5, 0xda, 0x91, 0xdc, 0x8e,
-    0xf1, 0x0f, 0xdf, 0xf1, 0x36, 0xe1, 0x75, 0x6f, 0x2d, 0x8a, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x9e, 0x3e, 0x3b, 0x27, 0x9f, 0x21, 0x32, 0x36, 0xe7, 0xa6, 0x2f, 0xc9, 0x8b, 0x94, 0x9b, 0x1b, 0x7d,
-    0x6d, 0x0e, 0xe7, 0x6c, 0xd6, 0xec, 0xb9, 0x79, 0xe1, 0x9f, 0xf3, 0x09, 0xcd, 0x7c, 0xee, 0xf1, 0x5c, 0xe4, 0xc8, 0xbc,
-    0xec, 0x6c, 0xae, 0xf3, 0x68, 0x4e, 0xa0, 0x4c, 0xee, 0xa4, 0xd9, 0xdc, 0xe9, 0xf1, 0x23, 0xce, 0xcc, 0x60, 0x9d, 0x9d,
-    0xf3, 0x76, 0x55, 0xc6, 0xe6, 0x6c, 0x9c, 0x8e, 0x65, 0xbd, 0xed, 0xe1, 0x4c, 0x75, 0xbb, 0xe5, 0x69, 0xa8, 0xce, 0x9a,
-    0xb1, 0x32, 0xfe, 0xdb, 0x50, 0x6e, 0xec, 0xb1, 0xf9, 0xce, 0xbd, 0x70, 0x46, 0xfb, 0x75, 0x39, 0xf7, 0xda, 0x74, 0x99,
-    0x44, 0x5b, 0xaa, 0xf7, 0xc7, 0x7f, 0xf6, 0xd8, 0xcf, 0xce, 0x6a, 0xdf, 0x36, 0x8b, 0xfd, 0x9d, 0xf1, 0x9f, 0xed, 0xdb,
-    0x1d, 0xb7, 0x7c, 0xf1, 0x8c, 0x07, 0xd7, 0x64, 0xb4, 0xe9, 0x1b, 0xc5, 0x7f, 0xfc, 0xdb, 0x56, 0xce, 0x61, 0x9f, 0x6b,
-    0x7b, 0x7b, 0x59, 0xfc, 0xe7, 0xfb, 0x3e, 0xbb, 0xb5, 0xf1, 0xb5, 0x59, 0x73, 0xd6, 0xc5, 0x7f, 0x2b, 0xcf, 0xca, 0xb4,
-    0x67, 0xfc, 0x8f, 0xb4, 0x0f, 0x99, 0xb1, 0x41, 0xfc, 0x3f, 0xb3, 0x35, 0x6e, 0xf4, 0xdb, 0x32, 0xed, 0xff, 0xf1, 0x51,
-    0x3e, 0xb9, 0xfd, 0xdf, 0x25, 0xfe, 0xdb, 0x56, 0xfd, 0xff, 0xd9, 0xab, 0x31, 0x16, 0xe7, 0xf7, 0xe5, 0x66, 0xdb, 0x7d,
-    0x25, 0xa3, 0xc8, 0x19, 0x9f, 0xcd, 0x8e, 0x9c, 0xbd, 0xef, 0x50, 0xb9, 0x62, 0xd3, 0xb3, 0xee, 0x71, 0xb5, 0xaf, 0x1c,
-    0xff, 0xe7, 0xef, 0xfb, 0x8a, 0xff, 0xd9, 0xfe, 0x74, 0xbb, 0x21, 0xfe, 0x57, 0x9d, 0xbb, 0x27, 0xc7, 0xff, 0x4c, 0xcf,
-    0xef, 0xaa, 0xf8, 0x6f, 0x1f, 0x57, 0xa1, 0x9a, 0x8d, 0xff, 0xfc, 0xda, 0x38, 0xd1, 0x38, 0xef, 0x37, 0x3e, 0xdf, 0x5a,
-    0x51, 0x07, 0xe6, 0x9f, 0x37, 0x34, 0xf1, 0xff, 0xa8, 0xf8, 0xbf, 0xbf, 0xfd, 0x1f, 0x5d, 0x5b, 0xf1, 0xbb, 0xe3, 0xbf,
-    0x4d, 0xdd, 0xe3, 0x5b, 0xf1, 0x7f, 0xbb, 0xf5, 0xff, 0xab, 0xeb, 0xce, 0x6b, 0xeb, 0xd3, 0x75, 0x7d, 0xdc, 0xdc, 0xfd,
-    0xa4, 0xdc, 0x6a, 0x06, 0xb9, 0xac, 0xd9, 0x6b, 0xae, 0xa9, 0x96, 0x5e, 0xc3, 0xab, 0x85, 0x6b, 0x00, 0xf1, 0xff, 0xeb,
-    0x96, 0x75, 0xab, 0x23, 0xc3, 0xea, 0x78, 0x7a, 0x56, 0xfc, 0xcf, 0xbd, 0x69, 0x50, 0xbf, 0xda, 0x60, 0xbf, 0xa1, 0xfd,
-    0x87, 0xb5, 0x4f, 0xd9, 0xeb, 0xfe, 0x9e, 0x8a, 0x3e, 0x3d, 0xf0, 0xbd, 0xfd, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xe0, 0x8d, 0x73, 0x05, 0x3e, 0xcf, 0xf2, 0x3c, 0xce, 0x82, 0xd1, 0x92, 0x59, 0xb0, 0xdb, 0x40,
-    0xe6, 0xe4, 0x9e, 0xfc, 0xbe, 0xc8, 0x2c, 0xe5, 0xdd, 0x72, 0x11, 0x44, 0xf3, 0x23, 0x46, 0x72, 0x63, 0xb7, 0x70, 0x9e,
-    0xaf, 0x6c, 0x16, 0x9b, 0x36, 0x99, 0x73, 0x34, 0x3f, 0xff, 0x2e, 0x3b, 0x83, 0x7a, 0x2c, 0xa3, 0xdb, 0xd8, 0xf7, 0xf4,
-    0xa1, 0x19, 0x7e, 0xb3, 0xa5, 0x50, 0x3f, 0x27, 0xb1, 0x5d, 0x9e, 0x75, 0xe3, 0xde, 0x6c, 0x4c, 0x4f, 0xca, 0xb7, 0x1d,
-    0xc9, 0xc3, 0x7b, 0x9e, 0xcf, 0x63, 0x3e, 0xfe, 0x47, 0x73, 0x0a, 0xf4, 0xc9, 0xac, 0x9f, 0xd1, 0xba, 0xe2, 0xf8, 0xbc,
-    0x1c, 0xcd, 0x4d, 0x8e, 0x45, 0x7f, 0x76, 0xfe, 0xcd, 0xf9, 0x3e, 0xac, 0x9b, 0x51, 0xfd, 0x1d, 0xf1, 0x1f, 0xaf, 0x41,
-    0x9f, 0x90, 0x6f, 0xbb, 0x15, 0xfc, 0xb6, 0x72, 0xe6, 0x7b, 0x36, 0xa7, 0x48, 0x36, 0xfe, 0x23, 0xb1, 0xf5, 0xb9, 0x96,
-    0x6b, 0x03, 0x19, 0xd4, 0xe6, 0xbf, 0x27, 0x13, 0xff, 0x3d, 0x9c, 0x6d, 0x25, 0xdb, 0xfe, 0xc7, 0x5a, 0x97, 0x3d, 0xe3,
-    0x3f, 0xd3, 0xe3, 0xec, 0x17, 0xc6, 0xff, 0x5c, 0x8e, 0xaf, 0x76, 0x79, 0xfc, 0xd7, 0xae, 0x53, 0x31, 0x36, 0x92, 0xa9,
-    0xe8, 0x69, 0xff, 0x34, 0x3a, 0x3c, 0x1a, 0x19, 0xd5, 0xc5, 0x7f, 0xff, 0xe1, 0x1b, 0x57, 0xb5, 0xff, 0x55, 0x19, 0x55,
-    0xfb, 0xc1, 0xfe, 0xbe, 0x21, 0xfe, 0xdb, 0x26, 0xfd, 0xff, 0xfa, 0xb5, 0xd4, 0xf6, 0x8c, 0xff, 0x78, 0x8f, 0x2b, 0xde,
-    0x7a, 0xc5, 0xfa, 0x0a, 0xe7, 0x23, 0x80, 0x5e, 0x50, 0x03, 0xf4, 0xdf, 0xd6, 0xa3, 0xaa, 0x1a, 0x85, 0xc7, 0x56, 0x12,
-    0xcb, 0xb5, 0xff, 0xfd, 0xb5, 0xed, 0x7f, 0xed, 0xf8, 0x7f, 0x55, 0x2e, 0xc2, 0xda, 0xf5, 0xb6, 0xaa, 0x72, 0x6d, 0xe6,
-    0xfa, 0x5a, 0xd9, 0xf6, 0xff, 0xac, 0x77, 0x30, 0x13, 0xff, 0x6d, 0x32, 0x2e, 0x63, 0xf5, 0x4c, 0x7f, 0x54, 0x06, 0x8e,
-    0x91, 0x35, 0xf2, 0xea, 0xae, 0xf4, 0xd1, 0x08, 0x8a, 0x6c, 0x9d, 0xcd, 0xaa, 0x36, 0xfe, 0xa4, 0x61, 0xa4, 0xa6, 0xfe,
-    0xfc, 0x94, 0x62, 0xe4, 0xac, 0x54, 0x8c, 0x01, 0x77, 0xed, 0xff, 0xdf, 0xd3, 0xfe, 0x8f, 0xb4, 0xfe, 0x35, 0x79, 0xc8,
-    0x7a, 0x79, 0xfe, 0x9d, 0x5e, 0xb8, 0x77, 0x75, 0x2d, 0xe4, 0x1d, 0x4f, 0x22, 0x57, 0xec, 0xd1, 0x7e, 0x59, 0xd2, 0x7a,
-    0xf2, 0xce, 0xf1, 0x5e, 0xfd, 0xff, 0xfc, 0xd8, 0x2a, 0x32, 0xaa, 0xaf, 0x7b, 0xfe, 0x57, 0xdd, 0x96, 0x3e, 0x2b, 0xfb,
-    0x96, 0xf8, 0xdf, 0xbb, 0x0c, 0xf6, 0x8a, 0xff, 0xd1, 0x55, 0xcc, 0x7b, 0xf9, 0x93, 0xf8, 0x67, 0xd4, 0xe0, 0xcf, 0x7d,
-    0xff, 0xe7, 0xfa, 0x95, 0x47, 0xef, 0x8e, 0xff, 0xdd, 0x6a, 0x80, 0xaa, 0x15, 0xaf, 0xdb, 0xe2, 0x37, 0x43, 0xee, 0x3f,
-    0x6b, 0x2b, 0x56, 0x08, 0x86, 0xb7, 0xbc, 0xbf, 0xd9, 0x5f, 0xdf, 0x6f, 0x7a, 0x62, 0x4f, 0x1b, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xd5, 0xfc, 0xbf, 0x3e, 0x39, 0x37, 0x30, 0x97, 0x59, 0xa8, 0x9d, 0xce,
-    0x30, 0xed, 0xe9, 0xbf, 0x89, 0x1c, 0x4b, 0x3e, 0x67, 0x45, 0x26, 0xe7, 0x76, 0x3b, 0xc9, 0x53, 0x53, 0x73, 0x6e, 0xae,
-    0x39, 0xce, 0xf3, 0xdc, 0x7a, 0xb1, 0xeb, 0x22, 0x72, 0xa6, 0xce, 0x73, 0xa6, 0x5c, 0x77, 0x1e, 0xb2, 0xe5, 0xdd, 0x4f,
-    0x66, 0x73, 0xf7, 0xc3, 0x4c, 0x35, 0x15, 0xb9, 0x54, 0xce, 0x3e, 0x3f, 0x9f, 0x79, 0xaf, 0x25, 0x32, 0xae, 0xf5, 0x3f,
-    0x72, 0x39, 0xf5, 0xd4, 0xdf, 0x44, 0x4b, 0x3d, 0xb7, 0x6d, 0x24, 0xa7, 0x63, 0x5d, 0x9e, 0xe8, 0xcc, 0xb9, 0x59, 0x7f,
-    0x9c, 0xf1, 0xeb, 0xa2, 0x17, 0x7d, 0xc3, 0x68, 0x1e, 0x92, 0xfd, 0xcb, 0xfb, 0x3c, 0x63, 0xec, 0x5c, 0x36, 0x85, 0xd5,
-    0xf1, 0x1f, 0xcb, 0xb9, 0x1a, 0xc9, 0x2b, 0x56, 0x19, 0xff, 0x7b, 0xf5, 0xc7, 0xf2, 0xab, 0x41, 0x54, 0x65, 0xd8, 0x7f,
-    0xc6, 0x2c, 0xdd, 0xfc, 0x4a, 0x04, 0xcf, 0x29, 0xef, 0xd5, 0xc7, 0x37, 0x52, 0x53, 0xce, 0xe5, 0x81, 0xb8, 0x2b, 0xfe,
-    0xeb, 0xfa, 0xff, 0xd9, 0xfe, 0x74, 0x66, 0x0d, 0xa4, 0xd9, 0xdc, 0x89, 0x33, 0x2b, 0x89, 0x5c, 0x7d, 0x2c, 0x73, 0xa3,
-    0x82, 0x91, 0x31, 0xeb, 0x0e, 0xe7, 0x61, 0xe6, 0x1c, 0xb5, 0xc9, 0x95, 0x16, 0xce, 0x23, 0xa0, 0x0f, 0x8c, 0x4f, 0xfa,
-    0x64, 0x0d, 0x13, 0x2d, 0xd1, 0xf3, 0x73, 0x55, 0x5b, 0x2f, 0xe6, 0x3e, 0x6f, 0xd7, 0x6d, 0x7d, 0x62, 0x1c, 0x73, 0xef,
-    0xca, 0x45, 0x35, 0xf1, 0x3f, 0xde, 0xab, 0xdd, 0xbd, 0x4c, 0xdb, 0xc0, 0x38, 0x79, 0xff, 0xf8, 0x8f, 0xc6, 0x61, 0x65,
-    0x1f, 0x77, 0x36, 0x9b, 0xf4, 0x3d, 0xdb, 0xe6, 0x57, 0x26, 0xd9, 0xfd, 0xda, 0xbe, 0x3b, 0xfe, 0xd7, 0xac, 0xfe, 0x52,
-    0x7d, 0x8e, 0xce, 0x46, 0x0d, 0x55, 0xed, 0xff, 0xd9, 0x08, 0xa4, 0x6f, 0x31, 0x2e, 0x1c, 0x8b, 0xed, 0xf8, 0xfd, 0xff,
-    0xb9, 0x6b, 0x65, 0xc5, 0xb6, 0xf9, 0xeb, 0x76, 0xdf, 0x18, 0xdf, 0x25, 0xfe, 0x9f, 0x50, 0x47, 0xce, 0xb4, 0xda, 0xd1,
-    0xf6, 0xbf, 0x5d, 0x18, 0xff, 0x35, 0x77, 0x2a, 0x7a, 0xe1, 0x8a, 0x76, 0x4f, 0xbf, 0x56, 0xe6, 0xef, 0xff, 0xad, 0x78,
-    0x02, 0xb2, 0x73, 0xfb, 0x2f, 0xfe, 0x9f, 0x16, 0xff, 0xd9, 0x67, 0xfb, 0x33, 0xfd, 0x91, 0x67, 0x8e, 0xff, 0x6b, 0xef,
-    0x43, 0x3d, 0xb5, 0xff, 0xff, 0xf4, 0x32, 0x9d, 0xeb, 0xb5, 0xcb, 0x90, 0xfc, 0x4d, 0x7d, 0x83, 0xd9, 0x3b, 0x9d, 0x6f,
-    0x8b, 0xff, 0x77, 0x97, 0x69, 0xf5, 0x0a, 0xe9, 0x7c, 0x4b, 0xfc, 0xb7, 0x0b, 0xdb, 0xc4, 0xf8, 0xfb, 0x86, 0xdf, 0x17,
-    0xff, 0xab, 0xde, 0x91, 0x10, 0xff, 0xcf, 0x8c, 0xff, 0xd5, 0x65, 0x7a, 0xed, 0x7b, 0x0e, 0x35, 0xef, 0xff, 0xad, 0x5a,
-    0xf5, 0x65, 0x87, 0xe7, 0xff, 0xcf, 0x7d, 0xf7, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8,
-    0xfb, 0x3d, 0xf7, 0xd8, 0x96, 0xe3, 0xb9, 0x48, 0xb1, 0xec, 0x7b, 0xbb, 0x67, 0x63, 0x6e, 0xb2, 0x6f, 0x87, 0x4a, 0x7f,
-    0xf4, 0x7c, 0xef, 0x54, 0xbe, 0x9f, 0x4b, 0xac, 0xdf, 0x5e, 0x66, 0xb1, 0x98, 0x8a, 0x1f, 0x67, 0xc5, 0xe7, 0xe4, 0xa3,
-    0xff, 0xca, 0xac, 0xd4, 0xb2, 0x6f, 0xaf, 0xce, 0xbe, 0x1d, 0x39, 0xdf, 0xfb, 0x94, 0x6f, 0x7c, 0xbe, 0xd5, 0xb5, 0x65,
-    0xb6, 0xd7, 0x6c, 0xbe, 0xaa, 0x19, 0x86, 0x7b, 0xcd, 0x54, 0xec, 0x13, 0x19, 0xd5, 0xbb, 0xec, 0xdb, 0x8f, 0xe8, 0xe7,
-    0x56, 0xac, 0x8c, 0xf1, 0x9e, 0x98, 0xba, 0x7b, 0x86, 0xeb, 0x73, 0xb2, 0x31, 0x8f, 0xf5, 0x61, 0x72, 0xab, 0x25, 0xbd,
-    0x27, 0xfb, 0xf6, 0x4f, 0xad, 0xdd, 0xb5, 0x33, 0x6a, 0xab, 0xca, 0xf7, 0x38, 0xc7, 0xee, 0xce, 0xd9, 0x1f, 0x9e, 0x17,
-    0xff, 0xbb, 0x64, 0xa5, 0x6a, 0x27, 0x25, 0x9e, 0xbf, 0xae, 0xbe, 0x29, 0xfb, 0xee, 0x3b, 0x32, 0xa8, 0xf4, 0xad, 0xae,
-    0xcd, 0x77, 0xc7, 0x7f, 0x26, 0x1e, 0x57, 0x6c, 0xab, 0xc9, 0x0c, 0xff, 0xed, 0xd9, 0x77, 0xdf, 0x13, 0xff, 0x4d, 0xfc,
-    0xdf, 0xde, 0xff, 0xbf, 0x6e, 0xdb, 0x7c, 0xdf, 0x60, 0xc5, 0xfd, 0xff, 0xe7, 0x65, 0xdf, 0x7d, 0x53, 0xfb, 0xbf, 0x4b,
-    0xc6, 0xc4, 0x68, 0x4c, 0xf5, 0x17, 0xc4, 0xff, 0x8e, 0xed, 0xa9, 0xec, 0x9b, 0xdf, 0x11, 0xff, 0x7d, 0xc3, 0xe3, 0xea,
-    0x45, 0x75, 0xd7, 0x35, 0xd7, 0x57, 0xf4, 0x2e, 0xcb, 0x2e, 0x71, 0x51, 0x7d, 0x6f, 0x70, 0xfc, 0x09, 0xfb, 0x1b, 0xb3,
-    0x6f, 0xbe, 0x35, 0xdb, 0xe6, 0xca, 0xfd, 0x6b, 0xe1, 0xb5, 0xf8, 0xf3, 0x4f, 0x68, 0x56, 0xd5, 0xa5, 0x15, 0x2b, 0x6f,
-    0xef, 0x94, 0x8d, 0x51, 0xf6, 0xcd, 0x15, 0xcf, 0xa2, 0x9e, 0x9c, 0x6d, 0xf3, 0x3c, 0x56, 0xe3, 0xdb, 0xd6, 0xc7, 0xf4,
-    0x55, 0x75, 0xe9, 0xfb, 0x72, 0x8f, 0xca, 0xa8, 0xca, 0x33, 0xde, 0xb7, 0xc9, 0xdd, 0xe7, 0xa8, 0xbd, 0xe6, 0x45, 0x0a,
-    0xdc, 0xf5, 0x6e, 0x90, 0xb6, 0x8a, 0xdd, 0xfc, 0xe5, 0x1c, 0xe8, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xdd, 0x4b, 0x92, 0xe4, 0x26, 0x10, 0x00, 0x50, 0xce, 0xe5, 0xfb, 0xdf, 0x0b, 0x87, 0xc3, 0x0b, 0xc7, 0x8c, 0xa7, 0x05,
+    0x64, 0xa6, 0x24, 0xa8, 0x7a, 0xf3, 0x76, 0xa3, 0xee, 0xea, 0x12, 0x52, 0xf2, 0x93, 0x48, 0x7a, 0x03, 0x00, 0x00, 0x00,
+    0xbe, 0xdc, 0x3f, 0xff, 0xfe, 0xff, 0x7f, 0xed, 0x0f, 0xff, 0xfb, 0xdf, 0xcf, 0xf6, 0x3f, 0x1e, 0xbd, 0x3a, 0x12, 0xff,
+    0xcd, 0xeb, 0x6f, 0x32, 0xf7, 0x09, 0xed, 0xe2, 0xc8, 0xf8, 0x3b, 0xff, 0xfe, 0x7f, 0xbd, 0xe4, 0xaf, 0xff, 0xf4, 0x39,
+    0xa3, 0x6f, 0x14, 0x39, 0x76, 0xf5, 0xa9, 0xfd, 0xe2, 0x9c, 0xda, 0xc4, 0x91, 0x1e, 0x3a, 0xbb, 0x9e, 0xbe, 0xaa, 0x6b,
+    0x57, 0x67, 0x7c, 0xfe, 0x6d, 0xf9, 0x1c, 0xdb, 0x0d, 0xc7, 0x7a, 0xf2, 0x1a, 0xdf, 0x19, 0xff, 0xbf, 0xff, 0xab, 0x8c,
+    0xff, 0xeb, 0xcf, 0xcc, 0xdc, 0x13, 0xff, 0x9d, 0x4d, 0x2f, 0x88, 0xff, 0xf5, 0x5a, 0xe4, 0xfa, 0x0c, 0x7e, 0xbe, 0x8b,
+    0xdb, 0xf2, 0xef, 0x8c, 0xeb, 0xd7, 0xca, 0x4f, 0xbd, 0xf3, 0xd8, 0x5c, 0xd4, 0xe6, 0xef, 0xf3, 0xd1, 0xb7, 0xc9, 0x5d,
+    0xc3, 0x27, 0x8f, 0xd5, 0xc6, 0xff, 0xe8, 0x67, 0xa3, 0x35, 0x7b, 0xbc, 0x77, 0x30, 0xdb, 0x9a, 0xf7, 0xa5, 0x7b, 0x7f,
+    0xdc, 0x8a, 0xd5, 0x94, 0xf0, 0xea, 0x19, 0x5f, 0xd7, 0x25, 0xa3, 0xa3, 0xf9, 0x36, 0x77, 0xe5, 0xde, 0x78, 0xe3, 0x2e,
+    0x1e, 0x5f, 0xcd, 0x8a, 0x76, 0xa9, 0xff, 0x52, 0xda, 0xe2, 0x7f, 0xf6, 0xae, 0xed, 0x37, 0xb7, 0xb4, 0x6d, 0xb9, 0xa5,
+    0x8d, 0xf5, 0x59, 0xea, 0x4a, 0xb8, 0x2a, 0xfe, 0x7b, 0x22, 0xfa, 0x5b, 0xa0, 0xc7, 0x79, 0x5d, 0x6b, 0x8f, 0xbe, 0x7f,
+    0xf4, 0x2e, 0xa9, 0xbd, 0x67, 0xb3, 0xf1, 0x7f, 0xdd, 0x1f, 0x6e, 0x97, 0xf5, 0xcd, 0x73, 0x3d, 0xae, 0x9d, 0xe2, 0x3f,
+    0xda, 0x43, 0x9e, 0x1f, 0xdd, 0xd4, 0xb5, 0xff, 0xf7, 0xc7, 0xff, 0x28, 0x22, 0xfb, 0xe2, 0x48, 0xb5, 0xb6, 0x35, 0x9e,
+    0x19, 0x4f, 0x47, 0x6b, 0xf4, 0xf5, 0x31, 0xee, 0xf3, 0xfd, 0xff, 0xf1, 0xb8, 0xb1, 0xdf, 0x36, 0x72, 0xaa, 0x8f, 0xb0,
+    0x7d, 0xfb, 0xff, 0x73, 0xfd, 0x82, 0x7b, 0xfa, 0xff, 0xa3, 0xf1, 0x7f, 0x7b, 0xbc, 0xf5, 0x1f, 0x45, 0x56, 0xfc, 0xea,
+    0xf7, 0x50, 0x0f, 0x28, 0x37, 0xab, 0x10, 0xbb, 0x9e, 0xb9, 0xf8, 0xbf, 0xa3, 0x0f, 0xb0, 0x3a, 0xfa, 0xfb, 0x8c, 0xfe,
+    0x7f, 0xa4, 0x04, 0xa3, 0xf3, 0xcc, 0x55, 0x67, 0xb6, 0x3e, 0xcf, 0xff, 0x5e, 0x89, 0xd5, 0xd5, 0xf3, 0xd9, 0x12, 0xac,
+    0xff, 0xd4, 0x58, 0xaf, 0x7a, 0xf5, 0x2e, 0xee, 0xaf, 0x3e, 0x1b, 0xeb, 0x47, 0xcc, 0x9c, 0x3e, 0xd1, 0xfe, 0x8f, 0xe6,
+    0xff, 0x33, 0xb3, 0x03, 0x6b, 0x4f, 0x36, 0xfa, 0x86, 0xf7, 0x8a, 0xf8, 0x3f, 0xa5, 0x15, 0xab, 0xea, 0x55, 0x9b, 0xff,
+    0x8b, 0x3c, 0xd3, 0xae, 0xe8, 0xcf, 0x9d, 0x12, 0xff, 0x7d, 0xa2, 0x36, 0x9d, 0x3f, 0x12, 0x7f, 0xe2, 0x7e, 0xd7, 0x5b,
+    0x05, 0xa3, 0xa7, 0x8d, 0xcf, 0x3d, 0xc5, 0xde, 0x31, 0xfe, 0xcf, 0x78, 0xfe, 0xbf, 0x47, 0x59, 0xde, 0x3b, 0x92, 0xdb,
+    0x31, 0xfe, 0xe1, 0x3b, 0xde, 0x26, 0x7c, 0xee, 0xad, 0x45, 0xf1, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xc0, 0xe9, 0xab, 0x73, 0xe2, 0x19, 0x22, 0xd7, 0xd6, 0xdc, 0xf4, 0x5b, 0xf2, 0x22, 0xc5, 0xd6, 0x46,
+    0x3f, 0x9b, 0xc3, 0x39, 0x9a, 0x35, 0x3b, 0xb7, 0x2e, 0xfc, 0xe7, 0x7c, 0x42, 0x99, 0xcf, 0xbd, 0x5e, 0x8b, 0xbc, 0xb2,
+    0x2e, 0x3b, 0x9a, 0xeb, 0x7c, 0x35, 0x27, 0x50, 0x24, 0x77, 0x52, 0x36, 0x77, 0xfa, 0xfa, 0x19, 0x47, 0x56, 0xb0, 0x66,
+    0xd7, 0xbc, 0x3d, 0x95, 0xb1, 0x39, 0x1a, 0xa7, 0x73, 0x59, 0x6f, 0xfb, 0x72, 0xa6, 0xba, 0xdd, 0xf2, 0x34, 0x54, 0x67,
+    0xcd, 0xb8, 0x33, 0xfe, 0xdb, 0x54, 0x6e, 0xec, 0xb9, 0xf5, 0xce, 0xbd, 0x70, 0x45, 0xfb, 0x73, 0x39, 0xf7, 0x5a, 0xfa,
+    0x9a, 0xac, 0xb6, 0x54, 0x9f, 0x1f, 0xff, 0xd1, 0x73, 0x1f, 0x95, 0x6a, 0xdf, 0x36, 0x8b, 0xfd, 0x9b, 0xf1, 0x1f, 0xed,
+    0xdb, 0x5d, 0xb7, 0x7c, 0xeb, 0x19, 0x0f, 0x9e, 0xc9, 0x68, 0xd3, 0x37, 0x8a, 0xff, 0xf5, 0xbf, 0x76, 0xe7, 0x1a, 0xf6,
+    0x5c, 0xdb, 0xdb, 0xcb, 0xe2, 0x3f, 0xde, 0xf7, 0xd9, 0xad, 0x8d, 0xaf, 0xcd, 0x9a, 0x73, 0x5f, 0xfc, 0xb7, 0xf2, 0xac,
+    0x4c, 0x7b, 0xc6, 0xff, 0x4c, 0xfb, 0x10, 0x19, 0x1b, 0xac, 0xff, 0x66, 0xb4, 0xc6, 0x5d, 0xfd, 0x6b, 0x91, 0xf6, 0xff,
+    0xfa, 0x2c, 0x4f, 0x6e, 0xff, 0x77, 0x89, 0xff, 0xb6, 0x55, 0xff, 0x3f, 0x7b, 0x37, 0xae, 0xc5, 0xf9, 0x7b, 0xb9, 0xd9,
+    0x76, 0xdf, 0xc9, 0x68, 0xa5, 0xc4, 0xb3, 0xd9, 0x91, 0xa3, 0xf3, 0x0e, 0x95, 0x3b, 0x36, 0x9d, 0x35, 0xc7, 0xd5, 0xbe,
+    0x72, 0xfc, 0x1f, 0x9f, 0xf7, 0x15, 0xff, 0xd9, 0xfe, 0x74, 0x7b, 0x21, 0xfe, 0xef, 0x2a, 0xbb, 0x93, 0xe3, 0x3f, 0xd3,
+    0xf3, 0x7b, 0x2a, 0xfe, 0xdb, 0x8f, 0xbb, 0x50, 0x65, 0xe3, 0x3f, 0xbe, 0x37, 0xce, 0x6a, 0x9c, 0xf7, 0x17, 0x9f, 0x6f,
+    0xdd, 0x51, 0x07, 0xc6, 0x9f, 0x37, 0x34, 0xf1, 0x7f, 0x54, 0xfc, 0xbf, 0xdf, 0xfe, 0xcf, 0xee, 0xad, 0xf8, 0xdd, 0xf1,
+    0xdf, 0x52, 0x73, 0x7c, 0x77, 0xfc, 0xde, 0x6e, 0xfd, 0xff, 0xea, 0xba, 0xf3, 0xd9, 0xfa, 0xf4, 0xbe, 0x3e, 0x6e, 0x6c,
+    0x3e, 0x29, 0xb6, 0x9b, 0x41, 0x2c, 0x6b, 0xf6, 0x3d, 0xf7, 0x54, 0x0b, 0xef, 0xe1, 0xd5, 0x96, 0x6b, 0x00, 0xf1, 0xff,
+    0xeb, 0x91, 0xfb, 0x76, 0x47, 0x86, 0xbb, 0xe3, 0xe9, 0xac, 0xf8, 0xcf, 0xbd, 0x69, 0x50, 0xbf, 0xdb, 0x60, 0x7f, 0xa1,
+    0xfd, 0x87, 0x7b, 0x9f, 0xb2, 0xd7, 0xfd, 0x3c, 0x15, 0x7d, 0x7a, 0xe0, 0x7b, 0xfb, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x27, 0xae, 0x15, 0xf8, 0x79, 0x95, 0xe7, 0x75, 0x16, 0x8c, 0x16, 0xcc, 0x82, 0xdd,
+    0x26, 0x32, 0x27, 0xf7, 0xe0, 0xdf, 0x5b, 0x59, 0xa5, 0xbc, 0x5b, 0x2e, 0x82, 0xd5, 0xfc, 0x88, 0x2b, 0xb9, 0xb1, 0xdb,
+    0x72, 0x9e, 0xaf, 0x68, 0x16, 0x9b, 0x96, 0xcc, 0x39, 0x1a, 0x5f, 0x7f, 0x17, 0x5d, 0x41, 0x9d, 0xc9, 0xe8, 0xd8, 0xa7,
+    0x56, 0xf4, 0x65, 0x4b, 0x3d, 0xbf, 0xd2, 0x27, 0x12, 0xff, 0x3b, 0x66, 0xdd, 0xab, 0xca, 0xf2, 0x71, 0x52, 0xbe, 0xed,
+    0x95, 0x3c, 0xbc, 0xe3, 0x7c, 0x1e, 0xf9, 0xf8, 0x9f, 0xcd, 0x29, 0xd0, 0x93, 0x59, 0x3f, 0x57, 0xeb, 0x8a, 0xeb, 0x72,
+    0xb9, 0x5a, 0x9b, 0xdc, 0xa7, 0xb2, 0x9d, 0xf6, 0xd0, 0xfa, 0x9c, 0x48, 0xed, 0x5a, 0xbf, 0xda, 0xe7, 0x3b, 0xe2, 0x7f,
+    0xbd, 0x46, 0x3d, 0x21, 0xdf, 0x76, 0x2b, 0xf8, 0xdf, 0xca, 0x95, 0xef, 0xd1, 0x9c, 0x22, 0xd1, 0xf8, 0x5f, 0x89, 0xb5,
+    0x9f, 0x6b, 0xb9, 0x36, 0x91, 0x41, 0x6d, 0xfd, 0x73, 0x23, 0xf1, 0xdf, 0x97, 0xb3, 0xab, 0x54, 0xb5, 0xff, 0x6b, 0xad,
+    0xcb, 0x9e, 0xf1, 0x1f, 0xe9, 0x71, 0xf6, 0x07, 0xe3, 0x3f, 0x97, 0xe3, 0xab, 0x3d, 0x1e, 0xff, 0xb5, 0xfb, 0x54, 0xcc,
+    0x8d, 0x64, 0x66, 0xef, 0xe7, 0xf9, 0x9f, 0xed, 0x83, 0x96, 0x3a, 0x13, 0xff, 0xfd, 0x0f, 0x7f, 0xe1, 0xae, 0xf6, 0xff,
+    0xae, 0x0c, 0xaa, 0xfd, 0xe2, 0xfb, 0x7f, 0x42, 0xfc, 0xb7, 0x4d, 0xfa, 0xff, 0xf5, 0x7b, 0xa9, 0xed, 0x19, 0xff, 0xeb,
+    0x3d, 0xae, 0xf5, 0xd6, 0x6c, 0xad, 0xaf, 0x30, 0x1e, 0x01, 0xf4, 0x40, 0x0d, 0xd0, 0x7f, 0xdb, 0x7f, 0xaa, 0xaa, 0xd7,
+    0xbd, 0xb6, 0x73, 0x58, 0x4d, 0xfb, 0xdf, 0x3f, 0xb6, 0xfd, 0xaf, 0x1d, 0xff, 0xdf, 0x95, 0x8b, 0xb0, 0x76, 0xbf, 0xad,
+    0xaa, 0x5c, 0x9b, 0xb1, 0xbe, 0x56, 0xb4, 0xfd, 0x1f, 0xf5, 0x0e, 0x32, 0xf1, 0xdf, 0x92, 0x71, 0xda, 0x7f, 0x9c, 0x75,
+    0x8e, 0xb5, 0xff, 0xbb, 0xcd, 0xff, 0xf7, 0x40, 0x84, 0xdc, 0x95, 0x75, 0xb3, 0x2f, 0xcf, 0xc5, 0x64, 0xb3, 0xaa, 0xcd,
+    0x3f, 0x69, 0x98, 0xa9, 0xb9, 0x7f, 0x7e, 0x4a, 0x31, 0x53, 0x2a, 0x15, 0x63, 0xc2, 0x5d, 0xfb, 0xff, 0xef, 0xb4, 0xff,
+    0x33, 0xad, 0x7f, 0x34, 0x07, 0x60, 0x75, 0xbe, 0x9d, 0x9e, 0xf8, 0x36, 0xd9, 0xf9, 0xbf, 0xf7, 0xf3, 0x08, 0x56, 0xcf,
+    0xfc, 0x3c, 0xf9, 0x59, 0x6f, 0x7d, 0xa3, 0x1d, 0xfb, 0xff, 0xf1, 0xb1, 0xd5, 0xca, 0xa8, 0xbe, 0xee, 0xf9, 0xdf, 0x3d,
+    0x73, 0xa1, 0xa7, 0x3d, 0xff, 0x17, 0xff, 0x7b, 0x5e, 0x83, 0xbd, 0xe2, 0x7f, 0x76, 0x17, 0xf3, 0x5e, 0xfe, 0x24, 0xfe,
+    0x8c, 0x1a, 0xfc, 0xb3, 0xe2, 0xbf, 0xbd, 0xd2, 0x13, 0x79, 0xee, 0x8a, 0xef, 0x55, 0x03, 0x54, 0xed, 0x78, 0x5d, 0xf5,
+    0xa4, 0x28, 0xf2, 0x14, 0x6f, 0xf7, 0xfa, 0x12, 0x3e, 0xff, 0xfd, 0xcd, 0xfe, 0xf1, 0xfd, 0xa6, 0x4f, 0xe8, 0x79, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xad, 0xff, 0xeb, 0xc9, 0xb5, 0x81, 0xb1, 0xcc,
+    0x42, 0x6d, 0xb8, 0xc2, 0xb4, 0x87, 0x7f, 0x66, 0xe5, 0x5c, 0xe2, 0x39, 0x2b, 0x22, 0x39, 0xb7, 0xdb, 0x20, 0x4f, 0x4d,
+    0x4d, 0xd9, 0x3c, 0x73, 0x9e, 0xe3, 0xdc, 0x7a, 0x6b, 0xf7, 0xc5, 0x4a, 0x49, 0x8d, 0x73, 0xa6, 0x3c, 0x57, 0x0e, 0xd1,
+    0xeb, 0xdd, 0x07, 0xab, 0xb9, 0xfb, 0x65, 0xa6, 0x9a, 0x8a, 0x5c, 0x2a, 0xa3, 0xcf, 0x8f, 0x67, 0xde, 0x6b, 0xa1, 0x8c,
+    0x6b, 0x7d, 0x3a, 0x63, 0xc1, 0xea, 0x0a, 0xd1, 0x68, 0xd6, 0xba, 0xc8, 0xbd, 0x9f, 0xc9, 0x46, 0x35, 0x8a, 0xa7, 0x4c,
+    0x86, 0xed, 0xfa, 0xf3, 0x5c, 0xbf, 0x2f, 0x7a, 0xd1, 0x5f, 0x98, 0xcd, 0x43, 0xb2, 0xff, 0xf5, 0x1e, 0x67, 0x8c, 0xcd,
+    0x65, 0x53, 0xb8, 0x3b, 0xfe, 0xd7, 0x72, 0xae, 0xae, 0xe4, 0x15, 0xab, 0x8c, 0xff, 0xbd, 0xfa, 0x63, 0xf1, 0xdd, 0x21,
+    0xaa, 0x32, 0xec, 0x9f, 0xb1, 0x4a, 0x37, 0xbe, 0x13, 0xc1, 0x39, 0xd7, 0xfb, 0xee, 0xf3, 0x9b, 0xa9, 0x29, 0x73, 0x79,
+    0x20, 0xde, 0x8a, 0xff, 0xba, 0xfe, 0x7f, 0x66, 0xff, 0x97, 0xb5, 0x63, 0xf9, 0xdc, 0x89, 0x99, 0x9d, 0x44, 0x9e, 0x3e,
+    0x97, 0xdc, 0xa8, 0x60, 0x66, 0xcc, 0xba, 0x43, 0x39, 0x64, 0xca, 0xa8, 0x25, 0x77, 0x5a, 0x18, 0x47, 0x40, 0x9f, 0x18,
+    0x9f, 0x64, 0x33, 0x8c, 0xaf, 0x5e, 0xd1, 0x71, 0x59, 0xd5, 0xd6, 0x8b, 0xb1, 0xcf, 0xdb, 0xf5, 0x58, 0x4f, 0x8c, 0x63,
+    0xde, 0xdd, 0xb9, 0xa8, 0x26, 0xfe, 0xe7, 0x7b, 0xb5, 0xbb, 0x5f, 0xd3, 0x36, 0x31, 0x4e, 0xde, 0x3f, 0xfe, 0x57, 0xe3,
+    0xb0, 0xb2, 0x8f, 0x9b, 0xcd, 0x26, 0xfd, 0xce, 0xb1, 0xfc, 0xce, 0x24, 0xbb, 0xdf, 0xdb, 0x6f, 0xc7, 0xff, 0x3d, 0xbb,
+    0xbf, 0x54, 0x97, 0xd1, 0x68, 0xd4, 0x50, 0xd5, 0xfe, 0x8f, 0x46, 0x20, 0x7d, 0x8b, 0x71, 0xe1, 0x5c, 0x6c, 0xaf, 0xcf,
+    0xff, 0xe7, 0xee, 0x95, 0x3b, 0x8e, 0xe5, 0xef, 0xdb, 0x7d, 0x63, 0x7c, 0x97, 0xf8, 0x3f, 0xa1, 0x8e, 0xcc, 0xb4, 0xda,
+    0xab, 0xed, 0x7f, 0x7b, 0x30, 0xfe, 0x6b, 0x66, 0x2a, 0x7a, 0xe1, 0x8e, 0x76, 0xa7, 0xdf, 0x2b, 0xf9, 0xf9, 0xbf, 0x3b,
+    0x9e, 0x80, 0xec, 0xdc, 0xfe, 0x8b, 0xff, 0xd3, 0xe2, 0x3f, 0xfa, 0x6c, 0x3f, 0xd3, 0x1f, 0x39, 0x73, 0xfc, 0x5f, 0x3b,
+    0x0f, 0x75, 0x6a, 0xff, 0xff, 0xf4, 0x6b, 0x9a, 0xeb, 0xb5, 0xcb, 0x90, 0xfc, 0x4d, 0x7d, 0x83, 0xec, 0x4c, 0xe7, 0xa7,
+    0xc5, 0xff, 0x67, 0x5f, 0xd3, 0xea, 0x1d, 0xd2, 0xf9, 0x96, 0xf8, 0x6f, 0x0f, 0xb6, 0x89, 0xeb, 0xef, 0x1b, 0x7e, 0x5f,
+    0xfc, 0xdf, 0xf5, 0x8e, 0x84, 0xf8, 0x3f, 0x33, 0xfe, 0xef, 0xbe, 0xa6, 0xcf, 0xbe, 0xe7, 0x50, 0xf3, 0xfe, 0xdf, 0x5d,
+    0xbb, 0xbe, 0xec, 0xf0, 0xfc, 0xff, 0xdc, 0x77, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0xb7, 0xdf, 0x73, 0x5f, 0x3b, 0x72, 0xbd, 0x16, 0x69, 0xf4, 0xae, 0x79, 0x6c, 0x35, 0xb2, 0x6c, 0xdb, 0x7b, 0x65, 0xdb,
+    0x3e, 0x25, 0x9b, 0xf6, 0xaf, 0x57, 0xa4, 0xbf, 0x7e, 0x4d, 0x5a, 0xe2, 0x3c, 0x9e, 0x8c, 0xfe, 0xe8, 0xf7, 0x18, 0x95,
+    0x56, 0x3f, 0x22, 0xfb, 0xb2, 0x6c, 0xdb, 0x2b, 0xeb, 0x69, 0x76, 0xbf, 0x9e, 0x3d, 0x1c, 0xc7, 0x4f, 0xc7, 0xc8, 0xd9,
+    0x2b, 0xe3, 0xce, 0x59, 0x99, 0xd8, 0x13, 0x19, 0xd4, 0xbb, 0x6c, 0xdb, 0x5b, 0xde, 0x95, 0xf9, 0x9c, 0x38, 0xdf, 0x14,
+    0x23, 0xe7, 0xac, 0x86, 0x7e, 0x3a, 0xfb, 0xf2, 0xb8, 0xd4, 0xe2, 0xbb, 0x23, 0x7d, 0x52, 0xb6, 0xed, 0xf6, 0xf0, 0x8a,
+    0xd9, 0x5c, 0x19, 0x7c, 0x72, 0x56, 0xa0, 0x73, 0xe2, 0x7f, 0x97, 0x2c, 0x54, 0x6d, 0x70, 0x47, 0xc4, 0xeb, 0x8d, 0x6f,
+    0xc9, 0xb6, 0x7b, 0x56, 0xc6, 0xe1, 0x7d, 0xee, 0xbd, 0xef, 0x8e, 0xff, 0xd8, 0xec, 0x60, 0xfd, 0xb1, 0x9a, 0x4c, 0xf0,
+    0xdf, 0x9c, 0x6d, 0xf7, 0xbc, 0x8c, 0xe3, 0xe2, 0x7f, 0xf7, 0x6b, 0xf4, 0xd4, 0xb1, 0x7c, 0xdf, 0xe0, 0x8e, 0xf9, 0xff,
+    0xb3, 0xb2, 0xed, 0x9e, 0xd6, 0xfe, 0xef, 0x92, 0x01, 0x31, 0xba, 0x43, 0xc9, 0x27, 0xc7, 0xff, 0x39, 0x75, 0x51, 0x6e,
+    0xc6, 0x4c, 0xff, 0xff, 0xbd, 0xdd, 0x74, 0x76, 0x8a, 0x83, 0x1e, 0xac, 0xab, 0x76, 0x8f, 0xff, 0xb9, 0x9d, 0xea, 0x76,
+    0x89, 0x8b, 0xea, 0xb9, 0xc1, 0x77, 0x62, 0xe6, 0xad, 0x6c, 0x9b, 0x9f, 0x92, 0x4d, 0xf3, 0xee, 0x39, 0x87, 0x48, 0x8c,
+    0x9f, 0x1b, 0xff, 0xd1, 0x37, 0x42, 0xf6, 0xc9, 0xbe, 0x28, 0xdb, 0x66, 0x45, 0x39, 0x9d, 0x94, 0x4d, 0x73, 0x1c, 0xab,
+    0xeb, 0xc7, 0x72, 0x57, 0x66, 0xe7, 0xf8, 0xcf, 0x3d, 0x3b, 0x3f, 0xe5, 0x0d, 0x07, 0x19, 0x54, 0xd9, 0x2d, 0xee, 0x9e,
+    0x7e, 0x67, 0xa2, 0x7f, 0xdd, 0xbb, 0x4d, 0xf0, 0xee, 0xbb, 0x41, 0xda, 0x1e, 0x4e, 0xf3, 0x97, 0x32, 0xd0, 0xbf, 0x04,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfa, 0xef, 0xc7,
-    0x79, 0x00, 0xf1, 0x0f, 0x7c, 0x5d, 0xfc, 0xff, 0x0d };
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xa6, 0xfc, 0xfb, 0x4f, 0x39, 0x80, 0xf8, 0x07, 0xbe, 0x2e, 0xfe, 0xff, 0x06 };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle candyFontRecs[189] = {
+static const Rectangle candyFontRecs[184] = {
     { 4, 4, 3 , 15 },
     { 15, 4, 2 , 9 },
     { 25, 4, 3 , 2 },
@@ -255,14 +254,13 @@
     { 372, 50, 8 , 8 },
     { 388, 50, 5 , 7 },
     { 401, 50, 7 , 6 },
-    { 416, 50, 0 , 0 },
-    { 424, 50, 8 , 8 },
-    { 440, 50, 6 , 1 },
-    { 454, 50, 4 , 5 },
-    { 466, 50, 6 , 7 },
-    { 480, 50, 3 , 5 },
-    { 491, 50, 3 , 5 },
-    { 502, 50, 0 , 0 },
+    { 416, 50, 8 , 8 },
+    { 432, 50, 6 , 1 },
+    { 446, 50, 4 , 5 },
+    { 458, 50, 6 , 7 },
+    { 472, 50, 3 , 5 },
+    { 483, 50, 3 , 5 },
+    { 494, 50, 0 , 0 },
     { 4, 73, 6 , 9 },
     { 18, 73, 6 , 9 },
     { 32, 73, 4 , 4 },
@@ -304,45 +302,41 @@
     { 18, 96, 6 , 12 },
     { 32, 96, 6 , 11 },
     { 46, 96, 6 , 12 },
-    { 60, 96, 0 , 0 },
-    { 68, 96, 6 , 10 },
-    { 82, 96, 6 , 10 },
-    { 96, 96, 6 , 10 },
-    { 110, 96, 6 , 10 },
-    { 124, 96, 6 , 10 },
-    { 138, 96, 6 , 9 },
-    { 152, 96, 6 , 11 },
-    { 166, 96, 10 , 7 },
-    { 184, 96, 6 , 10 },
-    { 198, 96, 6 , 10 },
-    { 212, 96, 6 , 10 },
-    { 226, 96, 6 , 10 },
-    { 240, 96, 6 , 9 },
-    { 254, 96, 3 , 10 },
-    { 265, 96, 3 , 10 },
-    { 276, 96, 4 , 10 },
-    { 288, 96, 4 , 9 },
-    { 300, 96, 0 , 0 },
-    { 308, 96, 6 , 13 },
-    { 322, 96, 6 , 10 },
-    { 336, 96, 6 , 10 },
-    { 350, 96, 6 , 10 },
-    { 364, 96, 6 , 10 },
-    { 378, 96, 6 , 9 },
-    { 392, 96, 0 , 0 },
-    { 400, 96, 8 , 8 },
-    { 416, 96, 6 , 10 },
-    { 430, 96, 6 , 10 },
-    { 444, 96, 6 , 10 },
-    { 458, 96, 6 , 9 },
-    { 472, 96, 6 , 13 },
-    { 486, 96, 0 , 0 },
-    { 494, 96, 6 , 12 },
+    { 60, 96, 6 , 10 },
+    { 74, 96, 6 , 10 },
+    { 88, 96, 6 , 10 },
+    { 102, 96, 6 , 10 },
+    { 116, 96, 6 , 10 },
+    { 130, 96, 6 , 9 },
+    { 144, 96, 6 , 11 },
+    { 158, 96, 10 , 7 },
+    { 176, 96, 6 , 10 },
+    { 190, 96, 6 , 10 },
+    { 204, 96, 6 , 10 },
+    { 218, 96, 6 , 10 },
+    { 232, 96, 6 , 9 },
+    { 246, 96, 3 , 10 },
+    { 257, 96, 3 , 10 },
+    { 268, 96, 4 , 10 },
+    { 280, 96, 4 , 9 },
+    { 292, 96, 6 , 13 },
+    { 306, 96, 6 , 10 },
+    { 320, 96, 6 , 10 },
+    { 334, 96, 6 , 10 },
+    { 348, 96, 6 , 10 },
+    { 362, 96, 6 , 9 },
+    { 376, 96, 8 , 8 },
+    { 392, 96, 6 , 10 },
+    { 406, 96, 6 , 10 },
+    { 420, 96, 6 , 10 },
+    { 434, 96, 6 , 9 },
+    { 448, 96, 6 , 13 },
+    { 462, 96, 6 , 12 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo candyFontGlyphs[189] = {
+static const GlyphInfo candyFontGlyphs[184] = {
     { 32, 0, 0, 3, { 0 }},
     { 33, 0, 3, 3, { 0 }},
     { 34, 0, 2, 4, { 0 }},
@@ -449,7 +443,6 @@
     { 169, 0, 0, 9, { 0 }},
     { 170, 0, 0, 6, { 0 }},
     { 171, 1, 5, 9, { 0 }},
-    { 172, 0, 0, 0, { 0 }},
     { 174, 0, 0, 9, { 0 }},
     { 175, 0, 0, 7, { 0 }},
     { 176, 0, 0, 5, { 0 }},
@@ -498,7 +491,6 @@
     { 219, 0, 0, 7, { 0 }},
     { 220, 0, 1, 7, { 0 }},
     { 221, 0, 0, 7, { 0 }},
-    { 222, 0, 0, 0, { 0 }},
     { 223, 0, 3, 7, { 0 }},
     { 224, 0, 2, 7, { 0 }},
     { 225, 0, 2, 7, { 0 }},
@@ -516,21 +508,18 @@
     { 237, 0, 2, 4, { 0 }},
     { 238, 0, 2, 4, { 0 }},
     { 239, 0, 3, 4, { 0 }},
-    { 240, 0, 0, 0, { 0 }},
     { 241, 0, 2, 7, { 0 }},
     { 242, 0, 2, 7, { 0 }},
     { 243, 0, 2, 7, { 0 }},
     { 244, 0, 2, 7, { 0 }},
     { 245, 0, 2, 7, { 0 }},
     { 246, 0, 3, 7, { 0 }},
-    { 247, 0, 0, 0, { 0 }},
     { 248, 0, 5, 9, { 0 }},
     { 249, 0, 2, 7, { 0 }},
     { 250, 0, 2, 7, { 0 }},
     { 251, 0, 2, 7, { 0 }},
     { 252, 0, 3, 7, { 0 }},
     { 253, 0, 2, 7, { 0 }},
-    { 254, 0, 0, 0, { 0 }},
     { 255, 0, 3, 7, { 0 }},
 };
 
@@ -552,29 +541,40 @@
 
     Font font = { 0 };
     font.baseSize = 15;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 184;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, candyFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, candyFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "v5easter.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/cherry/style_cherry.h b/raygui/styles/cherry/style_cherry.h
--- a/raygui/styles/cherry/style_cherry.h
+++ b/raygui/styles/cherry/style_cherry.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,23 +15,23 @@
 
 // Custom style name: Cherry
 static const GuiStyleProp cherryStyleProps[CHERRY_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0xda5757ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x753233ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xe17373ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xfaaa97ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xe06262ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xfdb4aaff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xe03c46ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0x5b1e20ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xc2474fff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0xa19292ff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x706060ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x9e8585ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0xda5757ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x753233ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xe17373ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xfaaa97ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xe06262ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xfdb4aaff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xe03c46ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x5b1e20ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xc2474fff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0xa19292ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x706060ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x9e8585ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x0000000f },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0xfb8170ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x3a1720ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000016 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000007 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "Westington.ttf" (size: 15, spacing: 0)
@@ -589,27 +589,38 @@
     font.baseSize = 15;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, cherryFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, cherryFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "Westington.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/cyber/style_cyber.h b/raygui/styles/cyber/style_cyber.h
--- a/raygui/styles/cyber/style_cyber.h
+++ b/raygui/styles/cyber/style_cyber.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,150 +15,149 @@
 
 // Custom style name: Cyber
 static const GuiStyleProp cyberStyleProps[CYBER_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x2f7486ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x024658ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x51bfd3ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0x82cde0ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x3299b4ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xb6e1eaff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xeb7630ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xffbc51ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xd86f36ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x134b5aff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x02313dff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x17505fff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x2f7486ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x024658ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x51bfd3ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x82cde0ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x3299b4ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xb6e1eaff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xeb7630ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xffbc51ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xd86f36ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x134b5aff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x02313dff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x17505fff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x0000000e },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x81c0d0ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x00222bff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000015 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000007 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "Kyrou7Wide.ttf" (size: 14, spacing: 0)
 
-#define CYBER_STYLE_FONT_ATLAS_COMP_SIZE 2306
+#define CYBER_STYLE_FONT_ATLAS_COMP_SIZE 2297
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char cyberFontData[CYBER_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0xdd, 0x72, 0xe3, 0x36, 0x12, 0x06, 0x50, 0x96, 0x6b, 0xdf, 0xff, 0x85, 0x1d, 0xec, 0xb7, 0xb5, 0x93, 0x4c, 0xe2,
-    0xa9, 0x8c, 0x88, 0x7f, 0x8a, 0x92, 0xcf, 0x9c, 0xaa, 0xb9, 0x30, 0x2d, 0x89, 0x04, 0xd1, 0x40, 0x93, 0x34, 0x5a, 0x39,
-    0x00, 0x00, 0x00, 0x00, 0x16, 0xcb, 0xc5, 0x9f, 0x96, 0xe6, 0x9f, 0xae, 0x3b, 0xa2, 0x9f, 0xff, 0x9e, 0x7b, 0xec, 0xfa,
-    0x57, 0x7f, 0xbb, 0xe7, 0xe1, 0xb9, 0xd3, 0x9e, 0x5f, 0x7f, 0x92, 0xd3, 0xdf, 0xcd, 0x50, 0xeb, 0xa6, 0x7a, 0xc6, 0xce,
-    0xcf, 0x4c, 0x5f, 0xbc, 0x3d, 0xde, 0x87, 0x74, 0xbf, 0x62, 0xe7, 0xc8, 0xf8, 0xf3, 0x5f, 0xe9, 0xea, 0xef, 0xe7, 0xbd,
-    0xb8, 0xad, 0x97, 0xa7, 0xb2, 0x47, 0x69, 0xf8, 0x8d, 0xda, 0xeb, 0x8f, 0x89, 0xbd, 0x2f, 0x97, 0xce, 0x45, 0xa9, 0x8e,
-    0x19, 0xc7, 0x86, 0xa3, 0xc9, 0xe4, 0xb9, 0xcc, 0xf4, 0x88, 0xd6, 0x1e, 0xff, 0xb5, 0x7e, 0x91, 0x7f, 0xfd, 0x7f, 0x0c,
-    0x45, 0x5a, 0x36, 0xc6, 0xff, 0xd1, 0x35, 0xbe, 0xec, 0xcf, 0x8b, 0xd2, 0x10, 0xe9, 0xfd, 0xaf, 0x69, 0x3d, 0xda, 0xb1,
-    0x11, 0x2f, 0xcd, 0xbf, 0x9b, 0xa1, 0x23, 0x5e, 0x75, 0x46, 0x7a, 0x47, 0xce, 0x5a, 0x6b, 0xec, 0x38, 0x9a, 0xaf, 0x3f,
-    0xfb, 0x9c, 0x7c, 0x7d, 0xd9, 0x3e, 0x46, 0x96, 0x86, 0x96, 0x2a, 0xc3, 0x9f, 0x98, 0x81, 0x6c, 0x6e, 0xd5, 0xd9, 0xdf,
-    0x9d, 0x17, 0x66, 0x38, 0x96, 0x32, 0x75, 0xf6, 0xce, 0x3f, 0x77, 0x74, 0xfe, 0xde, 0x3b, 0xe2, 0xf5, 0xe7, 0xfa, 0x59,
-    0x34, 0x9a, 0x8f, 0x8d, 0x66, 0x3f, 0x5b, 0x2a, 0x1b, 0xe2, 0x77, 0xdd, 0x58, 0xbc, 0x32, 0x47, 0x9a, 0xc9, 0x3b, 0xcf,
-    0xb6, 0x7d, 0xfe, 0xd0, 0xbe, 0x57, 0xaf, 0x32, 0xff, 0x67, 0xe2, 0xfc, 0x65, 0xa8, 0x9d, 0x6b, 0x39, 0x65, 0xeb, 0x11,
-    0x9f, 0x7f, 0x7a, 0x19, 0x38, 0xe6, 0x8f, 0x94, 0xbf, 0x1d, 0x4b, 0x72, 0xda, 0x2c, 0x3c, 0x97, 0xe9, 0xbe, 0x56, 0xfa,
-    0x33, 0x6e, 0xc7, 0x73, 0xe6, 0xe4, 0xbf, 0x3f, 0x94, 0xcd, 0xb9, 0xd8, 0x15, 0xf1, 0xff, 0xcf, 0x28, 0x96, 0x89, 0x88,
-    0xcd, 0xe4, 0x0c, 0xb3, 0xf6, 0xfa, 0x7f, 0x5e, 0x99, 0x3a, 0x7f, 0x59, 0x7e, 0x55, 0xfb, 0x4f, 0xf4, 0x66, 0x28, 0x7f,
-    0xc8, 0xb2, 0x51, 0xb6, 0x6c, 0xbc, 0x97, 0x9c, 0x4d, 0x59, 0xda, 0xa3, 0xf9, 0xff, 0xba, 0x6c, 0x67, 0xcf, 0xd5, 0x52,
-    0xcf, 0xbd, 0xd3, 0xd1, 0xeb, 0xff, 0x34, 0x8e, 0x2e, 0xfb, 0xe2, 0xff, 0x7a, 0x7f, 0x4c, 0x9e, 0xbf, 0x5c, 0x7c, 0x7d,
-    0xbe, 0xe6, 0x0a, 0x7d, 0x3c, 0xe3, 0xd9, 0x7b, 0xfd, 0x7f, 0xd5, 0x88, 0xb1, 0x23, 0xff, 0xcf, 0x8b, 0xe7, 0xff, 0x3d,
-    0xf7, 0xff, 0xf3, 0x26, 0xf1, 0x9f, 0xe9, 0x27, 0x52, 0x59, 0x7e, 0x7f, 0xbe, 0x2d, 0xdb, 0x9d, 0x7b, 0xbe, 0x90, 0xa9,
-    0x23, 0x5e, 0x75, 0x2f, 0x26, 0x8b, 0x7e, 0x37, 0x8d, 0xb3, 0xe2, 0xd8, 0xfd, 0xdd, 0xe7, 0xde, 0xff, 0xf7, 0xfc, 0x1f,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9e, 0xd5, 0x9d, 0xb9, 0xe0, 0x75,
-    0x23, 0xab, 0x68, 0x67, 0x56, 0xdd, 0xce, 0xac, 0xd9, 0x1d, 0x7d, 0x65, 0xbd, 0x0e, 0xd1, 0xf8, 0x3a, 0xe3, 0xf6, 0x55,
-    0xce, 0x7d, 0xeb, 0x86, 0xe7, 0xaa, 0xa3, 0xa4, 0xba, 0x8e, 0xbe, 0xad, 0x1e, 0x41, 0xbd, 0x76, 0x6b, 0xad, 0x92, 0xd5,
-    0xfe, 0xda, 0xaf, 0x3b, 0x6b, 0x53, 0x66, 0xb8, 0x05, 0x7b, 0x56, 0xbf, 0xa7, 0xab, 0x3e, 0xc1, 0xe8, 0x3a, 0xf4, 0xeb,
-    0xaa, 0x02, 0xce, 0xaf, 0x90, 0x3f, 0x7f, 0xe7, 0xb2, 0xfd, 0x28, 0xda, 0xf7, 0x38, 0x0b, 0xce, 0xd9, 0x8e, 0xf8, 0xcf,
-    0x69, 0x45, 0x80, 0x5c, 0x58, 0xdb, 0x75, 0x5f, 0x25, 0xdc, 0x7d, 0x95, 0x76, 0xea, 0xf1, 0xdf, 0x5e, 0xb3, 0x39, 0x8b,
-    0xa3, 0x35, 0xc3, 0xd1, 0xb3, 0x6a, 0x04, 0x18, 0x19, 0xb7, 0x56, 0xc4, 0xff, 0x68, 0xee, 0xf0, 0xda, 0xf1, 0x3f, 0x5a,
-    0x4f, 0x2c, 0x27, 0xe7, 0x3d, 0x8d, 0x7d, 0xfb, 0x0e, 0xdb, 0x8f, 0x9b, 0xc6, 0x7f, 0x3d, 0xa6, 0x32, 0x5d, 0xa5, 0x78,
-    0x5d, 0x7f, 0x5a, 0xa7, 0x34, 0x45, 0xe9, 0x58, 0x4d, 0xcf, 0x32, 0x3c, 0xb2, 0xec, 0xca, 0xff, 0x53, 0xb9, 0xf2, 0x48,
-    0x53, 0x2e, 0xbb, 0x76, 0x8c, 0x6d, 0x1d, 0xb5, 0x1e, 0x57, 0x14, 0xab, 0xd5, 0x2b, 0x7c, 0xfe, 0xfc, 0x3e, 0x57, 0x4f,
-    0xf9, 0x9a, 0xf8, 0x9f, 0x8f, 0xc4, 0x3c, 0x65, 0xce, 0x5a, 0x73, 0x6f, 0x22, 0x83, 0xf3, 0xd6, 0x9e, 0xd7, 0x5e, 0x31,
-    0xff, 0xe7, 0xa5, 0xe6, 0xff, 0x96, 0xeb, 0xff, 0x2c, 0xb8, 0x7a, 0x1d, 0x6b, 0xb5, 0xd2, 0x7c, 0x2e, 0x77, 0xe4, 0xff,
-    0x2d, 0x33, 0xfb, 0xfc, 0xfc, 0x3f, 0xb3, 0x35, 0xcd, 0xb3, 0xf0, 0xf5, 0xf1, 0xdf, 0x76, 0x4c, 0xb9, 0xf4, 0xb5, 0xaf,
-    0x17, 0xff, 0xb9, 0xc5, 0xfd, 0xbf, 0x6c, 0xac, 0xcd, 0x9c, 0x25, 0xa3, 0xdb, 0x9e, 0xf8, 0x6f, 0xab, 0x87, 0x3e, 0x73,
-    0xfd, 0x3f, 0x17, 0xe1, 0xf5, 0x08, 0xf8, 0x43, 0xfc, 0x2f, 0xca, 0xff, 0x57, 0xbd, 0xba, 0xff, 0x5e, 0xc9, 0xcc, 0x0c,
-    0xda, 0x7e, 0x4c, 0x59, 0x9e, 0x7f, 0xcf, 0xd6, 0xf6, 0xdd, 0x9d, 0xff, 0xaf, 0x7a, 0xfd, 0x31, 0x7c, 0xde, 0xeb, 0x5b,
-    0xe6, 0x7a, 0xe5, 0xf1, 0x84, 0x6f, 0x73, 0xd8, 0xfd, 0x7c, 0xcf, 0x77, 0x94, 0xbe, 0xdf, 0x53, 0x6c, 0x6d, 0x70, 0xef,
-    0xe7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x5e, 0x65, 0x75, 0xbf,
-    0x15, 0x53, 0x69, 0x58, 0x1f, 0xda, 0x52, 0x3f, 0xf3, 0xbc, 0xfa, 0xe6, 0xa3, 0x1a, 0x12, 0xa5, 0xa9, 0xf6, 0xe6, 0xaa,
-    0xd6, 0x6c, 0xad, 0x83, 0x30, 0x5b, 0xa7, 0x73, 0xe4, 0xdd, 0x5b, 0x5a, 0xb9, 0xbe, 0xe6, 0x31, 0x95, 0x75, 0xc0, 0xc7,
-    0xc2, 0x1e, 0x58, 0x5f, 0xf3, 0x9c, 0x89, 0x9a, 0x0b, 0x33, 0x55, 0x04, 0xb3, 0x71, 0x85, 0x69, 0x86, 0x5a, 0xa5, 0xbd,
-    0x02, 0x47, 0xeb, 0xd6, 0x2c, 0xaa, 0xf2, 0xb0, 0xbb, 0x5f, 0xaf, 0xd8, 0xda, 0x5f, 0x47, 0xe1, 0x19, 0xf1, 0x7f, 0xde,
-    0x43, 0xb2, 0xf8, 0x6c, 0xf7, 0xfd, 0xb4, 0x16, 0xfb, 0x8f, 0x6b, 0x2b, 0x7f, 0x34, 0xf6, 0x9b, 0x9e, 0xed, 0x99, 0x3e,
-    0xcb, 0x99, 0xac, 0x84, 0x50, 0x3a, 0xe7, 0x9b, 0xf6, 0xe8, 0x9f, 0xeb, 0x79, 0xfb, 0x56, 0xc0, 0xbf, 0x53, 0xfc, 0x1f,
-    0x83, 0x15, 0x0b, 0x77, 0xc7, 0xff, 0xd1, 0xb4, 0x4f, 0x59, 0x76, 0x44, 0xeb, 0xaa, 0x6f, 0x7f, 0x74, 0xe7, 0x58, 0x6b,
-    0x6a, 0x59, 0xe5, 0xc2, 0x5a, 0x0f, 0xe9, 0xe8, 0x5d, 0xa3, 0x23, 0x40, 0x06, 0xe7, 0xff, 0xfe, 0x96, 0x5e, 0x95, 0x63,
-    0xbc, 0x66, 0xfc, 0x8f, 0xb5, 0x66, 0x26, 0xce, 0xf0, 0xde, 0xf9, 0x7f, 0x65, 0xe5, 0xee, 0x91, 0xe8, 0x28, 0x0f, 0xde,
-    0xa5, 0x0c, 0xcf, 0xce, 0xe3, 0x57, 0x07, 0x47, 0xd3, 0x77, 0x32, 0x94, 0xee, 0xd7, 0xe5, 0x97, 0xf8, 0xcc, 0x96, 0x6b,
-    0xf4, 0x9c, 0xb4, 0xf0, 0x68, 0x35, 0xd2, 0xde, 0xf8, 0xcf, 0xa5, 0xf3, 0xff, 0xd1, 0xf8, 0xed, 0x19, 0xc7, 0xd0, 0xf9,
-    0x3a, 0x06, 0xdf, 0x75, 0xfc, 0x95, 0xa9, 0xf6, 0xd8, 0x3d, 0xf5, 0x68, 0x57, 0x7e, 0x43, 0x47, 0x16, 0xf4, 0xdb, 0x54,
-    0x3e, 0x21, 0x83, 0x39, 0x78, 0x6f, 0xe6, 0xdf, 0x33, 0xce, 0xa6, 0xe3, 0xce, 0x40, 0x4e, 0xc6, 0xc0, 0x6c, 0xca, 0xc1,
-    0x57, 0xce, 0x83, 0x59, 0x9a, 0xaf, 0xed, 0xbb, 0xbb, 0xb8, 0x33, 0xa3, 0xbb, 0xe6, 0xdd, 0x9e, 0xd5, 0x26, 0x57, 0xce,
-    0xff, 0xe9, 0xce, 0x76, 0x67, 0xe6, 0xff, 0x4c, 0xd7, 0xc9, 0xac, 0xe5, 0x7e, 0xc7, 0xed, 0xe6, 0xff, 0xb6, 0xd8, 0xcc,
-    0xe5, 0xf9, 0xbf, 0xf8, 0xbf, 0xfa, 0x49, 0xcb, 0xf1, 0x12, 0xf1, 0xbf, 0xf7, 0xfa, 0x7f, 0xcd, 0x08, 0x32, 0x3a, 0xcb,
-    0x1e, 0x9b, 0x9f, 0x11, 0x8c, 0xbf, 0x6a, 0x5f, 0xfc, 0x1f, 0xdf, 0xaa, 0x5a, 0xe3, 0xbb, 0xd5, 0xa6, 0x7c, 0x46, 0xfc,
-    0xb7, 0xe4, 0xff, 0x19, 0xbc, 0xff, 0xdf, 0xfe, 0x0d, 0x5b, 0xe9, 0xca, 0x59, 0xda, 0xf3, 0x8e, 0xf7, 0xec, 0x11, 0xbc,
-    0xf3, 0x88, 0x36, 0xf7, 0xfc, 0xff, 0x6e, 0x63, 0xf0, 0xdc, 0x77, 0xaa, 0x7c, 0xe7, 0xfe, 0xaf, 0xee, 0x32, 0xfe, 0x5a,
-    0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xd9, 0xeb, 0x16, 0x72, 0xe9, 0x7a, 0xf9,
-    0xd1, 0xba, 0x75, 0xfd, 0x2b, 0x56, 0xb3, 0xa8, 0x65, 0xb2, 0xe8, 0x6c, 0x95, 0x86, 0xd5, 0xf9, 0x99, 0x6c, 0xf7, 0x4c,
-    0xff, 0x4e, 0x1a, 0x56, 0x84, 0x65, 0xe8, 0x0c, 0xdf, 0x6f, 0xdd, 0xea, 0xcc, 0xaa, 0xc1, 0x2c, 0x6d, 0xdd, 0x95, 0xe7,
-    0x3b, 0xd5, 0x6a, 0xd8, 0x5f, 0x95, 0xc1, 0xea, 0x2b, 0x19, 0x5a, 0x31, 0x99, 0xe1, 0xda, 0x04, 0xbd, 0xe3, 0x5d, 0x3a,
-    0xdb, 0xac, 0xf7, 0x5c, 0x7f, 0x6d, 0xe3, 0xd6, 0x2a, 0x33, 0x5f, 0xb7, 0x97, 0xc1, 0x33, 0xfe, 0x91, 0xcf, 0xa9, 0x7e,
-    0x9f, 0xe1, 0x11, 0xfa, 0x58, 0x52, 0xd7, 0xbb, 0xa5, 0x1a, 0x47, 0x69, 0x58, 0x43, 0x9f, 0xe9, 0xda, 0x60, 0x19, 0x6e,
-    0x87, 0x95, 0x3d, 0x6f, 0xee, 0xd3, 0x6a, 0x6b, 0xb5, 0x33, 0x31, 0x83, 0x66, 0xb0, 0xfe, 0x5d, 0x26, 0x2b, 0x43, 0xe4,
-    0x64, 0x8d, 0x77, 0xb6, 0xad, 0x6f, 0x4f, 0x67, 0xf4, 0xb7, 0x1f, 0x6f, 0x9a, 0xdb, 0xb4, 0xad, 0x5e, 0xf5, 0xc7, 0xed,
-    0xb3, 0xd2, 0x32, 0x34, 0xdb, 0x8c, 0xb5, 0xe9, 0xd5, 0xf9, 0xc6, 0xdd, 0x6b, 0x7b, 0xd4, 0xab, 0x8f, 0xed, 0xbf, 0x36,
-    0x18, 0xa9, 0xc5, 0xb2, 0x2e, 0xfe, 0xd3, 0x5d, 0x51, 0xaa, 0x4c, 0x5d, 0x75, 0xf4, 0xc5, 0x7f, 0xdb, 0xfb, 0x66, 0x68,
-    0xfe, 0xaf, 0xc5, 0xdf, 0xde, 0xed, 0xb3, 0xd5, 0xf6, 0x47, 0xe3, 0xbf, 0xbf, 0x0f, 0x64, 0x43, 0x8d, 0xd4, 0x5a, 0x56,
-    0x32, 0xb2, 0x65, 0xfe, 0x1a, 0x7b, 0x5f, 0xfc, 0x9f, 0xb5, 0xde, 0x6c, 0xbe, 0xb1, 0x6a, 0xfe, 0xcf, 0x74, 0xfe, 0xdf,
-    0xda, 0x57, 0xd3, 0xfc, 0xfd, 0x42, 0x2d, 0x39, 0x55, 0x1e, 0xc6, 0x7e, 0xc9, 0x67, 0xf5, 0x9b, 0x32, 0x8e, 0xc1, 0x6f,
-    0xc3, 0xd8, 0xbd, 0xbd, 0x67, 0xdc, 0x5e, 0x53, 0xb9, 0xf3, 0xfa, 0xad, 0x2b, 0xc6, 0xbe, 0x7b, 0xc4, 0x7f, 0x36, 0x65,
-    0x3a, 0x99, 0x6a, 0xd7, 0x74, 0xed, 0xfb, 0x35, 0x77, 0x97, 0x72, 0x59, 0x55, 0xd1, 0xff, 0xc7, 0xfe, 0xc7, 0x70, 0x4e,
-    0xbc, 0x7f, 0x7b, 0xeb, 0x38, 0x58, 0x2e, 0x98, 0xff, 0x77, 0xde, 0x01, 0x1d, 0xaf, 0x0a, 0x7f, 0x4d, 0xfc, 0x3f, 0xeb,
-    0xda, 0xe8, 0xd8, 0x32, 0x36, 0xf6, 0xc6, 0x7f, 0x2e, 0x3e, 0x8e, 0xeb, 0xe2, 0xbf, 0x9c, 0x5e, 0x03, 0xa4, 0x23, 0xaf,
-    0xdd, 0xb3, 0x7d, 0xe5, 0xf8, 0x32, 0xfb, 0xbd, 0x3f, 0xcf, 0xc9, 0xff, 0x9f, 0x1f, 0xff, 0x77, 0xbe, 0x43, 0x91, 0x37,
-    0xba, 0x43, 0x93, 0x5f, 0xee, 0xb2, 0x5c, 0xf3, 0x3c, 0xf6, 0x3f, 0x29, 0x3f, 0x7c, 0x3e, 0xf8, 0x1e, 0xad, 0x7b, 0xe7,
-    0xff, 0xbd, 0xf1, 0x3f, 0x73, 0xff, 0xff, 0xfb, 0xe6, 0xff, 0x77, 0xfe, 0x9b, 0x05, 0x7f, 0xb7, 0xb1, 0xb3, 0x9d, 0xee,
-    0x1f, 0xdf, 0xeb, 0x47, 0xe6, 0xf2, 0xe0, 0x7a, 0xe8, 0xfb, 0xe6, 0xff, 0xf7, 0xff, 0x8b, 0x25, 0xd5, 0x56, 0xaf, 0xb8,
-    0x26, 0xb9, 0xe3, 0xfd, 0xbd, 0xd5, 0xfd, 0xbd, 0x9c, 0xdc, 0x0b, 0xdd, 0x95, 0xff, 0x1f, 0x37, 0xbf, 0xff, 0x0f, 0xaf,
-    0x39, 0x3e, 0x01, 0xe2, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7d, 0xff, 0x9a, 0x32, 0xc3,
-    0xeb, 0x26, 0xf2, 0xa3, 0x96, 0xcc, 0xc7, 0xc4, 0x6a, 0xa4, 0x7d, 0x55, 0x64, 0xcf, 0x6b, 0x60, 0x7d, 0x4e, 0xfc, 0xfd,
-    0xe8, 0xde, 0xe3, 0xca, 0xa2, 0xf5, 0xa3, 0xcf, 0x38, 0xb2, 0x0c, 0x9e, 0xab, 0xb9, 0xcf, 0xfc, 0x77, 0x55, 0xa4, 0x63,
-    0xf9, 0x5a, 0xdf, 0xe3, 0xaf, 0xba, 0x49, 0xab, 0xcf, 0x48, 0xcf, 0xca, 0xc3, 0x7b, 0x55, 0x28, 0x2c, 0x3f, 0xda, 0x23,
-    0xa7, 0x75, 0x24, 0xef, 0x5c, 0x45, 0xb6, 0x0c, 0x55, 0x97, 0xd9, 0x7f, 0x5c, 0x73, 0xf1, 0x90, 0x4a, 0x5d, 0xcf, 0xe7,
-    0x54, 0xbb, 0xad, 0x9d, 0xab, 0xf3, 0x5a, 0xd8, 0xa5, 0x71, 0xbd, 0xfc, 0x79, 0x55, 0xe4, 0x4c, 0x8e, 0x7e, 0xf5, 0xe8,
-    0xcf, 0xd0, 0xd1, 0xfd, 0xee, 0x8c, 0xa5, 0xf9, 0x13, 0xb2, 0xa8, 0x3a, 0xd7, 0x79, 0x6b, 0x94, 0x17, 0x5e, 0x29, 0x5c,
-    0xba, 0xe2, 0x3f, 0x5f, 0x32, 0x84, 0xbc, 0xe0, 0xea, 0x96, 0xd6, 0xf1, 0xf8, 0xb5, 0x56, 0xce, 0xa4, 0x79, 0x45, 0xf8,
-    0x4c, 0xc5, 0x1d, 0xeb, 0xa9, 0xda, 0x7b, 0x62, 0xbd, 0x9f, 0xde, 0xbb, 0x8a, 0xec, 0x67, 0xe5, 0xb8, 0xf2, 0xb2, 0xd5,
-    0x6f, 0xda, 0x5a, 0x25, 0x03, 0xd9, 0xc1, 0xb3, 0xb6, 0x9e, 0x67, 0x71, 0xbf, 0x9b, 0xff, 0xc7, 0x32, 0x9b, 0x67, 0x1d,
-    0x7b, 0xeb, 0xbe, 0x66, 0xcb, 0x95, 0x60, 0x4b, 0x4f, 0xc8, 0x69, 0xb6, 0xf5, 0x8a, 0x71, 0xd2, 0x92, 0x89, 0xde, 0x73,
-    0xbf, 0xd3, 0xd8, 0x1b, 0x72, 0x92, 0x87, 0xdf, 0xb5, 0xee, 0xed, 0xcc, 0xa8, 0x94, 0x86, 0x2b, 0xfc, 0x96, 0xec, 0xa0,
-    0x5c, 0xba, 0xf5, 0xae, 0xf1, 0xdf, 0x32, 0xff, 0xe7, 0x4d, 0xe3, 0xbf, 0xdc, 0x7c, 0xbf, 0xc7, 0xbf, 0xff, 0xac, 0x75,
-    0xfe, 0xbf, 0xd7, 0xd6, 0x95, 0x19, 0xfc, 0xe3, 0xfb, 0x6d, 0xfb, 0x2a, 0x7d, 0xf6, 0xdf, 0x77, 0x7c, 0x8d, 0xf8, 0xbf,
-    0xf3, 0x3c, 0x39, 0x1e, 0xff, 0x9f, 0x2f, 0xb0, 0xdf, 0x19, 0xba, 0xa3, 0x53, 0x8b, 0xff, 0x72, 0xcb, 0xad, 0x2b, 0x2b,
-    0x5b, 0x8d, 0x3e, 0xab, 0xda, 0x59, 0xe9, 0xf3, 0xbe, 0xf1, 0xdf, 0x92, 0x2f, 0xbd, 0xea, 0x75, 0xf2, 0x31, 0x1d, 0x41,
-    0x77, 0x8d, 0xff, 0xfa, 0x93, 0x87, 0xf1, 0x27, 0x64, 0xcf, 0xd8, 0x5a, 0x2e, 0xba, 0x83, 0xf7, 0xbc, 0x63, 0x7f, 0x5e,
-    0xfc, 0xcf, 0x54, 0x28, 0x3c, 0xbf, 0xef, 0x72, 0x87, 0xeb, 0xe4, 0x1d, 0xf5, 0x10, 0xef, 0xb1, 0xdf, 0xd9, 0x34, 0x17,
-    0xdd, 0xfb, 0x49, 0x8e, 0x3b, 0xf8, 0xf7, 0x7c, 0x6a, 0x30, 0xd6, 0x8f, 0x77, 0x6f, 0x7f, 0x56, 0x6f, 0xbc, 0x62, 0xbf,
-    0x45, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x77, 0x5a, 0xc9, 0x93, 0xca, 0x2a,
-    0xe0, 0xa3, 0xab, 0x76, 0xd1, 0xaf, 0x46, 0x6b, 0xa6, 0x66, 0x41, 0x95, 0xcc, 0x47, 0x6b, 0x6f, 0xca, 0xe5, 0x47, 0x73,
-    0x4c, 0xbe, 0x33, 0x5c, 0xb5, 0x9a, 0xef, 0x77, 0xeb, 0xc5, 0x47, 0xfb, 0xfc, 0x68, 0xcd, 0xd4, 0xb9, 0x7a, 0xb1, 0xb5,
-    0x95, 0xd2, 0x9f, 0x83, 0xe3, 0xd9, 0xae, 0x0a, 0xb0, 0x67, 0xef, 0x5c, 0xaf, 0xe7, 0x6b, 0x3d, 0x20, 0xf3, 0xd1, 0xff,
-    0x1d, 0x7a, 0x50, 0xb6, 0xe5, 0x15, 0x3b, 0xf7, 0xf9, 0x43, 0x0f, 0xe5, 0x49, 0x39, 0x40, 0xdb, 0x5a, 0xf6, 0x72, 0xab,
-    0xad, 0x8f, 0xf7, 0x39, 0x8d, 0x95, 0xfd, 0xee, 0xb5, 0x75, 0xa6, 0x9e, 0x2f, 0xb4, 0x5c, 0x11, 0xd7, 0xab, 0xa2, 0xbe,
-    0xce, 0xd6, 0x96, 0xa3, 0x3d, 0xde, 0xe4, 0x58, 0xc5, 0x3f, 0xab, 0xe6, 0xfc, 0x77, 0xea, 0xf5, 0x99, 0x6a, 0x0b, 0xf1,
-    0x8f, 0xf8, 0xff, 0x6e, 0xbd, 0x5e, 0xfc, 0xf3, 0x7d, 0xf3, 0xff, 0x32, 0x55, 0x2f, 0xfe, 0xb8, 0xd5, 0xd6, 0xf9, 0x6b,
-    0xa1, 0xfb, 0x6c, 0xbd, 0x6b, 0x15, 0x44, 0xe0, 0x8a, 0x3b, 0xb0, 0x73, 0x4f, 0x70, 0x81, 0xd7, 0xc8, 0xc1, 0x46, 0xe2,
-    0xda, 0xec, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xdd, 0xe9, 0x72, 0xe3, 0x36, 0x16, 0x06, 0x50, 0x96, 0x6b, 0xde, 0xff, 0x85, 0x1d, 0xcc, 0x37, 0x35, 0x9d, 0x74, 0xe2,
+    0x24, 0x2d, 0x12, 0x2b, 0x17, 0xf9, 0xf4, 0xa9, 0xea, 0x1f, 0xa6, 0x25, 0x71, 0xc1, 0x05, 0x2e, 0x41, 0xe3, 0x2a, 0x1b,
+    0x00, 0x00, 0x00, 0xc0, 0x64, 0x39, 0xf9, 0xd3, 0x52, 0xfd, 0xd3, 0x79, 0x47, 0xf4, 0xf3, 0xdf, 0xb5, 0xc7, 0xae, 0x7d,
+    0xb5, 0x9f, 0xf7, 0xbc, 0xbc, 0x76, 0xce, 0xe7, 0xd7, 0x9f, 0x64, 0xf7, 0x77, 0xd3, 0x75, 0x76, 0x73, 0x78, 0xc5, 0xf6,
+    0xaf, 0x4c, 0x5b, 0xbc, 0xbd, 0xde, 0x87, 0x34, 0xbf, 0x62, 0x65, 0xcf, 0xf8, 0xf3, 0x5f, 0x69, 0x6a, 0xef, 0xfb, 0xad,
+    0xb8, 0xae, 0x95, 0xe7, 0x60, 0x8f, 0x52, 0xf1, 0x1b, 0x47, 0xaf, 0xdf, 0x06, 0xf6, 0xbe, 0x9c, 0x3a, 0x16, 0xe5, 0xb0,
+    0xcf, 0xd8, 0x16, 0x1c, 0x4d, 0x06, 0xaf, 0x65, 0x86, 0x7b, 0xb4, 0xfa, 0xf8, 0x3f, 0x6a, 0x17, 0xf9, 0xd7, 0xff, 0x5b,
+    0x57, 0xa4, 0x65, 0x61, 0xfc, 0x6f, 0x4d, 0xfd, 0xcb, 0xfa, 0xbc, 0x28, 0x15, 0x91, 0xde, 0xfe, 0x9a, 0xda, 0xa3, 0xed,
+    0xeb, 0xf1, 0x52, 0xfd, 0xbb, 0xe9, 0x3a, 0xe2, 0x59, 0x57, 0xa4, 0xb5, 0xe7, 0x3c, 0x3a, 0x1b, 0x2b, 0x8e, 0xe6, 0xeb,
+    0xcf, 0x3e, 0x07, 0x5f, 0x5f, 0x96, 0xf7, 0x91, 0xa5, 0xe2, 0x4c, 0x95, 0xee, 0x4f, 0x4c, 0x47, 0x36, 0x37, 0xeb, 0xea,
+    0xaf, 0xce, 0x0b, 0xd3, 0x1d, 0x4b, 0x19, 0xba, 0x7a, 0xfb, 0x9f, 0xdb, 0x3b, 0x7e, 0xaf, 0xed, 0xf1, 0xda, 0x73, 0xfd,
+    0x4c, 0xea, 0xcd, 0xfb, 0x7a, 0xb3, 0x9f, 0x67, 0x2a, 0x0b, 0xe2, 0x77, 0x5e, 0x5f, 0x3c, 0x33, 0x47, 0x1a, 0xc9, 0x3b,
+    0xf7, 0xb6, 0x7d, 0xfe, 0x50, 0xbf, 0x57, 0x4f, 0x19, 0xff, 0x33, 0x70, 0xfd, 0xd2, 0x75, 0x9e, 0x8f, 0x72, 0xca, 0xda,
+    0x23, 0xde, 0xff, 0xf4, 0xd2, 0x71, 0xcc, 0x1f, 0x29, 0x7f, 0xda, 0xa6, 0xe4, 0xb4, 0x99, 0x78, 0x2d, 0xd3, 0x7c, 0xaf,
+    0xf4, 0x7b, 0xdc, 0xf6, 0xe7, 0xcc, 0xc9, 0x7f, 0x7f, 0x28, 0x8b, 0x73, 0xb1, 0x33, 0xe2, 0xff, 0xaf, 0x5e, 0x2c, 0x03,
+    0x11, 0x9b, 0xc1, 0x11, 0x66, 0xee, 0xfd, 0xff, 0xb8, 0x32, 0x74, 0xfd, 0x32, 0xfd, 0xae, 0xf6, 0xaf, 0xe8, 0x4d, 0x57,
+    0xfe, 0x90, 0x69, 0xbd, 0x6c, 0x59, 0x38, 0x97, 0x9c, 0x45, 0x59, 0xda, 0xab, 0xf1, 0xff, 0xbc, 0x6c, 0x67, 0xcd, 0xdd,
+    0x52, 0xcb, 0xdc, 0x69, 0xef, 0xfd, 0x7f, 0x2a, 0x7b, 0x97, 0x75, 0xf1, 0x7f, 0xbe, 0xdf, 0x06, 0xaf, 0x5f, 0x4e, 0xbe,
+    0x3f, 0x9f, 0x73, 0x87, 0xde, 0x9f, 0xf1, 0xac, 0xbd, 0xff, 0x3f, 0xab, 0xc7, 0x58, 0x91, 0xff, 0xe7, 0xe1, 0xf9, 0x7f,
+    0xcb, 0xfc, 0x7f, 0xde, 0x24, 0xfe, 0x33, 0xfc, 0x44, 0x2a, 0xd3, 0xe7, 0xe7, 0xeb, 0xb2, 0xdd, 0xb1, 0xe7, 0x0b, 0x19,
+    0x3a, 0xe2, 0x59, 0x73, 0x31, 0x99, 0xf4, 0xbb, 0xa9, 0x1c, 0x15, 0xfb, 0xe6, 0x77, 0xaf, 0x9d, 0xff, 0xf7, 0xfc, 0x1f,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x96, 0xd5, 0x9d, 0x39, 0xe1, 0x75,
+    0x3d, 0xab, 0x68, 0x47, 0x56, 0xdd, 0x8e, 0xac, 0xd9, 0xed, 0x7d, 0xe5, 0x71, 0x1d, 0xa2, 0xfe, 0x75, 0xc6, 0xf5, 0xab,
+    0x9c, 0xdb, 0xd6, 0x0d, 0x8f, 0x55, 0x47, 0xc9, 0xe1, 0x3a, 0xfa, 0xba, 0x7a, 0x04, 0xc7, 0xb5, 0x5b, 0x8f, 0x2a, 0x59,
+    0xad, 0xaf, 0xfd, 0xba, 0xb2, 0x36, 0x65, 0xba, 0xcf, 0x60, 0xcb, 0xea, 0xf7, 0x34, 0xd5, 0x27, 0xe8, 0x5d, 0x87, 0x7e,
+    0x5e, 0x55, 0xc0, 0xf1, 0x15, 0xf2, 0xfb, 0xef, 0x5c, 0x96, 0x1f, 0x45, 0xfd, 0x1e, 0x67, 0xc2, 0x35, 0x5b, 0x11, 0xff,
+    0xd9, 0xad, 0x08, 0x90, 0x13, 0x6b, 0xbb, 0xae, 0xab, 0x84, 0xbb, 0xae, 0xd2, 0xce, 0x71, 0xfc, 0xd7, 0xd7, 0x6c, 0xce,
+    0xe4, 0x68, 0x4d, 0x77, 0xf4, 0xcc, 0xea, 0x01, 0x7a, 0xfa, 0xad, 0x19, 0xf1, 0xdf, 0x9b, 0x3b, 0x3c, 0x3b, 0xfe, 0x7b,
+    0xeb, 0x89, 0x65, 0xe7, 0xba, 0xa7, 0xb2, 0x6d, 0xdf, 0x61, 0xfb, 0x76, 0xd3, 0xf8, 0x3f, 0x8e, 0xa9, 0x0c, 0x57, 0x29,
+    0x9e, 0xd7, 0x9e, 0xe6, 0x29, 0x55, 0x51, 0xda, 0x57, 0xd3, 0xb3, 0x74, 0xf7, 0x2c, 0xab, 0xf2, 0xff, 0x1c, 0xdc, 0x79,
+    0xa4, 0x2a, 0x97, 0x9d, 0xdb, 0xc7, 0xd6, 0xf6, 0x5a, 0xaf, 0x2b, 0x8a, 0x1d, 0xd5, 0x2b, 0xbc, 0x7e, 0x7c, 0x1f, 0xab,
+    0xa7, 0x7c, 0x4e, 0xfc, 0x8f, 0x47, 0x62, 0x2e, 0x19, 0xb3, 0xe6, 0xcc, 0x4d, 0xa4, 0x73, 0xdc, 0x5a, 0xf3, 0xda, 0x33,
+    0xc6, 0xff, 0x3c, 0x6a, 0xfc, 0xaf, 0xb9, 0xff, 0xcf, 0x84, 0xbb, 0xd7, 0xbe, 0xb3, 0x56, 0xaa, 0xaf, 0xe5, 0x8a, 0xfc,
+    0xbf, 0x66, 0x64, 0x1f, 0x1f, 0xff, 0x47, 0xb6, 0xa6, 0x7a, 0x14, 0x3e, 0x3f, 0xfe, 0xeb, 0x8e, 0x29, 0xa7, 0xbe, 0xf6,
+    0x79, 0xf1, 0x9f, 0x5b, 0xcc, 0xff, 0x65, 0x61, 0x6d, 0xe6, 0x4c, 0xe9, 0xdd, 0xd6, 0xc4, 0x7f, 0x5d, 0x3d, 0xf4, 0x91,
+    0xfb, 0xff, 0xb1, 0x08, 0x3f, 0x8e, 0x80, 0xdf, 0xc4, 0xff, 0xa4, 0xfc, 0x7f, 0xd6, 0xab, 0xdb, 0xe7, 0x4a, 0x46, 0x46,
+    0xd0, 0xfa, 0x63, 0xca, 0xf4, 0xfc, 0x7b, 0xb4, 0xb6, 0xef, 0xea, 0xfc, 0x7f, 0xd6, 0xeb, 0xb7, 0xee, 0xeb, 0x7e, 0xbc,
+    0x65, 0xac, 0x55, 0x6e, 0x17, 0x7c, 0x9b, 0xc3, 0xea, 0xe7, 0x7b, 0xbe, 0xa3, 0xf4, 0xfd, 0x9e, 0x62, 0x3b, 0x07, 0xf7,
+    0x7e, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xe7, 0x55, 0x56, 0xf7,
+    0x5b, 0x31, 0x95, 0x8a, 0xf5, 0xa1, 0x35, 0xf5, 0x33, 0xf7, 0xab, 0x6f, 0xbe, 0xaa, 0x21, 0x51, 0xaa, 0x6a, 0x6f, 0xce,
+    0x3a, 0x9b, 0xb5, 0x75, 0x10, 0x46, 0xeb, 0x74, 0xf6, 0xbc, 0x7b, 0xcd, 0x59, 0x3e, 0x5e, 0xf3, 0x98, 0x83, 0x75, 0xc0,
+    0xdb, 0xc4, 0x16, 0x78, 0xbc, 0xe6, 0x39, 0x03, 0x35, 0x17, 0x46, 0xaa, 0x08, 0x66, 0xe1, 0x0a, 0xd3, 0x74, 0x9d, 0x95,
+    0xfa, 0x0a, 0x1c, 0xb5, 0x5b, 0x33, 0xa9, 0xca, 0xc3, 0xea, 0x76, 0x3d, 0x63, 0x6b, 0x7b, 0x1d, 0x85, 0x2b, 0xe2, 0x7f,
+    0xbf, 0x85, 0x64, 0xf2, 0xd5, 0x6e, 0xfb, 0xe9, 0x51, 0xec, 0xbf, 0xae, 0xad, 0xfc, 0x51, 0xd9, 0x6e, 0x5a, 0xb6, 0x67,
+    0xf8, 0x2a, 0x67, 0xb0, 0x12, 0x42, 0x69, 0x1c, 0x6f, 0xea, 0xa3, 0x7f, 0xac, 0xe5, 0xad, 0x5b, 0x01, 0xff, 0x4e, 0xf1,
+    0xbf, 0x75, 0x56, 0x2c, 0x5c, 0x1d, 0xff, 0x5b, 0xd5, 0x3e, 0x65, 0xda, 0x11, 0xcd, 0xab, 0xbe, 0xfd, 0xd1, 0x9c, 0x63,
+    0xcd, 0xa9, 0x65, 0x95, 0x13, 0x6b, 0x3d, 0xa4, 0xa1, 0x75, 0xf5, 0xf6, 0x00, 0xe9, 0x1c, 0xff, 0xdb, 0xcf, 0xf4, 0xac,
+    0x1c, 0xe3, 0x99, 0xf1, 0xdf, 0x77, 0x36, 0x33, 0x70, 0x85, 0xd7, 0x8e, 0xff, 0x33, 0x2b, 0x77, 0xf7, 0x44, 0x47, 0x79,
+    0xf1, 0x2e, 0xa5, 0x7b, 0x74, 0xee, 0xbf, 0x3b, 0xd8, 0xaa, 0xbe, 0x93, 0xa1, 0x34, 0xbf, 0x2e, 0x7f, 0x8b, 0xcf, 0x2c,
+    0xb9, 0x47, 0xcf, 0xce, 0x19, 0xee, 0xad, 0x46, 0xda, 0x1a, 0xff, 0x39, 0x75, 0xfc, 0xdf, 0x2a, 0xbf, 0x3d, 0x63, 0xeb,
+    0xba, 0x5e, 0x5b, 0xe7, 0xbb, 0xf6, 0xbf, 0x32, 0x87, 0x2d, 0x76, 0x4d, 0x3d, 0xda, 0x99, 0xdf, 0xd0, 0x91, 0x09, 0xed,
+    0x36, 0x07, 0x9f, 0x90, 0xce, 0x1c, 0xbc, 0x35, 0xf3, 0x6f, 0xe9, 0x67, 0xd3, 0x30, 0x33, 0x90, 0x9d, 0x3e, 0x30, 0x8b,
+    0x72, 0xf0, 0x99, 0xe3, 0x60, 0xa6, 0xe6, 0x6b, 0xeb, 0x66, 0x17, 0x57, 0x66, 0x74, 0xe7, 0xbc, 0xdb, 0x55, 0xe7, 0xe4,
+    0xcc, 0xf1, 0x3f, 0xcd, 0xd9, 0xee, 0xc8, 0xf8, 0x9f, 0xe1, 0x3a, 0x99, 0x47, 0xb9, 0xdf, 0x76, 0xbb, 0xf1, 0xbf, 0x2e,
+    0x36, 0x73, 0x7a, 0xfe, 0x2f, 0xfe, 0xcf, 0x7e, 0xd2, 0xb2, 0x3d, 0x22, 0xfe, 0xd7, 0xde, 0xff, 0xcf, 0xe9, 0x41, 0x7a,
+    0x47, 0xd9, 0x6d, 0xf1, 0x33, 0x82, 0xfe, 0x57, 0xad, 0x8b, 0xff, 0xed, 0x5b, 0x55, 0x6b, 0x7c, 0xb7, 0xda, 0x94, 0x57,
+    0xc4, 0x7f, 0x4d, 0xfe, 0x9f, 0xce, 0xf9, 0xff, 0xfa, 0x6f, 0xd8, 0x4a, 0x53, 0xce, 0x52, 0x9f, 0x77, 0xbc, 0x67, 0x8b,
+    0xe0, 0x9d, 0x7b, 0xb4, 0xb1, 0xe7, 0xff, 0x77, 0xeb, 0x83, 0xc7, 0xbe, 0x53, 0xe5, 0x3b, 0xb7, 0x7f, 0x75, 0x97, 0xf1,
+    0xd7, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xaf, 0x5b, 0xc8, 0xa9, 0xeb,
+    0xe3, 0x7b, 0xeb, 0xd4, 0xb5, 0xaf, 0x50, 0xcd, 0xa4, 0xb5, 0x8e, 0x99, 0x74, 0x75, 0x4a, 0xc5, 0x6a, 0xfc, 0x0c, 0x9e,
+    0xf7, 0x0c, 0xff, 0x4e, 0x2a, 0x56, 0x80, 0xa5, 0xeb, 0x0a, 0xdf, 0x6f, 0x9d, 0xea, 0xc8, 0x2a, 0xc1, 0x4c, 0x3d, 0xbb,
+    0xb3, 0xaa, 0x11, 0xef, 0xaf, 0x7a, 0xfe, 0x55, 0xed, 0xb2, 0xd2, 0x59, 0x6d, 0x25, 0x5d, 0x2b, 0x24, 0xd3, 0x5d, 0x8b,
+    0xa0, 0xb5, 0x7f, 0xcb, 0x40, 0x8d, 0x86, 0x9a, 0x6b, 0xfd, 0xf5, 0x9c, 0xd6, 0x56, 0x95, 0xf9, 0xba, 0xbd, 0x74, 0xb6,
+    0xeb, 0x8f, 0x7c, 0x0e, 0xb5, 0xfb, 0x74, 0xf7, 0xd0, 0xdb, 0x94, 0x3a, 0xde, 0x35, 0xd5, 0x37, 0x4a, 0xc5, 0x9a, 0xf9,
+    0x0c, 0xd7, 0x02, 0x4b, 0xf7, 0x79, 0x98, 0xd9, 0xf2, 0xe6, 0xf6, 0x9a, 0x47, 0x6b, 0xb5, 0x5b, 0xea, 0x7c, 0xa4, 0xb3,
+    0xde, 0xdd, 0x68, 0x16, 0x92, 0x9d, 0x35, 0xdd, 0x59, 0xb6, 0x9e, 0x3d, 0x8d, 0xd1, 0x5f, 0x7f, 0xbc, 0xa9, 0x3e, 0xa7,
+    0x75, 0xf5, 0xa9, 0x3f, 0x6e, 0x9f, 0x85, 0xbe, 0xee, 0xdb, 0x4a, 0xe5, 0x18, 0x98, 0x09, 0x75, 0x7e, 0x56, 0x67, 0xda,
+    0x79, 0xc4, 0x6a, 0xe4, 0xe3, 0xea, 0x63, 0xab, 0x32, 0xa4, 0xb6, 0xfe, 0x64, 0x5e, 0xfc, 0xa7, 0xb9, 0x82, 0x54, 0x19,
+    0xba, 0xeb, 0x68, 0x8b, 0xff, 0xba, 0xf7, 0x4d, 0xd7, 0xf8, 0x7f, 0x14, 0x7f, 0x6b, 0xb7, 0x8f, 0x56, 0xd7, 0xef, 0x8d,
+    0xff, 0xf6, 0x36, 0x90, 0x05, 0x35, 0x51, 0x8f, 0x22, 0xb6, 0x67, 0xcb, 0x8c, 0xde, 0x2d, 0x03, 0xf7, 0xd6, 0x5b, 0x45,
+    0x55, 0xda, 0xf6, 0xd1, 0x3f, 0xdd, 0x57, 0x6c, 0xde, 0xdc, 0xc0, 0xe8, 0x59, 0x4e, 0x53, 0xa6, 0xf4, 0x75, 0x5b, 0x4d,
+    0x4e, 0x95, 0x97, 0xb1, 0x5f, 0xf2, 0x79, 0xf8, 0xcd, 0x18, 0x5b, 0xe7, 0xb7, 0x5f, 0xac, 0xde, 0xde, 0xd2, 0x6f, 0xcf,
+    0xa9, 0xd4, 0x79, 0xfe, 0xd6, 0x19, 0x7d, 0xdf, 0x3d, 0xe2, 0x3f, 0x8b, 0x32, 0x9d, 0x0c, 0x9d, 0xd7, 0x34, 0xed, 0xfb,
+    0x39, 0xb3, 0x4b, 0x39, 0xad, 0x8a, 0xe8, 0xff, 0x63, 0xff, 0xa3, 0x3b, 0x27, 0x5e, 0xbf, 0xbd, 0xb6, 0x1f, 0x2c, 0x27,
+    0x8c, 0xff, 0x2b, 0x67, 0x40, 0xfb, 0xab, 0xc0, 0x5f, 0x13, 0xff, 0x57, 0xdd, 0x2b, 0xcd, 0x3d, 0xce, 0x4c, 0x99, 0xdf,
+    0x7e, 0x72, 0xfc, 0x97, 0xdd, 0x7b, 0x80, 0x34, 0xe4, 0xb5, 0x6b, 0xb6, 0xcf, 0xec, 0x5f, 0x46, 0xbf, 0xe7, 0xe7, 0x9a,
+    0xfc, 0xff, 0x7e, 0xf1, 0x7f, 0xa7, 0xea, 0xa3, 0x79, 0xa3, 0x19, 0x9a, 0xfc, 0x6d, 0x56, 0x65, 0xe6, 0x27, 0xbe, 0x7e,
+    0x8f, 0xff, 0xa4, 0xfc, 0xf0, 0xf9, 0xe2, 0x7b, 0xb3, 0xee, 0x9d, 0xff, 0xb7, 0xc6, 0xff, 0xc8, 0xfc, 0xbf, 0xfc, 0xff,
+    0x8e, 0xb3, 0xc3, 0xfe, 0x4e, 0x63, 0xe5, 0x79, 0xba, 0x7f, 0x7c, 0xcf, 0xef, 0x99, 0xcb, 0x8b, 0xfb, 0xa1, 0xf7, 0xc8,
+    0xff, 0xdf, 0xa9, 0x1a, 0x69, 0xde, 0xaa, 0x0a, 0xfa, 0xdd, 0xfb, 0x8d, 0x7b, 0xce, 0xef, 0xcd, 0x1e, 0x0b, 0xca, 0xce,
+    0x5c, 0xe8, 0xaa, 0xfc, 0x7f, 0x3b, 0x79, 0xfe, 0x1f, 0xbe, 0x47, 0xff, 0x04, 0x88, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xae, 0x96, 0xc8, 0x8f, 0x0a, 0x32, 0x1f, 0x03, 0xeb, 0xce, 0xd6, 0xd5, 0x8e, 0xdd,
+    0xaf, 0x7c, 0xf5, 0x39, 0xf0, 0x57, 0xa3, 0x6b, 0x8f, 0x2b, 0x93, 0x56, 0x8d, 0x5e, 0x71, 0x64, 0xe9, 0xbc, 0x56, 0x63,
+    0x9f, 0xf9, 0xef, 0x5a, 0x48, 0xdb, 0xf4, 0x15, 0xbe, 0xdb, 0x1f, 0xd5, 0x92, 0x66, 0x5f, 0x91, 0x96, 0xf5, 0x86, 0x69,
+    0x5e, 0x39, 0x34, 0xd2, 0x4e, 0x8e, 0x56, 0x2d, 0x95, 0x1f, 0xe7, 0x23, 0xbb, 0xd5, 0x23, 0xef, 0x5c, 0x3b, 0xb6, 0x74,
+    0xd5, 0x94, 0x59, 0x7f, 0x5c, 0x63, 0xf1, 0x90, 0x83, 0x6a, 0x9e, 0xd7, 0xd4, 0xb8, 0x3d, 0xba, 0x56, 0xfb, 0x15, 0xb0,
+    0x4b, 0xe5, 0x2a, 0xf9, 0xfd, 0x5a, 0xc8, 0x19, 0xec, 0xfd, 0x8e, 0xa3, 0x3f, 0x5d, 0x47, 0xf7, 0xab, 0x2b, 0x96, 0xea,
+    0x4f, 0xc8, 0xb2, 0xb5, 0xfe, 0xf9, 0xc7, 0x15, 0x78, 0xea, 0xfa, 0xe0, 0xd2, 0x14, 0xff, 0xf9, 0x92, 0x21, 0xe4, 0x81,
+    0x6b, 0x5a, 0x6a, 0xfb, 0xe3, 0x67, 0xad, 0x97, 0x49, 0xf5, 0x3a, 0xf0, 0x91, 0x3a, 0x3b, 0xef, 0xb8, 0x3e, 0x2a, 0x8b,
+    0x5a, 0x62, 0xaa, 0x6b, 0x0d, 0xdc, 0xb3, 0x76, 0xec, 0xe7, 0xc1, 0x71, 0xe5, 0xb1, 0x35, 0x6f, 0xea, 0xce, 0x4a, 0x3a,
+    0xb2, 0x83, 0xab, 0xb6, 0xee, 0x67, 0x71, 0xbf, 0x1a, 0xff, 0xfb, 0x32, 0x9b, 0xab, 0x8e, 0xbd, 0x76, 0x5f, 0xb3, 0x20,
+    0x17, 0xad, 0x3b, 0x1b, 0xd9, 0xcd, 0xb6, 0x9e, 0x18, 0x27, 0x35, 0x99, 0xe8, 0x3d, 0xf7, 0x3b, 0x95, 0xad, 0x21, 0x3b,
+    0x79, 0xf8, 0x5d, 0xab, 0xdd, 0x8e, 0xf4, 0x4a, 0xa9, 0xb8, 0xc3, 0xaf, 0xc9, 0x0e, 0xca, 0xa9, 0x5b, 0x57, 0xc5, 0xff,
+    0x78, 0x6d, 0x9c, 0xe3, 0xf1, 0x3f, 0x6f, 0x1a, 0xff, 0xe5, 0xe6, 0xfb, 0xdd, 0xff, 0xad, 0x67, 0xa9, 0x6e, 0x35, 0x77,
+    0xda, 0x3a, 0x33, 0x83, 0x7f, 0x3d, 0xdf, 0xb6, 0xae, 0xbe, 0x67, 0xfb, 0xbc, 0xe3, 0x68, 0xfc, 0xcf, 0xa8, 0x8c, 0x50,
+    0x93, 0xff, 0xdf, 0x77, 0x9c, 0xec, 0x8f, 0xff, 0xcf, 0x07, 0xec, 0x77, 0x2a, 0xee, 0x86, 0xdb, 0x7b, 0x87, 0x72, 0xcb,
+    0xad, 0x33, 0xeb, 0x59, 0xf5, 0x3e, 0xab, 0x5a, 0x59, 0xdf, 0xf3, 0xbe, 0xf1, 0x5f, 0x93, 0x2f, 0x3d, 0xf5, 0x3e, 0x79,
+    0x1b, 0x8e, 0xa0, 0xbb, 0xc6, 0xff, 0xf1, 0x8c, 0x50, 0xff, 0x13, 0xb2, 0x2b, 0xb6, 0x96, 0x93, 0x66, 0xf0, 0xae, 0x3b,
+    0xf6, 0x95, 0xf9, 0x7f, 0x59, 0xfe, 0xa4, 0x38, 0xb7, 0xbd, 0x4f, 0x5e, 0x51, 0x05, 0xf1, 0x1e, 0xfb, 0x9d, 0x45, 0x63,
+    0xd1, 0xbd, 0x9f, 0xe4, 0xa8, 0xf1, 0x75, 0xcf, 0x27, 0x32, 0x7d, 0xed, 0x78, 0xf5, 0xf6, 0xab, 0x5a, 0xe3, 0x19, 0xfb,
+    0x2d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65, 0x9d, 0x89, 0x57, 0x7a,
+    0xab, 0xa5, 0x66, 0x42, 0x7d, 0xcc, 0x57, 0xab, 0x6e, 0xca, 0xe9, 0x47, 0xb3, 0x0d, 0xbe, 0x33, 0x5c, 0xb5, 0xbe, 0xaf,
+    0x77, 0x0d, 0xea, 0x36, 0x50, 0x2d, 0x75, 0xac, 0x52, 0xec, 0xd1, 0x1a, 0xe9, 0xcf, 0xce, 0xfe, 0x6c, 0x55, 0xed, 0xd7,
+    0xbd, 0x77, 0x3e, 0xae, 0xe4, 0x6b, 0x25, 0x20, 0xb4, 0xf5, 0x66, 0xcf, 0x89, 0x97, 0xa3, 0xf8, 0x87, 0xab, 0x57, 0xb9,
+    0x97, 0x5b, 0x6d, 0x7d, 0xbd, 0xcf, 0xa9, 0xac, 0xe9, 0x77, 0xaf, 0xad, 0x23, 0x95, 0x7c, 0x61, 0x74, 0xc4, 0x7c, 0x5a,
+    0xc4, 0xd4, 0xf4, 0x67, 0xef, 0x72, 0xac, 0xe2, 0x1f, 0xf1, 0x3f, 0x67, 0x26, 0x4e, 0xfc, 0xc3, 0xf7, 0x6d, 0xf5, 0xe2,
+    0x1f, 0xda, 0xda, 0xd7, 0xf3, 0xbe, 0x29, 0xa6, 0x7f, 0xb6, 0xe3, 0x9a, 0xad, 0x77, 0xad, 0x7f, 0x08, 0xac, 0xea, 0x6d,
+    0xdb, 0xef, 0x64, 0xc4, 0x3f, 0x3c, 0xfb, 0x29, 0x4b, 0x4f, 0x5c, 0x1b, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8b, 0x3f, 0xff, 0x69, 0x07, 0x10, 0xff, 0xc0,
-    0xb7, 0x8b, 0xff, 0xff, 0x01 };
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x98, 0xe1, 0xf7, 0x7f, 0xce, 0x03, 0x88, 0x7f, 0xe0, 0xdb, 0xc5, 0xff, 0xff, 0x00 };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle cyberFontRecs[189] = {
+static const Rectangle cyberFontRecs[188] = {
     { 4, 4, 4 , 14 },
     { 16, 4, 1 , 8 },
     { 25, 4, 4 , 3 },
@@ -267,92 +266,91 @@
     { 497, 48, 5 , 3 },
     { 4, 70, 5 , 3 },
     { 17, 70, 8 , 8 },
-    { 33, 70, 0 , 0 },
-    { 41, 70, 4 , 3 },
-    { 53, 70, 8 , 6 },
-    { 69, 70, 4 , 5 },
-    { 81, 70, 4 , 5 },
-    { 93, 70, 8 , 10 },
-    { 109, 70, 7 , 7 },
-    { 124, 70, 5 , 7 },
-    { 137, 70, 1 , 1 },
-    { 146, 70, 7 , 8 },
-    { 161, 70, 2 , 5 },
-    { 171, 70, 4 , 5 },
-    { 183, 70, 5 , 3 },
-    { 196, 70, 14 , 8 },
-    { 218, 70, 13 , 5 },
-    { 239, 70, 8 , 9 },
-    { 255, 70, 7 , 8 },
-    { 270, 70, 8 , 10 },
-    { 286, 70, 8 , 10 },
-    { 302, 70, 8 , 10 },
-    { 318, 70, 8 , 10 },
-    { 334, 70, 8 , 9 },
-    { 350, 70, 8 , 12 },
-    { 366, 70, 14 , 8 },
-    { 388, 70, 8 , 10 },
-    { 404, 70, 7 , 10 },
-    { 419, 70, 7 , 10 },
-    { 434, 70, 7 , 10 },
-    { 449, 70, 7 , 9 },
-    { 464, 70, 5 , 10 },
-    { 477, 70, 5 , 10 },
-    { 490, 70, 5 , 10 },
-    { 4, 92, 5 , 9 },
-    { 17, 92, 8 , 8 },
-    { 33, 92, 8 , 10 },
-    { 49, 92, 8 , 10 },
-    { 65, 92, 8 , 10 },
-    { 81, 92, 8 , 10 },
-    { 97, 92, 8 , 10 },
-    { 113, 92, 8 , 9 },
-    { 129, 92, 4 , 4 },
-    { 141, 92, 8 , 8 },
-    { 157, 92, 8 , 10 },
-    { 173, 92, 8 , 10 },
-    { 189, 92, 8 , 10 },
-    { 205, 92, 8 , 9 },
-    { 221, 92, 8 , 10 },
-    { 237, 92, 7 , 9 },
-    { 252, 92, 7 , 9 },
-    { 267, 92, 7 , 8 },
-    { 282, 92, 7 , 8 },
-    { 297, 92, 7 , 8 },
-    { 312, 92, 7 , 8 },
-    { 327, 92, 7 , 8 },
-    { 342, 92, 7 , 9 },
-    { 357, 92, 13 , 5 },
-    { 378, 92, 7 , 7 },
-    { 393, 92, 7 , 8 },
-    { 408, 92, 7 , 8 },
-    { 423, 92, 7 , 8 },
-    { 438, 92, 7 , 8 },
-    { 453, 92, 3 , 8 },
-    { 464, 92, 2 , 8 },
-    { 474, 92, 3 , 8 },
-    { 485, 92, 3 , 8 },
-    { 4, 114, 8 , 8 },
-    { 20, 114, 7 , 8 },
-    { 35, 114, 7 , 8 },
-    { 50, 114, 7 , 8 },
-    { 65, 114, 7 , 8 },
-    { 80, 114, 7 , 8 },
-    { 95, 114, 7 , 8 },
-    { 110, 114, 5 , 6 },
-    { 123, 114, 7 , 5 },
-    { 138, 114, 7 , 8 },
-    { 153, 114, 7 , 8 },
-    { 168, 114, 7 , 8 },
-    { 183, 114, 7 , 8 },
-    { 198, 114, 7 , 10 },
-    { 213, 114, 7 , 10 },
-    { 228, 114, 7 , 10 },
+    { 33, 70, 4 , 3 },
+    { 45, 70, 8 , 6 },
+    { 61, 70, 4 , 5 },
+    { 73, 70, 4 , 5 },
+    { 85, 70, 8 , 10 },
+    { 101, 70, 7 , 7 },
+    { 116, 70, 5 , 7 },
+    { 129, 70, 1 , 1 },
+    { 138, 70, 7 , 8 },
+    { 153, 70, 2 , 5 },
+    { 163, 70, 4 , 5 },
+    { 175, 70, 5 , 3 },
+    { 188, 70, 14 , 8 },
+    { 210, 70, 13 , 5 },
+    { 231, 70, 8 , 9 },
+    { 247, 70, 7 , 8 },
+    { 262, 70, 8 , 10 },
+    { 278, 70, 8 , 10 },
+    { 294, 70, 8 , 10 },
+    { 310, 70, 8 , 10 },
+    { 326, 70, 8 , 9 },
+    { 342, 70, 8 , 12 },
+    { 358, 70, 14 , 8 },
+    { 380, 70, 8 , 10 },
+    { 396, 70, 7 , 10 },
+    { 411, 70, 7 , 10 },
+    { 426, 70, 7 , 10 },
+    { 441, 70, 7 , 9 },
+    { 456, 70, 5 , 10 },
+    { 469, 70, 5 , 10 },
+    { 482, 70, 5 , 10 },
+    { 495, 70, 5 , 9 },
+    { 4, 92, 8 , 8 },
+    { 20, 92, 8 , 10 },
+    { 36, 92, 8 , 10 },
+    { 52, 92, 8 , 10 },
+    { 68, 92, 8 , 10 },
+    { 84, 92, 8 , 10 },
+    { 100, 92, 8 , 9 },
+    { 116, 92, 4 , 4 },
+    { 128, 92, 8 , 8 },
+    { 144, 92, 8 , 10 },
+    { 160, 92, 8 , 10 },
+    { 176, 92, 8 , 10 },
+    { 192, 92, 8 , 9 },
+    { 208, 92, 8 , 10 },
+    { 224, 92, 7 , 9 },
+    { 239, 92, 7 , 9 },
+    { 254, 92, 7 , 8 },
+    { 269, 92, 7 , 8 },
+    { 284, 92, 7 , 8 },
+    { 299, 92, 7 , 8 },
+    { 314, 92, 7 , 8 },
+    { 329, 92, 7 , 9 },
+    { 344, 92, 13 , 5 },
+    { 365, 92, 7 , 7 },
+    { 380, 92, 7 , 8 },
+    { 395, 92, 7 , 8 },
+    { 410, 92, 7 , 8 },
+    { 425, 92, 7 , 8 },
+    { 440, 92, 3 , 8 },
+    { 451, 92, 2 , 8 },
+    { 461, 92, 3 , 8 },
+    { 472, 92, 3 , 8 },
+    { 483, 92, 8 , 8 },
+    { 4, 114, 7 , 8 },
+    { 19, 114, 7 , 8 },
+    { 34, 114, 7 , 8 },
+    { 49, 114, 7 , 8 },
+    { 64, 114, 7 , 8 },
+    { 79, 114, 7 , 8 },
+    { 94, 114, 5 , 6 },
+    { 107, 114, 7 , 5 },
+    { 122, 114, 7 , 8 },
+    { 137, 114, 7 , 8 },
+    { 152, 114, 7 , 8 },
+    { 167, 114, 7 , 8 },
+    { 182, 114, 7 , 10 },
+    { 197, 114, 7 , 10 },
+    { 212, 114, 7 , 10 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo cyberFontGlyphs[189] = {
+static const GlyphInfo cyberFontGlyphs[188] = {
     { 32, 0, 0, 4, { 0 }},
     { 33, 0, 3, 2, { 0 }},
     { 34, 0, 3, 4, { 0 }},
@@ -461,7 +459,6 @@
     { 171, 0, 6, 6, { 0 }},
     { 172, 0, 7, 6, { 0 }},
     { 174, 0, 3, 9, { 0 }},
-    { 175, 0, 0, 0, { 0 }},
     { 176, 0, 3, 4, { 0 }},
     { 177, 0, 6, 8, { 0 }},
     { 178, 0, 3, 4, { 0 }},
@@ -562,29 +559,40 @@
 
     Font font = { 0 };
     font.baseSize = 14;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 188;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, cyberFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, cyberFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "Kyrou7Wide.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/dark/style_dark.h b/raygui/styles/dark/style_dark.h
--- a/raygui/styles/dark/style_dark.h
+++ b/raygui/styles/dark/style_dark.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,147 +15,146 @@
 
 // Custom style name: Dark
 static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x878787ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x2c2c2cff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xc3c3c3ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xe1e1e1ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x848484ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0x181818ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x000000ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xefefefff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x202020ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x6a6a6aff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x818181ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x606060ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x878787ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x2c2c2cff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xc3c3c3ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xe1e1e1ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x848484ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0x181818ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x000000ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xefefefff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x202020ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x6a6a6aff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x818181ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x606060ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x9d9d9dff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x3c3c3cff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
-    { 1, 5, (int)0xf7f7f7ff },    // LABEL_TEXT_COLOR_FOCUSED 
-    { 1, 8, (int)0x898989ff },    // LABEL_TEXT_COLOR_PRESSED 
-    { 4, 5, (int)0xb0b0b0ff },    // SLIDER_TEXT_COLOR_FOCUSED 
-    { 5, 5, (int)0x848484ff },    // PROGRESSBAR_TEXT_COLOR_FOCUSED 
-    { 9, 5, (int)0xf5f5f5ff },    // TEXTBOX_TEXT_COLOR_FOCUSED 
-    { 10, 5, (int)0xf6f6f6ff },    // VALUEBOX_TEXT_COLOR_FOCUSED 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 5, (int)0xf7f7f7ff },    // LABEL_TEXT_COLOR_FOCUSED
+    { 1, 8, (int)0x898989ff },    // LABEL_TEXT_COLOR_PRESSED
+    { 4, 5, (int)0xb0b0b0ff },    // SLIDER_TEXT_COLOR_FOCUSED
+    { 5, 5, (int)0x848484ff },    // PROGRESSBAR_TEXT_COLOR_FOCUSED
+    { 9, 5, (int)0xf5f5f5ff },    // TEXTBOX_TEXT_COLOR_FOCUSED
+    { 10, 5, (int)0xf6f6f6ff },    // VALUEBOX_TEXT_COLOR_FOCUSED
 };
 
 // WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0)
 
-#define DARK_STYLE_FONT_ATLAS_COMP_SIZE 2138
+#define DARK_STYLE_FONT_ATLAS_COMP_SIZE 2116
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char darkFontData[DARK_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0xdb, 0x92, 0xa5, 0xba, 0x0d, 0x00, 0x50, 0xff, 0xff, 0x4f, 0x2b, 0x0f, 0xa9, 0x54, 0x32, 0x95, 0xd3, 0x80, 0x64,
-    0xd9, 0x98, 0x9e, 0x35, 0xeb, 0xad, 0x77, 0x4f, 0xc3, 0x36, 0x96, 0x6f, 0x80, 0x1c, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xeb,
-    0xc5, 0x3f, 0xfe, 0x24, 0x7e, 0xfc, 0xcd, 0x78, 0xfc, 0x77, 0xae, 0x7f, 0xfe, 0x9f, 0x4f, 0xe3, 0xe2, 0x58, 0xcf, 0xce,
-    0x35, 0x7b, 0xdc, 0x48, 0x94, 0xc4, 0x3f, 0x9f, 0x5f, 0x3c, 0xfe, 0xbb, 0x3f, 0x7d, 0xbf, 0xfc, 0xef, 0x5f, 0xfd, 0xa5,
-    0xeb, 0xb3, 0x8f, 0x54, 0xb9, 0xe7, 0xff, 0x4f, 0xee, 0x2a, 0xc6, 0x92, 0xb2, 0xbf, 0x3f, 0xbb, 0xfc, 0xb9, 0x77, 0xfe,
-    0x9f, 0xb8, 0xf8, 0x3e, 0x95, 0xab, 0xf4, 0x24, 0xb6, 0x4e, 0x88, 0xff, 0x78, 0x14, 0x89, 0xd1, 0x5a, 0x73, 0xfe, 0x7b,
-    0xd4, 0x68, 0x6c, 0xa9, 0xaa, 0x25, 0x79, 0x15, 0xe9, 0xf9, 0xf2, 0xb8, 0xaa, 0xfd, 0xf9, 0x16, 0x30, 0x5a, 0xbe, 0xcb,
-    0x7c, 0x6d, 0x8c, 0xe9, 0xdf, 0x7e, 0x56, 0x93, 0x7a, 0xbe, 0xd5, 0xcc, 0x27, 0xa3, 0xe5, 0x2a, 0xbd, 0x11, 0xff, 0x51,
-    0x6e, 0xa9, 0x22, 0x19, 0xd1, 0x1d, 0x25, 0x58, 0x69, 0x87, 0xc7, 0xc6, 0xf8, 0x8f, 0xd6, 0xb1, 0x4b, 0xb4, 0xd5, 0xb9,
-    0x37, 0xe2, 0xff, 0xba, 0xd7, 0x1e, 0x2d, 0xf5, 0x26, 0x6e, 0xca, 0xa8, 0x37, 0x96, 0xd7, 0x8e, 0x53, 0x57, 0xc7, 0xff,
-    0xf5, 0x6f, 0x66, 0xfb, 0xdb, 0x48, 0xf6, 0xdd, 0x1d, 0xe5, 0x54, 0xeb, 0xff, 0xfb, 0xcb, 0x31, 0x7e, 0xec, 0x9b, 0xab,
-    0xe3, 0x90, 0x4c, 0x09, 0x47, 0x72, 0x76, 0x35, 0xdb, 0xc3, 0xbe, 0xd9, 0xff, 0x3f, 0x1b, 0x0b, 0x8a, 0xff, 0xb5, 0xf1,
-    0x5f, 0xf9, 0x26, 0xf1, 0xf0, 0x0c, 0x2a, 0x7d, 0xe2, 0x38, 0x20, 0xfe, 0xb3, 0xed, 0xd0, 0x75, 0x59, 0x75, 0x8d, 0xe5,
-    0xb3, 0xeb, 0x12, 0xcf, 0x66, 0xd8, 0xfb, 0x6a, 0x61, 0x7e, 0x6c, 0x94, 0x8f, 0xff, 0x7c, 0xeb, 0x79, 0xf7, 0xd7, 0xb2,
-    0xa5, 0xfa, 0xf3, 0xcc, 0x6e, 0xbe, 0xc4, 0xf7, 0xc5, 0x7f, 0x14, 0xfa, 0x94, 0xf7, 0xe3, 0xb9, 0x27, 0xfe, 0xa3, 0xb0,
-    0x72, 0x31, 0xda, 0x56, 0xf9, 0x6a, 0xeb, 0x12, 0x7d, 0x6b, 0x06, 0xef, 0x5f, 0x81, 0xfb, 0xf8, 0xbf, 0x9b, 0x0f, 0xbe,
-    0xdf, 0xff, 0xc7, 0x11, 0xfd, 0x7f, 0x94, 0xd7, 0x86, 0x47, 0xa1, 0xf5, 0xfd, 0x5a, 0xfc, 0x47, 0x21, 0x66, 0xa2, 0x65,
-    0x5e, 0x3e, 0x96, 0xac, 0xe5, 0xf5, 0xae, 0x19, 0xee, 0xb9, 0x5a, 0x77, 0xbd, 0x68, 0xd7, 0xac, 0xe6, 0x77, 0xc5, 0xff,
-    0x68, 0xe8, 0xff, 0x9f, 0x8d, 0x01, 0x66, 0xbf, 0x47, 0x7c, 0xac, 0xf7, 0xef, 0x8c, 0xff, 0x5d, 0x2b, 0xf6, 0xeb, 0x6b,
-    0x63, 0x1c, 0x71, 0x65, 0xac, 0xff, 0x77, 0x8e, 0xff, 0xeb, 0x6b, 0x00, 0xb9, 0x79, 0x4c, 0x1c, 0x1a, 0xfd, 0x95, 0x39,
-    0x73, 0xd7, 0x1d, 0xfb, 0xde, 0xa7, 0x09, 0xa2, 0xf0, 0xac, 0x46, 0xcf, 0x2a, 0xce, 0xea, 0x6b, 0x90, 0xef, 0xff, 0x77,
-    0xdd, 0xff, 0xbf, 0x1f, 0x73, 0x9f, 0xd1, 0xff, 0x8f, 0xdb, 0xde, 0xfd, 0x94, 0xf3, 0x01, 0xf6, 0xb6, 0x00, 0x21, 0xfa,
-    0xc1, 0x73, 0xc4, 0x80, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x9f, 0xcf,
-    0xef, 0xcf, 0x63, 0x90, 0xcf, 0x84, 0xbd, 0x3e, 0x03, 0xfb, 0x4c, 0x4e, 0xe0, 0x6a, 0x09, 0x75, 0xfd, 0xc5, 0xeb, 0xdc,
-    0xf1, 0x99, 0x4c, 0x0b, 0xcf, 0x6b, 0x46, 0xa4, 0x77, 0x3f, 0xe8, 0xcc, 0x28, 0x50, 0xc9, 0x69, 0x30, 0x92, 0x75, 0xa2,
-    0x37, 0x97, 0x52, 0xee, 0xec, 0xf7, 0xd4, 0xf8, 0x2f, 0xc4, 0xff, 0xfb, 0x9f, 0x8c, 0x42, 0xfe, 0x9e, 0x9d, 0xf1, 0x9f,
-    0xad, 0x7b, 0xb5, 0xfc, 0xb8, 0x73, 0x7d, 0xc9, 0xee, 0x8c, 0x62, 0xd1, 0x78, 0x0d, 0xf7, 0xf5, 0xab, 0x7f, 0xe6, 0xd0,
-    0xd9, 0x51, 0xaf, 0x67, 0xe2, 0x3f, 0x9b, 0xfb, 0x34, 0x2e, 0x5a, 0xe1, 0x73, 0xe2, 0x7f, 0x6c, 0x89, 0xff, 0xf8, 0x48,
-    0xfc, 0x77, 0x67, 0x92, 0xe9, 0xca, 0x42, 0x5e, 0xc9, 0x7c, 0x93, 0xbf, 0x86, 0xf5, 0x0c, 0xbf, 0xd5, 0x1a, 0xf7, 0x9d,
-    0xf8, 0xaf, 0xd4, 0xad, 0xeb, 0x3c, 0xab, 0xe2, 0xff, 0xbe, 0x6c, 0x2b, 0xbd, 0xc9, 0xfc, 0xcf, 0x7b, 0x22, 0x7f, 0x4f,
-    0x1e, 0xdd, 0xbb, 0x7d, 0xb4, 0xd6, 0xd6, 0x95, 0xd9, 0xbe, 0xf2, 0x2b, 0xf1, 0x1f, 0xc5, 0xbf, 0x12, 0x37, 0x2d, 0x4a,
-    0x6f, 0x06, 0xf6, 0x9e, 0xac, 0x6d, 0x7b, 0xe3, 0xbf, 0x7b, 0xdf, 0x9f, 0x33, 0xe2, 0xff, 0xfd, 0x3c, 0xba, 0xab, 0xe6,
-    0x70, 0xbd, 0x7d, 0xe5, 0xef, 0xee, 0xff, 0xef, 0x5b, 0xc9, 0x1d, 0xf5, 0x63, 0xa6, 0xa7, 0x7f, 0xb3, 0xff, 0x7f, 0xef,
-    0xe7, 0xef, 0xc6, 0x7f, 0x57, 0x6d, 0x8f, 0x8d, 0x23, 0x93, 0x6a, 0x5f, 0xb9, 0x73, 0x95, 0x6c, 0xf7, 0xfc, 0x7f, 0xd5,
-    0x37, 0x1b, 0xe9, 0xd1, 0x44, 0x1c, 0x1b, 0xff, 0x33, 0xab, 0x90, 0xeb, 0xc6, 0x0b, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0xdb,
-    0x56, 0x76, 0x05, 0x3c, 0xad, 0xff, 0xdf, 0x75, 0x97, 0x6c, 0x6c, 0x8e, 0xc9, 0xbd, 0xc7, 0xea, 0xdc, 0xa5, 0x2e, 0x9f,
-    0xbf, 0x3f, 0x9a, 0x47, 0x78, 0x5f, 0x8f, 0xff, 0xfa, 0x2a, 0xff, 0x68, 0x5a, 0x95, 0x7c, 0x6f, 0xfc, 0xbf, 0x7b, 0xa7,
-    0x93, 0xca, 0x51, 0x7a, 0xda, 0xdf, 0x67, 0x77, 0x85, 0x7b, 0x7b, 0x81, 0x9f, 0xef, 0x36, 0x44, 0x53, 0xcf, 0xd1, 0x95,
-    0xbf, 0xff, 0xcf, 0x73, 0xcb, 0xef, 0x78, 0x96, 0xbf, 0x13, 0x1f, 0xc9, 0xfd, 0xf4, 0xdf, 0x88, 0xff, 0xca, 0x91, 0x2b,
-    0xff, 0x2b, 0x7b, 0x0d, 0x3b, 0xe3, 0xff, 0xbd, 0x16, 0x40, 0xde, 0x4d, 0x38, 0x71, 0x14, 0x03, 0xfc, 0x9e, 0x16, 0xc0,
-    0x0e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xee, 0x37, 0xb1, 0x7f, 0xce,
-    0xcd, 0x55, 0xc9, 0x1a, 0x9f, 0x7f, 0x4f, 0x7a, 0x67, 0xc6, 0xfc, 0x71, 0x93, 0x85, 0xec, 0xfa, 0xb7, 0xfe, 0xfc, 0xa4,
-    0x23, 0x1f, 0x6f, 0x34, 0xbe, 0xb5, 0x9e, 0xc9, 0xe5, 0x1d, 0x85, 0x6c, 0x03, 0x57, 0x6f, 0xc6, 0xe6, 0xae, 0x41, 0xee,
-    0x18, 0xd1, 0x9e, 0xcf, 0x2c, 0xd2, 0xd9, 0x63, 0xfe, 0xf7, 0x9c, 0x9f, 0x67, 0xfa, 0x8d, 0xf2, 0x9b, 0xc6, 0x77, 0xb9,
-    0xcc, 0xf2, 0xf9, 0x11, 0x2a, 0x39, 0xf3, 0xf2, 0x79, 0x36, 0x4f, 0xcf, 0x98, 0x3f, 0x9f, 0x79, 0x27, 0x6e, 0xea, 0xe4,
-    0xf3, 0x5a, 0xfa, 0x24, 0x73, 0x44, 0x4f, 0x06, 0xa1, 0xda, 0x37, 0x8e, 0xe9, 0xda, 0x5a, 0xb9, 0xde, 0x99, 0x23, 0xc4,
-    0xf4, 0xfb, 0xfc, 0x95, 0xfa, 0x1e, 0x93, 0xd7, 0xbd, 0xfe, 0x8d, 0x67, 0xb2, 0x10, 0x44, 0xa9, 0xa7, 0xeb, 0x2c, 0xc1,
-    0xeb, 0x4f, 0xf2, 0x19, 0x33, 0xe3, 0x61, 0x7c, 0x75, 0xff, 0x74, 0x24, 0xdb, 0x9b, 0x4a, 0xbe, 0xba, 0x99, 0x5d, 0x33,
-    0xe6, 0xc6, 0x88, 0xe3, 0x22, 0xbb, 0x52, 0x3e, 0xfa, 0x7f, 0xee, 0x6f, 0x62, 0x32, 0xfe, 0xa3, 0x98, 0x59, 0xa8, 0x1e,
-    0x23, 0xd9, 0xf8, 0x9f, 0xbf, 0x0a, 0xbb, 0xe2, 0xbf, 0x92, 0xf5, 0xe0, 0xfd, 0x8c, 0xd9, 0xb5, 0x9e, 0x70, 0x6f, 0xfc,
-    0xc7, 0x83, 0xf6, 0x6b, 0xa4, 0xe7, 0x2f, 0xa3, 0x90, 0xe1, 0xfc, 0xf9, 0xec, 0x22, 0x5a, 0xfb, 0xff, 0x71, 0x59, 0x26,
-    0xf1, 0xc2, 0xf8, 0xbf, 0xb6, 0xdf, 0x5b, 0x2e, 0xfe, 0x67, 0x5a, 0xa7, 0xfd, 0xfd, 0x7f, 0xad, 0x5f, 0x3b, 0xb9, 0xff,
-    0x7f, 0x27, 0x63, 0x76, 0x14, 0xe6, 0xd9, 0x95, 0xe3, 0xc6, 0xe4, 0xc8, 0xe0, 0xd9, 0x5c, 0x30, 0x1a, 0xe6, 0xab, 0x1d,
-    0xf1, 0xdf, 0x3f, 0xc2, 0xae, 0xcc, 0xad, 0x6a, 0xfd, 0x7f, 0xb4, 0xce, 0xff, 0x23, 0xdd, 0xce, 0xcf, 0xc5, 0x7f, 0xe7,
-    0x6e, 0x4b, 0x2b, 0x32, 0xe6, 0xe6, 0x77, 0x76, 0x7c, 0xab, 0xff, 0x1f, 0xa5, 0xfe, 0xbf, 0xd6, 0x7b, 0xcd, 0xd4, 0xca,
-    0xd8, 0x90, 0xeb, 0x2e, 0x37, 0xfe, 0x5f, 0x3d, 0xca, 0xce, 0xcf, 0x28, 0x63, 0x53, 0xfb, 0xd4, 0x3d, 0xf7, 0xab, 0x45,
-    0x4b, 0xa4, 0xc7, 0xd7, 0x3b, 0x33, 0xe6, 0x56, 0xd6, 0x9e, 0xcf, 0x8f, 0xff, 0xce, 0x3d, 0x4c, 0x2a, 0x77, 0x17, 0xa2,
-    0xa1, 0x6f, 0x5e, 0xdd, 0xff, 0xcf, 0xce, 0xff, 0x2b, 0xb9, 0xf4, 0xf7, 0xac, 0xff, 0x8d, 0xa5, 0x6b, 0x3f, 0xd1, 0x7a,
-    0x3f, 0x71, 0x1c, 0xd0, 0x7e, 0x77, 0x66, 0x89, 0x7f, 0x63, 0xfe, 0xdf, 0x95, 0x81, 0x7d, 0x94, 0xef, 0x09, 0xd5, 0xd7,
-    0xff, 0x67, 0x6b, 0x60, 0x1c, 0xd3, 0xf7, 0x8f, 0xc7, 0x7b, 0xe8, 0xc4, 0x4b, 0xd1, 0x7f, 0x5a, 0xfc, 0x9f, 0xf2, 0x44,
-    0x43, 0x47, 0xbb, 0x15, 0x2d, 0xad, 0x5b, 0x65, 0xdf, 0x96, 0xce, 0x71, 0xd4, 0xfc, 0xfc, 0x7f, 0xcd, 0xba, 0xfa, 0x1b,
-    0xc7, 0x98, 0xb9, 0x23, 0x3b, 0x1f, 0xff, 0xb1, 0xbc, 0xe4, 0xe4, 0x23, 0xfe, 0x4e, 0x2b, 0x75, 0xde, 0xf1, 0xfe, 0xe6,
-    0xda, 0x13, 0x1b, 0x9f, 0xb5, 0x13, 0xa1, 0xc4, 0xd1, 0xf3, 0x21, 0xd7, 0x03, 0xfe, 0xe6, 0xf9, 0xd0, 0xdf, 0xfa, 0x1c,
-    0xbc, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x7d, 0x3b, 0xa4, 0x92, 0x59,
-    0x72, 0x34, 0xbf, 0x8b, 0x9e, 0xcf, 0xad, 0x5f, 0x3d, 0xbb, 0xbb, 0xf7, 0xa5, 0x6b, 0xf9, 0x79, 0x6b, 0xe5, 0x34, 0x97,
-    0x8f, 0x28, 0x97, 0x53, 0xed, 0x7e, 0xff, 0x83, 0x38, 0xf2, 0x6a, 0xde, 0x65, 0x75, 0x8d, 0x42, 0x3e, 0xd5, 0xce, 0xeb,
-    0x35, 0x4a, 0x65, 0xb7, 0xab, 0x96, 0x3d, 0x7f, 0x3b, 0x34, 0x36, 0xbc, 0x4f, 0x59, 0x8b, 0x85, 0x5a, 0x6e, 0xc3, 0xb9,
-    0xdc, 0x61, 0xb1, 0xf8, 0x9b, 0xe5, 0xca, 0x6f, 0x7e, 0x3f, 0x89, 0xfb, 0x6c, 0xab, 0xf1, 0xb9, 0xab, 0x59, 0xcd, 0xf8,
-    0xde, 0x7d, 0xbd, 0xea, 0xb5, 0xe5, 0x84, 0x5a, 0xb6, 0x7e, 0x67, 0x89, 0x37, 0xde, 0x6e, 0xad, 0x66, 0xc4, 0x8d, 0xcf,
-    0xbf, 0x73, 0x1a, 0x1f, 0xcd, 0x05, 0x50, 0xcb, 0x13, 0xb9, 0xeb, 0x5b, 0x55, 0x8e, 0x14, 0xa5, 0x3d, 0x9b, 0xc6, 0xf6,
-    0xec, 0x10, 0xf9, 0xec, 0xe7, 0xa3, 0x94, 0xef, 0xb3, 0xfb, 0x93, 0xca, 0x15, 0xa9, 0xc7, 0xff, 0x55, 0x39, 0x55, 0x3e,
-    0x99, 0xed, 0xff, 0xc7, 0xf2, 0x7d, 0x18, 0x4e, 0xb9, 0x9a, 0x77, 0xfd, 0x7f, 0xb4, 0xed, 0x98, 0xb4, 0xf7, 0x93, 0x1d,
-    0xe5, 0xda, 0x11, 0x0b, 0xbb, 0xf6, 0xfb, 0x8b, 0x74, 0xad, 0x18, 0xe9, 0x1c, 0x7b, 0xf5, 0xd9, 0xd7, 0xae, 0x4f, 0x56,
-    0xc4, 0x7f, 0x5c, 0xcc, 0x93, 0xbb, 0x77, 0x1d, 0xeb, 0xbe, 0x9a, 0x4f, 0x5a, 0x86, 0x2f, 0xc6, 0xff, 0x8e, 0xf8, 0x99,
-    0x9d, 0xff, 0x47, 0x79, 0x37, 0x9d, 0x33, 0x6b, 0x4c, 0x3c, 0xcc, 0xe8, 0xfc, 0xdb, 0xe2, 0x7f, 0x6f, 0x19, 0x77, 0xb7,
-    0xe6, 0xd7, 0x23, 0xec, 0xf1, 0xd1, 0xf8, 0x9f, 0xdd, 0xef, 0x6d, 0x7e, 0xee, 0x7a, 0xbf, 0xfe, 0xdf, 0xb9, 0xb2, 0x71,
-    0x46, 0xfc, 0x9f, 0x12, 0xe5, 0xb9, 0x32, 0x5f, 0x1b, 0xff, 0xef, 0xc7, 0x50, 0x57, 0x1f, 0xf6, 0xde, 0xb9, 0x47, 0xdb,
-    0xfc, 0xff, 0x7e, 0x97, 0xe4, 0xdc, 0xdd, 0x9d, 0xbd, 0xab, 0x49, 0x3b, 0x4b, 0xbd, 0x73, 0xcf, 0xe1, 0xa7, 0x63, 0x87,
-    0xee, 0xf9, 0xee, 0x19, 0xfd, 0x7f, 0x88, 0xff, 0x05, 0x6b, 0xe1, 0x27, 0xf4, 0x92, 0xab, 0xee, 0xe5, 0xe5, 0xb3, 0xd8,
-    0xf7, 0x7e, 0x32, 0x5b, 0x52, 0xf9, 0xfb, 0xff, 0x5f, 0x1f, 0xff, 0x3f, 0xd9, 0xe1, 0xe7, 0x5b, 0xf1, 0x1f, 0xc5, 0x15,
-    0xc5, 0x33, 0xe2, 0x3f, 0x36, 0x8e, 0x6a, 0x57, 0xdc, 0xcb, 0x3f, 0x79, 0xfc, 0xdf, 0xbf, 0x13, 0xd4, 0xd7, 0xe3, 0xff,
-    0x0b, 0x63, 0xe8, 0x35, 0x4f, 0xa1, 0xbc, 0x17, 0xff, 0x73, 0x77, 0x86, 0x4f, 0x1e, 0xff, 0x9f, 0x1e, 0xff, 0xb3, 0x57,
-    0x25, 0x36, 0xcd, 0xff, 0x9f, 0x8e, 0x34, 0x7e, 0x7f, 0xfc, 0x8f, 0xad, 0x7b, 0xf7, 0xd7, 0xe7, 0x9b, 0xe3, 0xd0, 0x67,
-    0x61, 0xce, 0x79, 0x8a, 0xe3, 0xfd, 0x99, 0xcd, 0xfc, 0xae, 0xa8, 0xeb, 0xef, 0xff, 0x8f, 0x65, 0xfd, 0x7f, 0xef, 0x93,
-    0x2d, 0xbb, 0xee, 0xff, 0xef, 0x7d, 0xa2, 0xa8, 0xfb, 0x0c, 0xc5, 0xff, 0x37, 0xda, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x73, 0xf2, 0x2b, 0x72, 0xeb, 0xf7, 0xe7, 0xc3, 0x38, 0x3d, 0xb7, 0xfe,
-    0xdd, 0xfb, 0x33, 0xe3, 0xd8, 0xdc, 0xfa, 0xe3, 0x51, 0x8e, 0xa2, 0xef, 0xe5, 0xd6, 0xf7, 0xee, 0xc7, 0xd3, 0xb7, 0x64,
-    0xd6, 0xe5, 0xd6, 0xef, 0x7b, 0x87, 0xfa, 0xf4, 0xdc, 0xfa, 0xe3, 0x26, 0x13, 0xd1, 0xc9, 0xb9, 0xf5, 0xeb, 0x6f, 0x51,
-    0x9d, 0x9a, 0x5b, 0x9f, 0xb5, 0xef, 0x4e, 0x3e, 0x6d, 0xfb, 0xe3, 0xc5, 0x6b, 0xf6, 0x46, 0x36, 0x84, 0x93, 0x6b, 0x64,
-    0x3e, 0x5b, 0xd3, 0x8a, 0x16, 0xa5, 0xf3, 0x7d, 0xcd, 0xb3, 0x73, 0xeb, 0x7f, 0x3d, 0xc6, 0xeb, 0xd9, 0x58, 0xa3, 0x9c,
-    0xf3, 0xbe, 0xef, 0x5d, 0xed, 0x48, 0x8d, 0x1b, 0xd7, 0xe6, 0xd6, 0xba, 0x6e, 0x47, 0xcf, 0xdd, 0x29, 0xe1, 0xdb, 0xb9,
-    0xb5, 0xc5, 0x7f, 0x4f, 0xab, 0x1b, 0x4d, 0x51, 0xf7, 0xf4, 0x93, 0x7d, 0x59, 0x83, 0xfa, 0xe2, 0x3f, 0xda, 0x3f, 0xdb,
-    0x9b, 0x5b, 0xab, 0xba, 0x9e, 0x20, 0xfe, 0x7f, 0x57, 0x3b, 0x90, 0x99, 0xd1, 0x3e, 0x29, 0xf7, 0x37, 0x6b, 0xc0, 0xce,
-    0xdc, 0x5a, 0x5f, 0x8f, 0xff, 0x4a, 0xff, 0x20, 0xfe, 0x7f, 0xcf, 0xf8, 0xbf, 0xaf, 0x2f, 0xaf, 0xaf, 0xff, 0x7f, 0x79,
-    0x6f, 0xad, 0xdf, 0x19, 0xff, 0x67, 0xe4, 0xd6, 0x15, 0xff, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0x13, 0xac, 0x58, 0xcd, 0xed,
-    0x9d, 0x4d, 0x88, 0xff, 0xd5, 0x75, 0xe7, 0xa4, 0x9d, 0x21, 0xc4, 0x78, 0x7d, 0xfe, 0x5f, 0xdb, 0x13, 0xb4, 0xda, 0x02,
-    0xec, 0xcb, 0xd5, 0xfa, 0x46, 0x6e, 0x7d, 0xb9, 0x75, 0x67, 0xae, 0xd7, 0xf5, 0xe8, 0xef, 0x9b, 0xf7, 0x63, 0x4e, 0x1f,
-    0xff, 0xf7, 0xde, 0xab, 0xf9, 0xff, 0x35, 0xa5, 0xd5, 0x2b, 0xde, 0xab, 0xc6, 0xff, 0x2b, 0xda, 0xd8, 0x37, 0x4b, 0x63,
-    0xcd, 0xbd, 0xa3, 0xfe, 0x33, 0x8c, 0xa6, 0xd1, 0x1f, 0xef, 0xb4, 0x1a, 0xb0, 0x66, 0x9c, 0xf1, 0x7e, 0x4b, 0x08, 0x7c,
-    0xed, 0x49, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xdd, 0x49, 0xb2, 0xe3, 0x36, 0x0c, 0x00, 0x50, 0xde, 0xff, 0xd2, 0xc8, 0x22, 0x95, 0x4a, 0xba, 0x2a, 0x96, 0x44, 0x10,
+    0x1c, 0x64, 0xbf, 0x7e, 0xbb, 0x6f, 0xb7, 0x6d, 0x51, 0x04, 0x27, 0x49, 0x60, 0x34, 0x00, 0x00, 0x00, 0xe0, 0xe7, 0xc5,
+    0xff, 0xfe, 0x25, 0x3e, 0xbe, 0x33, 0x1e, 0x7f, 0xce, 0xf5, 0xdf, 0xff, 0x79, 0x35, 0x2e, 0xbe, 0xeb, 0xd9, 0x6f, 0xed,
+    0xfd, 0xde, 0xe8, 0x28, 0x89, 0xff, 0xff, 0x7d, 0xf1, 0xf8, 0x73, 0x3f, 0x1d, 0x5f, 0xff, 0xfb, 0xaf, 0x3e, 0xe9, 0xfa,
+    0xd7, 0x47, 0x57, 0xb9, 0xf7, 0xff, 0x9f, 0xbe, 0xb3, 0x18, 0x53, 0xca, 0xfe, 0xfe, 0xd7, 0xf5, 0xff, 0xf6, 0xca, 0xff,
+    0x13, 0x17, 0xc7, 0x93, 0x39, 0x4b, 0x4f, 0x62, 0xeb, 0x84, 0xf8, 0x8f, 0x47, 0x91, 0x18, 0xa5, 0x35, 0xe7, 0xdf, 0x6f,
+    0x8d, 0xc2, 0x96, 0x2a, 0x5b, 0x92, 0x57, 0x91, 0xde, 0x5f, 0x1e, 0x57, 0xb5, 0xbf, 0xbf, 0x05, 0x8c, 0x92, 0x63, 0x19,
+    0xaf, 0x8d, 0x31, 0xfc, 0xee, 0x67, 0x35, 0xa9, 0xe6, 0xa8, 0x46, 0x5e, 0x69, 0x25, 0x67, 0x69, 0x47, 0xfc, 0x47, 0xba,
+    0xa5, 0x8a, 0xce, 0x88, 0xae, 0x28, 0xc1, 0x4c, 0x3b, 0xdc, 0x16, 0xc6, 0x7f, 0x94, 0x8e, 0x5d, 0xa2, 0xac, 0xce, 0xed,
+    0x88, 0xff, 0xeb, 0x5e, 0xbb, 0x95, 0xd4, 0x9b, 0xb8, 0x29, 0xa3, 0xda, 0x58, 0x9e, 0x3b, 0x4e, 0x9d, 0x1d, 0xff, 0xd7,
+    0xef, 0xec, 0xed, 0x6f, 0xa3, 0xb3, 0xef, 0xae, 0x28, 0xa7, 0x5c, 0xff, 0x5f, 0x5f, 0x8e, 0xf1, 0xb1, 0x6f, 0xce, 0x8e,
+    0x43, 0x7a, 0x4a, 0x38, 0x3a, 0x67, 0x57, 0xa3, 0x3d, 0xec, 0xce, 0xfe, 0xff, 0xd9, 0x58, 0x50, 0xfc, 0xcf, 0x8d, 0xff,
+    0xcc, 0x91, 0xc4, 0xc3, 0x5f, 0x90, 0xe9, 0x13, 0xdb, 0x01, 0xf1, 0xdf, 0xdb, 0x0e, 0x5d, 0x97, 0x55, 0xd5, 0x58, 0xbe,
+    0x77, 0x5d, 0xe2, 0xd9, 0x0c, 0x7b, 0x5d, 0x2d, 0xec, 0x1f, 0x1b, 0xf5, 0xc7, 0x7f, 0x7f, 0xeb, 0x79, 0xf7, 0x69, 0xbd,
+    0xa5, 0xfa, 0x79, 0x66, 0x37, 0x5e, 0xe2, 0xeb, 0xe2, 0x3f, 0x12, 0x7d, 0xca, 0xfe, 0x78, 0xae, 0x89, 0xff, 0x48, 0xac,
+    0x5c, 0xb4, 0xb2, 0x55, 0xbe, 0xdc, 0xba, 0x44, 0xdd, 0x9a, 0xc1, 0xfe, 0x33, 0x70, 0x1f, 0xff, 0x77, 0xf3, 0xc1, 0xfd,
+    0xfd, 0x7f, 0x1c, 0xd1, 0xff, 0x47, 0x7a, 0x6d, 0xb8, 0x25, 0x5a, 0xdf, 0xb7, 0xc5, 0x7f, 0x24, 0x62, 0x26, 0x4a, 0xe6,
+    0xe5, 0x6d, 0xca, 0x5a, 0x5e, 0xed, 0x9a, 0xe1, 0x9a, 0xb3, 0x75, 0xd7, 0x8b, 0x56, 0xcd, 0x6a, 0xbe, 0x2b, 0xfe, 0x5b,
+    0x41, 0xff, 0xff, 0x6c, 0x0c, 0x30, 0x7a, 0x1c, 0xf1, 0xb2, 0xde, 0xbf, 0x32, 0xfe, 0x57, 0xad, 0xd8, 0xcf, 0xaf, 0x8d,
+    0x71, 0xc4, 0x99, 0xb1, 0xfe, 0x5f, 0x39, 0xfe, 0xcf, 0xaf, 0x01, 0xf4, 0xcd, 0x63, 0xe2, 0xd0, 0xe8, 0xcf, 0xcc, 0x99,
+    0xab, 0xae, 0xd8, 0xd7, 0xde, 0x4d, 0x10, 0x89, 0x7b, 0x35, 0x6a, 0x56, 0x71, 0x66, 0x9f, 0x83, 0xfe, 0xfe, 0x7f, 0xd5,
+    0xf5, 0xff, 0xfb, 0x31, 0xf7, 0x19, 0xfd, 0x7f, 0xbb, 0xed, 0xdd, 0x4f, 0xf9, 0x3d, 0xc0, 0xda, 0x16, 0x20, 0x44, 0x3f,
+    0xb8, 0x8f, 0x18, 0x10, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xfd, 0xf9,
+    0xf5, 0x79, 0x0c, 0xfa, 0x33, 0x61, 0xcf, 0xcf, 0xc0, 0x3e, 0x92, 0x13, 0x38, 0x5b, 0x42, 0x55, 0x9f, 0x78, 0x9d, 0x3b,
+    0xbe, 0x27, 0xd3, 0xc2, 0xf3, 0x9a, 0x11, 0xdd, 0xbb, 0x1f, 0x54, 0x66, 0x14, 0xc8, 0xe4, 0x34, 0x68, 0x9d, 0x75, 0xa2,
+    0x36, 0x97, 0x52, 0xdf, 0xaf, 0x5f, 0x53, 0xe3, 0xdf, 0x10, 0xff, 0xfb, 0x5f, 0x69, 0x89, 0xfc, 0x3d, 0x2b, 0xe3, 0xbf,
+    0xb7, 0xee, 0xe5, 0xf2, 0xe3, 0x8e, 0xf5, 0x25, 0xab, 0x33, 0x8a, 0x45, 0xe1, 0x39, 0x5c, 0xd7, 0xaf, 0xfe, 0x99, 0x43,
+    0x67, 0x45, 0xbd, 0x1e, 0x89, 0xff, 0xde, 0xdc, 0xa7, 0x71, 0xd1, 0x0a, 0x9f, 0x13, 0xff, 0x6d, 0x49, 0xfc, 0xc7, 0x4b,
+    0xe2, 0xbf, 0x3a, 0x93, 0x4c, 0x55, 0x16, 0xf2, 0x4c, 0xe6, 0x9b, 0xfe, 0x73, 0x98, 0xcf, 0xf0, 0x9b, 0xad, 0x71, 0xef,
+    0x89, 0xff, 0x4c, 0xdd, 0xba, 0xce, 0xb3, 0x2a, 0xfe, 0xef, 0xcb, 0x36, 0xd3, 0x9b, 0x8c, 0xff, 0xbd, 0x26, 0xf2, 0xd7,
+    0xe4, 0xd1, 0xbd, 0xdb, 0x47, 0x6b, 0x6e, 0x5d, 0x19, 0xed, 0x2b, 0xdf, 0x12, 0xff, 0x91, 0xfc, 0x94, 0xb8, 0x69, 0x51,
+    0x6a, 0x33, 0xb0, 0xd7, 0x64, 0x6d, 0x5b, 0x1b, 0xff, 0xd5, 0xfb, 0xfe, 0x9c, 0x11, 0xff, 0xfb, 0xf3, 0xe8, 0xce, 0x9a,
+    0xc3, 0xd5, 0xf6, 0x95, 0xdf, 0xdd, 0xff, 0xdf, 0xb7, 0x92, 0x2b, 0xea, 0xc7, 0x48, 0x4f, 0xbf, 0xb3, 0xff, 0xdf, 0xf7,
+    0xf7, 0xbd, 0xf1, 0x5f, 0x55, 0xdb, 0x63, 0xe1, 0xc8, 0x24, 0xdb, 0x57, 0xae, 0x5c, 0x25, 0x5b, 0x3d, 0xff, 0x9f, 0x75,
+    0x64, 0xad, 0x7b, 0x34, 0x11, 0xc7, 0xc6, 0xff, 0xc8, 0x2a, 0xe4, 0xbc, 0xf1, 0xc2, 0x9e, 0xf1, 0x7f, 0x6e, 0x7f, 0xdb,
+    0xcc, 0xae, 0x80, 0xa7, 0xf5, 0xff, 0xab, 0xae, 0x92, 0xb5, 0xc5, 0x31, 0xb9, 0xf6, 0xbb, 0x2a, 0x77, 0xa9, 0xeb, 0xcf,
+    0xdf, 0x1f, 0xc5, 0x23, 0xbc, 0xb7, 0xc7, 0x7f, 0x7e, 0x95, 0xbf, 0x15, 0xad, 0x4a, 0xee, 0x1b, 0xff, 0xaf, 0xde, 0xe9,
+    0x24, 0xf3, 0x2d, 0x35, 0xed, 0xef, 0xb3, 0xab, 0xc2, 0xb5, 0xbd, 0xc0, 0xe7, 0xab, 0x0d, 0x51, 0xd4, 0x73, 0x54, 0xe5,
+    0xef, 0xff, 0xf3, 0xb7, 0xf5, 0xef, 0x78, 0xd6, 0x7f, 0x25, 0x3e, 0x3a, 0xf7, 0xd3, 0xdf, 0x11, 0xff, 0x99, 0x6f, 0xce,
+    0xfc, 0xaf, 0xde, 0x73, 0x58, 0x19, 0xff, 0xfb, 0x5a, 0x00, 0x79, 0x37, 0xe1, 0xc4, 0x51, 0x0c, 0xf0, 0x3d, 0x2d, 0x80,
+    0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd5, 0x4f, 0x62, 0x7f, 0xce,
+    0xcd, 0x95, 0xc9, 0x1a, 0xdf, 0xff, 0x9c, 0xf4, 0xca, 0x8c, 0xf9, 0xed, 0x26, 0x0b, 0xd9, 0xf5, 0xbb, 0xfe, 0x7c, 0xa5,
+    0x22, 0x1f, 0x6f, 0x14, 0x3e, 0xb5, 0x9e, 0xcb, 0x2d, 0x1a, 0x37, 0xcf, 0xda, 0x47, 0xa2, 0x8c, 0xfb, 0xcb, 0xff, 0xee,
+    0x09, 0xfe, 0x96, 0xcc, 0x13, 0xf4, 0x3c, 0xf3, 0xff, 0x93, 0x7c, 0x2e, 0xd7, 0xdf, 0x12, 0xb7, 0x19, 0xff, 0xfb, 0xf3,
+    0xbe, 0xd6, 0x65, 0x72, 0xcb, 0xe4, 0xcc, 0xeb, 0xcf, 0xb3, 0x79, 0x7a, 0xc6, 0xfc, 0xf1, 0xcc, 0x3b, 0x71, 0x53, 0x87,
+    0xfb, 0xcf, 0xe1, 0xfc, 0x3c, 0x46, 0xcf, 0xde, 0xdf, 0x5f, 0xfb, 0xf3, 0xe7, 0xb3, 0xf6, 0xd7, 0x5f, 0xd7, 0xcf, 0x28,
+    0x39, 0x4f, 0x91, 0xca, 0x0a, 0x10, 0xd3, 0xf2, 0x07, 0x44, 0x61, 0xfc, 0x67, 0x5a, 0x99, 0xfd, 0x19, 0x33, 0x23, 0xd5,
+    0x46, 0xd6, 0x64, 0xde, 0xea, 0x69, 0x6f, 0x32, 0xf9, 0xea, 0x62, 0x51, 0x26, 0x8a, 0xff, 0xb6, 0x66, 0x99, 0x6c, 0x8a,
+    0x9f, 0xfb, 0x93, 0xe8, 0x8c, 0xff, 0x48, 0xe4, 0xfc, 0xa9, 0x8d, 0xff, 0xfb, 0x52, 0x9a, 0x11, 0xff, 0x51, 0x5a, 0x03,
+    0xb3, 0xfd, 0x7f, 0xff, 0x08, 0x75, 0x7f, 0xc6, 0xec, 0x5c, 0xc9, 0xad, 0x8d, 0xff, 0x78, 0xd0, 0x7e, 0xf5, 0x8f, 0x9f,
+    0x33, 0x7b, 0x7c, 0xc5, 0x6d, 0xdb, 0x9a, 0xeb, 0xff, 0xdb, 0xe5, 0x31, 0x47, 0xc1, 0xf8, 0x3f, 0xb7, 0x3f, 0x5b, 0x5f,
+    0xfc, 0xc7, 0x6d, 0xb6, 0xf9, 0xd1, 0xfe, 0x3f, 0x93, 0x1f, 0x35, 0x97, 0x97, 0xae, 0x32, 0xfe, 0xb3, 0xe3, 0xe8, 0xdd,
+    0xfd, 0xff, 0x9e, 0x8c, 0xd9, 0x91, 0x98, 0x77, 0x67, 0xbe, 0xb7, 0xb6, 0xec, 0x9f, 0xd4, 0xc0, 0x28, 0x8c, 0xff, 0xec,
+    0x98, 0x36, 0x9b, 0xed, 0x31, 0x86, 0xcf, 0xe0, 0x7d, 0x89, 0x47, 0xaa, 0x8f, 0x6a, 0x13, 0xf2, 0xd2, 0x56, 0xc6, 0x7f,
+    0xe5, 0x6e, 0x4b, 0x33, 0x32, 0xe6, 0xf6, 0xef, 0xec, 0xb8, 0xab, 0xff, 0x6f, 0xa9, 0xfe, 0x3f, 0xd7, 0x1b, 0xf6, 0xce,
+    0x26, 0x66, 0xec, 0x01, 0x56, 0x37, 0xf6, 0xce, 0xc6, 0x7f, 0xa6, 0xed, 0xaa, 0x9b, 0x53, 0xf7, 0xcc, 0xff, 0x23, 0x3d,
+    0x86, 0x8d, 0xc2, 0xf5, 0xff, 0x9a, 0xf1, 0xff, 0xea, 0x8c, 0xb9, 0x99, 0xb5, 0xe9, 0xf3, 0xe3, 0xbf, 0x72, 0x0f, 0x93,
+    0x27, 0x57, 0x13, 0x22, 0xb5, 0x0b, 0x68, 0x6d, 0xff, 0x1f, 0x89, 0x11, 0xd1, 0xdd, 0x8a, 0x41, 0xcd, 0xfa, 0x5f, 0x1b,
+    0x5a, 0x8b, 0xb9, 0x5f, 0xff, 0xcf, 0xaf, 0x86, 0xc6, 0x82, 0x75, 0xc3, 0xeb, 0x23, 0xdb, 0x7b, 0x3d, 0xb3, 0x66, 0x8c,
+    0xbe, 0x7b, 0xfe, 0x5f, 0x95, 0x81, 0x3d, 0xb3, 0x9f, 0x76, 0x4c, 0xa8, 0x19, 0xb3, 0x3f, 0xf3, 0xf9, 0xa7, 0xf7, 0xc4,
+    0x7f, 0x2c, 0xab, 0x81, 0x33, 0xe7, 0x73, 0x2b, 0xe3, 0xff, 0x94, 0x3b, 0x1a, 0x2a, 0xda, 0xad, 0x28, 0x69, 0xdd, 0x32,
+    0xfb, 0xb6, 0x54, 0x8e, 0xa3, 0xda, 0xc0, 0x1c, 0x2a, 0x26, 0xdc, 0x69, 0x12, 0x93, 0xaf, 0x75, 0xd5, 0xc5, 0x7f, 0x0c,
+    0x1f, 0xe9, 0xc8, 0xf1, 0xf6, 0xdf, 0x03, 0x12, 0xf2, 0x11, 0xbf, 0xa8, 0x95, 0xda, 0xff, 0x7d, 0x6f, 0xae, 0x2d, 0xb1,
+    0xf0, 0xde, 0xb8, 0x78, 0xc5, 0x11, 0xda, 0x8d, 0x40, 0xfd, 0xfd, 0x9d, 0x5a, 0xf1, 0xfd, 0xb5, 0x5c, 0xfc, 0xb3, 0x6f,
+    0x3e, 0xf4, 0x96, 0xfb, 0xd6, 0xd5, 0x76, 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xbf, 0xfc, 0x2c, 0x5a, 0x7f, 0xae, 0xfb, 0x6c, 0xde, 0xf2, 0xa7, 0xf9, 0xd2, 0xc7, 0x9f, 0x7a, 0xbf, 0xff, 0xfb, 0x58,
+    0x7e, 0xa0, 0xbe, 0x1c, 0x67, 0xf7, 0xf9, 0xf0, 0x63, 0xc1, 0x31, 0x57, 0x67, 0x59, 0x8e, 0x8b, 0xdc, 0x41, 0x6b, 0xce,
+    0x57, 0x4b, 0x95, 0xdd, 0xba, 0x5a, 0x36, 0x23, 0x7e, 0xf2, 0x99, 0x2f, 0x32, 0xb1, 0x10, 0xa9, 0xe7, 0x13, 0x6b, 0xf2,
+    0xa5, 0x3f, 0x3d, 0x37, 0xb9, 0x5a, 0xf3, 0xf4, 0xb3, 0x62, 0xf8, 0x93, 0xef, 0xb3, 0x9f, 0x66, 0xb2, 0x04, 0xee, 0x3d,
+    0x9b, 0xd9, 0x0c, 0xec, 0xd5, 0xe7, 0xab, 0x3a, 0x7f, 0xd6, 0xb9, 0x25, 0x1e, 0x47, 0x3d, 0xff, 0x97, 0xcf, 0x68, 0x16,
+    0x07, 0x3c, 0x2b, 0x3f, 0xeb, 0x99, 0xd2, 0x78, 0xe9, 0x13, 0x9b, 0x91, 0xdc, 0x97, 0x67, 0xcd, 0x51, 0xe5, 0x32, 0xde,
+    0x46, 0x3a, 0xa7, 0xe4, 0xa9, 0x25, 0x3e, 0xf2, 0xfb, 0xfb, 0xb3, 0xc3, 0x8f, 0x65, 0x36, 0xae, 0x8d, 0xff, 0xab, 0xbc,
+    0xb7, 0x99, 0x57, 0x46, 0xfb, 0xff, 0x36, 0x7d, 0x5f, 0x84, 0x19, 0xe7, 0x2c, 0x0a, 0xf3, 0x36, 0xdf, 0xed, 0x1c, 0xd7,
+    0x7f, 0xc4, 0x6b, 0x5f, 0x39, 0xb7, 0xc4, 0x9f, 0xf4, 0x5b, 0x95, 0x7b, 0xa5, 0x64, 0xea, 0xe6, 0xb3, 0xdc, 0xeb, 0x9f,
+    0xfe, 0x4f, 0x94, 0x8d, 0xbd, 0xaa, 0x5f, 0x99, 0x11, 0xff, 0x71, 0x31, 0x4f, 0xae, 0xde, 0x05, 0xac, 0xfa, 0x6c, 0x3e,
+    0x69, 0x19, 0xde, 0x18, 0xff, 0xb1, 0x20, 0x4a, 0x22, 0x55, 0xdb, 0xda, 0x94, 0x71, 0xcb, 0x09, 0x35, 0x26, 0x1e, 0x66,
+    0x6c, 0xfe, 0xb6, 0xf8, 0x5f, 0x5b, 0xc6, 0xd5, 0xad, 0xf9, 0x75, 0x6f, 0xd4, 0x5e, 0x1a, 0xff, 0xa3, 0xfb, 0xaf, 0x8d,
+    0xbf, 0x32, 0xbe, 0x87, 0xe6, 0x99, 0xfd, 0x7f, 0xf5, 0x8e, 0x9d, 0x73, 0x5e, 0xe9, 0x99, 0x7b, 0xcd, 0x8d, 0xff, 0xfd,
+    0x31, 0x34, 0x9a, 0x4b, 0x7d, 0xff, 0x6f, 0x8f, 0xb2, 0xf9, 0xff, 0xfd, 0xae, 0xc6, 0x55, 0xaf, 0x64, 0x6a, 0x6f, 0x7e,
+    0xfd, 0xbf, 0xbe, 0xd4, 0x2b, 0xf7, 0x00, 0x7e, 0x3a, 0x76, 0xa8, 0x9e, 0x7d, 0x9d, 0xd1, 0xff, 0x87, 0xf8, 0x1f, 0x5c,
+    0x25, 0xa9, 0x5a, 0xff, 0x3f, 0xa3, 0xc4, 0x67, 0xac, 0x4d, 0xd7, 0xae, 0x9f, 0x8d, 0x96, 0x47, 0xff, 0xf5, 0xff, 0xb7,
+    0x8f, 0xff, 0x9f, 0xec, 0xc0, 0xf3, 0xae, 0xf8, 0x8f, 0xe4, 0xfa, 0xd6, 0x19, 0xf1, 0x1f, 0x07, 0xb4, 0x5a, 0x99, 0x1d,
+    0x41, 0xeb, 0xaf, 0xa0, 0xd4, 0x8f, 0xff, 0x67, 0xec, 0x86, 0xf0, 0xee, 0xf8, 0x7f, 0xc3, 0x18, 0xba, 0x2d, 0xde, 0x6f,
+    0x7a, 0x76, 0xfc, 0x8f, 0xf5, 0x93, 0xb3, 0x5f, 0xa9, 0xbe, 0xba, 0xf7, 0x86, 0xf9, 0xff, 0x48, 0x0b, 0x30, 0x63, 0xfe,
+    0xff, 0x74, 0xa4, 0xf1, 0xfd, 0xf1, 0xdf, 0x26, 0xec, 0x01, 0x34, 0x63, 0xbe, 0xb9, 0xf7, 0xae, 0x91, 0xb6, 0xf8, 0xee,
+    0x94, 0x93, 0xe3, 0x7f, 0x56, 0xfb, 0x95, 0xd9, 0xf7, 0x36, 0x33, 0x7f, 0x99, 0xd5, 0xff, 0xd7, 0xde, 0xd9, 0xb2, 0xea,
+    0x6a, 0xf4, 0xda, 0xfb, 0x5b, 0xaa, 0x7f, 0xa1, 0x3c, 0xf8, 0x27, 0x3e, 0x63, 0xe0, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xed, 0xf3, 0x18, 0x99, 0xa7, 0x2b, 0xce, 0xc8, 0xac, 0x7f, 0xf7, 0xf4, 0x4c,
+    0x3b, 0x36, 0xb3, 0x7e, 0x7b, 0x94, 0xa1, 0xe8, 0x7d, 0x99, 0xf5, 0x3d, 0xf9, 0xf1, 0xbe, 0xa7, 0x72, 0xde, 0x9b, 0x59,
+    0xff, 0x2e, 0x8f, 0xc2, 0xc9, 0x99, 0xf5, 0xf3, 0xcf, 0x50, 0x9d, 0x9a, 0x59, 0x9f, 0xd3, 0xe3, 0x7f, 0xe7, 0x38, 0x63,
+    0xde, 0x11, 0x9c, 0x5c, 0x23, 0xef, 0x72, 0x43, 0xac, 0x69, 0x51, 0x2a, 0x9f, 0xd6, 0x3c, 0x3d, 0xb3, 0x3e, 0xbd, 0xd1,
+    0x53, 0xf7, 0xa4, 0x76, 0x74, 0x8d, 0x1b, 0xe7, 0x66, 0xd6, 0xba, 0xce, 0x19, 0x71, 0x76, 0x9e, 0xf7, 0xf7, 0x66, 0xd6,
+    0x16, 0xff, 0xef, 0x8a, 0xff, 0xf5, 0x59, 0xa6, 0xea, 0xe2, 0x3f, 0xca, 0x5f, 0x5b, 0x9b, 0x59, 0x2b, 0xbb, 0x9e, 0x20,
+    0xfe, 0xa9, 0x1a, 0xe7, 0x55, 0xbf, 0xb2, 0x32, 0xb3, 0xd6, 0xdb, 0xe3, 0x3f, 0x33, 0x2a, 0x17, 0xff, 0xac, 0x99, 0x87,
+    0x9e, 0xbf, 0xb3, 0xd6, 0x77, 0xc6, 0xff, 0x19, 0x99, 0x75, 0xc5, 0xff, 0x6f, 0xcc, 0x01, 0xe6, 0x64, 0xd6, 0xd5, 0xff,
+    0xcf, 0x8a, 0x88, 0xb3, 0xa3, 0x3c, 0x16, 0x67, 0x19, 0x64, 0xb4, 0x05, 0x58, 0x97, 0xa9, 0x75, 0x47, 0x66, 0x7d, 0x99,
+    0x75, 0x47, 0xce, 0xd7, 0xf5, 0xe8, 0xef, 0x9d, 0xd7, 0x63, 0x7e, 0x79, 0xfc, 0xbf, 0x62, 0x2d, 0x7c, 0xd6, 0xf8, 0xbf,
+    0xfa, 0x8e, 0x07, 0x99, 0x75, 0x6b, 0xcf, 0x9a, 0xf1, 0x3f, 0xfc, 0xd2, 0x8a, 0xf1, 0xfe, 0x96, 0x10, 0x78, 0xdb, 0x9d,
+    0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x80, 0x93, 0xfc, 0xfb, 0x9f, 0x72, 0x00, 0xf1, 0x0f, 0xfc, 0x75, 0xf1, 0xff, 0x2f };
+    0x00, 0x00, 0xbf, 0xed, 0xef, 0x7f, 0xca, 0x01, 0xc4, 0x3f, 0xf0, 0x73, 0xf1, 0xff, 0x17 };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle darkFontRecs[189] = {
+static const Rectangle darkFontRecs[182] = {
     { 4, 4, 4 , 16 },
     { 16, 4, 1 , 9 },
     { 25, 4, 3 , 3 },
@@ -257,99 +256,92 @@
     { 218, 52, 6 , 9 },
     { 232, 52, 5 , 9 },
     { 245, 52, 5 , 12 },
-    { 258, 52, 0 , 0 },
-    { 266, 52, 5 , 10 },
-    { 279, 52, 7 , 9 },
-    { 294, 52, 0 , 0 },
-    { 302, 52, 6 , 5 },
-    { 316, 52, 5 , 3 },
-    { 329, 52, 7 , 9 },
-    { 344, 52, 0 , 0 },
-    { 352, 52, 4 , 4 },
-    { 364, 52, 5 , 7 },
-    { 377, 52, 0 , 0 },
-    { 385, 52, 0 , 0 },
-    { 393, 52, 5 , 12 },
-    { 406, 52, 5 , 9 },
-    { 419, 52, 7 , 9 },
-    { 434, 52, 1 , 1 },
-    { 443, 52, 5 , 10 },
-    { 456, 52, 0 , 0 },
-    { 464, 52, 0 , 0 },
-    { 472, 52, 6 , 5 },
-    { 486, 52, 9 , 9 },
-    { 4, 76, 9 , 7 },
-    { 21, 76, 5 , 11 },
-    { 34, 76, 5 , 9 },
-    { 47, 76, 5 , 12 },
-    { 60, 76, 5 , 12 },
-    { 73, 76, 5 , 12 },
-    { 86, 76, 6 , 12 },
-    { 100, 76, 5 , 11 },
-    { 113, 76, 5 , 13 },
-    { 126, 76, 9 , 9 },
-    { 143, 76, 5 , 12 },
-    { 156, 76, 5 , 12 },
-    { 169, 76, 5 , 12 },
-    { 182, 76, 5 , 12 },
-    { 195, 76, 5 , 11 },
-    { 208, 76, 2 , 12 },
-    { 218, 76, 2 , 12 },
-    { 228, 76, 3 , 12 },
-    { 239, 76, 3 , 11 },
-    { 250, 76, 6 , 9 },
-    { 264, 76, 6 , 12 },
-    { 278, 76, 5 , 12 },
-    { 291, 76, 5 , 12 },
-    { 304, 76, 5 , 12 },
-    { 317, 76, 6 , 12 },
-    { 331, 76, 5 , 11 },
-    { 344, 76, 5 , 5 },
-    { 357, 76, 7 , 9 },
-    { 372, 76, 5 , 12 },
-    { 385, 76, 5 , 12 },
-    { 398, 76, 5 , 12 },
-    { 411, 76, 5 , 11 },
-    { 424, 76, 5 , 12 },
-    { 437, 76, 5 , 9 },
-    { 450, 76, 5 , 9 },
-    { 463, 76, 5 , 10 },
-    { 476, 76, 5 , 10 },
-    { 489, 76, 5 , 10 },
-    { 4, 100, 6 , 10 },
-    { 18, 100, 5 , 9 },
-    { 31, 100, 5 , 11 },
-    { 44, 100, 9 , 7 },
-    { 61, 100, 5 , 10 },
-    { 74, 100, 5 , 10 },
-    { 87, 100, 5 , 10 },
-    { 100, 100, 5 , 10 },
-    { 113, 100, 5 , 9 },
-    { 126, 100, 2 , 10 },
-    { 136, 100, 2 , 10 },
-    { 146, 100, 3 , 10 },
-    { 157, 100, 3 , 9 },
-    { 168, 100, 6 , 9 },
-    { 182, 100, 6 , 10 },
-    { 196, 100, 5 , 10 },
-    { 209, 100, 5 , 10 },
-    { 222, 100, 5 , 10 },
-    { 235, 100, 6 , 10 },
-    { 249, 100, 5 , 9 },
-    { 262, 100, 5 , 5 },
-    { 275, 100, 7 , 7 },
-    { 290, 100, 5 , 10 },
-    { 303, 100, 5 , 10 },
-    { 316, 100, 5 , 10 },
-    { 329, 100, 5 , 9 },
-    { 342, 100, 5 , 12 },
-    { 355, 100, 5 , 11 },
-    { 368, 100, 5 , 11 },
+    { 258, 52, 5 , 10 },
+    { 271, 52, 7 , 9 },
+    { 286, 52, 6 , 5 },
+    { 300, 52, 5 , 3 },
+    { 313, 52, 7 , 9 },
+    { 328, 52, 4 , 4 },
+    { 340, 52, 5 , 7 },
+    { 353, 52, 5 , 12 },
+    { 366, 52, 5 , 9 },
+    { 379, 52, 7 , 9 },
+    { 394, 52, 1 , 1 },
+    { 403, 52, 5 , 10 },
+    { 416, 52, 6 , 5 },
+    { 430, 52, 9 , 9 },
+    { 447, 52, 9 , 7 },
+    { 464, 52, 5 , 11 },
+    { 477, 52, 5 , 9 },
+    { 490, 52, 5 , 12 },
+    { 4, 76, 5 , 12 },
+    { 17, 76, 5 , 12 },
+    { 30, 76, 6 , 12 },
+    { 44, 76, 5 , 11 },
+    { 57, 76, 5 , 13 },
+    { 70, 76, 9 , 9 },
+    { 87, 76, 5 , 12 },
+    { 100, 76, 5 , 12 },
+    { 113, 76, 5 , 12 },
+    { 126, 76, 5 , 12 },
+    { 139, 76, 5 , 11 },
+    { 152, 76, 2 , 12 },
+    { 162, 76, 2 , 12 },
+    { 172, 76, 3 , 12 },
+    { 183, 76, 3 , 11 },
+    { 194, 76, 6 , 9 },
+    { 208, 76, 6 , 12 },
+    { 222, 76, 5 , 12 },
+    { 235, 76, 5 , 12 },
+    { 248, 76, 5 , 12 },
+    { 261, 76, 6 , 12 },
+    { 275, 76, 5 , 11 },
+    { 288, 76, 5 , 5 },
+    { 301, 76, 7 , 9 },
+    { 316, 76, 5 , 12 },
+    { 329, 76, 5 , 12 },
+    { 342, 76, 5 , 12 },
+    { 355, 76, 5 , 11 },
+    { 368, 76, 5 , 12 },
+    { 381, 76, 5 , 9 },
+    { 394, 76, 5 , 9 },
+    { 407, 76, 5 , 10 },
+    { 420, 76, 5 , 10 },
+    { 433, 76, 5 , 10 },
+    { 446, 76, 6 , 10 },
+    { 460, 76, 5 , 9 },
+    { 473, 76, 5 , 11 },
+    { 486, 76, 9 , 7 },
+    { 4, 100, 5 , 10 },
+    { 17, 100, 5 , 10 },
+    { 30, 100, 5 , 10 },
+    { 43, 100, 5 , 10 },
+    { 56, 100, 5 , 9 },
+    { 69, 100, 2 , 10 },
+    { 79, 100, 2 , 10 },
+    { 89, 100, 3 , 10 },
+    { 100, 100, 3 , 9 },
+    { 111, 100, 6 , 9 },
+    { 125, 100, 6 , 10 },
+    { 139, 100, 5 , 10 },
+    { 152, 100, 5 , 10 },
+    { 165, 100, 5 , 10 },
+    { 178, 100, 6 , 10 },
+    { 192, 100, 5 , 9 },
+    { 205, 100, 5 , 5 },
+    { 218, 100, 7 , 7 },
+    { 233, 100, 5 , 10 },
+    { 246, 100, 5 , 10 },
+    { 259, 100, 5 , 10 },
+    { 272, 100, 5 , 9 },
+    { 285, 100, 5 , 12 },
+    { 298, 100, 5 , 11 },
+    { 311, 100, 5 , 11 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo darkFontGlyphs[189] = {
+static const GlyphInfo darkFontGlyphs[182] = {
     { 32, 0, 0, 4, { 0 }},
     { 33, 2, 4, 5, { 0 }},
     { 34, 2, 4, 7, { 0 }},
@@ -451,25 +443,18 @@
     { 8364, 1, 4, 8, { 0 }},
     { 165, 1, 4, 7, { 0 }},
     { 352, 1, 1, 7, { 0 }},
-    { 167, 0, 0, 0, { 0 }},
     { 353, 1, 3, 7, { 0 }},
     { 169, 1, 4, 9, { 0 }},
-    { 170, 0, 0, 0, { 0 }},
     { 171, 1, 6, 8, { 0 }},
     { 172, 1, 8, 7, { 0 }},
     { 174, 1, 4, 9, { 0 }},
-    { 175, 0, 0, 0, { 0 }},
     { 176, 1, 4, 6, { 0 }},
     { 177, 1, 6, 7, { 0 }},
-    { 178, 0, 0, 0, { 0 }},
-    { 179, 0, 0, 0, { 0 }},
     { 381, 1, 1, 7, { 0 }},
     { 181, 1, 6, 7, { 0 }},
     { 182, 1, 4, 9, { 0 }},
     { 183, 2, 8, 5, { 0 }},
     { 382, 1, 3, 7, { 0 }},
-    { 185, 0, 0, 0, { 0 }},
-    { 186, 0, 0, 0, { 0 }},
     { 187, 1, 6, 8, { 0 }},
     { 338, 1, 4, 11, { 0 }},
     { 339, 1, 6, 11, { 0 }},
@@ -559,29 +544,40 @@
 
     Font font = { 0 };
     font.baseSize = 16;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 182;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, darkFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, darkFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "PixelOperator.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/enefete/style_enefete.h b/raygui/styles/enefete/style_enefete.h
--- a/raygui/styles/enefete/style_enefete.h
+++ b/raygui/styles/enefete/style_enefete.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,23 +15,23 @@
 
 // Custom style name: Enefete
 static const GuiStyleProp enefeteStyleProps[ENEFETE_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x1980d5ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x4df3ebff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x103e60ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xe7e2f7ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x23d4ddff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xf1f1f1ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x6413a6ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xea66d9ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x9f00bbff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x4b909eff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x73c7d0ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x448894ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x1980d5ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x4df3ebff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x103e60ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xe7e2f7ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x23d4ddff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xf1f1f1ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x6413a6ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xea66d9ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x9f00bbff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x4b909eff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x73c7d0ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x448894ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x1d3f6cff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x29c9e5ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "GMSN.ttf" (size: 16, spacing: 0)
@@ -570,27 +570,38 @@
     font.baseSize = 16;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, enefeteFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, enefeteFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "GMSN.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/genesis/style_genesis.h b/raygui/styles/genesis/style_genesis.h
--- a/raygui/styles/genesis/style_genesis.h
+++ b/raygui/styles/genesis/style_genesis.h
@@ -7,155 +7,155 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
-#define GENESIS_STYLE_PROPS_COUNT  23
+#define GENESIS_STYLE_PROPS_COUNT  24
 
 // Custom style name: Genesis
 static const GuiStyleProp genesisStyleProps[GENESIS_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x667384ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x181b1eff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xc2c8d0ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xd3dbdfff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xa7afb0ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0x020202ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x181b1eff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xac3c3cff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xdededeff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x3e4550ff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x2e353dff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x484f57ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x667384ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x181b1eff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xc2c8d0ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xd3dbdfff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xa7afb0ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0x020202ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x181b1eff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xac3c3cff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xdededeff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x3e4550ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x2e353dff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x484f57ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x96a3b4ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x292c33ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
-    { 1, 5, (int)0x97a9aeff },    // LABEL_TEXT_COLOR_FOCUSED 
-    { 4, 5, (int)0xa69a9aff },    // SLIDER_TEXT_COLOR_FOCUSED 
-    { 4, 6, (int)0xc3ccd5ff },    // SLIDER_BORDER_COLOR_PRESSED 
-    { 6, 6, (int)0xa7aeb5ff },    // CHECKBOX_BORDER_COLOR_PRESSED 
-    { 9, 5, (int)0xa9a5a5ff },    // TEXTBOX_TEXT_COLOR_FOCUSED 
-    { 10, 5, (int)0xc9c7c7ff },    // VALUEBOX_TEXT_COLOR_FOCUSED 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 5, (int)0x97a9aeff },    // LABEL_TEXT_COLOR_FOCUSED
+    { 4, 5, (int)0xa69a9aff },    // SLIDER_TEXT_COLOR_FOCUSED
+    { 4, 6, (int)0xc3ccd5ff },    // SLIDER_BORDER_COLOR_PRESSED
+    { 6, 5, (int)0xa7afb0ff },    // CHECKBOX_TEXT_COLOR_FOCUSED
+    { 6, 6, (int)0xa7aeb5ff },    // CHECKBOX_BORDER_COLOR_PRESSED
+    { 9, 5, (int)0xa9a5a5ff },    // TEXTBOX_TEXT_COLOR_FOCUSED
+    { 10, 5, (int)0xc9c7c7ff },    // VALUEBOX_TEXT_COLOR_FOCUSED
 };
 
 // WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0)
 
-#define GENESIS_STYLE_FONT_ATLAS_COMP_SIZE 2138
+#define GENESIS_STYLE_FONT_ATLAS_COMP_SIZE 2116
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char genesisFontData[GENESIS_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0xdb, 0x92, 0xa5, 0xba, 0x0d, 0x00, 0x50, 0xff, 0xff, 0x4f, 0x2b, 0x0f, 0xa9, 0x54, 0x32, 0x95, 0xd3, 0x80, 0x64,
-    0xd9, 0x98, 0x9e, 0x35, 0xeb, 0xad, 0x77, 0x4f, 0xc3, 0x36, 0x96, 0x6f, 0x80, 0x1c, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xeb,
-    0xc5, 0x3f, 0xfe, 0x24, 0x7e, 0xfc, 0xcd, 0x78, 0xfc, 0x77, 0xae, 0x7f, 0xfe, 0x9f, 0x4f, 0xe3, 0xe2, 0x58, 0xcf, 0xce,
-    0x35, 0x7b, 0xdc, 0x48, 0x94, 0xc4, 0x3f, 0x9f, 0x5f, 0x3c, 0xfe, 0xbb, 0x3f, 0x7d, 0xbf, 0xfc, 0xef, 0x5f, 0xfd, 0xa5,
-    0xeb, 0xb3, 0x8f, 0x54, 0xb9, 0xe7, 0xff, 0x4f, 0xee, 0x2a, 0xc6, 0x92, 0xb2, 0xbf, 0x3f, 0xbb, 0xfc, 0xb9, 0x77, 0xfe,
-    0x9f, 0xb8, 0xf8, 0x3e, 0x95, 0xab, 0xf4, 0x24, 0xb6, 0x4e, 0x88, 0xff, 0x78, 0x14, 0x89, 0xd1, 0x5a, 0x73, 0xfe, 0x7b,
-    0xd4, 0x68, 0x6c, 0xa9, 0xaa, 0x25, 0x79, 0x15, 0xe9, 0xf9, 0xf2, 0xb8, 0xaa, 0xfd, 0xf9, 0x16, 0x30, 0x5a, 0xbe, 0xcb,
-    0x7c, 0x6d, 0x8c, 0xe9, 0xdf, 0x7e, 0x56, 0x93, 0x7a, 0xbe, 0xd5, 0xcc, 0x27, 0xa3, 0xe5, 0x2a, 0xbd, 0x11, 0xff, 0x51,
-    0x6e, 0xa9, 0x22, 0x19, 0xd1, 0x1d, 0x25, 0x58, 0x69, 0x87, 0xc7, 0xc6, 0xf8, 0x8f, 0xd6, 0xb1, 0x4b, 0xb4, 0xd5, 0xb9,
-    0x37, 0xe2, 0xff, 0xba, 0xd7, 0x1e, 0x2d, 0xf5, 0x26, 0x6e, 0xca, 0xa8, 0x37, 0x96, 0xd7, 0x8e, 0x53, 0x57, 0xc7, 0xff,
-    0xf5, 0x6f, 0x66, 0xfb, 0xdb, 0x48, 0xf6, 0xdd, 0x1d, 0xe5, 0x54, 0xeb, 0xff, 0xfb, 0xcb, 0x31, 0x7e, 0xec, 0x9b, 0xab,
-    0xe3, 0x90, 0x4c, 0x09, 0x47, 0x72, 0x76, 0x35, 0xdb, 0xc3, 0xbe, 0xd9, 0xff, 0x3f, 0x1b, 0x0b, 0x8a, 0xff, 0xb5, 0xf1,
-    0x5f, 0xf9, 0x26, 0xf1, 0xf0, 0x0c, 0x2a, 0x7d, 0xe2, 0x38, 0x20, 0xfe, 0xb3, 0xed, 0xd0, 0x75, 0x59, 0x75, 0x8d, 0xe5,
-    0xb3, 0xeb, 0x12, 0xcf, 0x66, 0xd8, 0xfb, 0x6a, 0x61, 0x7e, 0x6c, 0x94, 0x8f, 0xff, 0x7c, 0xeb, 0x79, 0xf7, 0xd7, 0xb2,
-    0xa5, 0xfa, 0xf3, 0xcc, 0x6e, 0xbe, 0xc4, 0xf7, 0xc5, 0x7f, 0x14, 0xfa, 0x94, 0xf7, 0xe3, 0xb9, 0x27, 0xfe, 0xa3, 0xb0,
-    0x72, 0x31, 0xda, 0x56, 0xf9, 0x6a, 0xeb, 0x12, 0x7d, 0x6b, 0x06, 0xef, 0x5f, 0x81, 0xfb, 0xf8, 0xbf, 0x9b, 0x0f, 0xbe,
-    0xdf, 0xff, 0xc7, 0x11, 0xfd, 0x7f, 0x94, 0xd7, 0x86, 0x47, 0xa1, 0xf5, 0xfd, 0x5a, 0xfc, 0x47, 0x21, 0x66, 0xa2, 0x65,
-    0x5e, 0x3e, 0x96, 0xac, 0xe5, 0xf5, 0xae, 0x19, 0xee, 0xb9, 0x5a, 0x77, 0xbd, 0x68, 0xd7, 0xac, 0xe6, 0x77, 0xc5, 0xff,
-    0x68, 0xe8, 0xff, 0x9f, 0x8d, 0x01, 0x66, 0xbf, 0x47, 0x7c, 0xac, 0xf7, 0xef, 0x8c, 0xff, 0x5d, 0x2b, 0xf6, 0xeb, 0x6b,
-    0x63, 0x1c, 0x71, 0x65, 0xac, 0xff, 0x77, 0x8e, 0xff, 0xeb, 0x6b, 0x00, 0xb9, 0x79, 0x4c, 0x1c, 0x1a, 0xfd, 0x95, 0x39,
-    0x73, 0xd7, 0x1d, 0xfb, 0xde, 0xa7, 0x09, 0xa2, 0xf0, 0xac, 0x46, 0xcf, 0x2a, 0xce, 0xea, 0x6b, 0x90, 0xef, 0xff, 0x77,
-    0xdd, 0xff, 0xbf, 0x1f, 0x73, 0x9f, 0xd1, 0xff, 0x8f, 0xdb, 0xde, 0xfd, 0x94, 0xf3, 0x01, 0xf6, 0xb6, 0x00, 0x21, 0xfa,
-    0xc1, 0x73, 0xc4, 0x80, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x9f, 0xcf,
-    0xef, 0xcf, 0x63, 0x90, 0xcf, 0x84, 0xbd, 0x3e, 0x03, 0xfb, 0x4c, 0x4e, 0xe0, 0x6a, 0x09, 0x75, 0xfd, 0xc5, 0xeb, 0xdc,
-    0xf1, 0x99, 0x4c, 0x0b, 0xcf, 0x6b, 0x46, 0xa4, 0x77, 0x3f, 0xe8, 0xcc, 0x28, 0x50, 0xc9, 0x69, 0x30, 0x92, 0x75, 0xa2,
-    0x37, 0x97, 0x52, 0xee, 0xec, 0xf7, 0xd4, 0xf8, 0x2f, 0xc4, 0xff, 0xfb, 0x9f, 0x8c, 0x42, 0xfe, 0x9e, 0x9d, 0xf1, 0x9f,
-    0xad, 0x7b, 0xb5, 0xfc, 0xb8, 0x73, 0x7d, 0xc9, 0xee, 0x8c, 0x62, 0xd1, 0x78, 0x0d, 0xf7, 0xf5, 0xab, 0x7f, 0xe6, 0xd0,
-    0xd9, 0x51, 0xaf, 0x67, 0xe2, 0x3f, 0x9b, 0xfb, 0x34, 0x2e, 0x5a, 0xe1, 0x73, 0xe2, 0x7f, 0x6c, 0x89, 0xff, 0xf8, 0x48,
-    0xfc, 0x77, 0x67, 0x92, 0xe9, 0xca, 0x42, 0x5e, 0xc9, 0x7c, 0x93, 0xbf, 0x86, 0xf5, 0x0c, 0xbf, 0xd5, 0x1a, 0xf7, 0x9d,
-    0xf8, 0xaf, 0xd4, 0xad, 0xeb, 0x3c, 0xab, 0xe2, 0xff, 0xbe, 0x6c, 0x2b, 0xbd, 0xc9, 0xfc, 0xcf, 0x7b, 0x22, 0x7f, 0x4f,
-    0x1e, 0xdd, 0xbb, 0x7d, 0xb4, 0xd6, 0xd6, 0x95, 0xd9, 0xbe, 0xf2, 0x2b, 0xf1, 0x1f, 0xc5, 0xbf, 0x12, 0x37, 0x2d, 0x4a,
-    0x6f, 0x06, 0xf6, 0x9e, 0xac, 0x6d, 0x7b, 0xe3, 0xbf, 0x7b, 0xdf, 0x9f, 0x33, 0xe2, 0xff, 0xfd, 0x3c, 0xba, 0xab, 0xe6,
-    0x70, 0xbd, 0x7d, 0xe5, 0xef, 0xee, 0xff, 0xef, 0x5b, 0xc9, 0x1d, 0xf5, 0x63, 0xa6, 0xa7, 0x7f, 0xb3, 0xff, 0x7f, 0xef,
-    0xe7, 0xef, 0xc6, 0x7f, 0x57, 0x6d, 0x8f, 0x8d, 0x23, 0x93, 0x6a, 0x5f, 0xb9, 0x73, 0x95, 0x6c, 0xf7, 0xfc, 0x7f, 0xd5,
-    0x37, 0x1b, 0xe9, 0xd1, 0x44, 0x1c, 0x1b, 0xff, 0x33, 0xab, 0x90, 0xeb, 0xc6, 0x0b, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0xdb,
-    0x56, 0x76, 0x05, 0x3c, 0xad, 0xff, 0xdf, 0x75, 0x97, 0x6c, 0x6c, 0x8e, 0xc9, 0xbd, 0xc7, 0xea, 0xdc, 0xa5, 0x2e, 0x9f,
-    0xbf, 0x3f, 0x9a, 0x47, 0x78, 0x5f, 0x8f, 0xff, 0xfa, 0x2a, 0xff, 0x68, 0x5a, 0x95, 0x7c, 0x6f, 0xfc, 0xbf, 0x7b, 0xa7,
-    0x93, 0xca, 0x51, 0x7a, 0xda, 0xdf, 0x67, 0x77, 0x85, 0x7b, 0x7b, 0x81, 0x9f, 0xef, 0x36, 0x44, 0x53, 0xcf, 0xd1, 0x95,
-    0xbf, 0xff, 0xcf, 0x73, 0xcb, 0xef, 0x78, 0x96, 0xbf, 0x13, 0x1f, 0xc9, 0xfd, 0xf4, 0xdf, 0x88, 0xff, 0xca, 0x91, 0x2b,
-    0xff, 0x2b, 0x7b, 0x0d, 0x3b, 0xe3, 0xff, 0xbd, 0x16, 0x40, 0xde, 0x4d, 0x38, 0x71, 0x14, 0x03, 0xfc, 0x9e, 0x16, 0xc0,
-    0x0e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xee, 0x37, 0xb1, 0x7f, 0xce,
-    0xcd, 0x55, 0xc9, 0x1a, 0x9f, 0x7f, 0x4f, 0x7a, 0x67, 0xc6, 0xfc, 0x71, 0x93, 0x85, 0xec, 0xfa, 0xb7, 0xfe, 0xfc, 0xa4,
-    0x23, 0x1f, 0x6f, 0x34, 0xbe, 0xb5, 0x9e, 0xc9, 0xe5, 0x1d, 0x85, 0x6c, 0x03, 0x57, 0x6f, 0xc6, 0xe6, 0xae, 0x41, 0xee,
-    0x18, 0xd1, 0x9e, 0xcf, 0x2c, 0xd2, 0xd9, 0x63, 0xfe, 0xf7, 0x9c, 0x9f, 0x67, 0xfa, 0x8d, 0xf2, 0x9b, 0xc6, 0x77, 0xb9,
-    0xcc, 0xf2, 0xf9, 0x11, 0x2a, 0x39, 0xf3, 0xf2, 0x79, 0x36, 0x4f, 0xcf, 0x98, 0x3f, 0x9f, 0x79, 0x27, 0x6e, 0xea, 0xe4,
-    0xf3, 0x5a, 0xfa, 0x24, 0x73, 0x44, 0x4f, 0x06, 0xa1, 0xda, 0x37, 0x8e, 0xe9, 0xda, 0x5a, 0xb9, 0xde, 0x99, 0x23, 0xc4,
-    0xf4, 0xfb, 0xfc, 0x95, 0xfa, 0x1e, 0x93, 0xd7, 0xbd, 0xfe, 0x8d, 0x67, 0xb2, 0x10, 0x44, 0xa9, 0xa7, 0xeb, 0x2c, 0xc1,
-    0xeb, 0x4f, 0xf2, 0x19, 0x33, 0xe3, 0x61, 0x7c, 0x75, 0xff, 0x74, 0x24, 0xdb, 0x9b, 0x4a, 0xbe, 0xba, 0x99, 0x5d, 0x33,
-    0xe6, 0xc6, 0x88, 0xe3, 0x22, 0xbb, 0x52, 0x3e, 0xfa, 0x7f, 0xee, 0x6f, 0x62, 0x32, 0xfe, 0xa3, 0x98, 0x59, 0xa8, 0x1e,
-    0x23, 0xd9, 0xf8, 0x9f, 0xbf, 0x0a, 0xbb, 0xe2, 0xbf, 0x92, 0xf5, 0xe0, 0xfd, 0x8c, 0xd9, 0xb5, 0x9e, 0x70, 0x6f, 0xfc,
-    0xc7, 0x83, 0xf6, 0x6b, 0xa4, 0xe7, 0x2f, 0xa3, 0x90, 0xe1, 0xfc, 0xf9, 0xec, 0x22, 0x5a, 0xfb, 0xff, 0x71, 0x59, 0x26,
-    0xf1, 0xc2, 0xf8, 0xbf, 0xb6, 0xdf, 0x5b, 0x2e, 0xfe, 0x67, 0x5a, 0xa7, 0xfd, 0xfd, 0x7f, 0xad, 0x5f, 0x3b, 0xb9, 0xff,
-    0x7f, 0x27, 0x63, 0x76, 0x14, 0xe6, 0xd9, 0x95, 0xe3, 0xc6, 0xe4, 0xc8, 0xe0, 0xd9, 0x5c, 0x30, 0x1a, 0xe6, 0xab, 0x1d,
-    0xf1, 0xdf, 0x3f, 0xc2, 0xae, 0xcc, 0xad, 0x6a, 0xfd, 0x7f, 0xb4, 0xce, 0xff, 0x23, 0xdd, 0xce, 0xcf, 0xc5, 0x7f, 0xe7,
-    0x6e, 0x4b, 0x2b, 0x32, 0xe6, 0xe6, 0x77, 0x76, 0x7c, 0xab, 0xff, 0x1f, 0xa5, 0xfe, 0xbf, 0xd6, 0x7b, 0xcd, 0xd4, 0xca,
-    0xd8, 0x90, 0xeb, 0x2e, 0x37, 0xfe, 0x5f, 0x3d, 0xca, 0xce, 0xcf, 0x28, 0x63, 0x53, 0xfb, 0xd4, 0x3d, 0xf7, 0xab, 0x45,
-    0x4b, 0xa4, 0xc7, 0xd7, 0x3b, 0x33, 0xe6, 0x56, 0xd6, 0x9e, 0xcf, 0x8f, 0xff, 0xce, 0x3d, 0x4c, 0x2a, 0x77, 0x17, 0xa2,
-    0xa1, 0x6f, 0x5e, 0xdd, 0xff, 0xcf, 0xce, 0xff, 0x2b, 0xb9, 0xf4, 0xf7, 0xac, 0xff, 0x8d, 0xa5, 0x6b, 0x3f, 0xd1, 0x7a,
-    0x3f, 0x71, 0x1c, 0xd0, 0x7e, 0x77, 0x66, 0x89, 0x7f, 0x63, 0xfe, 0xdf, 0x95, 0x81, 0x7d, 0x94, 0xef, 0x09, 0xd5, 0xd7,
-    0xff, 0x67, 0x6b, 0x60, 0x1c, 0xd3, 0xf7, 0x8f, 0xc7, 0x7b, 0xe8, 0xc4, 0x4b, 0xd1, 0x7f, 0x5a, 0xfc, 0x9f, 0xf2, 0x44,
-    0x43, 0x47, 0xbb, 0x15, 0x2d, 0xad, 0x5b, 0x65, 0xdf, 0x96, 0xce, 0x71, 0xd4, 0xfc, 0xfc, 0x7f, 0xcd, 0xba, 0xfa, 0x1b,
-    0xc7, 0x98, 0xb9, 0x23, 0x3b, 0x1f, 0xff, 0xb1, 0xbc, 0xe4, 0xe4, 0x23, 0xfe, 0x4e, 0x2b, 0x75, 0xde, 0xf1, 0xfe, 0xe6,
-    0xda, 0x13, 0x1b, 0x9f, 0xb5, 0x13, 0xa1, 0xc4, 0xd1, 0xf3, 0x21, 0xd7, 0x03, 0xfe, 0xe6, 0xf9, 0xd0, 0xdf, 0xfa, 0x1c,
-    0xbc, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x7d, 0x3b, 0xa4, 0x92, 0x59,
-    0x72, 0x34, 0xbf, 0x8b, 0x9e, 0xcf, 0xad, 0x5f, 0x3d, 0xbb, 0xbb, 0xf7, 0xa5, 0x6b, 0xf9, 0x79, 0x6b, 0xe5, 0x34, 0x97,
-    0x8f, 0x28, 0x97, 0x53, 0xed, 0x7e, 0xff, 0x83, 0x38, 0xf2, 0x6a, 0xde, 0x65, 0x75, 0x8d, 0x42, 0x3e, 0xd5, 0xce, 0xeb,
-    0x35, 0x4a, 0x65, 0xb7, 0xab, 0x96, 0x3d, 0x7f, 0x3b, 0x34, 0x36, 0xbc, 0x4f, 0x59, 0x8b, 0x85, 0x5a, 0x6e, 0xc3, 0xb9,
-    0xdc, 0x61, 0xb1, 0xf8, 0x9b, 0xe5, 0xca, 0x6f, 0x7e, 0x3f, 0x89, 0xfb, 0x6c, 0xab, 0xf1, 0xb9, 0xab, 0x59, 0xcd, 0xf8,
-    0xde, 0x7d, 0xbd, 0xea, 0xb5, 0xe5, 0x84, 0x5a, 0xb6, 0x7e, 0x67, 0x89, 0x37, 0xde, 0x6e, 0xad, 0x66, 0xc4, 0x8d, 0xcf,
-    0xbf, 0x73, 0x1a, 0x1f, 0xcd, 0x05, 0x50, 0xcb, 0x13, 0xb9, 0xeb, 0x5b, 0x55, 0x8e, 0x14, 0xa5, 0x3d, 0x9b, 0xc6, 0xf6,
-    0xec, 0x10, 0xf9, 0xec, 0xe7, 0xa3, 0x94, 0xef, 0xb3, 0xfb, 0x93, 0xca, 0x15, 0xa9, 0xc7, 0xff, 0x55, 0x39, 0x55, 0x3e,
-    0x99, 0xed, 0xff, 0xc7, 0xf2, 0x7d, 0x18, 0x4e, 0xb9, 0x9a, 0x77, 0xfd, 0x7f, 0xb4, 0xed, 0x98, 0xb4, 0xf7, 0x93, 0x1d,
-    0xe5, 0xda, 0x11, 0x0b, 0xbb, 0xf6, 0xfb, 0x8b, 0x74, 0xad, 0x18, 0xe9, 0x1c, 0x7b, 0xf5, 0xd9, 0xd7, 0xae, 0x4f, 0x56,
-    0xc4, 0x7f, 0x5c, 0xcc, 0x93, 0xbb, 0x77, 0x1d, 0xeb, 0xbe, 0x9a, 0x4f, 0x5a, 0x86, 0x2f, 0xc6, 0xff, 0x8e, 0xf8, 0x99,
-    0x9d, 0xff, 0x47, 0x79, 0x37, 0x9d, 0x33, 0x6b, 0x4c, 0x3c, 0xcc, 0xe8, 0xfc, 0xdb, 0xe2, 0x7f, 0x6f, 0x19, 0x77, 0xb7,
-    0xe6, 0xd7, 0x23, 0xec, 0xf1, 0xd1, 0xf8, 0x9f, 0xdd, 0xef, 0x6d, 0x7e, 0xee, 0x7a, 0xbf, 0xfe, 0xdf, 0xb9, 0xb2, 0x71,
-    0x46, 0xfc, 0x9f, 0x12, 0xe5, 0xb9, 0x32, 0x5f, 0x1b, 0xff, 0xef, 0xc7, 0x50, 0x57, 0x1f, 0xf6, 0xde, 0xb9, 0x47, 0xdb,
-    0xfc, 0xff, 0x7e, 0x97, 0xe4, 0xdc, 0xdd, 0x9d, 0xbd, 0xab, 0x49, 0x3b, 0x4b, 0xbd, 0x73, 0xcf, 0xe1, 0xa7, 0x63, 0x87,
-    0xee, 0xf9, 0xee, 0x19, 0xfd, 0x7f, 0x88, 0xff, 0x05, 0x6b, 0xe1, 0x27, 0xf4, 0x92, 0xab, 0xee, 0xe5, 0xe5, 0xb3, 0xd8,
-    0xf7, 0x7e, 0x32, 0x5b, 0x52, 0xf9, 0xfb, 0xff, 0x5f, 0x1f, 0xff, 0x3f, 0xd9, 0xe1, 0xe7, 0x5b, 0xf1, 0x1f, 0xc5, 0x15,
-    0xc5, 0x33, 0xe2, 0x3f, 0x36, 0x8e, 0x6a, 0x57, 0xdc, 0xcb, 0x3f, 0x79, 0xfc, 0xdf, 0xbf, 0x13, 0xd4, 0xd7, 0xe3, 0xff,
-    0x0b, 0x63, 0xe8, 0x35, 0x4f, 0xa1, 0xbc, 0x17, 0xff, 0x73, 0x77, 0x86, 0x4f, 0x1e, 0xff, 0x9f, 0x1e, 0xff, 0xb3, 0x57,
-    0x25, 0x36, 0xcd, 0xff, 0x9f, 0x8e, 0x34, 0x7e, 0x7f, 0xfc, 0x8f, 0xad, 0x7b, 0xf7, 0xd7, 0xe7, 0x9b, 0xe3, 0xd0, 0x67,
-    0x61, 0xce, 0x79, 0x8a, 0xe3, 0xfd, 0x99, 0xcd, 0xfc, 0xae, 0xa8, 0xeb, 0xef, 0xff, 0x8f, 0x65, 0xfd, 0x7f, 0xef, 0x93,
-    0x2d, 0xbb, 0xee, 0xff, 0xef, 0x7d, 0xa2, 0xa8, 0xfb, 0x0c, 0xc5, 0xff, 0x37, 0xda, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x73, 0xf2, 0x2b, 0x72, 0xeb, 0xf7, 0xe7, 0xc3, 0x38, 0x3d, 0xb7, 0xfe,
-    0xdd, 0xfb, 0x33, 0xe3, 0xd8, 0xdc, 0xfa, 0xe3, 0x51, 0x8e, 0xa2, 0xef, 0xe5, 0xd6, 0xf7, 0xee, 0xc7, 0xd3, 0xb7, 0x64,
-    0xd6, 0xe5, 0xd6, 0xef, 0x7b, 0x87, 0xfa, 0xf4, 0xdc, 0xfa, 0xe3, 0x26, 0x13, 0xd1, 0xc9, 0xb9, 0xf5, 0xeb, 0x6f, 0x51,
-    0x9d, 0x9a, 0x5b, 0x9f, 0xb5, 0xef, 0x4e, 0x3e, 0x6d, 0xfb, 0xe3, 0xc5, 0x6b, 0xf6, 0x46, 0x36, 0x84, 0x93, 0x6b, 0x64,
-    0x3e, 0x5b, 0xd3, 0x8a, 0x16, 0xa5, 0xf3, 0x7d, 0xcd, 0xb3, 0x73, 0xeb, 0x7f, 0x3d, 0xc6, 0xeb, 0xd9, 0x58, 0xa3, 0x9c,
-    0xf3, 0xbe, 0xef, 0x5d, 0xed, 0x48, 0x8d, 0x1b, 0xd7, 0xe6, 0xd6, 0xba, 0x6e, 0x47, 0xcf, 0xdd, 0x29, 0xe1, 0xdb, 0xb9,
-    0xb5, 0xc5, 0x7f, 0x4f, 0xab, 0x1b, 0x4d, 0x51, 0xf7, 0xf4, 0x93, 0x7d, 0x59, 0x83, 0xfa, 0xe2, 0x3f, 0xda, 0x3f, 0xdb,
-    0x9b, 0x5b, 0xab, 0xba, 0x9e, 0x20, 0xfe, 0x7f, 0x57, 0x3b, 0x90, 0x99, 0xd1, 0x3e, 0x29, 0xf7, 0x37, 0x6b, 0xc0, 0xce,
-    0xdc, 0x5a, 0x5f, 0x8f, 0xff, 0x4a, 0xff, 0x20, 0xfe, 0x7f, 0xcf, 0xf8, 0xbf, 0xaf, 0x2f, 0xaf, 0xaf, 0xff, 0x7f, 0x79,
-    0x6f, 0xad, 0xdf, 0x19, 0xff, 0x67, 0xe4, 0xd6, 0x15, 0xff, 0xef, 0x8c, 0xff, 0x6b, 0xfb, 0x13, 0xac, 0x58, 0xcd, 0xed,
-    0x9d, 0x4d, 0x88, 0xff, 0xd5, 0x75, 0xe7, 0xa4, 0x9d, 0x21, 0xc4, 0x78, 0x7d, 0xfe, 0x5f, 0xdb, 0x13, 0xb4, 0xda, 0x02,
-    0xec, 0xcb, 0xd5, 0xfa, 0x46, 0x6e, 0x7d, 0xb9, 0x75, 0x67, 0xae, 0xd7, 0xf5, 0xe8, 0xef, 0x9b, 0xf7, 0x63, 0x4e, 0x1f,
-    0xff, 0xf7, 0xde, 0xab, 0xf9, 0xff, 0x35, 0xa5, 0xd5, 0x2b, 0xde, 0xab, 0xc6, 0xff, 0x2b, 0xda, 0xd8, 0x37, 0x4b, 0x63,
-    0xcd, 0xbd, 0xa3, 0xfe, 0x33, 0x8c, 0xa6, 0xd1, 0x1f, 0xef, 0xb4, 0x1a, 0xb0, 0x66, 0x9c, 0xf1, 0x7e, 0x4b, 0x08, 0x7c,
-    0xed, 0x49, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xdd, 0x49, 0xb2, 0xe3, 0x36, 0x0c, 0x00, 0x50, 0xde, 0xff, 0xd2, 0xc8, 0x22, 0x95, 0x4a, 0xba, 0x2a, 0x96, 0x44, 0x10,
+    0x1c, 0x64, 0xbf, 0x7e, 0xbb, 0x6f, 0xb7, 0x6d, 0x51, 0x04, 0x27, 0x49, 0x60, 0x34, 0x00, 0x00, 0x00, 0xe0, 0xe7, 0xc5,
+    0xff, 0xfe, 0x25, 0x3e, 0xbe, 0x33, 0x1e, 0x7f, 0xce, 0xf5, 0xdf, 0xff, 0x79, 0x35, 0x2e, 0xbe, 0xeb, 0xd9, 0x6f, 0xed,
+    0xfd, 0xde, 0xe8, 0x28, 0x89, 0xff, 0xff, 0x7d, 0xf1, 0xf8, 0x73, 0x3f, 0x1d, 0x5f, 0xff, 0xfb, 0xaf, 0x3e, 0xe9, 0xfa,
+    0xd7, 0x47, 0x57, 0xb9, 0xf7, 0xff, 0x9f, 0xbe, 0xb3, 0x18, 0x53, 0xca, 0xfe, 0xfe, 0xd7, 0xf5, 0xff, 0xf6, 0xca, 0xff,
+    0x13, 0x17, 0xc7, 0x93, 0x39, 0x4b, 0x4f, 0x62, 0xeb, 0x84, 0xf8, 0x8f, 0x47, 0x91, 0x18, 0xa5, 0x35, 0xe7, 0xdf, 0x6f,
+    0x8d, 0xc2, 0x96, 0x2a, 0x5b, 0x92, 0x57, 0x91, 0xde, 0x5f, 0x1e, 0x57, 0xb5, 0xbf, 0xbf, 0x05, 0x8c, 0x92, 0x63, 0x19,
+    0xaf, 0x8d, 0x31, 0xfc, 0xee, 0x67, 0x35, 0xa9, 0xe6, 0xa8, 0x46, 0x5e, 0x69, 0x25, 0x67, 0x69, 0x47, 0xfc, 0x47, 0xba,
+    0xa5, 0x8a, 0xce, 0x88, 0xae, 0x28, 0xc1, 0x4c, 0x3b, 0xdc, 0x16, 0xc6, 0x7f, 0x94, 0x8e, 0x5d, 0xa2, 0xac, 0xce, 0xed,
+    0x88, 0xff, 0xeb, 0x5e, 0xbb, 0x95, 0xd4, 0x9b, 0xb8, 0x29, 0xa3, 0xda, 0x58, 0x9e, 0x3b, 0x4e, 0x9d, 0x1d, 0xff, 0xd7,
+    0xef, 0xec, 0xed, 0x6f, 0xa3, 0xb3, 0xef, 0xae, 0x28, 0xa7, 0x5c, 0xff, 0x5f, 0x5f, 0x8e, 0xf1, 0xb1, 0x6f, 0xce, 0x8e,
+    0x43, 0x7a, 0x4a, 0x38, 0x3a, 0x67, 0x57, 0xa3, 0x3d, 0xec, 0xce, 0xfe, 0xff, 0xd9, 0x58, 0x50, 0xfc, 0xcf, 0x8d, 0xff,
+    0xcc, 0x91, 0xc4, 0xc3, 0x5f, 0x90, 0xe9, 0x13, 0xdb, 0x01, 0xf1, 0xdf, 0xdb, 0x0e, 0x5d, 0x97, 0x55, 0xd5, 0x58, 0xbe,
+    0x77, 0x5d, 0xe2, 0xd9, 0x0c, 0x7b, 0x5d, 0x2d, 0xec, 0x1f, 0x1b, 0xf5, 0xc7, 0x7f, 0x7f, 0xeb, 0x79, 0xf7, 0x69, 0xbd,
+    0xa5, 0xfa, 0x79, 0x66, 0x37, 0x5e, 0xe2, 0xeb, 0xe2, 0x3f, 0x12, 0x7d, 0xca, 0xfe, 0x78, 0xae, 0x89, 0xff, 0x48, 0xac,
+    0x5c, 0xb4, 0xb2, 0x55, 0xbe, 0xdc, 0xba, 0x44, 0xdd, 0x9a, 0xc1, 0xfe, 0x33, 0x70, 0x1f, 0xff, 0x77, 0xf3, 0xc1, 0xfd,
+    0xfd, 0x7f, 0x1c, 0xd1, 0xff, 0x47, 0x7a, 0x6d, 0xb8, 0x25, 0x5a, 0xdf, 0xb7, 0xc5, 0x7f, 0x24, 0x62, 0x26, 0x4a, 0xe6,
+    0xe5, 0x6d, 0xca, 0x5a, 0x5e, 0xed, 0x9a, 0xe1, 0x9a, 0xb3, 0x75, 0xd7, 0x8b, 0x56, 0xcd, 0x6a, 0xbe, 0x2b, 0xfe, 0x5b,
+    0x41, 0xff, 0xff, 0x6c, 0x0c, 0x30, 0x7a, 0x1c, 0xf1, 0xb2, 0xde, 0xbf, 0x32, 0xfe, 0x57, 0xad, 0xd8, 0xcf, 0xaf, 0x8d,
+    0x71, 0xc4, 0x99, 0xb1, 0xfe, 0x5f, 0x39, 0xfe, 0xcf, 0xaf, 0x01, 0xf4, 0xcd, 0x63, 0xe2, 0xd0, 0xe8, 0xcf, 0xcc, 0x99,
+    0xab, 0xae, 0xd8, 0xd7, 0xde, 0x4d, 0x10, 0x89, 0x7b, 0x35, 0x6a, 0x56, 0x71, 0x66, 0x9f, 0x83, 0xfe, 0xfe, 0x7f, 0xd5,
+    0xf5, 0xff, 0xfb, 0x31, 0xf7, 0x19, 0xfd, 0x7f, 0xbb, 0xed, 0xdd, 0x4f, 0xf9, 0x3d, 0xc0, 0xda, 0x16, 0x20, 0x44, 0x3f,
+    0xb8, 0x8f, 0x18, 0x10, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xfd, 0xf9,
+    0xf5, 0x79, 0x0c, 0xfa, 0x33, 0x61, 0xcf, 0xcf, 0xc0, 0x3e, 0x92, 0x13, 0x38, 0x5b, 0x42, 0x55, 0x9f, 0x78, 0x9d, 0x3b,
+    0xbe, 0x27, 0xd3, 0xc2, 0xf3, 0x9a, 0x11, 0xdd, 0xbb, 0x1f, 0x54, 0x66, 0x14, 0xc8, 0xe4, 0x34, 0x68, 0x9d, 0x75, 0xa2,
+    0x36, 0x97, 0x52, 0xdf, 0xaf, 0x5f, 0x53, 0xe3, 0xdf, 0x10, 0xff, 0xfb, 0x5f, 0x69, 0x89, 0xfc, 0x3d, 0x2b, 0xe3, 0xbf,
+    0xb7, 0xee, 0xe5, 0xf2, 0xe3, 0x8e, 0xf5, 0x25, 0xab, 0x33, 0x8a, 0x45, 0xe1, 0x39, 0x5c, 0xd7, 0xaf, 0xfe, 0x99, 0x43,
+    0x67, 0x45, 0xbd, 0x1e, 0x89, 0xff, 0xde, 0xdc, 0xa7, 0x71, 0xd1, 0x0a, 0x9f, 0x13, 0xff, 0x6d, 0x49, 0xfc, 0xc7, 0x4b,
+    0xe2, 0xbf, 0x3a, 0x93, 0x4c, 0x55, 0x16, 0xf2, 0x4c, 0xe6, 0x9b, 0xfe, 0x73, 0x98, 0xcf, 0xf0, 0x9b, 0xad, 0x71, 0xef,
+    0x89, 0xff, 0x4c, 0xdd, 0xba, 0xce, 0xb3, 0x2a, 0xfe, 0xef, 0xcb, 0x36, 0xd3, 0x9b, 0x8c, 0xff, 0xbd, 0x26, 0xf2, 0xd7,
+    0xe4, 0xd1, 0xbd, 0xdb, 0x47, 0x6b, 0x6e, 0x5d, 0x19, 0xed, 0x2b, 0xdf, 0x12, 0xff, 0x91, 0xfc, 0x94, 0xb8, 0x69, 0x51,
+    0x6a, 0x33, 0xb0, 0xd7, 0x64, 0x6d, 0x5b, 0x1b, 0xff, 0xd5, 0xfb, 0xfe, 0x9c, 0x11, 0xff, 0xfb, 0xf3, 0xe8, 0xce, 0x9a,
+    0xc3, 0xd5, 0xf6, 0x95, 0xdf, 0xdd, 0xff, 0xdf, 0xb7, 0x92, 0x2b, 0xea, 0xc7, 0x48, 0x4f, 0xbf, 0xb3, 0xff, 0xdf, 0xf7,
+    0xf7, 0xbd, 0xf1, 0x5f, 0x55, 0xdb, 0x63, 0xe1, 0xc8, 0x24, 0xdb, 0x57, 0xae, 0x5c, 0x25, 0x5b, 0x3d, 0xff, 0x9f, 0x75,
+    0x64, 0xad, 0x7b, 0x34, 0x11, 0xc7, 0xc6, 0xff, 0xc8, 0x2a, 0xe4, 0xbc, 0xf1, 0xc2, 0x9e, 0xf1, 0x7f, 0x6e, 0x7f, 0xdb,
+    0xcc, 0xae, 0x80, 0xa7, 0xf5, 0xff, 0xab, 0xae, 0x92, 0xb5, 0xc5, 0x31, 0xb9, 0xf6, 0xbb, 0x2a, 0x77, 0xa9, 0xeb, 0xcf,
+    0xdf, 0x1f, 0xc5, 0x23, 0xbc, 0xb7, 0xc7, 0x7f, 0x7e, 0x95, 0xbf, 0x15, 0xad, 0x4a, 0xee, 0x1b, 0xff, 0xaf, 0xde, 0xe9,
+    0x24, 0xf3, 0x2d, 0x35, 0xed, 0xef, 0xb3, 0xab, 0xc2, 0xb5, 0xbd, 0xc0, 0xe7, 0xab, 0x0d, 0x51, 0xd4, 0x73, 0x54, 0xe5,
+    0xef, 0xff, 0xf3, 0xb7, 0xf5, 0xef, 0x78, 0xd6, 0x7f, 0x25, 0x3e, 0x3a, 0xf7, 0xd3, 0xdf, 0x11, 0xff, 0x99, 0x6f, 0xce,
+    0xfc, 0xaf, 0xde, 0x73, 0x58, 0x19, 0xff, 0xfb, 0x5a, 0x00, 0x79, 0x37, 0xe1, 0xc4, 0x51, 0x0c, 0xf0, 0x3d, 0x2d, 0x80,
+    0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd5, 0x4f, 0x62, 0x7f, 0xce,
+    0xcd, 0x95, 0xc9, 0x1a, 0xdf, 0xff, 0x9c, 0xf4, 0xca, 0x8c, 0xf9, 0xed, 0x26, 0x0b, 0xd9, 0xf5, 0xbb, 0xfe, 0x7c, 0xa5,
+    0x22, 0x1f, 0x6f, 0x14, 0x3e, 0xb5, 0x9e, 0xcb, 0x2d, 0x1a, 0x37, 0xcf, 0xda, 0x47, 0xa2, 0x8c, 0xfb, 0xcb, 0xff, 0xee,
+    0x09, 0xfe, 0x96, 0xcc, 0x13, 0xf4, 0x3c, 0xf3, 0xff, 0x93, 0x7c, 0x2e, 0xd7, 0xdf, 0x12, 0xb7, 0x19, 0xff, 0xfb, 0xf3,
+    0xbe, 0xd6, 0x65, 0x72, 0xcb, 0xe4, 0xcc, 0xeb, 0xcf, 0xb3, 0x79, 0x7a, 0xc6, 0xfc, 0xf1, 0xcc, 0x3b, 0x71, 0x53, 0x87,
+    0xfb, 0xcf, 0xe1, 0xfc, 0x3c, 0x46, 0xcf, 0xde, 0xdf, 0x5f, 0xfb, 0xf3, 0xe7, 0xb3, 0xf6, 0xd7, 0x5f, 0xd7, 0xcf, 0x28,
+    0x39, 0x4f, 0x91, 0xca, 0x0a, 0x10, 0xd3, 0xf2, 0x07, 0x44, 0x61, 0xfc, 0x67, 0x5a, 0x99, 0xfd, 0x19, 0x33, 0x23, 0xd5,
+    0x46, 0xd6, 0x64, 0xde, 0xea, 0x69, 0x6f, 0x32, 0xf9, 0xea, 0x62, 0x51, 0x26, 0x8a, 0xff, 0xb6, 0x66, 0x99, 0x6c, 0x8a,
+    0x9f, 0xfb, 0x93, 0xe8, 0x8c, 0xff, 0x48, 0xe4, 0xfc, 0xa9, 0x8d, 0xff, 0xfb, 0x52, 0x9a, 0x11, 0xff, 0x51, 0x5a, 0x03,
+    0xb3, 0xfd, 0x7f, 0xff, 0x08, 0x75, 0x7f, 0xc6, 0xec, 0x5c, 0xc9, 0xad, 0x8d, 0xff, 0x78, 0xd0, 0x7e, 0xf5, 0x8f, 0x9f,
+    0x33, 0x7b, 0x7c, 0xc5, 0x6d, 0xdb, 0x9a, 0xeb, 0xff, 0xdb, 0xe5, 0x31, 0x47, 0xc1, 0xf8, 0x3f, 0xb7, 0x3f, 0x5b, 0x5f,
+    0xfc, 0xc7, 0x6d, 0xb6, 0xf9, 0xd1, 0xfe, 0x3f, 0x93, 0x1f, 0x35, 0x97, 0x97, 0xae, 0x32, 0xfe, 0xb3, 0xe3, 0xe8, 0xdd,
+    0xfd, 0xff, 0x9e, 0x8c, 0xd9, 0x91, 0x98, 0x77, 0x67, 0xbe, 0xb7, 0xb6, 0xec, 0x9f, 0xd4, 0xc0, 0x28, 0x8c, 0xff, 0xec,
+    0x98, 0x36, 0x9b, 0xed, 0x31, 0x86, 0xcf, 0xe0, 0x7d, 0x89, 0x47, 0xaa, 0x8f, 0x6a, 0x13, 0xf2, 0xd2, 0x56, 0xc6, 0x7f,
+    0xe5, 0x6e, 0x4b, 0x33, 0x32, 0xe6, 0xf6, 0xef, 0xec, 0xb8, 0xab, 0xff, 0x6f, 0xa9, 0xfe, 0x3f, 0xd7, 0x1b, 0xf6, 0xce,
+    0x26, 0x66, 0xec, 0x01, 0x56, 0x37, 0xf6, 0xce, 0xc6, 0x7f, 0xa6, 0xed, 0xaa, 0x9b, 0x53, 0xf7, 0xcc, 0xff, 0x23, 0x3d,
+    0x86, 0x8d, 0xc2, 0xf5, 0xff, 0x9a, 0xf1, 0xff, 0xea, 0x8c, 0xb9, 0x99, 0xb5, 0xe9, 0xf3, 0xe3, 0xbf, 0x72, 0x0f, 0x93,
+    0x27, 0x57, 0x13, 0x22, 0xb5, 0x0b, 0x68, 0x6d, 0xff, 0x1f, 0x89, 0x11, 0xd1, 0xdd, 0x8a, 0x41, 0xcd, 0xfa, 0x5f, 0x1b,
+    0x5a, 0x8b, 0xb9, 0x5f, 0xff, 0xcf, 0xaf, 0x86, 0xc6, 0x82, 0x75, 0xc3, 0xeb, 0x23, 0xdb, 0x7b, 0x3d, 0xb3, 0x66, 0x8c,
+    0xbe, 0x7b, 0xfe, 0x5f, 0x95, 0x81, 0x3d, 0xb3, 0x9f, 0x76, 0x4c, 0xa8, 0x19, 0xb3, 0x3f, 0xf3, 0xf9, 0xa7, 0xf7, 0xc4,
+    0x7f, 0x2c, 0xab, 0x81, 0x33, 0xe7, 0x73, 0x2b, 0xe3, 0xff, 0x94, 0x3b, 0x1a, 0x2a, 0xda, 0xad, 0x28, 0x69, 0xdd, 0x32,
+    0xfb, 0xb6, 0x54, 0x8e, 0xa3, 0xda, 0xc0, 0x1c, 0x2a, 0x26, 0xdc, 0x69, 0x12, 0x93, 0xaf, 0x75, 0xd5, 0xc5, 0x7f, 0x0c,
+    0x1f, 0xe9, 0xc8, 0xf1, 0xf6, 0xdf, 0x03, 0x12, 0xf2, 0x11, 0xbf, 0xa8, 0x95, 0xda, 0xff, 0x7d, 0x6f, 0xae, 0x2d, 0xb1,
+    0xf0, 0xde, 0xb8, 0x78, 0xc5, 0x11, 0xda, 0x8d, 0x40, 0xfd, 0xfd, 0x9d, 0x5a, 0xf1, 0xfd, 0xb5, 0x5c, 0xfc, 0xb3, 0x6f,
+    0x3e, 0xf4, 0x96, 0xfb, 0xd6, 0xd5, 0x76, 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xbf, 0xfc, 0x2c, 0x5a, 0x7f, 0xae, 0xfb, 0x6c, 0xde, 0xf2, 0xa7, 0xf9, 0xd2, 0xc7, 0x9f, 0x7a, 0xbf, 0xff, 0xfb, 0x58,
+    0x7e, 0xa0, 0xbe, 0x1c, 0x67, 0xf7, 0xf9, 0xf0, 0x63, 0xc1, 0x31, 0x57, 0x67, 0x59, 0x8e, 0x8b, 0xdc, 0x41, 0x6b, 0xce,
+    0x57, 0x4b, 0x95, 0xdd, 0xba, 0x5a, 0x36, 0x23, 0x7e, 0xf2, 0x99, 0x2f, 0x32, 0xb1, 0x10, 0xa9, 0xe7, 0x13, 0x6b, 0xf2,
+    0xa5, 0x3f, 0x3d, 0x37, 0xb9, 0x5a, 0xf3, 0xf4, 0xb3, 0x62, 0xf8, 0x93, 0xef, 0xb3, 0x9f, 0x66, 0xb2, 0x04, 0xee, 0x3d,
+    0x9b, 0xd9, 0x0c, 0xec, 0xd5, 0xe7, 0xab, 0x3a, 0x7f, 0xd6, 0xb9, 0x25, 0x1e, 0x47, 0x3d, 0xff, 0x97, 0xcf, 0x68, 0x16,
+    0x07, 0x3c, 0x2b, 0x3f, 0xeb, 0x99, 0xd2, 0x78, 0xe9, 0x13, 0x9b, 0x91, 0xdc, 0x97, 0x67, 0xcd, 0x51, 0xe5, 0x32, 0xde,
+    0x46, 0x3a, 0xa7, 0xe4, 0xa9, 0x25, 0x3e, 0xf2, 0xfb, 0xfb, 0xb3, 0xc3, 0x8f, 0x65, 0x36, 0xae, 0x8d, 0xff, 0xab, 0xbc,
+    0xb7, 0x99, 0x57, 0x46, 0xfb, 0xff, 0x36, 0x7d, 0x5f, 0x84, 0x19, 0xe7, 0x2c, 0x0a, 0xf3, 0x36, 0xdf, 0xed, 0x1c, 0xd7,
+    0x7f, 0xc4, 0x6b, 0x5f, 0x39, 0xb7, 0xc4, 0x9f, 0xf4, 0x5b, 0x95, 0x7b, 0xa5, 0x64, 0xea, 0xe6, 0xb3, 0xdc, 0xeb, 0x9f,
+    0xfe, 0x4f, 0x94, 0x8d, 0xbd, 0xaa, 0x5f, 0x99, 0x11, 0xff, 0x71, 0x31, 0x4f, 0xae, 0xde, 0x05, 0xac, 0xfa, 0x6c, 0x3e,
+    0x69, 0x19, 0xde, 0x18, 0xff, 0xb1, 0x20, 0x4a, 0x22, 0x55, 0xdb, 0xda, 0x94, 0x71, 0xcb, 0x09, 0x35, 0x26, 0x1e, 0x66,
+    0x6c, 0xfe, 0xb6, 0xf8, 0x5f, 0x5b, 0xc6, 0xd5, 0xad, 0xf9, 0x75, 0x6f, 0xd4, 0x5e, 0x1a, 0xff, 0xa3, 0xfb, 0xaf, 0x8d,
+    0xbf, 0x32, 0xbe, 0x87, 0xe6, 0x99, 0xfd, 0x7f, 0xf5, 0x8e, 0x9d, 0x73, 0x5e, 0xe9, 0x99, 0x7b, 0xcd, 0x8d, 0xff, 0xfd,
+    0x31, 0x34, 0x9a, 0x4b, 0x7d, 0xff, 0x6f, 0x8f, 0xb2, 0xf9, 0xff, 0xfd, 0xae, 0xc6, 0x55, 0xaf, 0x64, 0x6a, 0x6f, 0x7e,
+    0xfd, 0xbf, 0xbe, 0xd4, 0x2b, 0xf7, 0x00, 0x7e, 0x3a, 0x76, 0xa8, 0x9e, 0x7d, 0x9d, 0xd1, 0xff, 0x87, 0xf8, 0x1f, 0x5c,
+    0x25, 0xa9, 0x5a, 0xff, 0x3f, 0xa3, 0xc4, 0x67, 0xac, 0x4d, 0xd7, 0xae, 0x9f, 0x8d, 0x96, 0x47, 0xff, 0xf5, 0xff, 0xb7,
+    0x8f, 0xff, 0x9f, 0xec, 0xc0, 0xf3, 0xae, 0xf8, 0x8f, 0xe4, 0xfa, 0xd6, 0x19, 0xf1, 0x1f, 0x07, 0xb4, 0x5a, 0x99, 0x1d,
+    0x41, 0xeb, 0xaf, 0xa0, 0xd4, 0x8f, 0xff, 0x67, 0xec, 0x86, 0xf0, 0xee, 0xf8, 0x7f, 0xc3, 0x18, 0xba, 0x2d, 0xde, 0x6f,
+    0x7a, 0x76, 0xfc, 0x8f, 0xf5, 0x93, 0xb3, 0x5f, 0xa9, 0xbe, 0xba, 0xf7, 0x86, 0xf9, 0xff, 0x48, 0x0b, 0x30, 0x63, 0xfe,
+    0xff, 0x74, 0xa4, 0xf1, 0xfd, 0xf1, 0xdf, 0x26, 0xec, 0x01, 0x34, 0x63, 0xbe, 0xb9, 0xf7, 0xae, 0x91, 0xb6, 0xf8, 0xee,
+    0x94, 0x93, 0xe3, 0x7f, 0x56, 0xfb, 0x95, 0xd9, 0xf7, 0x36, 0x33, 0x7f, 0x99, 0xd5, 0xff, 0xd7, 0xde, 0xd9, 0xb2, 0xea,
+    0x6a, 0xf4, 0xda, 0xfb, 0x5b, 0xaa, 0x7f, 0xa1, 0x3c, 0xf8, 0x27, 0x3e, 0x63, 0xe0, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xed, 0xf3, 0x18, 0x99, 0xa7, 0x2b, 0xce, 0xc8, 0xac, 0x7f, 0xf7, 0xf4, 0x4c,
+    0x3b, 0x36, 0xb3, 0x7e, 0x7b, 0x94, 0xa1, 0xe8, 0x7d, 0x99, 0xf5, 0x3d, 0xf9, 0xf1, 0xbe, 0xa7, 0x72, 0xde, 0x9b, 0x59,
+    0xff, 0x2e, 0x8f, 0xc2, 0xc9, 0x99, 0xf5, 0xf3, 0xcf, 0x50, 0x9d, 0x9a, 0x59, 0x9f, 0xd3, 0xe3, 0x7f, 0xe7, 0x38, 0x63,
+    0xde, 0x11, 0x9c, 0x5c, 0x23, 0xef, 0x72, 0x43, 0xac, 0x69, 0x51, 0x2a, 0x9f, 0xd6, 0x3c, 0x3d, 0xb3, 0x3e, 0xbd, 0xd1,
+    0x53, 0xf7, 0xa4, 0x76, 0x74, 0x8d, 0x1b, 0xe7, 0x66, 0xd6, 0xba, 0xce, 0x19, 0x71, 0x76, 0x9e, 0xf7, 0xf7, 0x66, 0xd6,
+    0x16, 0xff, 0xef, 0x8a, 0xff, 0xf5, 0x59, 0xa6, 0xea, 0xe2, 0x3f, 0xca, 0x5f, 0x5b, 0x9b, 0x59, 0x2b, 0xbb, 0x9e, 0x20,
+    0xfe, 0xa9, 0x1a, 0xe7, 0x55, 0xbf, 0xb2, 0x32, 0xb3, 0xd6, 0xdb, 0xe3, 0x3f, 0x33, 0x2a, 0x17, 0xff, 0xac, 0x99, 0x87,
+    0x9e, 0xbf, 0xb3, 0xd6, 0x77, 0xc6, 0xff, 0x19, 0x99, 0x75, 0xc5, 0xff, 0x6f, 0xcc, 0x01, 0xe6, 0x64, 0xd6, 0xd5, 0xff,
+    0xcf, 0x8a, 0x88, 0xb3, 0xa3, 0x3c, 0x16, 0x67, 0x19, 0x64, 0xb4, 0x05, 0x58, 0x97, 0xa9, 0x75, 0x47, 0x66, 0x7d, 0x99,
+    0x75, 0x47, 0xce, 0xd7, 0xf5, 0xe8, 0xef, 0x9d, 0xd7, 0x63, 0x7e, 0x79, 0xfc, 0xbf, 0x62, 0x2d, 0x7c, 0xd6, 0xf8, 0xbf,
+    0xfa, 0x8e, 0x07, 0x99, 0x75, 0x6b, 0xcf, 0x9a, 0xf1, 0x3f, 0xfc, 0xd2, 0x8a, 0xf1, 0xfe, 0x96, 0x10, 0x78, 0xdb, 0x9d,
+    0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x80, 0x93, 0xfc, 0xfb, 0x9f, 0x72, 0x00, 0xf1, 0x0f, 0xfc, 0x75, 0xf1, 0xff, 0x2f };
+    0x00, 0x00, 0xbf, 0xed, 0xef, 0x7f, 0xca, 0x01, 0xc4, 0x3f, 0xf0, 0x73, 0xf1, 0xff, 0x17 };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle genesisFontRecs[189] = {
+static const Rectangle genesisFontRecs[182] = {
     { 4, 4, 4 , 16 },
     { 16, 4, 1 , 9 },
     { 25, 4, 3 , 3 },
@@ -257,99 +257,92 @@
     { 218, 52, 6 , 9 },
     { 232, 52, 5 , 9 },
     { 245, 52, 5 , 12 },
-    { 258, 52, 0 , 0 },
-    { 266, 52, 5 , 10 },
-    { 279, 52, 7 , 9 },
-    { 294, 52, 0 , 0 },
-    { 302, 52, 6 , 5 },
-    { 316, 52, 5 , 3 },
-    { 329, 52, 7 , 9 },
-    { 344, 52, 0 , 0 },
-    { 352, 52, 4 , 4 },
-    { 364, 52, 5 , 7 },
-    { 377, 52, 0 , 0 },
-    { 385, 52, 0 , 0 },
-    { 393, 52, 5 , 12 },
-    { 406, 52, 5 , 9 },
-    { 419, 52, 7 , 9 },
-    { 434, 52, 1 , 1 },
-    { 443, 52, 5 , 10 },
-    { 456, 52, 0 , 0 },
-    { 464, 52, 0 , 0 },
-    { 472, 52, 6 , 5 },
-    { 486, 52, 9 , 9 },
-    { 4, 76, 9 , 7 },
-    { 21, 76, 5 , 11 },
-    { 34, 76, 5 , 9 },
-    { 47, 76, 5 , 12 },
-    { 60, 76, 5 , 12 },
-    { 73, 76, 5 , 12 },
-    { 86, 76, 6 , 12 },
-    { 100, 76, 5 , 11 },
-    { 113, 76, 5 , 13 },
-    { 126, 76, 9 , 9 },
-    { 143, 76, 5 , 12 },
-    { 156, 76, 5 , 12 },
-    { 169, 76, 5 , 12 },
-    { 182, 76, 5 , 12 },
-    { 195, 76, 5 , 11 },
-    { 208, 76, 2 , 12 },
-    { 218, 76, 2 , 12 },
-    { 228, 76, 3 , 12 },
-    { 239, 76, 3 , 11 },
-    { 250, 76, 6 , 9 },
-    { 264, 76, 6 , 12 },
-    { 278, 76, 5 , 12 },
-    { 291, 76, 5 , 12 },
-    { 304, 76, 5 , 12 },
-    { 317, 76, 6 , 12 },
-    { 331, 76, 5 , 11 },
-    { 344, 76, 5 , 5 },
-    { 357, 76, 7 , 9 },
-    { 372, 76, 5 , 12 },
-    { 385, 76, 5 , 12 },
-    { 398, 76, 5 , 12 },
-    { 411, 76, 5 , 11 },
-    { 424, 76, 5 , 12 },
-    { 437, 76, 5 , 9 },
-    { 450, 76, 5 , 9 },
-    { 463, 76, 5 , 10 },
-    { 476, 76, 5 , 10 },
-    { 489, 76, 5 , 10 },
-    { 4, 100, 6 , 10 },
-    { 18, 100, 5 , 9 },
-    { 31, 100, 5 , 11 },
-    { 44, 100, 9 , 7 },
-    { 61, 100, 5 , 10 },
-    { 74, 100, 5 , 10 },
-    { 87, 100, 5 , 10 },
-    { 100, 100, 5 , 10 },
-    { 113, 100, 5 , 9 },
-    { 126, 100, 2 , 10 },
-    { 136, 100, 2 , 10 },
-    { 146, 100, 3 , 10 },
-    { 157, 100, 3 , 9 },
-    { 168, 100, 6 , 9 },
-    { 182, 100, 6 , 10 },
-    { 196, 100, 5 , 10 },
-    { 209, 100, 5 , 10 },
-    { 222, 100, 5 , 10 },
-    { 235, 100, 6 , 10 },
-    { 249, 100, 5 , 9 },
-    { 262, 100, 5 , 5 },
-    { 275, 100, 7 , 7 },
-    { 290, 100, 5 , 10 },
-    { 303, 100, 5 , 10 },
-    { 316, 100, 5 , 10 },
-    { 329, 100, 5 , 9 },
-    { 342, 100, 5 , 12 },
-    { 355, 100, 5 , 11 },
-    { 368, 100, 5 , 11 },
+    { 258, 52, 5 , 10 },
+    { 271, 52, 7 , 9 },
+    { 286, 52, 6 , 5 },
+    { 300, 52, 5 , 3 },
+    { 313, 52, 7 , 9 },
+    { 328, 52, 4 , 4 },
+    { 340, 52, 5 , 7 },
+    { 353, 52, 5 , 12 },
+    { 366, 52, 5 , 9 },
+    { 379, 52, 7 , 9 },
+    { 394, 52, 1 , 1 },
+    { 403, 52, 5 , 10 },
+    { 416, 52, 6 , 5 },
+    { 430, 52, 9 , 9 },
+    { 447, 52, 9 , 7 },
+    { 464, 52, 5 , 11 },
+    { 477, 52, 5 , 9 },
+    { 490, 52, 5 , 12 },
+    { 4, 76, 5 , 12 },
+    { 17, 76, 5 , 12 },
+    { 30, 76, 6 , 12 },
+    { 44, 76, 5 , 11 },
+    { 57, 76, 5 , 13 },
+    { 70, 76, 9 , 9 },
+    { 87, 76, 5 , 12 },
+    { 100, 76, 5 , 12 },
+    { 113, 76, 5 , 12 },
+    { 126, 76, 5 , 12 },
+    { 139, 76, 5 , 11 },
+    { 152, 76, 2 , 12 },
+    { 162, 76, 2 , 12 },
+    { 172, 76, 3 , 12 },
+    { 183, 76, 3 , 11 },
+    { 194, 76, 6 , 9 },
+    { 208, 76, 6 , 12 },
+    { 222, 76, 5 , 12 },
+    { 235, 76, 5 , 12 },
+    { 248, 76, 5 , 12 },
+    { 261, 76, 6 , 12 },
+    { 275, 76, 5 , 11 },
+    { 288, 76, 5 , 5 },
+    { 301, 76, 7 , 9 },
+    { 316, 76, 5 , 12 },
+    { 329, 76, 5 , 12 },
+    { 342, 76, 5 , 12 },
+    { 355, 76, 5 , 11 },
+    { 368, 76, 5 , 12 },
+    { 381, 76, 5 , 9 },
+    { 394, 76, 5 , 9 },
+    { 407, 76, 5 , 10 },
+    { 420, 76, 5 , 10 },
+    { 433, 76, 5 , 10 },
+    { 446, 76, 6 , 10 },
+    { 460, 76, 5 , 9 },
+    { 473, 76, 5 , 11 },
+    { 486, 76, 9 , 7 },
+    { 4, 100, 5 , 10 },
+    { 17, 100, 5 , 10 },
+    { 30, 100, 5 , 10 },
+    { 43, 100, 5 , 10 },
+    { 56, 100, 5 , 9 },
+    { 69, 100, 2 , 10 },
+    { 79, 100, 2 , 10 },
+    { 89, 100, 3 , 10 },
+    { 100, 100, 3 , 9 },
+    { 111, 100, 6 , 9 },
+    { 125, 100, 6 , 10 },
+    { 139, 100, 5 , 10 },
+    { 152, 100, 5 , 10 },
+    { 165, 100, 5 , 10 },
+    { 178, 100, 6 , 10 },
+    { 192, 100, 5 , 9 },
+    { 205, 100, 5 , 5 },
+    { 218, 100, 7 , 7 },
+    { 233, 100, 5 , 10 },
+    { 246, 100, 5 , 10 },
+    { 259, 100, 5 , 10 },
+    { 272, 100, 5 , 9 },
+    { 285, 100, 5 , 12 },
+    { 298, 100, 5 , 11 },
+    { 311, 100, 5 , 11 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo genesisFontGlyphs[189] = {
+static const GlyphInfo genesisFontGlyphs[182] = {
     { 32, 0, 0, 4, { 0 }},
     { 33, 2, 4, 5, { 0 }},
     { 34, 2, 4, 7, { 0 }},
@@ -451,25 +444,18 @@
     { 8364, 1, 4, 8, { 0 }},
     { 165, 1, 4, 7, { 0 }},
     { 352, 1, 1, 7, { 0 }},
-    { 167, 0, 0, 0, { 0 }},
     { 353, 1, 3, 7, { 0 }},
     { 169, 1, 4, 9, { 0 }},
-    { 170, 0, 0, 0, { 0 }},
     { 171, 1, 6, 8, { 0 }},
     { 172, 1, 8, 7, { 0 }},
     { 174, 1, 4, 9, { 0 }},
-    { 175, 0, 0, 0, { 0 }},
     { 176, 1, 4, 6, { 0 }},
     { 177, 1, 6, 7, { 0 }},
-    { 178, 0, 0, 0, { 0 }},
-    { 179, 0, 0, 0, { 0 }},
     { 381, 1, 1, 7, { 0 }},
     { 181, 1, 6, 7, { 0 }},
     { 182, 1, 4, 9, { 0 }},
     { 183, 2, 8, 5, { 0 }},
     { 382, 1, 3, 7, { 0 }},
-    { 185, 0, 0, 0, { 0 }},
-    { 186, 0, 0, 0, { 0 }},
     { 187, 1, 6, 8, { 0 }},
     { 338, 1, 4, 11, { 0 }},
     { 339, 1, 6, 11, { 0 }},
@@ -559,29 +545,40 @@
 
     Font font = { 0 };
     font.baseSize = 16;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 182;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, genesisFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, genesisFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "PixelOperator.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/jungle/style_jungle.h b/raygui/styles/jungle/style_jungle.h
--- a/raygui/styles/jungle/style_jungle.h
+++ b/raygui/styles/jungle/style_jungle.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,137 +15,134 @@
 
 // Custom style name: Jungle
 static const GuiStyleProp jungleStyleProps[JUNGLE_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x60827dff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x2c3334ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x82a29fff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0x5f9aa8ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x334e57ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0x6aa9b8ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xa9cb8dff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0x3b6357ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x97af81ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x5b6462ff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x2c3334ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x666b69ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x60827dff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x2c3334ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x82a29fff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x5f9aa8ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x334e57ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0x6aa9b8ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xa9cb8dff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x3b6357ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x97af81ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x5b6462ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x2c3334ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x666b69ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x0000000c },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x638465ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x2b3a3aff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000012 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000006 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "PixelIntv.otf" (size: 12, spacing: 0)
 
-#define JUNGLE_STYLE_FONT_ATLAS_COMP_SIZE 2059
+#define JUNGLE_STYLE_FONT_ATLAS_COMP_SIZE 1995
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char jungleFontData[JUNGLE_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0x9d, 0xbd, 0x8e, 0x1d, 0x35, 0x18, 0x86, 0x8d, 0x39, 0x1d, 0x25, 0xa2, 0x00, 0x09, 0x91, 0x06, 0x89, 0x86, 0x86, 0x28,
-    0x12, 0x74, 0x7b, 0x01, 0xd4, 0x08, 0x51, 0x20, 0x2a, 0x1a, 0xe0, 0x1e, 0xc8, 0x95, 0xa5, 0xa1, 0xe7, 0x06, 0xb8, 0x0b,
-    0x2e, 0xe0, 0x8b, 0x36, 0x9b, 0xdd, 0xec, 0xee, 0x99, 0xb1, 0xfd, 0xfd, 0xd8, 0x9e, 0x9f, 0x67, 0x1f, 0x25, 0x52, 0xc6,
-    0x67, 0x66, 0x6c, 0xbf, 0xb6, 0x67, 0x36, 0xdf, 0x7b, 0x3e, 0x4b, 0x02, 0x00, 0x00, 0x00, 0xb8, 0xe2, 0xf6, 0x67, 0xf9,
-    0xd8, 0x52, 0x49, 0x7a, 0x5f, 0xd2, 0x7e, 0xad, 0xfb, 0xe3, 0x77, 0x25, 0x79, 0xf5, 0x13, 0xcb, 0x57, 0xcc, 0x2b, 0x75,
-    0x58, 0xab, 0xf5, 0x7a, 0xcd, 0x92, 0xaa, 0x64, 0xfd, 0xfa, 0xeb, 0xfd, 0x95, 0x14, 0x6d, 0x78, 0xfa, 0x93, 0x14, 0x6d,
-    0x29, 0x9f, 0xd7, 0x5b, 0xff, 0x72, 0x1f, 0xac, 0x97, 0xdd, 0xfd, 0xb9, 0xed, 0x89, 0xac, 0xb8, 0xe6, 0xfa, 0xe7, 0x93,
-    0x6a, 0x04, 0xea, 0x47, 0x86, 0xae, 0x77, 0x4b, 0x9f, 0xae, 0xb5, 0x41, 0x94, 0x35, 0xb8, 0x3f, 0xde, 0x53, 0xff, 0xf4,
-    0x70, 0x8f, 0xf6, 0xf9, 0x5f, 0x53, 0x45, 0xe4, 0xb2, 0xd8, 0x13, 0xa9, 0xa8, 0x4d, 0x36, 0xdc, 0x29, 0x62, 0x34, 0xa7,
-    0xa0, 0xde, 0xcd, 0xc5, 0x36, 0x88, 0x41, 0x7f, 0xdb, 0x08, 0x8d, 0xba, 0x8e, 0x6d, 0xfe, 0xdf, 0x72, 0x79, 0x37, 0x02,
-    0xca, 0x57, 0xf5, 0xd7, 0x38, 0x6a, 0xfe, 0xa7, 0xae, 0xea, 0x7b, 0xf4, 0x1f, 0xb1, 0xfe, 0x97, 0x3f, 0x5f, 0xee, 0xb3,
-    0xe5, 0xeb, 0xe5, 0xf7, 0xf3, 0x5f, 0xff, 0xf4, 0x8c, 0xd0, 0x5f, 0xff, 0xfc, 0xef, 0xab, 0x7e, 0xc4, 0xfa, 0xbf, 0xc5,
-    0xf7, 0xc8, 0xda, 0x73, 0x7c, 0x79, 0xec, 0x48, 0xf7, 0xf9, 0x3f, 0x83, 0x92, 0xfa, 0xb5, 0xf7, 0x3f, 0x71, 0xac, 0xb3,
-    0xbd, 0xe7, 0xbf, 0xe5, 0x5a, 0xf7, 0x3d, 0x21, 0x86, 0xf9, 0xb9, 0x57, 0xfd, 0x4b, 0xea, 0x43, 0xc4, 0x5a, 0xa3, 0x79,
-    0xca, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x33, 0x62, 0x52, 0x8e, 0xbf, 0x47,
-    0x46, 0x22, 0x7b, 0x95, 0xb5, 0xbb, 0x0d, 0x34, 0xce, 0x95, 0x6c, 0xe8, 0xb1, 0x59, 0xfd, 0xd2, 0xcb, 0xed, 0x97, 0xd4,
-    0xde, 0x8c, 0x96, 0xda, 0x58, 0xef, 0xe7, 0xd1, 0x3f, 0x2b, 0x63, 0xaf, 0x65, 0x87, 0xde, 0x9a, 0x9f, 0x71, 0x3d, 0x72,
-    0xed, 0x6d, 0x9f, 0xb6, 0x4c, 0xb7, 0x02, 0xa4, 0x21, 0xf3, 0xbf, 0xcd, 0xc3, 0xd4, 0xc7, 0xdd, 0xb8, 0xec, 0x33, 0x2b,
-    0xd5, 0xf5, 0xa2, 0x76, 0x14, 0x7e, 0x88, 0x36, 0xf7, 0x1d, 0xdf, 0xd1, 0xae, 0x4f, 0xab, 0xa3, 0xc4, 0x32, 0x26, 0x2d,
-    0x0e, 0xd6, 0x88, 0xf5, 0x3f, 0x66, 0xfe, 0x97, 0xc6, 0xa9, 0x3c, 0xfb, 0x13, 0xb3, 0x8e, 0xcf, 0xd2, 0xbf, 0xc7, 0x5a,
-    0x9d, 0x1a, 0x56, 0x05, 0x6b, 0x5d, 0x6c, 0xcf, 0x7f, 0x8b, 0x53, 0xa7, 0xe4, 0x56, 0xb2, 0xbf, 0x4f, 0xcd, 0x98, 0xff,
-    0x9e, 0x39, 0x6e, 0x5b, 0xff, 0xcb, 0xfa, 0xc7, 0xb9, 0xdb, 0x64, 0xca, 0xdb, 0x74, 0xcb, 0x1c, 0xdb, 0xd6, 0xf3, 0x1f,
-    0x22, 0xfd, 0x8c, 0xf3, 0x7e, 0x9f, 0x42, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xe8, 0xeb, 0xc7, 0x1b, 0xe5, 0x29, 0x91, 0xc6, 0x2c, 0x3e, 0xeb, 0x7e, 0xad, 0x51, 0x6e, 0xbd, 0xf1, 0xfd, 0x1d, 0xed,
-    0xfb, 0x88, 0x88, 0x49, 0x5b, 0x32, 0x98, 0xf9, 0xbd, 0x88, 0xb2, 0x09, 0x47, 0x5e, 0x8f, 0x7e, 0x9b, 0xa9, 0xbf, 0xa5,
-    0x3e, 0x76, 0xfd, 0xc5, 0x98, 0x61, 0xb0, 0x96, 0x19, 0x66, 0x5b, 0xfa, 0x5b, 0x5c, 0x07, 0x1e, 0xfd, 0xeb, 0x6b, 0x55,
-    0x2a, 0xe8, 0xa1, 0x5f, 0xe3, 0xad, 0xfa, 0x8b, 0x31, 0xef, 0x63, 0x9f, 0xa7, 0x58, 0x1f, 0xfd, 0x2d, 0xfd, 0x76, 0x94,
-    0xf5, 0xbf, 0x7e, 0xcd, 0x6c, 0x5c, 0xff, 0xa5, 0xba, 0xaa, 0x48, 0xb8, 0x1b, 0x55, 0x3f, 0xa7, 0x5a, 0xfb, 0xe7, 0xbc,
-    0xfa, 0xa7, 0x2e, 0xfa, 0xf7, 0xb9, 0xe3, 0x7e, 0x9e, 0xff, 0x96, 0xec, 0xd5, 0x33, 0x7c, 0x6e, 0x3e, 0x6f, 0x78, 0xad,
-    0x74, 0x44, 0xcf, 0xf4, 0x5b, 0xff, 0x71, 0x01, 0xee, 0xc7, 0x25, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x30, 0x22, 0x46, 0x61, 0x8f, 0x9d, 0xf5, 0x88, 0x00, 0x5e, 0x1f, 0xcf, 0x0d, 0x31, 0xcc, 0xe7, 0xc7,
-    0xf3, 0x8a, 0x63, 0x44, 0x94, 0x39, 0xff, 0x6c, 0xfb, 0xf1, 0xb6, 0xe6, 0x41, 0xb3, 0x3b, 0x08, 0x23, 0xe2, 0x80, 0xe3,
-    0xf5, 0x4f, 0x4d, 0xf1, 0xd8, 0x6b, 0x25, 0xb3, 0xc1, 0x33, 0x94, 0x95, 0x19, 0x9f, 0x4a, 0x19, 0xa2, 0xf4, 0x6e, 0xa6,
-    0x7a, 0x2f, 0x58, 0x72, 0xdd, 0xd5, 0xae, 0x66, 0xdb, 0xa1, 0xb8, 0xe4, 0x8e, 0xa9, 0x79, 0x59, 0xf4, 0x2d, 0xcf, 0xea,
-    0xb6, 0xe5, 0x86, 0x35, 0xa0, 0xbf, 0x47, 0x3a, 0xa9, 0xe7, 0xa3, 0xcf, 0x77, 0xd7, 0x5f, 0xff, 0xd4, 0xe0, 0xf1, 0x8b,
-    0x76, 0xa4, 0x48, 0x65, 0xf7, 0x5b, 0xcb, 0x08, 0xe8, 0xad, 0x7f, 0xad, 0xad, 0x76, 0x97, 0x50, 0x0a, 0x1d, 0x37, 0xd1,
-    0xfa, 0xb7, 0x8c, 0xd3, 0xe8, 0x11, 0x6c, 0x19, 0x01, 0x63, 0xe6, 0xbf, 0xa8, 0xf5, 0x2f, 0xaf, 0x0d, 0xf1, 0xbd, 0x67,
-    0x71, 0x01, 0xd9, 0x56, 0x14, 0xaf, 0x5b, 0xcd, 0xa2, 0x62, 0x36, 0xad, 0x1c, 0x23, 0xde, 0xa0, 0x6d, 0x7b, 0x55, 0x47,
-    0x3b, 0x36, 0x6d, 0x3d, 0x31, 0x5e, 0x7f, 0x31, 0xef, 0xf8, 0x9d, 0x37, 0xb7, 0xfb, 0xb5, 0x6d, 0xd6, 0xd9, 0x1d, 0x7b,
-    0xf1, 0xf3, 0x7f, 0x7b, 0xdf, 0x46, 0x1b, 0x71, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xc0, 0x39, 0x73, 0x14, 0xe8, 0x33, 0xd5, 0xd4, 0xcf, 0xb0, 0xee, 0x9d, 0x35, 0x72, 0xef, 0xdc, 0x5e, 0xfb, 0xdb, 0xd9,
-    0xf3, 0x82, 0x49, 0x97, 0x1d, 0xe0, 0xe2, 0xe3, 0x66, 0xbe, 0x2c, 0x66, 0xb5, 0x1e, 0xb2, 0x66, 0xdc, 0xd2, 0x7a, 0x30,
-    0x3c, 0xbe, 0x1e, 0xab, 0xe7, 0x23, 0xde, 0x87, 0x17, 0xe3, 0x6d, 0xb3, 0xcd, 0x7f, 0x9b, 0x2f, 0x64, 0x6b, 0xfa, 0xa7,
-    0x41, 0xfe, 0x3c, 0x8f, 0xfe, 0xde, 0xdd, 0x9f, 0xed, 0x8e, 0x2c, 0x7d, 0xaf, 0x1e, 0x41, 0xff, 0x36, 0xf7, 0xae, 0xc5,
-    0x47, 0x18, 0xed, 0xc3, 0x9b, 0xa5, 0xbf, 0x98, 0xf6, 0xce, 0xf5, 0xe8, 0xef, 0xf3, 0xcb, 0x8f, 0x9b, 0xff, 0xf6, 0x3b,
-    0xa6, 0x2e, 0x3b, 0xa3, 0x7b, 0x67, 0xab, 0x2e, 0x53, 0xe3, 0x0c, 0xa7, 0x56, 0xbc, 0x5f, 0xae, 0x97, 0xb3, 0x6b, 0xae,
-    0x7b, 0x31, 0xca, 0xbf, 0xea, 0xcd, 0xfe, 0x3d, 0x43, 0x7f, 0xbc, 0x63, 0xc7, 0x1e, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x8b, 0xe3, 0xc4, 0xed, 0x47, 0xa5, 0xcd, 0xea, 0x26, 0x8b, 0x19, 0x3d,
-    0xac, 0xb9, 0x63, 0xb4, 0xde, 0x0a, 0x4d, 0xec, 0x5c, 0x13, 0xbb, 0xcc, 0x8f, 0x3e, 0x7b, 0xed, 0x83, 0xf8, 0x5e, 0x5e,
-    0x3c, 0xf0, 0x52, 0x3e, 0x5b, 0xcd, 0x72, 0xb2, 0xd4, 0x33, 0xb5, 0x73, 0xcb, 0x77, 0xb6, 0x38, 0x00, 0x74, 0xb9, 0xda,
-    0x74, 0x47, 0xb3, 0xb2, 0x9e, 0x16, 0xd7, 0x85, 0x2f, 0x43, 0x9f, 0xf5, 0xb3, 0xf9, 0x89, 0x92, 0x4f, 0x79, 0xf5, 0xa4,
-    0x77, 0x5f, 0x2e, 0xf6, 0x78, 0x5e, 0xc9, 0x75, 0x54, 0x3b, 0xb7, 0x7c, 0x67, 0xad, 0xfe, 0x59, 0x9d, 0xab, 0x4d, 0xaf,
-    0x4e, 0x8c, 0xaf, 0xd0, 0x96, 0x15, 0xc7, 0xa2, 0x7f, 0x5b, 0xfd, 0x1f, 0xaf, 0xac, 0xcf, 0x4b, 0x5f, 0x14, 0xfe, 0x75,
-    0x77, 0xf6, 0xe5, 0xe1, 0x6f, 0xfd, 0xb9, 0xa5, 0x3b, 0xeb, 0x9d, 0x3c, 0x36, 0x17, 0x97, 0x77, 0x04, 0x44, 0x66, 0x53,
-    0x4c, 0xae, 0x0c, 0xad, 0x36, 0xc7, 0x83, 0x3c, 0xd9, 0x5b, 0x5e, 0xab, 0x61, 0x69, 0xfe, 0xb7, 0xe9, 0xbf, 0x76, 0xe7,
-    0x64, 0xf4, 0xc7, 0xc9, 0x46, 0xe6, 0x7f, 0x8f, 0xac, 0x78, 0xa2, 0x9a, 0x27, 0xad, 0x6b, 0x85, 0x67, 0xfe, 0x97, 0x9e,
-    0xff, 0xf1, 0xfa, 0x5b, 0x5d, 0x70, 0xa3, 0xf5, 0x4f, 0x66, 0x9f, 0xaa, 0xf5, 0xad, 0xd1, 0xbe, 0x02, 0x94, 0x9f, 0xc2,
-    0x75, 0xfd, 0xd7, 0xa9, 0xeb, 0x6f, 0x79, 0xfe, 0xcb, 0x4e, 0xf4, 0x4f, 0x0e, 0x67, 0x6d, 0x94, 0x1f, 0xd5, 0xff, 0xfe,
-    0xdf, 0x53, 0x7f, 0xfd, 0xfb, 0x7f, 0xac, 0xb3, 0xd2, 0x96, 0xd5, 0x71, 0x4f, 0xdf, 0x94, 0xf3, 0xb7, 0xe6, 0xd7, 0x47,
-    0xbf, 0xc3, 0xbd, 0x92, 0x1f, 0x86, 0x9d, 0x0b, 0x31, 0x8e, 0x57, 0x3c, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xb0, 0x75, 0xea, 0x5e, 0xb4, 0xcf, 0x17, 0xe3, 0x48, 0xb5, 0xf3, 0xbc, 0xe5, 0x5a, 0x97, 0xda, 0xd7,
-    0xf2, 0xad, 0x7c, 0x79, 0x75, 0xf4, 0x8d, 0xbc, 0x91, 0xdf, 0xdc, 0x7d, 0x50, 0x2b, 0xbf, 0x8b, 0xb4, 0x2d, 0xc7, 0xdb,
-    0x96, 0x7e, 0x2c, 0x9f, 0xd1, 0xc7, 0xb5, 0xdb, 0xa2, 0x7f, 0x35, 0x3f, 0xd9, 0x8f, 0x72, 0x23, 0x7f, 0x1a, 0xce, 0xf3,
-    0x96, 0x6b, 0xf4, 0xff, 0x42, 0xfe, 0x93, 0x7f, 0xe5, 0xb5, 0x7c, 0xb5, 0x78, 0xd6, 0xdf, 0xee, 0x3e, 0xf0, 0xf8, 0xf5,
-    0x34, 0x3b, 0x21, 0xc7, 0x45, 0x18, 0xdb, 0xa3, 0xff, 0xb5, 0x78, 0xf2, 0x2f, 0xf2, 0x91, 0xfc, 0xb4, 0xe0, 0x44, 0xab,
-    0x9d, 0xe7, 0x2d, 0xd7, 0xe8, 0xff, 0x97, 0x88, 0xfc, 0x23, 0xbf, 0xcb, 0xc7, 0x57, 0x25, 0x37, 0x72, 0xd3, 0x70, 0x6d,
-    0x7f, 0x5d, 0x2f, 0xef, 0xea, 0x75, 0x71, 0xee, 0x84, 0x1d, 0x39, 0xff, 0xa3, 0xfc, 0x04, 0x9f, 0xca, 0xcf, 0xf2, 0x5d,
-    0x87, 0x3e, 0x8b, 0xd4, 0xff, 0x1b, 0xf9, 0x7f, 0x45, 0xff, 0x98, 0x3e, 0xf0, 0xf8, 0xf5, 0xae, 0xb5, 0x8d, 0x71, 0x16,
-    0x48, 0x63, 0x26, 0x5d, 0x6f, 0xdb, 0x7b, 0xf5, 0x99, 0x45, 0xff, 0xf5, 0x36, 0x7d, 0x22, 0xaf, 0x27, 0xea, 0x5f, 0x7b,
-    0xfe, 0x27, 0x45, 0xce, 0x58, 0x8d, 0x1b, 0x35, 0xc2, 0xa9, 0xb2, 0x27, 0xfd, 0x4b, 0xe5, 0x7f, 0x4c, 0xd4, 0x7f, 0x8c,
-    0x6b, 0xa8, 0xfd, 0xba, 0xe8, 0xbf, 0x2d, 0xfd, 0x2d, 0xef, 0xf6, 0x9e, 0xf5, 0x50, 0x73, 0x2f, 0xab, 0x9f, 0xac, 0x76,
-    0x9e, 0xb7, 0x5c, 0x8b, 0x47, 0xff, 0xd1, 0x75, 0xdd, 0x8f, 0x53, 0x11, 0xce, 0xed, 0x54, 0x05, 0xf4, 0x07, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3d, 0x93, 0x2b, 0xb9, 0xdf, 0x72, 0xa1, 0xc4, 0xe2, 0x67, 0x68, 0xdb, 0x01,
-    0x58, 0x8c, 0x39, 0x09, 0x73, 0x68, 0x3b, 0xeb, 0x6d, 0x19, 0x77, 0xbf, 0x52, 0xcb, 0x4b, 0x7a, 0xd4, 0xff, 0xbf, 0x38,
-    0x17, 0x4a, 0xb2, 0x3a, 0x77, 0x9f, 0x6f, 0x07, 0x58, 0x9f, 0xb7, 0x21, 0x9b, 0x3c, 0x91, 0xa5, 0x76, 0x6e, 0xe7, 0x7e,
-    0xe5, 0xb2, 0x3c, 0x24, 0xe7, 0xcb, 0xec, 0xb8, 0xc5, 0x99, 0x63, 0x1a, 0x52, 0x75, 0x41, 0x8f, 0xf3, 0x11, 0xf4, 0x2e,
-    0xb3, 0xe6, 0xf9, 0xdc, 0x62, 0x5b, 0x22, 0xcb, 0xd6, 0xe7, 0xbf, 0x6d, 0x7e, 0xd8, 0xd7, 0x9b, 0xb1, 0x65, 0x1a, 0xdf,
-    0xdb, 0xa8, 0xb2, 0xd1, 0xf7, 0x8c, 0xf2, 0x7c, 0x1d, 0x41, 0x7f, 0x4b, 0x86, 0xd0, 0xa3, 0xeb, 0x2f, 0xc1, 0x99, 0xf3,
-    0x66, 0xae, 0x6f, 0xbe, 0x6b, 0xa7, 0x21, 0x65, 0x33, 0xf4, 0x6f, 0xd9, 0x23, 0x7e, 0xaf, 0xf3, 0x5f, 0x5b, 0xe7, 0xb3,
-    0xcd, 0xff, 0xb6, 0xef, 0x47, 0x1c, 0x5d, 0x7f, 0x41, 0xff, 0x40, 0xcf, 0xd7, 0x1e, 0xe7, 0xff, 0x59, 0xdf, 0xff, 0xdb,
-    0xc6, 0x21, 0x9e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe7, 0x61, 0xb3, 0x7a, 0x03, 0xdb,
-    0xbc, 0x6f, 0xdb, 0xf0, 0xfd, 0x65, 0xd3, 0x6e, 0x62, 0xe5, 0x36, 0xd8, 0xbc, 0x64, 0x7e, 0xdf, 0x57, 0xbc, 0x87, 0xcd,
-    0xda, 0xaf, 0xf6, 0x1c, 0x59, 0xa3, 0x7d, 0x7f, 0xa5, 0x5d, 0x71, 0xad, 0xbb, 0x4d, 0xdb, 0xc6, 0xf0, 0x7a, 0x1b, 0xf6,
-    0xec, 0x01, 0x5c, 0x3a, 0x9e, 0x77, 0xb0, 0xfb, 0xd6, 0xac, 0xd8, 0xd7, 0x11, 0x62, 0x66, 0xa9, 0x5a, 0x92, 0x37, 0xef,
-    0x53, 0xaa, 0x97, 0x8d, 0xf5, 0xa7, 0x1c, 0xc5, 0xff, 0x75, 0xf4, 0xb2, 0xf1, 0x8e, 0x81, 0x7d, 0xc5, 0xff, 0xf7, 0xa4,
-    0xb1, 0xcd, 0xbf, 0xcb, 0xfc, 0xf7, 0x3c, 0xa7, 0xb6, 0x36, 0x36, 0xb4, 0x1e, 0xad, 0xda, 0xb3, 0xc1, 0x52, 0x76, 0x16,
-    0xff, 0xcf, 0x96, 0xe6, 0xf8, 0x96, 0xde, 0xc3, 0xd0, 0xbf, 0x5f, 0x3d, 0x8f, 0xf2, 0x3d, 0xa4, 0xbd, 0xf8, 0xdb, 0xb6,
-    0xd4, 0x86, 0xb3, 0x7f, 0x0f, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xc1, 0x98, 0x3c, 0x7e,
-    0x5b, 0x77, 0xf3, 0x8d, 0xbd, 0x9f, 0x3d, 0x8b, 0x5f, 0x0e, 0xd8, 0xf1, 0x37, 0xca, 0xab, 0xd7, 0xe2, 0x75, 0xb4, 0x46,
-    0x57, 0x8e, 0x9c, 0xc5, 0x2f, 0x15, 0x47, 0x46, 0xd9, 0xcd, 0x69, 0x1b, 0xa7, 0x33, 0x63, 0x4a, 0xa2, 0x8e, 0x92, 0x1f,
-    0xdf, 0x6d, 0x1d, 0x1f, 0x01, 0x8b, 0xa8, 0x4d, 0x6c, 0x99, 0xcf, 0xcb, 0x34, 0xc3, 0x75, 0xa8, 0xcd, 0x36, 0x63, 0x2d,
-    0x6b, 0x73, 0x01, 0xce, 0x71, 0x01, 0xc4, 0x94, 0xf9, 0x9e, 0xff, 0x5b, 0x8b, 0xe6, 0xf7, 0xc9, 0xe2, 0xa6, 0x2f, 0xed,
-    0xe3, 0xaa, 0x98, 0xe5, 0x3b, 0x4b, 0xa6, 0xdd, 0xab, 0x67, 0x44, 0xf3, 0x8f, 0xaf, 0xff, 0x2c, 0xdf, 0xd9, 0x39, 0xb3,
-    0x78, 0xb5, 0x8c, 0xc4, 0x19, 0xf3, 0x7f, 0xbe, 0x8f, 0x67, 0x7b, 0x8e, 0xa4, 0xf1, 0xbd, 0x53, 0xd6, 0x7f, 0xbc, 0x1a,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x67, 0x07, 0x60, 0xb4, 0x37, 0xd0, 0xe2, 0x7d,
-    0x89, 0xce, 0x80, 0xe7, 0xc9, 0xe2, 0x27, 0x06, 0x5f, 0xdb, 0x3e, 0xfd, 0x48, 0x3d, 0xf6, 0xf8, 0x5d, 0xef, 0xbb, 0x1c,
-    0xee, 0xfb, 0x8c, 0xcf, 0xe2, 0x97, 0x4e, 0xa4, 0xff, 0x48, 0x4f, 0x59, 0x29, 0x8b, 0xdb, 0x5e, 0xda, 0x70, 0x1e, 0x37,
-    0x62, 0x7c, 0xc4, 0xd9, 0x93, 0x1d, 0xaf, 0x47, 0x99, 0xe5, 0xcc, 0x1e, 0xbb, 0x30, 0xcf, 0xd5, 0xbf, 0x8f, 0xa3, 0xce,
-    0x32, 0xda, 0x46, 0xea, 0x3f, 0xcf, 0xfb, 0x74, 0x06, 0xfd, 0xad, 0x35, 0x41, 0x7f, 0xf4, 0xdf, 0x8a, 0xfe, 0x72, 0x12,
-    0xfd, 0xb7, 0xe1, 0xff, 0x9b, 0x97, 0x6d, 0x58, 0xcc, 0xdf, 0x50, 0xe0, 0x5d, 0xff, 0x38, 0x2b, 0xa0, 0xf6, 0x1b, 0x4a,
-    0xe8, 0x7f, 0xdc, 0xdf, 0x53, 0xf9, 0xdd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x9d, 0x3b, 0x8e, 0x25, 0x35, 0x14, 0x86, 0x8d, 0xe9, 0x8c, 0x10, 0x11, 0x80, 0x84, 0x98, 0x04, 0x89, 0x84, 0x84, 0xd1,
+    0x48, 0x90, 0xcd, 0x02, 0x88, 0x11, 0x22, 0x40, 0x44, 0x24, 0xc0, 0x1e, 0x98, 0x95, 0x4d, 0x42, 0xce, 0x06, 0xd8, 0x05,
+    0x0b, 0x38, 0x68, 0x5e, 0x4d, 0xf7, 0xdc, 0x2a, 0xdb, 0xe7, 0xe5, 0xf2, 0xad, 0xfb, 0xf5, 0xa7, 0x1e, 0x69, 0xca, 0xb7,
+    0xaa, 0x5c, 0xfe, 0x7d, 0xec, 0xea, 0xf6, 0xdf, 0xc7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x78, 0xf5, 0xb5, 0x7d, 0x6c,
+    0xab, 0xa4, 0xbc, 0x2d, 0x19, 0xbf, 0xd6, 0xbb, 0xe3, 0x6f, 0x4a, 0xea, 0xee, 0x27, 0xb6, 0xaf, 0x58, 0x77, 0xea, 0xb0,
+    0x57, 0xeb, 0xfd, 0x9a, 0x15, 0x55, 0xc9, 0xfe, 0xf5, 0xf7, 0xdb, 0xab, 0x28, 0x9e, 0xe1, 0xf1, 0x57, 0x51, 0x3c, 0x4b,
+    0xfb, 0xbc, 0x6c, 0xfd, 0xdb, 0x6d, 0xb0, 0x5f, 0xf6, 0xe6, 0xfb, 0x55, 0x4b, 0x54, 0xc5, 0x35, 0xf7, 0x3f, 0x5f, 0x54,
+    0x3d, 0x50, 0xdf, 0x33, 0x74, 0xad, 0xdb, 0xfa, 0x74, 0xef, 0x19, 0x44, 0x59, 0x83, 0x77, 0xc7, 0x33, 0xf5, 0x2f, 0xf7,
+    0xf7, 0x18, 0x8f, 0xff, 0x9e, 0x2a, 0x22, 0x77, 0x9b, 0x2d, 0x51, 0x9a, 0xda, 0x54, 0xc3, 0x9d, 0x22, 0x7a, 0x73, 0x09,
+    0x6a, 0xdd, 0xda, 0x7c, 0x06, 0x31, 0xe8, 0x6f, 0xeb, 0xa1, 0x51, 0xd7, 0xb1, 0xc5, 0xff, 0x2b, 0xee, 0x5e, 0xf7, 0x80,
+    0xf6, 0x55, 0xfd, 0x35, 0x8e, 0x8a, 0xff, 0x92, 0xaa, 0xbe, 0x47, 0xff, 0x19, 0xe3, 0x7f, 0xfb, 0xf3, 0xed, 0x36, 0xdb,
+    0xbe, 0x5e, 0x7d, 0x1b, 0xff, 0xfa, 0xd9, 0x33, 0x42, 0x7f, 0xfd, 0xfc, 0x9f, 0xab, 0x7e, 0xc4, 0xf8, 0xbf, 0xe2, 0x7b,
+    0x64, 0x6f, 0x1e, 0xdf, 0xee, 0x3b, 0x92, 0x1e, 0xff, 0x47, 0xd0, 0x52, 0xbf, 0xf7, 0xfe, 0x27, 0x8e, 0x71, 0x36, 0x3b,
+    0xfe, 0x2d, 0xd7, 0x7a, 0xd7, 0x12, 0x62, 0x88, 0xcf, 0x6b, 0xd5, 0xbf, 0xa5, 0x3e, 0x44, 0x8c, 0x35, 0x9a, 0x59, 0x1e,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9c, 0x2b, 0x26, 0xed, 0xf5, 0xf7, 0xc8, 0x95,
+    0xc8, 0xac, 0xb2, 0x71, 0xb7, 0x81, 0xc6, 0xb9, 0x52, 0x0d, 0x2d, 0x76, 0x54, 0xbb, 0x64, 0xb9, 0xfd, 0x8a, 0xda, 0x9b,
+    0x31, 0x52, 0x1b, 0xeb, 0xfd, 0x3c, 0xfa, 0x57, 0xe5, 0xda, 0x6b, 0xdb, 0xa1, 0xb7, 0xe7, 0x67, 0xdc, 0x5f, 0xb9, 0xf6,
+    0x3e, 0x9f, 0xb6, 0x4c, 0x37, 0x02, 0x94, 0x29, 0xf1, 0x3f, 0xe6, 0x61, 0xca, 0x71, 0x37, 0x6e, 0xfb, 0xcc, 0x5a, 0x75,
+    0xbd, 0x53, 0x3b, 0x0a, 0xff, 0x5f, 0x6d, 0xce, 0xed, 0xdf, 0xd1, 0xae, 0x4f, 0xab, 0xa3, 0xc4, 0xd2, 0x27, 0x2d, 0x0e,
+    0xd6, 0x88, 0xf1, 0x3f, 0x26, 0xfe, 0x5b, 0xfd, 0x54, 0xde, 0xfb, 0x8e, 0x19, 0xc7, 0x8f, 0xd2, 0x3f, 0x63, 0xac, 0x2e,
+    0x03, 0xa3, 0x82, 0xb5, 0x2e, 0xb6, 0xf9, 0xdf, 0xe2, 0xd4, 0x69, 0xb9, 0x95, 0xec, 0xef, 0x53, 0x47, 0xc4, 0xbf, 0x27,
+    0xc6, 0x6d, 0xe3, 0x7f, 0x5b, 0xff, 0x38, 0x77, 0x9b, 0x1c, 0xf2, 0x36, 0x3d, 0x12, 0x63, 0x6b, 0xcd, 0xff, 0x10, 0xe9,
+    0x67, 0x3c, 0xee, 0xe7, 0x29, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5c,
+    0x3f, 0xde, 0x2c, 0x4f, 0x89, 0x0c, 0x66, 0xf1, 0xd9, 0xf7, 0x6b, 0xcd, 0x72, 0xeb, 0xcd, 0x6f, 0xef, 0x68, 0xdf, 0x47,
+    0xc4, 0x9a, 0xb4, 0x25, 0x83, 0x99, 0xdf, 0x8b, 0x28, 0x4b, 0x38, 0xf2, 0x32, 0xda, 0xed, 0x48, 0xfd, 0x2d, 0xf5, 0xb1,
+    0xeb, 0x2f, 0xc6, 0x0c, 0x83, 0xbd, 0xcc, 0x30, 0x6b, 0xe9, 0x6f, 0x71, 0x1d, 0x78, 0xf4, 0xef, 0x8f, 0x55, 0xa5, 0xa1,
+    0x87, 0x7e, 0x8c, 0xb7, 0xea, 0x2f, 0xc6, 0xbc, 0x8f, 0x39, 0xb3, 0x58, 0x8e, 0xfe, 0x96, 0x76, 0x3b, 0xcb, 0xf8, 0xdf,
+    0xbf, 0x66, 0x35, 0x8e, 0xff, 0xd2, 0x1d, 0x55, 0x24, 0xdc, 0x8d, 0xaa, 0x8f, 0xa9, 0xd1, 0xf6, 0xb9, 0x5d, 0xfd, 0x4b,
+    0x8a, 0xfe, 0x39, 0x77, 0xbc, 0x9e, 0xf9, 0xdf, 0x92, 0xbd, 0xfa, 0x08, 0x9f, 0x9b, 0xcf, 0x1b, 0xde, 0x2b, 0x9d, 0xd1,
+    0x32, 0x79, 0xe3, 0x3f, 0x2e, 0xc0, 0xeb, 0x71, 0x89, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xcc, 0x58, 0xa3, 0xb0, 0xaf, 0x9d, 0x65, 0xac, 0x00, 0x5e, 0x1e, 0xaf, 0x03, 0x6b, 0x98, 0xef, 0x1f, 0xaf, 0x3b,
+    0x8e, 0x11, 0x51, 0xe6, 0xfc, 0xb3, 0xed, 0xc7, 0x3b, 0x9a, 0x07, 0xcd, 0xee, 0x20, 0x8c, 0x58, 0x07, 0x9c, 0xaf, 0x7f,
+    0x19, 0x5a, 0x8f, 0xbd, 0x54, 0xb2, 0x1a, 0x3c, 0x43, 0x55, 0x99, 0xf1, 0xa9, 0x95, 0x21, 0x4a, 0xef, 0x66, 0xea, 0xb7,
+    0x82, 0x25, 0xd7, 0x5d, 0xef, 0x6a, 0xb6, 0x1d, 0x8a, 0x5b, 0xee, 0x98, 0x9e, 0x97, 0x45, 0xff, 0xe4, 0x55, 0xfd, 0x6c,
+    0x75, 0x60, 0x0c, 0xc8, 0xf7, 0x48, 0x17, 0x75, 0x3c, 0xfa, 0x7c, 0x77, 0xf9, 0xfa, 0x97, 0x01, 0x8f, 0x5f, 0xb4, 0x23,
+    0x45, 0x3a, 0xbb, 0xdf, 0x5a, 0x7a, 0x40, 0xb6, 0xfe, 0xbd, 0x67, 0xb5, 0xbb, 0x84, 0x4a, 0x68, 0xbf, 0x89, 0xd6, 0x7f,
+    0xa4, 0x9f, 0x46, 0xf7, 0x60, 0x4b, 0x0f, 0x98, 0x13, 0xff, 0xa2, 0xd6, 0xbf, 0x3d, 0x36, 0xc4, 0xb7, 0x9e, 0xc5, 0x05,
+    0x64, 0x1b, 0x51, 0xbc, 0x6e, 0x35, 0x8b, 0x8a, 0xd5, 0x34, 0x72, 0xcc, 0x78, 0x83, 0xb6, 0xed, 0x55, 0x1d, 0xed, 0xd8,
+    0xb4, 0xb5, 0xc4, 0x7c, 0xfd, 0xc5, 0xbc, 0xe3, 0x77, 0x5d, 0x6e, 0xf7, 0x6b, 0x5b, 0xd4, 0xd9, 0x1d, 0x7b, 0xf1, 0xf1,
+    0xbf, 0xde, 0x5f, 0xa3, 0xcd, 0x38, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x36,
+    0x73, 0x14, 0xe8, 0x33, 0xd5, 0xf4, 0xcf, 0xb0, 0xee, 0x9d, 0x35, 0x73, 0xef, 0xdc, 0xac, 0xfd, 0xed, 0xec, 0x79, 0xc1,
+    0x24, 0x65, 0x07, 0xb8, 0xf8, 0x75, 0x33, 0x5f, 0x16, 0xb3, 0x5e, 0x0b, 0x59, 0x33, 0x6e, 0x69, 0x3d, 0x18, 0x1e, 0x5f,
+    0x8f, 0xd5, 0xf3, 0x11, 0xef, 0xc3, 0x8b, 0xf1, 0xb6, 0xd9, 0xe2, 0xdf, 0xe6, 0x0b, 0x59, 0x4d, 0xff, 0x32, 0xc9, 0x9f,
+    0xe7, 0xd1, 0xdf, 0xbb, 0xfb, 0xb3, 0xdd, 0x91, 0xa5, 0x6f, 0xd5, 0x33, 0xe8, 0x3f, 0xe6, 0xde, 0xb5, 0xf8, 0x08, 0xa3,
+    0x7d, 0x78, 0x47, 0xe9, 0x2f, 0xa6, 0xbd, 0x73, 0x3d, 0xfa, 0xfb, 0xfc, 0xf2, 0xf3, 0xe2, 0xdf, 0x7e, 0xc7, 0x92, 0xb2,
+    0x33, 0xba, 0x37, 0x5a, 0x75, 0x99, 0x1a, 0x8f, 0x70, 0x6a, 0xc5, 0xfb, 0xe5, 0xb2, 0x9c, 0x5d, 0xc7, 0xba, 0x17, 0xa3,
+    0xfc, 0xab, 0xde, 0xec, 0xdf, 0x47, 0xe8, 0x8f, 0x77, 0xec, 0xdc, 0xbd, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xe0, 0xd6, 0xd6, 0x71, 0xe2, 0xf6, 0xa3, 0xd2, 0x66, 0x75, 0x93, 0xcd, 0x8c, 0x1e, 0xd6, 0xdc,
+    0x31, 0x5a, 0x6f, 0x85, 0x75, 0xad, 0xb2, 0x3e, 0x28, 0xbb, 0xf4, 0x39, 0x7c, 0x2b, 0x4f, 0xee, 0x79, 0x2a, 0x9f, 0xec,
+    0x66, 0x31, 0xd9, 0x7a, 0xf2, 0xde, 0xb9, 0xde, 0x3b, 0xeb, 0x1d, 0x00, 0xba, 0x5c, 0x6d, 0xba, 0xa3, 0xb5, 0xe9, 0x14,
+    0x89, 0x71, 0x5d, 0x58, 0x33, 0xf4, 0xb5, 0xcb, 0xea, 0x23, 0x25, 0x1f, 0xf3, 0xec, 0x51, 0xeb, 0x3d, 0xdd, 0x6c, 0xd1,
+    0xba, 0x93, 0xcb, 0xa8, 0x77, 0xae, 0xef, 0xce, 0x5a, 0xfd, 0xab, 0x3a, 0x57, 0x9b, 0x5e, 0x9d, 0x18, 0x5f, 0xa1, 0x2d,
+    0x2b, 0x8e, 0x67, 0x57, 0x71, 0x79, 0xe0, 0x58, 0x7a, 0xcc, 0x93, 0xc6, 0xff, 0xde, 0x9c, 0x7d, 0x77, 0xff, 0xaf, 0xfe,
+    0x5c, 0xcf, 0x9d, 0xf5, 0x4e, 0x1e, 0x9b, 0x8b, 0xcb, 0xdb, 0x03, 0x22, 0xb3, 0x29, 0x5a, 0x1d, 0x59, 0xed, 0x7e, 0x53,
+    0x1a, 0x3b, 0x47, 0xf6, 0x54, 0x68, 0xc5, 0xff, 0x98, 0xfe, 0xd6, 0x3b, 0x17, 0xa3, 0x3f, 0x4e, 0x16, 0x89, 0xff, 0x8c,
+    0xac, 0x78, 0xb6, 0xdd, 0x68, 0x7d, 0x51, 0xb8, 0x3f, 0xff, 0xcf, 0xd7, 0xdf, 0xea, 0x82, 0x9b, 0xad, 0x7f, 0x31, 0xfb,
+    0x54, 0xbd, 0x6f, 0x8d, 0xda, 0xf9, 0xdf, 0xae, 0xc2, 0x88, 0xfe, 0xd1, 0x77, 0x8e, 0xcd, 0x1a, 0x99, 0xab, 0x7f, 0x71,
+    0x38, 0x6b, 0x23, 0x77, 0xa3, 0x6f, 0xbf, 0x85, 0x67, 0xea, 0x9f, 0x77, 0xe7, 0x18, 0x67, 0xa5, 0x2d, 0xab, 0xe3, 0xca,
+    0x7f, 0x19, 0xa7, 0xaf, 0xfd, 0xcf, 0x0f, 0x7e, 0x0a, 0x7b, 0x26, 0xdf, 0x4d, 0x3b, 0xd7, 0x7b, 0x36, 0x1c, 0xed, 0x55,
+    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe2, 0xd3, 0x4d, 0x8f, 0x47, 0xcf, 0x49, 0xe6,
+    0x2d, 0xef, 0xb9, 0xce, 0xbe, 0x94, 0xaf, 0xe5, 0xf3, 0x8b, 0xa3, 0x2f, 0xe5, 0xa5, 0xfc, 0x92, 0x50, 0x97, 0xba, 0xbb,
+    0xc7, 0xf0, 0xd6, 0x97, 0xe5, 0x33, 0xfd, 0x75, 0xe8, 0x7d, 0x17, 0x5c, 0xed, 0x78, 0xf3, 0xaa, 0xca, 0x5b, 0xf9, 0x98,
+    0xef, 0xe5, 0xb9, 0xfc, 0xbe, 0x71, 0xbc, 0xe7, 0x24, 0xf3, 0x96, 0xb7, 0xf4, 0xff, 0x4c, 0xfe, 0x91, 0xbf, 0xe5, 0x85,
+    0x7c, 0xb1, 0x79, 0xd6, 0x9f, 0xe1, 0x75, 0x69, 0xf9, 0x71, 0x34, 0x3b, 0x19, 0x7b, 0x32, 0x31, 0x55, 0x53, 0xdf, 0xd8,
+    0xdf, 0xe1, 0x78, 0xd4, 0x5b, 0xf9, 0x93, 0x7c, 0x20, 0x3f, 0x6c, 0x38, 0xd1, 0x7a, 0x2b, 0xc9, 0xde, 0xf2, 0x96, 0xfe,
+    0x7f, 0x88, 0xc8, 0x5f, 0xf2, 0xab, 0x7c, 0x78, 0x51, 0xf2, 0x5c, 0x9e, 0x27, 0xd4, 0xa5, 0xc8, 0xdd, 0xeb, 0x7a, 0xdc,
+    0x39, 0x77, 0xb2, 0xf6, 0xc4, 0xff, 0x51, 0x7c, 0x2c, 0x3f, 0xca, 0x37, 0x06, 0x1f, 0x42, 0xa6, 0xfe, 0x5f, 0xc9, 0xbf,
+    0x3b, 0xfa, 0xdb, 0x3c, 0x13, 0x1e, 0x3f, 0xde, 0xa5, 0xb6, 0xc5, 0xdc, 0x47, 0xac, 0x3b, 0x62, 0x46, 0x97, 0xcd, 0x68,
+    0xd3, 0x11, 0xfd, 0xf7, 0xeb, 0xf7, 0x91, 0xbc, 0x98, 0xa8, 0x7f, 0x6f, 0xfe, 0x2f, 0x8a, 0x9c, 0xaf, 0xd6, 0xbd, 0xc0,
+    0x4b, 0xf0, 0x2e, 0xfb, 0xbe, 0xac, 0x80, 0xb3, 0xe2, 0x7f, 0x9f, 0xdf, 0x26, 0xea, 0x9f, 0xe3, 0x02, 0x3a, 0x56, 0x63,
+    0xf4, 0x8f, 0xd3, 0x7f, 0xe4, 0xdd, 0xde, 0xe3, 0x26, 0x5a, 0x71, 0xfc, 0xef, 0x39, 0xc9, 0xbc, 0xe5, 0x3d, 0x34, 0xfa,
+    0x67, 0xd7, 0xe5, 0x48, 0xa7, 0xe1, 0x51, 0xf1, 0x0f, 0xe8, 0x0f, 0xe8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xe7, 0xfc, 0xdd, 0x63, 0x19, 0xd8, 0xad, 0xd0, 0xb3, 0x06, 0x15, 0xed, 0x79, 0xeb, 0x3f, 0xcb, 0xbc, 0xfb,
+    0xb5, 0x9e, 0xbc, 0xe7, 0xcd, 0x8b, 0xae, 0x67, 0x96, 0xfe, 0x1e, 0x5f, 0x43, 0x8e, 0xe7, 0x6d, 0x9d, 0xfb, 0xf5, 0xb2,
+    0x07, 0xb6, 0xb4, 0x8a, 0xae, 0xe7, 0x51, 0xd9, 0x51, 0x6e, 0x79, 0xed, 0x41, 0xba, 0x0e, 0xe7, 0xf5, 0xb3, 0x9c, 0xe8,
+    0x3c, 0xcf, 0x45, 0xed, 0x79, 0x5a, 0xc5, 0x0f, 0x91, 0x55, 0x56, 0x1a, 0xd9, 0xe3, 0x8a, 0x21, 0xcb, 0x5d, 0x86, 0xdf,
+    0x23, 0x73, 0x7d, 0x71, 0xa5, 0xb2, 0xd9, 0xf7, 0xbc, 0x16, 0xbf, 0xd7, 0x0c, 0xfd, 0xad, 0x7e, 0xc8, 0x33, 0xeb, 0x2f,
+    0x0b, 0xe9, 0xef, 0x1d, 0xdf, 0x7c, 0xe3, 0x55, 0x99, 0x52, 0x76, 0x84, 0xfe, 0x23, 0xfb, 0xb9, 0x5f, 0x6b, 0xfc, 0x6b,
+    0xaf, 0x7f, 0x6b, 0xf1, 0xdf, 0xaf, 0xc7, 0x2d, 0xe8, 0x2f, 0xe8, 0xbf, 0xb8, 0xdf, 0xeb, 0x28, 0x0f, 0xd9, 0xd9, 0xdf,
+    0xff, 0xc7, 0xfa, 0xe1, 0x3a, 0x7e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1f, 0x2d, 0x2f,
+    0x9a, 0xe7, 0x77, 0xd1, 0x2b, 0xf9, 0xfe, 0xaa, 0x29, 0x1f, 0x57, 0xfb, 0x19, 0x6c, 0x1e, 0x2d, 0x5b, 0xbe, 0x3e, 0xab,
+    0x47, 0x6f, 0xec, 0x77, 0xd1, 0xd6, 0x76, 0xb5, 0xe7, 0xc3, 0x9a, 0xed, 0xfb, 0x6b, 0xed, 0x60, 0x6b, 0x59, 0x87, 0xb5,
+    0xf7, 0x61, 0x5b, 0xbe, 0xbe, 0x4c, 0xfd, 0x23, 0x3c, 0x80, 0x5b, 0xc7, 0xeb, 0x15, 0xac, 0x45, 0x90, 0x3f, 0xc1, 0xb3,
+    0xa6, 0xd4, 0x2b, 0xa9, 0x4b, 0x78, 0x9f, 0x7c, 0x65, 0xf3, 0xfc, 0x29, 0x59, 0x9e, 0x97, 0xd5, 0xd6, 0xa2, 0xcf, 0x50,
+    0xb6, 0x9e, 0xbb, 0x71, 0xbe, 0xfe, 0x67, 0xe9, 0x53, 0x56, 0x1f, 0xd6, 0xad, 0xc7, 0xbf, 0x67, 0x4e, 0x59, 0xad, 0x6f,
+    0xd8, 0x3c, 0x5a, 0xad, 0x77, 0xdf, 0x35, 0xca, 0x56, 0x7c, 0x07, 0x5a, 0x29, 0xc6, 0xcf, 0xee, 0x5d, 0x42, 0x7f, 0xfe,
+    0x0e, 0x29, 0xef, 0xfd, 0xff, 0x3a, 0x62, 0x07, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdf,
+    0xff, 0x92, 0xc5, 0x4f, 0xe7, 0x72, 0xe9, 0x65, 0xf1, 0x5b, 0xc9, 0x21, 0x98, 0xb9, 0x0a, 0x74, 0xe6, 0x2c, 0x7e, 0xa5,
+    0xd9, 0x33, 0xda, 0x59, 0xfc, 0x56, 0x72, 0x08, 0x7a, 0xe3, 0x9f, 0xd1, 0xf1, 0xac, 0x6d, 0xd0, 0xf7, 0x0f, 0xac, 0x94,
+    0xc5, 0xaf, 0x74, 0xf3, 0x3b, 0xc5, 0x96, 0x8d, 0xb9, 0x00, 0xaf, 0xd9, 0x05, 0xe0, 0x9b, 0xff, 0x57, 0x5b, 0xcd, 0xcf,
+    0xc9, 0xe2, 0xa6, 0x2f, 0xbd, 0xb6, 0xdd, 0x5e, 0x3d, 0x4e, 0xef, 0x95, 0x56, 0xf3, 0xd1, 0x5f, 0xd2, 0x66, 0xc1, 0x55,
+    0xbc, 0xac, 0xab, 0x64, 0xf1, 0xbb, 0xa5, 0xf8, 0xbf, 0x76, 0x27, 0x5c, 0xde, 0xdc, 0x59, 0x4e, 0xe1, 0x02, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf3, 0x79, 0x40, 0x2c, 0xde, 0x97, 0x68, 0x7f, 0x9b, 0x27,
+    0x8b, 0x9f, 0x18, 0x7c, 0x6d, 0xd0, 0x5f, 0xdd, 0xaa, 0xe1, 0xbe, 0xcf, 0xf8, 0x2c, 0x7e, 0x05, 0xfd, 0x43, 0x56, 0x70,
+    0xb7, 0x4b, 0xea, 0x15, 0xb4, 0x1d, 0x6b, 0x9f, 0x99, 0x9e, 0x9f, 0x55, 0x32, 0x20, 0x59, 0xce, 0xbc, 0x96, 0x5d, 0x98,
+    0xaf, 0x6d, 0xfe, 0x9f, 0x9f, 0xc9, 0xea, 0xa8, 0xfc, 0x58, 0x50, 0x26, 0xc6, 0x38, 0xfa, 0xa3, 0xbf, 0xc7, 0x89, 0x8d,
+    0xfe, 0xe7, 0xf4, 0xfd, 0x8d, 0x68, 0xcc, 0xbb, 0xe1, 0xed, 0xbc, 0x93, 0x6a, 0xff, 0x42, 0x09, 0xfd, 0xcf, 0xfb, 0x73,
+    0x2a, 0x3f, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x90, 0xb9, 0x10, 0xfd, 0xd1, 0xff, 0xe4, 0xfa, 0xbf, 0x05 };
+    0x00, 0x00, 0xc0, 0x6a, 0x90, 0x0d, 0x11, 0xfd, 0xd1, 0xff, 0xc6, 0xf5, 0xff, 0x0f };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle jungleFontRecs[189] = {
+static const Rectangle jungleFontRecs[184] = {
     { 4, 4, 5 , 12 },
     { 17, 4, 2 , 7 },
     { 27, 4, 5 , 3 },
@@ -246,100 +243,95 @@
     { 103, 104, 6 , 7 },
     { 117, 104, 6 , 7 },
     { 131, 104, 6 , 7 },
-    { 145, 104, 0 , 0 },
-    { 153, 104, 6 , 9 },
-    { 167, 104, 0 , 0 },
-    { 175, 104, 7 , 7 },
-    { 190, 104, 8 , 8 },
-    { 206, 104, 6 , 5 },
-    { 220, 104, 8 , 8 },
-    { 236, 104, 7 , 7 },
-    { 4, 124, 8 , 8 },
-    { 20, 124, 4 , 4 },
+    { 145, 104, 6 , 9 },
+    { 159, 104, 7 , 7 },
+    { 174, 104, 8 , 8 },
+    { 190, 104, 6 , 5 },
+    { 204, 104, 8 , 8 },
+    { 220, 104, 7 , 7 },
+    { 235, 104, 8 , 8 },
+    { 4, 124, 4 , 4 },
+    { 16, 124, 8 , 8 },
     { 32, 124, 8 , 8 },
     { 48, 124, 8 , 8 },
-    { 64, 124, 8 , 8 },
-    { 80, 124, 0 , 0 },
-    { 88, 124, 6 , 7 },
-    { 102, 124, 5 , 8 },
-    { 115, 124, 3 , 3 },
-    { 126, 124, 0 , 0 },
-    { 134, 124, 8 , 8 },
-    { 150, 124, 8 , 8 },
-    { 166, 124, 6 , 5 },
-    { 180, 124, 10 , 7 },
-    { 198, 124, 10 , 5 },
-    { 216, 124, 0 , 0 },
-    { 224, 124, 6 , 7 },
-    { 238, 124, 6 , 10 },
+    { 64, 124, 6 , 7 },
+    { 78, 124, 5 , 8 },
+    { 91, 124, 3 , 3 },
+    { 102, 124, 8 , 8 },
+    { 118, 124, 8 , 8 },
+    { 134, 124, 6 , 5 },
+    { 148, 124, 10 , 7 },
+    { 166, 124, 10 , 5 },
+    { 184, 124, 6 , 7 },
+    { 198, 124, 6 , 10 },
+    { 212, 124, 6 , 10 },
+    { 226, 124, 6 , 10 },
+    { 240, 124, 6 , 10 },
     { 4, 144, 6 , 10 },
     { 18, 144, 6 , 10 },
-    { 32, 144, 6 , 10 },
-    { 46, 144, 6 , 10 },
-    { 60, 144, 6 , 10 },
-    { 74, 144, 10 , 7 },
-    { 92, 144, 6 , 9 },
+    { 32, 144, 10 , 7 },
+    { 50, 144, 6 , 9 },
+    { 64, 144, 6 , 10 },
+    { 78, 144, 6 , 10 },
+    { 92, 144, 6 , 10 },
     { 106, 144, 6 , 10 },
     { 120, 144, 6 , 10 },
     { 134, 144, 6 , 10 },
     { 148, 144, 6 , 10 },
     { 162, 144, 6 , 10 },
-    { 176, 144, 6 , 10 },
+    { 176, 144, 6 , 7 },
     { 190, 144, 6 , 10 },
     { 204, 144, 6 , 10 },
-    { 218, 144, 6 , 7 },
+    { 218, 144, 6 , 10 },
     { 232, 144, 6 , 10 },
     { 4, 164, 6 , 10 },
     { 18, 164, 6 , 10 },
-    { 32, 164, 6 , 10 },
-    { 46, 164, 6 , 10 },
+    { 32, 164, 6 , 5 },
+    { 46, 164, 6 , 7 },
     { 60, 164, 6 , 10 },
-    { 74, 164, 6 , 5 },
-    { 88, 164, 6 , 7 },
+    { 74, 164, 6 , 10 },
+    { 88, 164, 6 , 10 },
     { 102, 164, 6 , 10 },
     { 116, 164, 6 , 10 },
-    { 130, 164, 6 , 10 },
-    { 144, 164, 6 , 10 },
-    { 158, 164, 6 , 10 },
-    { 172, 164, 6 , 7 },
-    { 186, 164, 6 , 7 },
+    { 130, 164, 6 , 7 },
+    { 144, 164, 6 , 7 },
+    { 158, 164, 6 , 8 },
+    { 172, 164, 6 , 8 },
+    { 186, 164, 6 , 8 },
     { 200, 164, 6 , 8 },
     { 214, 164, 6 , 8 },
     { 228, 164, 6 , 8 },
-    { 4, 184, 6 , 8 },
-    { 18, 184, 6 , 8 },
-    { 32, 184, 6 , 8 },
-    { 46, 184, 9 , 5 },
-    { 63, 184, 6 , 7 },
+    { 4, 184, 9 , 5 },
+    { 21, 184, 6 , 7 },
+    { 35, 184, 6 , 8 },
+    { 49, 184, 6 , 8 },
+    { 63, 184, 6 , 8 },
     { 77, 184, 6 , 8 },
     { 91, 184, 6 , 8 },
     { 105, 184, 6 , 8 },
     { 119, 184, 6 , 8 },
     { 133, 184, 6 , 8 },
-    { 147, 184, 6 , 8 },
+    { 147, 184, 6 , 7 },
     { 161, 184, 6 , 8 },
     { 175, 184, 6 , 8 },
-    { 189, 184, 6 , 7 },
+    { 189, 184, 6 , 8 },
     { 203, 184, 6 , 8 },
     { 217, 184, 6 , 8 },
     { 231, 184, 6 , 8 },
-    { 4, 204, 6 , 8 },
-    { 18, 204, 6 , 8 },
-    { 32, 204, 6 , 8 },
-    { 46, 204, 5 , 5 },
-    { 59, 204, 6 , 5 },
+    { 4, 204, 5 , 5 },
+    { 17, 204, 6 , 5 },
+    { 31, 204, 6 , 8 },
+    { 45, 204, 6 , 8 },
+    { 59, 204, 6 , 8 },
     { 73, 204, 6 , 8 },
-    { 87, 204, 6 , 8 },
-    { 101, 204, 6 , 8 },
-    { 115, 204, 6 , 8 },
-    { 129, 204, 6 , 10 },
-    { 143, 204, 6 , 9 },
-    { 157, 204, 6 , 10 },
+    { 87, 204, 6 , 10 },
+    { 101, 204, 6 , 9 },
+    { 115, 204, 6 , 10 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo jungleFontGlyphs[189] = {
+static const GlyphInfo jungleFontGlyphs[184] = {
     { 32, 0, 0, 5, { 0 }},
     { 33, 0, 2, 3, { 0 }},
     { 34, 0, 2, 6, { 0 }},
@@ -440,9 +432,7 @@
     { 163, 0, 2, 7, { 0 }},
     { 8364, 0, 2, 7, { 0 }},
     { 165, 0, 2, 7, { 0 }},
-    { 352, 0, 0, 0, { 0 }},
     { 167, 0, 1, 7, { 0 }},
-    { 353, 0, 0, 0, { 0 }},
     { 169, 0, 2, 8, { 0 }},
     { 170, 0, 1, 8, { 0 }},
     { 171, 0, 3, 7, { 0 }},
@@ -453,17 +443,14 @@
     { 177, 0, 1, 8, { 0 }},
     { 178, 0, 1, 8, { 0 }},
     { 179, 0, 1, 8, { 0 }},
-    { 381, 0, 0, 0, { 0 }},
     { 181, 0, 4, 7, { 0 }},
     { 182, 0, 1, 4, { 0 }},
     { 183, 0, 4, 4, { 0 }},
-    { 382, 0, 0, 0, { 0 }},
     { 185, 0, 1, 8, { 0 }},
     { 186, 0, 1, 8, { 0 }},
     { 187, 0, 3, 7, { 0 }},
     { 338, 0, 2, 11, { 0 }},
     { 339, 0, 4, 11, { 0 }},
-    { 376, 0, 0, 0, { 0 }},
     { 191, 0, 2, 7, { 0 }},
     { 192, 0, -1, 7, { 0 }},
     { 193, 0, -1, 7, { 0 }},
@@ -549,29 +536,40 @@
 
     Font font = { 0 };
     font.baseSize = 12;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 184;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, jungleFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, jungleFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "PixelIntv.otf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/lavanda/style_lavanda.h b/raygui/styles/lavanda/style_lavanda.h
--- a/raygui/styles/lavanda/style_lavanda.h
+++ b/raygui/styles/lavanda/style_lavanda.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,22 +15,22 @@
 
 // Custom style name: Lavanda
 static const GuiStyleProp lavandaStyleProps[LAVANDA_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0xab9bd3ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x3e4350ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xdadaf4ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xee84a0ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xf4b7c7ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xb7657bff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xd5c8dbff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0x966ec0ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xd7ccf7ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x8fa2bdff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x6b798dff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x8292a9ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0xab9bd3ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x3e4350ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xdadaf4ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xee84a0ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xf4b7c7ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xb7657bff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xd5c8dbff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x966ec0ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xd7ccf7ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x8fa2bdff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x6b798dff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x8292a9ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 18, (int)0x84adb7ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x5b5b81ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "Cartridge.ttf" (size: 16, spacing: 1)
@@ -579,27 +579,38 @@
     font.baseSize = 16;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, lavandaFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, lavandaFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "Cartridge.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/pocket/style_pocket.h b/raygui/styles/pocket/style_pocket.h
new file mode 100644
--- /dev/null
+++ b/raygui/styles/pocket/style_pocket.h
@@ -0,0 +1,607 @@
+//////////////////////////////////////////////////////////////////////////////////
+//                                                                              //
+// StyleAsCode exporter v2.0 - Style data exported as a values array            //
+//                                                                              //
+// USAGE: On init call: GuiLoadStylePocket();                                   //
+//                                                                              //
+// more info and bugs-report:  github.com/raysan5/raygui                        //
+// feedback and support:       ray[at]raylibtech.com                            //
+//                                                                              //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
+//                                                                              //
+//////////////////////////////////////////////////////////////////////////////////
+
+#define POCKET_STYLE_PROPS_COUNT  17
+
+// Custom style name: Pocket
+static const GuiStyleProp pocketStyleProps[POCKET_STYLE_PROPS_COUNT] = {
+    { 0, 0, (int)0x5e675eff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xb9c7b9ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x5e675eff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0x56591eff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x9ca04cff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xc4ca3fff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x0b320bff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x306230ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x9bbc0fff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x939792ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xbcbdb6ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x9a9697ff },    // DEFAULT_TEXT_COLOR_DISABLED
+    { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
+    { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
+    { 0, 18, (int)0x56591eff },    // DEFAULT_LINE_COLOR 
+    { 0, 19, (int)0xd9d9ceff },    // DEFAULT_BACKGROUND_COLOR 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+};
+
+// WARNING: This style uses a custom font: "GMSN.ttf" (size: 16, spacing: 0)
+
+#define POCKET_STYLE_FONT_ATLAS_COMP_SIZE 2438
+
+// Font atlas image pixels data: DEFLATE compressed
+static unsigned char pocketFontData[POCKET_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
+    0xdd, 0x5b, 0x92, 0xec, 0xb6, 0x0d, 0x00, 0x50, 0xee, 0x7f, 0xa1, 0xd9, 0x06, 0x53, 0xa9, 0x94, 0x2b, 0xf1, 0xf8, 0x8e,
+    0x48, 0x02, 0xa0, 0x9e, 0xc7, 0xa7, 0xfc, 0x33, 0xba, 0xdd, 0x52, 0x53, 0x82, 0xf8, 0x90, 0x08, 0xf6, 0x06, 0x00, 0x00,
+    0x00, 0x7c, 0xde, 0x7f, 0xfe, 0xfb, 0xf3, 0xdf, 0xfe, 0xb4, 0xe5, 0x78, 0xdb, 0x5f, 0xff, 0x62, 0xb4, 0xa5, 0xff, 0x7a,
+    0x24, 0xfd, 0x60, 0xdb, 0xdc, 0xbe, 0x62, 0xc7, 0xd5, 0x97, 0xca, 0xa6, 0x1f, 0x94, 0x5a, 0x4b, 0xff, 0xbd, 0x1d, 0x96,
+    0x7d, 0x0f, 0x94, 0x5e, 0x3b, 0x3c, 0xe6, 0xdf, 0x3f, 0x39, 0xde, 0x52, 0x79, 0x9c, 0x2b, 0x65, 0x5a, 0x79, 0x7e, 0x56,
+    0x4a, 0xb0, 0x2d, 0x6f, 0x3d, 0x2e, 0xa9, 0x36, 0x55, 0x8e, 0xe3, 0x6f, 0xee, 0x37, 0x89, 0xff, 0xe3, 0x5f, 0xf3, 0x57,
+    0x0c, 0x1e, 0x9d, 0xfd, 0xf9, 0x6b, 0xa3, 0x4d, 0xdf, 0x13, 0xfe, 0xb7, 0xef, 0xba, 0x08, 0xcd, 0x7e, 0x4b, 0x1f, 0xde,
+    0x09, 0x57, 0x4a, 0xe8, 0xb8, 0xf4, 0x5a, 0x28, 0x26, 0x46, 0xdf, 0x19, 0x39, 0x96, 0x99, 0x6d, 0x73, 0xc7, 0x17, 0xbb,
+    0xe6, 0xc7, 0xdf, 0x77, 0x7c, 0xa5, 0x1d, 0x9d, 0xe1, 0xd1, 0x95, 0x7b, 0xfc, 0xfb, 0xd6, 0xcf, 0x6a, 0x26, 0xea, 0xf7,
+    0xc4, 0x7f, 0xff, 0xbf, 0x38, 0xeb, 0xc1, 0x18, 0xcc, 0xd7, 0x0d, 0xeb, 0xb5, 0xc2, 0xf1, 0x3d, 0x6b, 0x5f, 0x09, 0x1f,
+    0x95, 0x53, 0x0f, 0x5c, 0xc3, 0xeb, 0xe7, 0x2c, 0xba, 0x9f, 0x1d, 0xf1, 0x5f, 0x11, 0xc5, 0x6d, 0xa2, 0x46, 0x8c, 0xb4,
+    0x29, 0x8e, 0x5b, 0x9c, 0xf9, 0x08, 0x1f, 0x1d, 0x4b, 0xa4, 0x3d, 0x93, 0x2f, 0xcb, 0xd5, 0x36, 0xc7, 0xbe, 0xf8, 0xaf,
+    0xa8, 0x6f, 0xd7, 0xeb, 0x92, 0x7d, 0xe5, 0x3b, 0x53, 0x5f, 0xdf, 0x3f, 0xfe, 0xd7, 0x7f, 0x5b, 0x45, 0xfc, 0xd7, 0x9c,
+    0x95, 0xf5, 0xf8, 0xef, 0xe2, 0x7f, 0xba, 0xfe, 0xff, 0xbd, 0xd4, 0x7b, 0xb0, 0xff, 0x95, 0xef, 0xb5, 0x57, 0xb5, 0xf3,
+    0xaf, 0x8d, 0xff, 0x51, 0x7f, 0xb0, 0x2d, 0xc7, 0x7f, 0xac, 0xf7, 0x19, 0xe9, 0x6d, 0x54, 0xb5, 0xff, 0xf7, 0xb6, 0x1e,
+    0x8e, 0x7b, 0x8f, 0x91, 0x08, 0x5f, 0x1b, 0xf3, 0xa8, 0xf9, 0xe6, 0x2b, 0xe2, 0xbf, 0x4d, 0x1c, 0x4d, 0x1f, 0xf6, 0xff,
+    0x67, 0xef, 0xf0, 0x6b, 0xf1, 0x5f, 0x57, 0x77, 0x5c, 0x19, 0xff, 0x3d, 0x38, 0x22, 0x56, 0xdd, 0x8f, 0x8f, 0xff, 0xb6,
+    0xb5, 0xf1, 0xb9, 0xf3, 0xfa, 0xff, 0xa3, 0x76, 0x60, 0x26, 0xfe, 0xbf, 0xd2, 0xfe, 0x9f, 0x69, 0x69, 0x8f, 0x4a, 0x71,
+    0xfe, 0x7e, 0x76, 0x45, 0x6d, 0x7e, 0x6d, 0xfc, 0xf7, 0xa9, 0x31, 0xec, 0x7b, 0xc7, 0x7f, 0x5b, 0xee, 0xe5, 0x55, 0x5e,
+    0xbb, 0xd1, 0x2b, 0x6a, 0x74, 0xe5, 0xce, 0xdc, 0xd5, 0xee, 0x19, 0xff, 0xb1, 0xeb, 0xb9, 0x0f, 0x5b, 0xf9, 0x3d, 0x11,
+    0xff, 0xed, 0x35, 0xf1, 0xdf, 0x83, 0xa3, 0x1d, 0xbf, 0xb7, 0xf7, 0x62, 0xe3, 0x71, 0x91, 0x96, 0x7c, 0xa6, 0x8d, 0x52,
+    0x15, 0xff, 0xf7, 0x38, 0x93, 0xea, 0xff, 0x8a, 0xf1, 0xff, 0x76, 0xd8, 0xc2, 0xff, 0x56, 0xfc, 0x1f, 0x3f, 0xff, 0x6b,
+    0xb7, 0x7f, 0x56, 0x17, 0x8d, 0xff, 0x9a, 0xf1, 0xff, 0xf3, 0xef, 0xd6, 0x33, 0x3d, 0xd7, 0x5c, 0xfc, 0xdf, 0xe9, 0xf9,
+    0xdf, 0xde, 0xf8, 0x1f, 0x3d, 0xf5, 0x7e, 0x53, 0xfb, 0xbf, 0x72, 0x1c, 0x3f, 0xfe, 0xce, 0xcd, 0xbe, 0x77, 0x8a, 0x5a,
+    0xe8, 0x4d, 0xae, 0x7b, 0x46, 0x7f, 0xf4, 0x39, 0x50, 0x6e, 0x94, 0xee, 0xea, 0xf7, 0x7f, 0xea, 0x4b, 0xf0, 0xbc, 0xe3,
+    0xe9, 0x37, 0x6e, 0x33, 0xf2, 0xae, 0xb7, 0x64, 0x5d, 0x5d, 0x67, 0x3e, 0x9f, 0x8d, 0xef, 0xcb, 0xf9, 0x61, 0x67, 0xcd,
+    0xa6, 0x24, 0x9e, 0x31, 0x66, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x9e, 0xbf,
+    0x10, 0x99, 0x6b, 0x18, 0xcd, 0x43, 0x50, 0x9b, 0x0f, 0xa1, 0xff, 0xc8, 0xc3, 0xba, 0xfa, 0xdd, 0xb3, 0x73, 0x2d, 0x33,
+    0xf3, 0x34, 0x6b, 0x3f, 0x5b, 0x95, 0x59, 0xa2, 0x76, 0xe6, 0xf9, 0x38, 0xdf, 0xcd, 0x6a, 0xb6, 0xe6, 0x58, 0x16, 0xb4,
+    0xf5, 0x9c, 0xe6, 0x99, 0x3c, 0x7c, 0xd5, 0x73, 0xab, 0x6b, 0xf2, 0xa3, 0xcd, 0xcf, 0x79, 0xaf, 0xc9, 0x34, 0x52, 0x17,
+    0xff, 0xeb, 0xe7, 0xa1, 0xff, 0x38, 0x8e, 0x7e, 0x41, 0x26, 0x86, 0xfa, 0xad, 0x73, 0x7f, 0xbf, 0x53, 0xfc, 0xcf, 0xde,
+    0x83, 0xb3, 0x57, 0x6f, 0x7c, 0xc6, 0xdd, 0x28, 0xfb, 0xc4, 0xf5, 0xb9, 0x55, 0x5a, 0x51, 0x7e, 0xd4, 0xfa, 0xf8, 0x6f,
+    0x27, 0xd5, 0xff, 0xd1, 0xf8, 0xef, 0xc3, 0xd5, 0x6c, 0xee, 0x1b, 0xff, 0xeb, 0x79, 0x27, 0xb2, 0x7b, 0xcd, 0xad, 0xe4,
+    0x10, 0xcf, 0x35, 0x9e, 0x8f, 0xff, 0x5c, 0xa6, 0xa0, 0x73, 0xeb, 0xd6, 0xeb, 0xe3, 0x3f, 0x5a, 0x22, 0x57, 0xc5, 0x7f,
+    0xfc, 0x2a, 0xe9, 0xc3, 0x6c, 0xd6, 0x77, 0x8c, 0xff, 0xfe, 0xf9, 0xf8, 0xaf, 0xcf, 0xe5, 0x1b, 0x8d, 0x80, 0x48, 0x1e,
+    0xf4, 0x99, 0x7e, 0xf5, 0x6a, 0xcf, 0x2e, 0xde, 0xef, 0x8a, 0xd6, 0xff, 0xa3, 0xcf, 0xcf, 0xfc, 0x92, 0xab, 0xe3, 0xbf,
+    0x0d, 0x23, 0xbc, 0x27, 0xa2, 0x34, 0x3e, 0x02, 0x92, 0xc9, 0x79, 0x75, 0x4d, 0xfc, 0xb7, 0xd0, 0x8a, 0x81, 0xf1, 0x7a,
+    0xfe, 0xee, 0xf1, 0x5f, 0xdd, 0x37, 0x88, 0x8e, 0x18, 0x54, 0x1f, 0xe3, 0xfd, 0xfa, 0xff, 0xbd, 0xa0, 0x95, 0xb8, 0x23,
+    0xfe, 0xb3, 0xe5, 0x13, 0x8d, 0xa6, 0x58, 0xfc, 0xcf, 0xd7, 0xee, 0xb1, 0xd5, 0x04, 0x62, 0xdb, 0xde, 0x1b, 0xff, 0xb5,
+    0xf9, 0x53, 0xd7, 0xc7, 0x8a, 0xdf, 0x14, 0xff, 0xd1, 0xfe, 0xff, 0x7c, 0x8f, 0xeb, 0x5e, 0xf1, 0xdf, 0x26, 0xd6, 0xe7,
+    0x39, 0x3b, 0xfe, 0x47, 0xd9, 0x56, 0xdf, 0x16, 0xff, 0xd1, 0xd8, 0x8a, 0xae, 0x67, 0xd4, 0xc2, 0x35, 0xdd, 0xdb, 0xeb,
+    0xff, 0xf6, 0xd2, 0xf8, 0x8f, 0xaf, 0x2f, 0xf3, 0xac, 0xf8, 0xaf, 0x6e, 0x35, 0x5c, 0x9f, 0x57, 0x2f, 0x3a, 0xda, 0x18,
+    0x1f, 0xa5, 0x7c, 0x77, 0xfb, 0xbf, 0x6f, 0x68, 0x85, 0x67, 0x9f, 0xff, 0x5f, 0x15, 0xff, 0xbb, 0x9e, 0xff, 0xb5, 0xe9,
+    0x35, 0xff, 0x76, 0x1d, 0x95, 0xf8, 0xaf, 0x8e, 0xff, 0xca, 0xb5, 0x13, 0xd7, 0xfe, 0x45, 0xf5, 0xfb, 0x3f, 0xf5, 0x23,
+    0x69, 0xfb, 0xdf, 0xff, 0xd9, 0x53, 0x3e, 0x6d, 0x6a, 0xc5, 0xb4, 0xf5, 0xbd, 0xb6, 0xc9, 0x55, 0x8d, 0x63, 0xc7, 0x5c,
+    0xff, 0xf6, 0xcd, 0xdd, 0xe3, 0x3f, 0xf6, 0xb6, 0x41, 0xf4, 0x93, 0xf1, 0x4f, 0xdc, 0x67, 0x2d, 0xb0, 0x6f, 0xbe, 0x45,
+    0xa9, 0x14, 0xaa, 0x4b, 0x48, 0xa9, 0xe2, 0x0e, 0xf0, 0xae, 0xf7, 0xcc, 0x77, 0xfd, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xef, 0xcd, 0x5e, 0x99, 0xcd, 0xb9, 0xfd, 0xcf, 0xbf, 0xf6, 0xd0, 0x7c, 0xd7,
+    0x9e, 0xfc, 0x5c, 0x5f, 0xce, 0x83, 0xb1, 0x36, 0xef, 0xb4, 0x22, 0x07, 0x43, 0x75, 0x1e, 0xa9, 0x71, 0xb9, 0xcc, 0x9e,
+    0xe9, 0xf1, 0x4c, 0xe2, 0xd5, 0x2b, 0x24, 0x32, 0xaf, 0x27, 0x93, 0x51, 0x27, 0xb3, 0x96, 0x40, 0x3c, 0x13, 0x62, 0x5b,
+    0xfc, 0xd6, 0xd8, 0x59, 0x9b, 0x99, 0x0f, 0xbe, 0xfa, 0x6d, 0x99, 0xf8, 0x8f, 0xe5, 0x96, 0xbc, 0x22, 0xd3, 0x5a, 0xfc,
+    0x6a, 0xaa, 0x3d, 0xc2, 0xfa, 0x52, 0x99, 0x3b, 0xda, 0xdc, 0xdf, 0x33, 0x73, 0xfa, 0x73, 0xb9, 0x07, 0x56, 0x4b, 0xa2,
+    0x4f, 0x65, 0x4b, 0x59, 0xfd, 0xe4, 0xef, 0x9f, 0x3b, 0xde, 0xd6, 0xa7, 0x32, 0x47, 0x44, 0xf6, 0x18, 0xcb, 0xbd, 0x52,
+    0x3f, 0xa3, 0xf5, 0x29, 0xf1, 0xdf, 0x02, 0xf7, 0xc5, 0x73, 0xe3, 0x3f, 0x7e, 0x9f, 0x6a, 0x85, 0x59, 0x7a, 0xd6, 0xd7,
+    0xc6, 0x88, 0xcc, 0xdc, 0xcd, 0xe7, 0x08, 0x3a, 0x23, 0xa3, 0xc6, 0x3f, 0xe3, 0x6d, 0xe5, 0xac, 0xcd, 0x45, 0xff, 0x9f,
+    0xef, 0x71, 0xed, 0xb0, 0xb5, 0xf5, 0xfb, 0x9d, 0xb1, 0x4f, 0xdc, 0xc5, 0xa2, 0xf5, 0xff, 0x7c, 0xfd, 0xf2, 0x9c, 0xf8,
+    0x9f, 0xe9, 0x6d, 0x9c, 0x17, 0xff, 0xe3, 0xbf, 0xd7, 0x65, 0xd5, 0xae, 0xcc, 0xb5, 0x33, 0xca, 0xb5, 0xdc, 0x42, 0x67,
+    0xa4, 0x07, 0xef, 0x2b, 0xbd, 0x38, 0x9f, 0x79, 0xff, 0xf1, 0xff, 0x6c, 0x4d, 0x3d, 0x1b, 0xff, 0xab, 0x7b, 0x8c, 0xe6,
+    0x64, 0xcc, 0x9e, 0xc9, 0xfe, 0xc2, 0xfa, 0xff, 0xf8, 0xba, 0x78, 0x4a, 0xfd, 0x5f, 0x99, 0x53, 0xab, 0x3e, 0xfe, 0x63,
+    0x11, 0x1e, 0xa9, 0xc9, 0xe7, 0x57, 0x3c, 0x58, 0x3b, 0x6f, 0xe3, 0x56, 0x7e, 0x4f, 0xb4, 0xff, 0xd7, 0xe3, 0x3f, 0x56,
+    0x32, 0x99, 0x75, 0x8a, 0xe2, 0x6b, 0x78, 0xec, 0x19, 0xe9, 0x8a, 0x8c, 0xff, 0xb5, 0x13, 0xfa, 0xff, 0xa3, 0x76, 0x62,
+    0xb4, 0x54, 0xea, 0xd7, 0xa6, 0xaa, 0xcc, 0xb6, 0xbd, 0x1a, 0xff, 0x99, 0xfa, 0x3f, 0x3a, 0x0e, 0x91, 0x69, 0x21, 0xb6,
+    0xc1, 0xc8, 0xc1, 0x68, 0x9f, 0xeb, 0x59, 0x43, 0x8f, 0xda, 0xff, 0x57, 0x8c, 0xff, 0xf7, 0xd3, 0xfa, 0xff, 0x2d, 0xb5,
+    0x8a, 0x51, 0x65, 0xfb, 0xbf, 0x25, 0x5a, 0x99, 0x99, 0xbb, 0x4d, 0xa4, 0xb4, 0xd7, 0xcb, 0xec, 0xca, 0xfa, 0x3f, 0xb7,
+    0xda, 0x5c, 0xdb, 0x96, 0xef, 0x34, 0xd2, 0xfe, 0xdf, 0x13, 0x85, 0x91, 0x3d, 0xf6, 0x44, 0x96, 0xd2, 0xda, 0xfa, 0xff,
+    0xcc, 0xbb, 0xd3, 0xce, 0xe3, 0xb9, 0x4f, 0xde, 0xb9, 0x3d, 0x79, 0xa4, 0xef, 0xd0, 0xff, 0x8f, 0x8c, 0xff, 0x47, 0x73,
+    0x1e, 0x8f, 0x6b, 0xe3, 0x3e, 0x18, 0x6f, 0xbb, 0x73, 0xfc, 0xef, 0x7d, 0xfe, 0x7f, 0x87, 0xdc, 0xcc, 0xdf, 0x8d, 0xff,
+    0x96, 0xca, 0x3f, 0x7d, 0x45, 0xfc, 0xcf, 0xb5, 0xac, 0x62, 0xfd, 0xd5, 0xdc, 0x8a, 0xc9, 0xd1, 0x3e, 0x5d, 0x3b, 0xf5,
+    0x4a, 0x6f, 0x17, 0xb4, 0xfe, 0xab, 0x57, 0xe4, 0x79, 0xe7, 0xfb, 0x50, 0xef, 0xf8, 0x05, 0x67, 0xdc, 0xcf, 0xfb, 0xa6,
+    0x96, 0x6a, 0x7c, 0x3d, 0x94, 0xd8, 0xdd, 0xaa, 0x5d, 0x90, 0x83, 0xf8, 0xec, 0x3d, 0xc6, 0x9f, 0x56, 0x20, 0xfe, 0x2b,
+    0xdf, 0x37, 0xa9, 0x68, 0x25, 0x55, 0xbd, 0xc3, 0xf0, 0xb5, 0x2b, 0x45, 0xc9, 0x7c, 0xe5, 0xbc, 0xae, 0x8f, 0xf4, 0xbe,
+    0xa5, 0x24, 0x5c, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xdb, 0x66, 0xff, 0x44,
+    0xf3, 0xa6, 0x45, 0x72, 0x35, 0x8d, 0x72, 0x0d, 0xb4, 0x92, 0xef, 0xf9, 0xb9, 0x42, 0x41, 0x1f, 0xfc, 0x8b, 0x16, 0x38,
+    0xd2, 0x1e, 0x9e, 0x53, 0xbc, 0xbe, 0xde, 0xc2, 0xcf, 0x23, 0x6e, 0x89, 0x12, 0x19, 0xcf, 0xd8, 0x5d, 0x5f, 0x99, 0x61,
+    0xef, 0x6f, 0xae, 0xc9, 0x7c, 0x1e, 0xc9, 0xe1, 0x37, 0x9b, 0x89, 0xa4, 0xdf, 0xea, 0x4a, 0x58, 0x9f, 0xb1, 0x19, 0xcb,
+    0xe3, 0xd0, 0x0f, 0x63, 0x28, 0x92, 0xa1, 0x61, 0x3e, 0x17, 0xf2, 0xec, 0x79, 0x9b, 0xb9, 0xae, 0xa2, 0x2b, 0x4d, 0xc4,
+    0xcf, 0x6b, 0x0b, 0x5d, 0xed, 0xf1, 0x48, 0xc9, 0x6d, 0x9d, 0x9b, 0x77, 0xbf, 0xe3, 0x37, 0xc7, 0x73, 0xd3, 0xce, 0x7f,
+    0x4f, 0xa6, 0xf6, 0x1b, 0xcf, 0xa8, 0xbc, 0xe2, 0x4a, 0xa8, 0xcc, 0x75, 0x11, 0x8f, 0xff, 0x9a, 0xf9, 0xe4, 0xe3, 0xb5,
+    0x10, 0x62, 0xab, 0x69, 0xcc, 0xe4, 0xea, 0x7e, 0x5f, 0x96, 0x80, 0x7c, 0xfc, 0x7f, 0x35, 0xb7, 0xc2, 0x5b, 0x4a, 0xa0,
+    0x2f, 0xb6, 0xfc, 0x6a, 0xe3, 0x7f, 0x7d, 0x05, 0x83, 0xfd, 0xf1, 0xdf, 0x43, 0xdf, 0x10, 0x6d, 0xb9, 0xdd, 0x73, 0x6b,
+    0x2e, 0xfe, 0xc7, 0x57, 0xd0, 0x9e, 0xad, 0x55, 0x2b, 0x22, 0xe5, 0xf2, 0x8d, 0xb7, 0x60, 0xef, 0x61, 0xdf, 0xd6, 0x68,
+    0xf6, 0x8f, 0xfd, 0xf1, 0x3f, 0x2e, 0xef, 0xd5, 0x73, 0x33, 0x6e, 0xb7, 0xc5, 0xc7, 0x0f, 0x32, 0xd7, 0xd2, 0x8e, 0x76,
+    0xf8, 0x19, 0x5b, 0x23, 0x39, 0xe0, 0xae, 0xda, 0xba, 0x3b, 0xfe, 0xfb, 0xdf, 0xd6, 0x44, 0x3c, 0xca, 0xa6, 0xb2, 0x7e,
+    0x77, 0xd8, 0xb7, 0x35, 0xdf, 0xd6, 0x59, 0x1d, 0xff, 0x6b, 0x81, 0x3b, 0xd1, 0x19, 0xed, 0xd9, 0xf9, 0x28, 0xad, 0xab,
+    0xff, 0xaf, 0x3a, 0xeb, 0xd9, 0xad, 0x99, 0xd1, 0xbd, 0xb7, 0xc6, 0xff, 0x5c, 0xb9, 0xbd, 0x23, 0xfe, 0xc7, 0x79, 0x5a,
+    0xa3, 0x19, 0x97, 0xaf, 0xe8, 0x4b, 0xce, 0x66, 0xda, 0xcf, 0xad, 0x25, 0xfb, 0xa6, 0xf8, 0x6f, 0x45, 0xed, 0xff, 0x33,
+    0xb7, 0xde, 0xa3, 0xfd, 0xdf, 0x5f, 0x10, 0xff, 0xd9, 0xe7, 0x3a, 0xf3, 0xc7, 0x71, 0xce, 0x38, 0x4a, 0x3c, 0x9b, 0x7e,
+    0xe6, 0x09, 0xc6, 0x95, 0x7d, 0xe1, 0xec, 0xd6, 0x6c, 0xfc, 0x7f, 0xb5, 0xfe, 0x7f, 0x43, 0xfc, 0xe7, 0x9f, 0x65, 0xf7,
+    0xc4, 0xea, 0x83, 0xfb, 0xde, 0x75, 0xe8, 0x1b, 0xe3, 0xbf, 0x7d, 0xb4, 0xfe, 0xaf, 0x59, 0x3f, 0xfe, 0x69, 0xf1, 0x3f,
+    0x33, 0xca, 0xf4, 0xd4, 0xf8, 0xaf, 0x88, 0x91, 0xaa, 0xf1, 0xff, 0xfa, 0xb7, 0x9d, 0x76, 0x66, 0xa1, 0x7f, 0x5e, 0x84,
+    0x8f, 0xe3, 0x3f, 0xf2, 0xfe, 0xcf, 0xbb, 0xe3, 0x7f, 0xee, 0xdd, 0x98, 0x67, 0xc7, 0x7f, 0x4f, 0xae, 0x3e, 0xf3, 0xce,
+    0xe7, 0xc3, 0xb1, 0xb5, 0xa4, 0x9f, 0x17, 0xff, 0xb9, 0x77, 0xc7, 0xde, 0xfc, 0xfc, 0x2f, 0xf7, 0x76, 0xc0, 0xbd, 0x9e,
+    0xff, 0x5d, 0xf1, 0x5e, 0x09, 0xef, 0x7f, 0x7b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x80, 0x33, 0xe6, 0xea, 0xcc, 0xcd, 0x10, 0xbb, 0x26, 0xe7, 0x7d, 0x24, 0x43, 0xc1, 0xcc, 0xf1, 0xc4, 0xf3, 0x1e, 0x44,
+    0xb2, 0xec, 0x1f, 0xe5, 0x51, 0x8a, 0xe6, 0x1a, 0xcf, 0xe4, 0x30, 0xda, 0xf5, 0x1b, 0xd7, 0xb3, 0xc1, 0xcf, 0xef, 0x61,
+    0x2e, 0xe7, 0xe3, 0x5a, 0xd9, 0x3f, 0xe5, 0x5c, 0x8f, 0x22, 0x30, 0x3b, 0x57, 0x6f, 0xee, 0x4a, 0xea, 0xe5, 0x59, 0x44,
+    0xf6, 0x64, 0xa6, 0x9e, 0x3b, 0xa7, 0xb1, 0x63, 0x8e, 0xdc, 0xad, 0x7a, 0x62, 0x05, 0x96, 0x36, 0x71, 0x25, 0x55, 0xe7,
+    0xf5, 0xc9, 0xac, 0xc8, 0x31, 0x7f, 0x47, 0xae, 0xcc, 0xd5, 0xdf, 0x12, 0xf9, 0xf2, 0xef, 0x72, 0xae, 0xf7, 0xc6, 0x7f,
+    0x7c, 0x8e, 0xe7, 0x71, 0xa6, 0xa3, 0xfb, 0xce, 0x57, 0xed, 0xa1, 0xac, 0xa6, 0xcf, 0xc9, 0x43, 0x10, 0xab, 0x73, 0xbf,
+    0xd7, 0xba, 0x7d, 0xcf, 0x0c, 0xec, 0x5c, 0xfe, 0x86, 0x71, 0x1d, 0xde, 0x02, 0xf1, 0x7f, 0xc7, 0xbc, 0x55, 0xb9, 0x8c,
+    0x57, 0x33, 0xb9, 0x17, 0xce, 0xda, 0x76, 0xe4, 0x5f, 0x81, 0x15, 0xd8, 0xae, 0xfc, 0x8d, 0xfb, 0x73, 0x75, 0x1c, 0x67,
+    0x11, 0xb9, 0xf7, 0xb9, 0x1e, 0x9f, 0xcb, 0xcc, 0x1d, 0x6e, 0xdc, 0xc3, 0x8f, 0xd6, 0xff, 0x4f, 0x8d, 0xff, 0xd1, 0x2a,
+    0x04, 0xbf, 0xaf, 0x47, 0x76, 0xde, 0xb6, 0x8a, 0x35, 0x0c, 0x56, 0x7b, 0x40, 0x3b, 0xb6, 0x5d, 0x99, 0xab, 0xeb, 0xec,
+    0xdf, 0x1a, 0x2f, 0xa3, 0x71, 0xeb, 0x66, 0x5f, 0xfc, 0xcf, 0xf4, 0xeb, 0xbe, 0x56, 0xff, 0xf7, 0xcb, 0xb7, 0xcd, 0xdf,
+    0xc5, 0xee, 0x7e, 0x6d, 0xef, 0x5f, 0xab, 0xe3, 0x09, 0x31, 0x9e, 0x5b, 0x57, 0x62, 0x5f, 0xfc, 0x3f, 0x33, 0xd3, 0x71,
+    0x26, 0xaf, 0x7c, 0x7b, 0xc8, 0x35, 0xd1, 0x93, 0x6b, 0x18, 0xc7, 0xda, 0x9a, 0xd5, 0xdb, 0xc4, 0xff, 0xbd, 0xe3, 0x3f,
+    0xd3, 0xfa, 0xb8, 0x32, 0x6f, 0x65, 0x76, 0x7d, 0xde, 0xb7, 0xb6, 0x17, 0x47, 0x63, 0x3a, 0xfb, 0x9e, 0xe4, 0xd4, 0x3c,
+    0xa7, 0xfd, 0x6a, 0xfc, 0x5f, 0xd7, 0xfe, 0x17, 0xff, 0xef, 0x8b, 0xff, 0x9e, 0xca, 0x61, 0xae, 0xfd, 0x7f, 0xa7, 0xf3,
+    0x99, 0x1d, 0xff, 0x17, 0xff, 0x7f, 0xea, 0x39, 0xdf, 0xbf, 0xff, 0xbf, 0xeb, 0x49, 0xe5, 0xdb, 0xc6, 0xff, 0xa3, 0x4f,
+    0x7b, 0x9f, 0xf2, 0xac, 0x27, 0xff, 0xec, 0xbf, 0xa7, 0xf6, 0x7d, 0x4d, 0x2e, 0xf3, 0xdc, 0xca, 0x94, 0x9e, 0xfb, 0xf2,
+    0xa6, 0x2b, 0xe1, 0xbb, 0x7b, 0x07, 0xc4, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+    0xe1, 0x1d, 0xfe, 0xf3, 0x32, 0xbe, 0x47, 0x66, 0x7d, 0xce, 0x7d, 0x27, 0x50, 0x7d, 0x07, 0xa8, 0xcf, 0xf8, 0x9e, 0x9f,
+    0x9d, 0xef, 0x7c, 0xc1, 0xd7, 0xda, 0x21, 0xc0, 0xae, 0x98, 0xbb, 0x4b, 0x16, 0xa4, 0x77, 0xac, 0xcd, 0x01, 0xe2, 0xff,
+    0x5e, 0x19, 0x2f, 0x01, 0xf1, 0x0f, 0x88, 0x7f, 0x40, 0xfc, 0x83, 0xf8, 0xbf, 0xc3, 0xca, 0x35, 0xb9, 0x9c, 0xbf, 0x40,
+    0xec, 0x0e, 0x70, 0x66, 0x56, 0xfb, 0x36, 0xbc, 0x6f, 0x78, 0x46, 0x08, 0xdf, 0x6d, 0x6f, 0x34, 0xcf, 0xff, 0xe0, 0xe5,
+    0xed, 0x8d, 0xc8, 0xfb, 0x7f, 0xa2, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xee, 0xe9, 0xbf, 0xff, 0x29, 0x07, 0x10, 0xff, 0xc0, 0xe7, 0xe2, 0xff, 0xdf };
+
+// Font glyphs rectangles data (on atlas)
+static const Rectangle pocketFontRecs[188] = {
+    { 4, 4, 4 , 16 },
+    { 16, 4, 2 , 10 },
+    { 26, 4, 5 , 3 },
+    { 39, 4, 7 , 10 },
+    { 54, 4, 7 , 13 },
+    { 69, 4, 7 , 10 },
+    { 84, 4, 7 , 10 },
+    { 99, 4, 2 , 3 },
+    { 109, 4, 3 , 12 },
+    { 120, 4, 3 , 12 },
+    { 131, 4, 5 , 6 },
+    { 144, 4, 6 , 5 },
+    { 158, 4, 2 , 4 },
+    { 168, 4, 5 , 1 },
+    { 181, 4, 2 , 2 },
+    { 191, 4, 4 , 10 },
+    { 203, 4, 6 , 10 },
+    { 217, 4, 4 , 10 },
+    { 229, 4, 6 , 10 },
+    { 243, 4, 6 , 10 },
+    { 257, 4, 6 , 10 },
+    { 271, 4, 6 , 10 },
+    { 285, 4, 6 , 10 },
+    { 299, 4, 6 , 10 },
+    { 313, 4, 6 , 10 },
+    { 327, 4, 6 , 10 },
+    { 341, 4, 2 , 6 },
+    { 351, 4, 2 , 8 },
+    { 361, 4, 7 , 7 },
+    { 376, 4, 5 , 3 },
+    { 389, 4, 7 , 7 },
+    { 404, 4, 6 , 10 },
+    { 418, 4, 7 , 12 },
+    { 433, 4, 7 , 10 },
+    { 448, 4, 7 , 10 },
+    { 463, 4, 7 , 10 },
+    { 478, 4, 7 , 10 },
+    { 493, 4, 7 , 10 },
+    { 4, 28, 7 , 10 },
+    { 19, 28, 7 , 10 },
+    { 34, 28, 7 , 10 },
+    { 49, 28, 2 , 10 },
+    { 59, 28, 5 , 10 },
+    { 72, 28, 7 , 10 },
+    { 87, 28, 6 , 10 },
+    { 101, 28, 9 , 10 },
+    { 118, 28, 7 , 10 },
+    { 133, 28, 7 , 10 },
+    { 148, 28, 7 , 10 },
+    { 163, 28, 7 , 12 },
+    { 178, 28, 7 , 10 },
+    { 193, 28, 7 , 10 },
+    { 208, 28, 6 , 10 },
+    { 222, 28, 7 , 10 },
+    { 237, 28, 7 , 10 },
+    { 252, 28, 8 , 10 },
+    { 268, 28, 7 , 10 },
+    { 283, 28, 6 , 10 },
+    { 297, 28, 7 , 10 },
+    { 312, 28, 4 , 12 },
+    { 324, 28, 4 , 10 },
+    { 336, 28, 4 , 12 },
+    { 348, 28, 6 , 3 },
+    { 362, 28, 7 , 1 },
+    { 377, 28, 4 , 3 },
+    { 389, 28, 6 , 7 },
+    { 403, 28, 6 , 10 },
+    { 417, 28, 6 , 7 },
+    { 431, 28, 6 , 10 },
+    { 445, 28, 6 , 7 },
+    { 459, 28, 4 , 10 },
+    { 471, 28, 6 , 9 },
+    { 485, 28, 6 , 10 },
+    { 499, 28, 2 , 10 },
+    { 4, 52, 5 , 12 },
+    { 17, 52, 6 , 10 },
+    { 31, 52, 3 , 10 },
+    { 42, 52, 8 , 7 },
+    { 58, 52, 6 , 7 },
+    { 72, 52, 6 , 7 },
+    { 86, 52, 6 , 9 },
+    { 100, 52, 6 , 9 },
+    { 114, 52, 5 , 7 },
+    { 127, 52, 6 , 7 },
+    { 141, 52, 4 , 10 },
+    { 153, 52, 6 , 7 },
+    { 167, 52, 6 , 7 },
+    { 181, 52, 8 , 7 },
+    { 197, 52, 6 , 7 },
+    { 211, 52, 6 , 9 },
+    { 225, 52, 6 , 7 },
+    { 239, 52, 5 , 12 },
+    { 252, 52, 2 , 12 },
+    { 262, 52, 5 , 12 },
+    { 275, 52, 7 , 3 },
+    { 290, 52, 2 , 9 },
+    { 300, 52, 6 , 11 },
+    { 314, 52, 7 , 10 },
+    { 329, 52, 7 , 9 },
+    { 344, 52, 6 , 10 },
+    { 358, 52, 7 , 11 },
+    { 373, 52, 6 , 12 },
+    { 387, 52, 6 , 10 },
+    { 401, 52, 7 , 10 },
+    { 416, 52, 5 , 5 },
+    { 429, 52, 7 , 6 },
+    { 444, 52, 6 , 3 },
+    { 458, 52, 7 , 10 },
+    { 473, 52, 4 , 4 },
+    { 485, 52, 6 , 7 },
+    { 499, 52, 4 , 5 },
+    { 4, 76, 4 , 5 },
+    { 16, 76, 7 , 11 },
+    { 31, 76, 6 , 9 },
+    { 45, 76, 7 , 12 },
+    { 60, 76, 2 , 2 },
+    { 70, 76, 6 , 10 },
+    { 84, 76, 3 , 5 },
+    { 95, 76, 4 , 5 },
+    { 107, 76, 7 , 6 },
+    { 122, 76, 9 , 10 },
+    { 139, 76, 8 , 7 },
+    { 155, 76, 6 , 11 },
+    { 169, 76, 6 , 11 },
+    { 183, 76, 7 , 11 },
+    { 198, 76, 7 , 11 },
+    { 213, 76, 7 , 11 },
+    { 228, 76, 7 , 11 },
+    { 243, 76, 7 , 11 },
+    { 258, 76, 7 , 11 },
+    { 273, 76, 9 , 10 },
+    { 290, 76, 7 , 12 },
+    { 305, 76, 7 , 11 },
+    { 320, 76, 7 , 11 },
+    { 335, 76, 7 , 11 },
+    { 350, 76, 7 , 11 },
+    { 365, 76, 3 , 11 },
+    { 376, 76, 3 , 11 },
+    { 387, 76, 5 , 11 },
+    { 400, 76, 5 , 11 },
+    { 413, 76, 8 , 10 },
+    { 429, 76, 7 , 11 },
+    { 444, 76, 7 , 11 },
+    { 459, 76, 7 , 11 },
+    { 474, 76, 7 , 11 },
+    { 489, 76, 7 , 11 },
+    { 4, 100, 7 , 11 },
+    { 19, 100, 7 , 7 },
+    { 34, 100, 7 , 13 },
+    { 49, 100, 7 , 11 },
+    { 64, 100, 7 , 11 },
+    { 79, 100, 7 , 11 },
+    { 94, 100, 7 , 11 },
+    { 109, 100, 6 , 11 },
+    { 123, 100, 7 , 10 },
+    { 138, 100, 7 , 10 },
+    { 153, 100, 6 , 10 },
+    { 167, 100, 6 , 10 },
+    { 181, 100, 6 , 10 },
+    { 195, 100, 6 , 10 },
+    { 209, 100, 6 , 10 },
+    { 223, 100, 6 , 11 },
+    { 237, 100, 8 , 7 },
+    { 253, 100, 6 , 9 },
+    { 267, 100, 6 , 10 },
+    { 281, 100, 6 , 10 },
+    { 295, 100, 6 , 10 },
+    { 309, 100, 6 , 10 },
+    { 323, 100, 3 , 10 },
+    { 334, 100, 3 , 10 },
+    { 345, 100, 5 , 10 },
+    { 358, 100, 5 , 10 },
+    { 371, 100, 6 , 10 },
+    { 385, 100, 6 , 10 },
+    { 399, 100, 6 , 10 },
+    { 413, 100, 6 , 10 },
+    { 427, 100, 6 , 10 },
+    { 441, 100, 6 , 10 },
+    { 455, 100, 6 , 10 },
+    { 469, 100, 6 , 7 },
+    { 483, 100, 7 , 11 },
+    { 4, 124, 6 , 10 },
+    { 18, 124, 6 , 10 },
+    { 32, 124, 6 , 10 },
+    { 46, 124, 6 , 10 },
+    { 60, 124, 6 , 12 },
+    { 74, 124, 6 , 12 },
+    { 88, 124, 6 , 12 },
+};
+
+// Font glyphs info data
+// NOTE: No glyphs.image data provided
+static const GlyphInfo pocketFontGlyphs[188] = {
+    { 32, 0, 0, 4, { 0 }},
+    { 33, 0, 2, 3, { 0 }},
+    { 34, 0, 2, 6, { 0 }},
+    { 35, 0, 2, 8, { 0 }},
+    { 36, 0, 1, 8, { 0 }},
+    { 37, 0, 2, 8, { 0 }},
+    { 38, 0, 2, 8, { 0 }},
+    { 39, 0, 2, 3, { 0 }},
+    { 40, 0, 2, 4, { 0 }},
+    { 41, 0, 2, 4, { 0 }},
+    { 42, 0, 4, 6, { 0 }},
+    { 43, 0, 6, 7, { 0 }},
+    { 44, 0, 10, 3, { 0 }},
+    { 45, 0, 8, 6, { 0 }},
+    { 46, 0, 10, 3, { 0 }},
+    { 47, 0, 2, 5, { 0 }},
+    { 48, 0, 2, 7, { 0 }},
+    { 49, 0, 2, 7, { 0 }},
+    { 50, 0, 2, 7, { 0 }},
+    { 51, 0, 2, 7, { 0 }},
+    { 52, 0, 2, 7, { 0 }},
+    { 53, 0, 2, 7, { 0 }},
+    { 54, 0, 2, 7, { 0 }},
+    { 55, 0, 2, 7, { 0 }},
+    { 56, 0, 2, 7, { 0 }},
+    { 57, 0, 2, 7, { 0 }},
+    { 58, 0, 4, 3, { 0 }},
+    { 59, 0, 4, 3, { 0 }},
+    { 60, 0, 4, 8, { 0 }},
+    { 61, 0, 6, 6, { 0 }},
+    { 62, 0, 4, 8, { 0 }},
+    { 63, 0, 2, 7, { 0 }},
+    { 64, 0, 2, 8, { 0 }},
+    { 65, 0, 2, 8, { 0 }},
+    { 66, 0, 2, 8, { 0 }},
+    { 67, 0, 2, 8, { 0 }},
+    { 68, 0, 2, 8, { 0 }},
+    { 69, 0, 2, 8, { 0 }},
+    { 70, 0, 2, 8, { 0 }},
+    { 71, 0, 2, 8, { 0 }},
+    { 72, 0, 2, 8, { 0 }},
+    { 73, 0, 2, 3, { 0 }},
+    { 74, 0, 2, 6, { 0 }},
+    { 75, 0, 2, 8, { 0 }},
+    { 76, 0, 2, 7, { 0 }},
+    { 77, 0, 2, 10, { 0 }},
+    { 78, 0, 2, 8, { 0 }},
+    { 79, 0, 2, 8, { 0 }},
+    { 80, 0, 2, 8, { 0 }},
+    { 81, 0, 2, 8, { 0 }},
+    { 82, 0, 2, 8, { 0 }},
+    { 83, 0, 2, 8, { 0 }},
+    { 84, 0, 2, 7, { 0 }},
+    { 85, 0, 2, 8, { 0 }},
+    { 86, 0, 2, 8, { 0 }},
+    { 87, 0, 2, 9, { 0 }},
+    { 88, 0, 2, 8, { 0 }},
+    { 89, 0, 2, 7, { 0 }},
+    { 90, 0, 2, 8, { 0 }},
+    { 91, 0, 2, 5, { 0 }},
+    { 92, 0, 2, 5, { 0 }},
+    { 93, 0, 2, 5, { 0 }},
+    { 94, 0, 2, 7, { 0 }},
+    { 95, 0, 14, 8, { 0 }},
+    { 96, 0, 2, 5, { 0 }},
+    { 97, 0, 5, 7, { 0 }},
+    { 98, 0, 2, 7, { 0 }},
+    { 99, 0, 5, 7, { 0 }},
+    { 100, 0, 2, 7, { 0 }},
+    { 101, 0, 5, 7, { 0 }},
+    { 102, 0, 2, 5, { 0 }},
+    { 103, 0, 5, 7, { 0 }},
+    { 104, 0, 2, 7, { 0 }},
+    { 105, 0, 2, 3, { 0 }},
+    { 106, 0, 2, 6, { 0 }},
+    { 107, 0, 2, 7, { 0 }},
+    { 108, 0, 2, 4, { 0 }},
+    { 109, 0, 5, 9, { 0 }},
+    { 110, 0, 5, 7, { 0 }},
+    { 111, 0, 5, 7, { 0 }},
+    { 112, 0, 5, 7, { 0 }},
+    { 113, 0, 5, 7, { 0 }},
+    { 114, 0, 5, 6, { 0 }},
+    { 115, 0, 5, 7, { 0 }},
+    { 116, 0, 2, 5, { 0 }},
+    { 117, 0, 5, 7, { 0 }},
+    { 118, 0, 5, 7, { 0 }},
+    { 119, 0, 5, 9, { 0 }},
+    { 120, 0, 5, 7, { 0 }},
+    { 121, 0, 5, 7, { 0 }},
+    { 122, 0, 5, 7, { 0 }},
+    { 123, 0, 2, 6, { 0 }},
+    { 124, 0, 2, 3, { 0 }},
+    { 125, 0, 2, 6, { 0 }},
+    { 126, 0, 6, 8, { 0 }},
+    { 161, 0, 5, 3, { 0 }},
+    { 162, 0, 3, 7, { 0 }},
+    { 163, 0, 2, 8, { 0 }},
+    { 8364, 0, 3, 8, { 0 }},
+    { 165, 0, 2, 7, { 0 }},
+    { 352, 0, 1, 8, { 0 }},
+    { 167, 0, 2, 7, { 0 }},
+    { 353, 0, 2, 7, { 0 }},
+    { 169, 0, 2, 8, { 0 }},
+    { 170, 0, 2, 6, { 0 }},
+    { 171, 0, 6, 8, { 0 }},
+    { 172, 0, 7, 7, { 0 }},
+    { 174, 0, 2, 8, { 0 }},
+    { 176, 0, 2, 5, { 0 }},
+    { 177, 0, 4, 7, { 0 }},
+    { 178, 0, 2, 5, { 0 }},
+    { 179, 0, 2, 5, { 0 }},
+    { 381, 0, 1, 8, { 0 }},
+    { 181, 0, 5, 7, { 0 }},
+    { 182, 0, 2, 8, { 0 }},
+    { 183, 0, 6, 3, { 0 }},
+    { 382, 0, 2, 7, { 0 }},
+    { 185, 0, 2, 4, { 0 }},
+    { 186, 0, 2, 5, { 0 }},
+    { 187, 0, 6, 8, { 0 }},
+    { 338, 0, 2, 10, { 0 }},
+    { 339, 0, 5, 9, { 0 }},
+    { 376, 0, 1, 7, { 0 }},
+    { 191, 0, 3, 7, { 0 }},
+    { 192, 0, 1, 8, { 0 }},
+    { 193, 0, 1, 8, { 0 }},
+    { 194, 0, 1, 8, { 0 }},
+    { 195, 0, 1, 8, { 0 }},
+    { 196, 0, 1, 8, { 0 }},
+    { 197, 0, 1, 8, { 0 }},
+    { 198, 0, 2, 10, { 0 }},
+    { 199, 0, 2, 8, { 0 }},
+    { 200, 0, 1, 8, { 0 }},
+    { 201, 0, 1, 8, { 0 }},
+    { 202, 0, 1, 8, { 0 }},
+    { 203, 0, 1, 8, { 0 }},
+    { 204, 0, 1, 4, { 0 }},
+    { 205, 0, 1, 4, { 0 }},
+    { 206, 0, 1, 6, { 0 }},
+    { 207, 0, 1, 6, { 0 }},
+    { 208, 0, 2, 9, { 0 }},
+    { 209, 0, 1, 8, { 0 }},
+    { 210, 0, 1, 8, { 0 }},
+    { 211, 0, 1, 8, { 0 }},
+    { 212, 0, 1, 8, { 0 }},
+    { 213, 0, 1, 8, { 0 }},
+    { 214, 0, 1, 8, { 0 }},
+    { 215, 0, 5, 8, { 0 }},
+    { 216, 0, 1, 8, { 0 }},
+    { 217, 0, 1, 8, { 0 }},
+    { 218, 0, 1, 8, { 0 }},
+    { 219, 0, 1, 8, { 0 }},
+    { 220, 0, 1, 8, { 0 }},
+    { 221, 0, 1, 7, { 0 }},
+    { 222, 0, 2, 8, { 0 }},
+    { 223, 0, 2, 8, { 0 }},
+    { 224, 0, 2, 7, { 0 }},
+    { 225, 0, 2, 7, { 0 }},
+    { 226, 0, 2, 7, { 0 }},
+    { 227, 0, 2, 7, { 0 }},
+    { 228, 0, 2, 7, { 0 }},
+    { 229, 0, 1, 7, { 0 }},
+    { 230, 0, 5, 9, { 0 }},
+    { 231, 0, 5, 7, { 0 }},
+    { 232, 0, 2, 7, { 0 }},
+    { 233, 0, 2, 7, { 0 }},
+    { 234, 0, 2, 7, { 0 }},
+    { 235, 0, 2, 7, { 0 }},
+    { 236, 0, 2, 4, { 0 }},
+    { 237, 0, 2, 4, { 0 }},
+    { 238, 0, 2, 6, { 0 }},
+    { 239, 0, 2, 6, { 0 }},
+    { 240, 0, 2, 7, { 0 }},
+    { 241, 0, 2, 7, { 0 }},
+    { 242, 0, 2, 7, { 0 }},
+    { 243, 0, 2, 7, { 0 }},
+    { 244, 0, 2, 7, { 0 }},
+    { 245, 0, 2, 7, { 0 }},
+    { 246, 0, 2, 7, { 0 }},
+    { 247, 0, 4, 7, { 0 }},
+    { 248, 0, 3, 8, { 0 }},
+    { 249, 0, 2, 7, { 0 }},
+    { 250, 0, 2, 7, { 0 }},
+    { 251, 0, 2, 7, { 0 }},
+    { 252, 0, 2, 7, { 0 }},
+    { 253, 0, 2, 7, { 0 }},
+    { 254, 0, 2, 7, { 0 }},
+    { 255, 0, 2, 7, { 0 }},
+};
+
+// Style loading function: Pocket
+static void GuiLoadStylePocket(void)
+{
+    // Load style properties provided
+    // NOTE: Default properties are propagated
+    for (int i = 0; i < POCKET_STYLE_PROPS_COUNT; i++)
+    {
+        GuiSetStyle(pocketStyleProps[i].controlId, pocketStyleProps[i].propertyId, pocketStyleProps[i].propertyValue);
+    }
+
+    // Custom font loading
+    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
+    int pocketFontDataSize = 0;
+    unsigned char *data = DecompressData(pocketFontData, POCKET_STYLE_FONT_ATLAS_COMP_SIZE, &pocketFontDataSize);
+    Image imFont = { data, 512, 256, 1, 2 };
+
+    Font font = { 0 };
+    font.baseSize = 16;
+    font.glyphCount = 188;
+
+    // Copy char recs data from global fontRecs
+    // NOTE: Required to avoid issues if trying to free font
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+    memcpy(font.recs, pocketFontRecs, font.glyphCount*sizeof(Rectangle));
+
+    // Copy font char info data from global fontChars
+    // NOTE: Required to avoid issues if trying to free font
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+    memcpy(font.glyphs, pocketFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
+
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
+    GuiSetFont(font);
+
+    // Setup a white rectangle on the font to be used on shapes drawing,
+    // it makes possible to draw shapes and text (full UI) in a single draw call
+    SetShapesTexture(font.texture, fontWhiteRec);
+
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "GMSN.ttf");
+    //-----------------------------------------------------------------
+
+    // TODO: Custom user style setup: Set specific properties here (if required)
+    // i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
+}
diff --git a/raygui/styles/rltech/style_rltech.h b/raygui/styles/rltech/style_rltech.h
--- a/raygui/styles/rltech/style_rltech.h
+++ b/raygui/styles/rltech/style_rltech.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,21 +15,21 @@
 
 // Custom style name: RLTech
 static const GuiStyleProp rltechStyleProps[RLTECH_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x000000ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0xf5f5f5ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x000000ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xe10000ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xffffffff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xed0000ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xed0000ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0x0f0f0fff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0xff2323ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0xcacacaff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0xe3e3e3ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0xb3b3b3ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x000000ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xf5f5f5ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x000000ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xe10000ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xffffffff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xed0000ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xed0000ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x0f0f0fff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0xff2323ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0xcacacaff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xe3e3e3ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0xb3b3b3ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 18, (int)0x352c2cff },    // DEFAULT_LINE_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "2a03.ttf" (size: 16, spacing: 1)
@@ -544,27 +544,38 @@
     font.baseSize = 16;
     font.glyphCount = 189;
 
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
-
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, rltechFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, rltechFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "2a03.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/sunny/style_sunny.h b/raygui/styles/sunny/style_sunny.h
--- a/raygui/styles/sunny/style_sunny.h
+++ b/raygui/styles/sunny/style_sunny.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,172 +15,172 @@
 
 // Custom style name: Sunny
 static const GuiStyleProp sunnyStyleProps[SUNNY_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x9c760aff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x594006ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0xf6d519ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xf6ee89ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0xf5f3d1ff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xf4cd19ff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0xf7e580ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0xf7f2c1ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x52470aff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0xc0be92ff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0xd3d3a1ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0xbcbc89ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x9c760aff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x594006ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xf6d519ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xf6ee89ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xf5f3d1ff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xf4cd19ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xf7e580ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xf7f2c1ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x52470aff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0xc0be92ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xd3d3a1ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0xbcbc89ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0x725706ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0xf0be4bff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
-    { 1, 2, (int)0x504506ff },    // LABEL_TEXT_COLOR_NORMAL 
-    { 1, 5, (int)0xfdeb9bff },    // LABEL_TEXT_COLOR_FOCUSED 
-    { 1, 8, (int)0xf5e8a4ff },    // LABEL_TEXT_COLOR_PRESSED 
-    { 2, 2, (int)0xebc21fff },    // BUTTON_TEXT_COLOR_NORMAL 
-    { 3, 2, (int)0xebc21fff },    // TOGGLE_TEXT_COLOR_NORMAL 
-    { 4, 2, (int)0x81700fff },    // SLIDER_TEXT_COLOR_NORMAL 
-    { 4, 5, (int)0xf4e49aff },    // SLIDER_TEXT_COLOR_FOCUSED 
-    { 7, 2, (int)0xebc21fff },    // COMBOBOX_TEXT_COLOR_NORMAL 
-    { 8, 2, (int)0xefd87bff },    // DROPDOWNBOX_TEXT_COLOR_NORMAL 
-    { 8, 5, (int)0xd4b219ff },    // DROPDOWNBOX_TEXT_COLOR_FOCUSED 
-    { 9, 2, (int)0x7a680bff },    // TEXTBOX_TEXT_COLOR_NORMAL 
-    { 9, 5, (int)0xad931fff },    // TEXTBOX_TEXT_COLOR_FOCUSED 
-    { 10, 2, (int)0x62570eff },    // VALUEBOX_TEXT_COLOR_NORMAL 
-    { 10, 5, (int)0xf2df88ff },    // VALUEBOX_TEXT_COLOR_FOCUSED 
-    { 12, 2, (int)0xf4e798ff },    // LISTVIEW_TEXT_COLOR_NORMAL 
-    { 15, 2, (int)0xebc21fff },    // STATUSBAR_TEXT_COLOR_NORMAL 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 2, (int)0x504506ff },    // LABEL_TEXT_COLOR_NORMAL
+    { 1, 5, (int)0xfdeb9bff },    // LABEL_TEXT_COLOR_FOCUSED
+    { 1, 8, (int)0xf5e8a4ff },    // LABEL_TEXT_COLOR_PRESSED
+    { 2, 2, (int)0xebc21fff },    // BUTTON_TEXT_COLOR_NORMAL
+    { 3, 2, (int)0xebc21fff },    // TOGGLE_TEXT_COLOR_NORMAL
+    { 4, 2, (int)0x81700fff },    // SLIDER_TEXT_COLOR_NORMAL
+    { 4, 5, (int)0xf4e49aff },    // SLIDER_TEXT_COLOR_FOCUSED
+    { 7, 2, (int)0xebc21fff },    // COMBOBOX_TEXT_COLOR_NORMAL
+    { 8, 2, (int)0xefd87bff },    // DROPDOWNBOX_TEXT_COLOR_NORMAL
+    { 8, 5, (int)0xd4b219ff },    // DROPDOWNBOX_TEXT_COLOR_FOCUSED
+    { 9, 2, (int)0x7a680bff },    // TEXTBOX_TEXT_COLOR_NORMAL
+    { 9, 5, (int)0xad931fff },    // TEXTBOX_TEXT_COLOR_FOCUSED
+    { 10, 2, (int)0x62570eff },    // VALUEBOX_TEXT_COLOR_NORMAL
+    { 10, 5, (int)0xf2df88ff },    // VALUEBOX_TEXT_COLOR_FOCUSED
+    { 12, 2, (int)0xf4e798ff },    // LISTVIEW_TEXT_COLOR_NORMAL
+    { 15, 2, (int)0xebc21fff },    // STATUSBAR_TEXT_COLOR_NORMAL
 };
 
 // WARNING: This style uses a custom font: "GMSN.ttf" (size: 16, spacing: 0)
 
-#define SUNNY_STYLE_FONT_ATLAS_COMP_SIZE 2434
+#define SUNNY_STYLE_FONT_ATLAS_COMP_SIZE 2438
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char sunnyFontData[SUNNY_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0x5b, 0x6e, 0xe4, 0x36, 0x10, 0x05, 0x50, 0xee, 0x7f, 0xa1, 0xd9, 0x06, 0x83, 0x20, 0x18, 0x24, 0xe3, 0xb1, 0x45,
-    0xb2, 0xaa, 0xa8, 0x57, 0x9f, 0x1c, 0xe4, 0xc7, 0x1a, 0xb7, 0xd5, 0x94, 0xae, 0x44, 0x3d, 0x58, 0xec, 0x0d, 0x00, 0x00,
-    0x00, 0xf8, 0x78, 0xff, 0xfc, 0xf7, 0xfd, 0xcf, 0xbe, 0x5b, 0x72, 0xbc, 0xec, 0xd7, 0xbf, 0x18, 0x2d, 0xe9, 0x3f, 0xae,
-    0x49, 0x3f, 0x58, 0x36, 0xf7, 0xb7, 0x62, 0xeb, 0xd5, 0x97, 0xda, 0xa6, 0x1f, 0xb4, 0x5a, 0x4b, 0xff, 0xbc, 0x1d, 0xb6,
-    0x7d, 0x0f, 0xb4, 0x5e, 0x3b, 0x5c, 0xe7, 0x9f, 0x7f, 0x73, 0xbc, 0xa4, 0x72, 0x3d, 0x57, 0xda, 0xb4, 0x72, 0xfb, 0xac,
-    0xb4, 0x60, 0x5b, 0x5e, 0x7a, 0xdc, 0x52, 0x6d, 0xaa, 0x1d, 0xc7, 0x9f, 0xdc, 0x6f, 0x92, 0xff, 0xe3, 0x6f, 0xf3, 0x2b,
-    0x83, 0x47, 0x5b, 0x7f, 0x7e, 0xdf, 0x68, 0xd3, 0xc7, 0x84, 0xff, 0xfe, 0x76, 0x5d, 0x42, 0xb3, 0x9f, 0xd2, 0x87, 0x47,
-    0xc2, 0x95, 0x16, 0x3a, 0x6e, 0xbd, 0x16, 0xca, 0xc4, 0xe8, 0x33, 0x23, 0xeb, 0x32, 0xb3, 0x6c, 0x6e, 0xfd, 0x62, 0xfb,
-    0xfc, 0xf8, 0xf3, 0x8e, 0xf7, 0xb4, 0xa3, 0x2d, 0x3c, 0xda, 0x73, 0x8f, 0xbf, 0xdf, 0xfa, 0x56, 0xcd, 0xa4, 0x7e, 0x4f,
-    0xfe, 0xfb, 0xff, 0x72, 0xd6, 0x83, 0x19, 0xcc, 0x9f, 0x1b, 0xd6, 0xcf, 0x0a, 0xc7, 0xc7, 0xac, 0x7d, 0x2d, 0x7c, 0xd4,
-    0x4e, 0x3d, 0xb0, 0x0f, 0xaf, 0x6f, 0xb3, 0xe8, 0xdf, 0xd9, 0x91, 0xff, 0x8a, 0x14, 0xb7, 0x89, 0x33, 0x62, 0xa4, 0x4f,
-    0x71, 0xdc, 0xe3, 0xcc, 0x27, 0x7c, 0xb4, 0x2e, 0x91, 0xfe, 0x4c, 0xbe, 0x2d, 0x57, 0xfb, 0x1c, 0xfb, 0xf2, 0x5f, 0x71,
-    0xbe, 0x5d, 0x3f, 0x97, 0xec, 0x6b, 0xdf, 0x99, 0xf3, 0xf5, 0xfd, 0xf3, 0xbf, 0xfe, 0xdd, 0x2a, 0xf2, 0x5f, 0xb3, 0x55,
-    0xd6, 0xf3, 0xdf, 0xe5, 0x7f, 0xfa, 0xfc, 0xff, 0x73, 0xab, 0xf7, 0xe0, 0xf5, 0x57, 0xfe, 0xaa, 0xbd, 0xaa, 0x9f, 0x7f,
-    0x6d, 0xfe, 0x47, 0xd7, 0x83, 0x6d, 0x39, 0xff, 0xb1, 0xab, 0xcf, 0xc8, 0xd5, 0x46, 0x55, 0xff, 0x7f, 0x6f, 0xef, 0xe1,
-    0xf8, 0xea, 0x31, 0x92, 0xf0, 0xb5, 0x7b, 0x1e, 0x35, 0x9f, 0x7c, 0x45, 0xfe, 0xdb, 0xc4, 0xda, 0xf4, 0xe1, 0xf5, 0xff,
-    0xec, 0x11, 0x7e, 0x2d, 0xff, 0x75, 0xe7, 0x8e, 0x2b, 0xf3, 0xdf, 0x83, 0x77, 0xc4, 0xaa, 0xaf, 0xe3, 0xe3, 0xdf, 0x6d,
-    0xed, 0xfe, 0xdc, 0x79, 0xd7, 0xff, 0xa3, 0x7e, 0x60, 0x26, 0xff, 0x9f, 0xd2, 0xff, 0x9f, 0xe9, 0x69, 0x8f, 0x5a, 0x71,
-    0xfe, 0x78, 0x76, 0xc5, 0xd9, 0xfc, 0xda, 0xfc, 0xf7, 0xa9, 0x7b, 0xd8, 0xf7, 0xce, 0x7f, 0x5b, 0xbe, 0xca, 0xab, 0xdc,
-    0x77, 0xa3, 0x7b, 0xd4, 0x68, 0xcf, 0x9d, 0x39, 0xaa, 0xdd, 0x33, 0xff, 0xb1, 0xfd, 0xb9, 0x0f, 0x7b, 0xf9, 0x3d, 0x91,
-    0xff, 0xf6, 0x9a, 0xfc, 0xf7, 0xe0, 0xdd, 0x8e, 0x9f, 0xfb, 0x7b, 0xb1, 0xfb, 0x71, 0x91, 0x9e, 0x7c, 0xa6, 0x8f, 0x52,
-    0x95, 0xff, 0x7b, 0x6c, 0x49, 0xe7, 0xff, 0x8a, 0xfb, 0xff, 0xed, 0xb0, 0x87, 0xff, 0x59, 0xf9, 0x3f, 0x7e, 0xfe, 0xd7,
-    0x6e, 0xff, 0xac, 0x2e, 0x9a, 0xff, 0x9a, 0xfb, 0xff, 0xe7, 0x1f, 0xad, 0x67, 0xae, 0x5c, 0x73, 0xf9, 0xbf, 0xd3, 0xf3,
-    0xbf, 0xbd, 0xf9, 0x1f, 0x3d, 0xf5, 0x7e, 0x53, 0xff, 0xbf, 0xf2, 0x3e, 0x7e, 0xfc, 0x9d, 0x9b, 0x7d, 0xef, 0x14, 0xb5,
-    0xd0, 0x9b, 0x5c, 0xf7, 0x4c, 0x7f, 0xf4, 0x39, 0x50, 0xee, 0x2e, 0xdd, 0xd5, 0xef, 0xff, 0xd4, 0xb7, 0xe0, 0x79, 0xeb,
-    0xd3, 0x6f, 0xdc, 0x67, 0xe4, 0x5d, 0x6f, 0xc9, 0xda, 0xbb, 0xce, 0x7c, 0x3e, 0x1b, 0xff, 0x5b, 0xb6, 0x0f, 0x3b, 0xcf,
-    0x6c, 0x5a, 0xe2, 0x19, 0xf7, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0xe3,
-    0x17, 0x22, 0x63, 0x0d, 0xa3, 0x75, 0x08, 0x6a, 0xeb, 0x21, 0xf4, 0x2f, 0x75, 0x58, 0x57, 0x3f, 0x7b, 0x76, 0xac, 0x65,
-    0x66, 0x9c, 0x66, 0xed, 0xef, 0x56, 0x55, 0x96, 0xa8, 0x1d, 0x79, 0x3e, 0xae, 0x77, 0xb3, 0x5a, 0xad, 0x39, 0x56, 0x05,
-    0x6d, 0xbd, 0xa6, 0x79, 0xa6, 0x0e, 0x5f, 0xf5, 0xd8, 0xea, 0x9a, 0xfa, 0x68, 0xf3, 0x63, 0xde, 0x6b, 0x2a, 0x8d, 0xd4,
-    0xe5, 0x7f, 0x7d, 0x3b, 0xf4, 0x2f, 0xeb, 0xd1, 0x2f, 0xa8, 0xc4, 0x50, 0xbf, 0x74, 0xee, 0xe7, 0x77, 0xca, 0xff, 0xec,
-    0x31, 0x38, 0xbb, 0xf7, 0xc6, 0x47, 0xdc, 0x8d, 0xaa, 0x4f, 0x5c, 0x5f, 0x5b, 0xa5, 0x15, 0xd5, 0x47, 0xad, 0xcf, 0x7f,
-    0x3b, 0xe9, 0xfc, 0x1f, 0xcd, 0x7f, 0x1f, 0xce, 0x66, 0x73, 0xdf, 0xfc, 0xaf, 0xd7, 0x9d, 0xc8, 0xfe, 0xd5, 0xdc, 0x4c,
-    0x0e, 0xf1, 0x5a, 0xe3, 0xf9, 0xfc, 0xe7, 0x2a, 0x05, 0x9d, 0x7b, 0x6e, 0xbd, 0x3e, 0xff, 0xd1, 0x16, 0xb9, 0x2a, 0xff,
-    0xf1, 0xbd, 0xa4, 0x0f, 0xab, 0x59, 0xdf, 0x31, 0xff, 0xfd, 0xe3, 0xf3, 0x5f, 0x5f, 0xcb, 0x37, 0x9a, 0x80, 0x48, 0x1d,
-    0xf4, 0x99, 0xeb, 0xea, 0xd5, 0x2b, 0xbb, 0xf8, 0x75, 0x57, 0xf4, 0xfc, 0x3f, 0xfa, 0xfd, 0x99, 0x6f, 0x72, 0x75, 0xfe,
-    0xdb, 0x30, 0xe1, 0x3d, 0x91, 0xd2, 0xf8, 0x1d, 0x90, 0x4c, 0xcd, 0xab, 0x6b, 0xf2, 0xdf, 0x42, 0x33, 0x06, 0xc6, 0xcf,
-    0xf3, 0x77, 0xcf, 0x7f, 0xf5, 0xb5, 0x41, 0xf4, 0x8e, 0x41, 0xf5, 0x3a, 0xde, 0xef, 0xfa, 0xbf, 0x17, 0xf4, 0x12, 0x77,
-    0xe4, 0x3f, 0xdb, 0x3e, 0xd1, 0x34, 0xc5, 0xf2, 0x3f, 0x7f, 0x76, 0x8f, 0xcd, 0x26, 0x10, 0x5b, 0xf6, 0xde, 0xfc, 0xd7,
-    0xd6, 0x4f, 0x5d, 0xbf, 0x57, 0xfc, 0xa6, 0xfc, 0x47, 0xaf, 0xff, 0xe7, 0xaf, 0xb8, 0xee, 0x95, 0xff, 0x36, 0x31, 0x3f,
-    0xcf, 0xd9, 0xf9, 0x1f, 0x55, 0x5b, 0x7d, 0x5b, 0xfe, 0xa3, 0xd9, 0x8a, 0xce, 0x67, 0xd4, 0xc2, 0x67, 0xba, 0xb7, 0x9f,
-    0xff, 0xdb, 0x4b, 0xf3, 0x1f, 0x9f, 0x5f, 0xe6, 0x59, 0xf9, 0xaf, 0xee, 0x35, 0x5c, 0x5f, 0x57, 0x2f, 0x7a, 0xb7, 0x31,
-    0x7e, 0x97, 0xf2, 0xdd, 0xfd, 0xff, 0xbe, 0xa1, 0x17, 0x9e, 0x7d, 0xfe, 0x7f, 0x55, 0xfe, 0x77, 0x3d, 0xff, 0x6b, 0xd3,
-    0x73, 0xfe, 0xed, 0x5a, 0x2b, 0xf9, 0xaf, 0xce, 0x7f, 0xe5, 0xdc, 0x89, 0x6b, 0xff, 0xa2, 0xfa, 0xfd, 0x9f, 0xfa, 0x3b,
-    0x69, 0xfb, 0xdf, 0xff, 0xd9, 0xd3, 0x3e, 0x6d, 0x6a, 0xc6, 0xb4, 0xf5, 0xbf, 0xda, 0x26, 0x67, 0x35, 0x8e, 0xad, 0x73,
-    0xfd, 0xdb, 0x37, 0x77, 0xcf, 0x7f, 0xec, 0x6d, 0x83, 0xe8, 0x6f, 0xc6, 0x7f, 0xe3, 0x3e, 0x73, 0x81, 0x7d, 0xe6, 0x5b,
-    0x94, 0x5a, 0xa1, 0xba, 0x85, 0xb4, 0x2a, 0x8e, 0x00, 0xef, 0x7a, 0xcf, 0x7c, 0xd7, 0xbf, 0x07, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbc, 0xd1, 0x2b, 0xb3, 0x35, 0xb7, 0xff, 0xfc, 0x69, 0x0f, 0x8d, 0x77,
-    0xed, 0xc9, 0xdf, 0xeb, 0xcb, 0x75, 0x30, 0xd6, 0xc6, 0x9d, 0x56, 0xd4, 0x60, 0xa8, 0xae, 0x23, 0x35, 0x6e, 0x97, 0xd9,
-    0x2d, 0x3d, 0x1e, 0x49, 0xbc, 0xba, 0x87, 0x44, 0xc6, 0xf5, 0x64, 0x2a, 0xea, 0x64, 0xe6, 0x12, 0x88, 0x57, 0x42, 0x6c,
-    0x8b, 0x9f, 0x1a, 0xdb, 0x6a, 0x91, 0xf1, 0xe1, 0x3b, 0xf3, 0x1f, 0xab, 0x2d, 0x79, 0x45, 0xa5, 0xb5, 0xf8, 0xde, 0x54,
-    0xbb, 0x86, 0xf5, 0xad, 0x32, 0xb7, 0xb6, 0xb9, 0x9f, 0x67, 0xc6, 0xf4, 0xe7, 0x6a, 0x0f, 0xac, 0xb6, 0x44, 0x9f, 0xaa,
-    0x96, 0xb2, 0xfa, 0x9b, 0x3f, 0xff, 0xde, 0xf1, 0xb2, 0x3e, 0x55, 0x39, 0x62, 0xed, 0x53, 0xbf, 0xff, 0xb7, 0xfb, 0x2a,
-    0x27, 0xbc, 0x23, 0xff, 0x2d, 0x70, 0x94, 0x3d, 0x37, 0xff, 0xf1, 0xe3, 0x54, 0x2b, 0xac, 0xd2, 0xb3, 0x3e, 0x37, 0x46,
-    0x64, 0xe4, 0x6e, 0xbe, 0x46, 0xd0, 0x19, 0x15, 0x35, 0xfe, 0xcc, 0xd7, 0xca, 0x56, 0x9b, 0x4b, 0xff, 0xf7, 0xc7, 0xb8,
-    0x76, 0xd0, 0xdb, 0x9a, 0xcd, 0x7f, 0x0f, 0xd4, 0x1e, 0xa9, 0xa9, 0xc8, 0xf7, 0x9c, 0xfc, 0xcf, 0x5c, 0x6d, 0x9c, 0x97,
-    0xff, 0xf1, 0xcf, 0xeb, 0xaa, 0x6a, 0x57, 0xd6, 0xda, 0x19, 0xd5, 0x5a, 0x6e, 0xa1, 0x2d, 0xd2, 0x83, 0xc7, 0x95, 0x5e,
-    0x5c, 0xcf, 0xbc, 0x7f, 0xf9, 0x7f, 0xf6, 0x4c, 0x3d, 0x9b, 0xff, 0xd5, 0xbf, 0x78, 0x4d, 0xff, 0x7f, 0x65, 0x7f, 0x79,
-    0x52, 0xfe, 0xdb, 0x54, 0x2d, 0xb2, 0x7b, 0x9f, 0xff, 0x2b, 0x6b, 0x6a, 0xd5, 0xe7, 0x3f, 0x96, 0xf0, 0xc8, 0xfe, 0x3e,
-    0x3f, 0xe3, 0xc1, 0xda, 0x76, 0x1b, 0xf7, 0xf2, 0x7b, 0xa2, 0xff, 0x9f, 0xcf, 0x7f, 0x5d, 0x9f, 0x67, 0xed, 0xea, 0xf9,
-    0x8a, 0xfc, 0xf7, 0x44, 0x65, 0xf4, 0xfd, 0xd7, 0xff, 0xa3, 0x7e, 0x62, 0xb4, 0x55, 0xea, 0xe7, 0xa6, 0xaa, 0xac, 0xb6,
-    0xbd, 0x9a, 0xff, 0xcc, 0xf9, 0x3f, 0x7a, 0x1f, 0x22, 0xd3, 0x43, 0x5c, 0xbb, 0x1e, 0xcf, 0x1f, 0x01, 0xd6, 0xfa, 0xff,
-    0x67, 0xdc, 0xff, 0xef, 0xa7, 0x5d, 0xff, 0xb7, 0xd4, 0x2c, 0x46, 0x95, 0xfd, 0xff, 0x96, 0xe8, 0x65, 0x66, 0x8e, 0x36,
-    0x91, 0xd6, 0x5e, 0x6f, 0xb3, 0x2b, 0xcf, 0xff, 0xb9, 0xd9, 0xe6, 0xda, 0xb6, 0x7a, 0xa7, 0x91, 0xfe, 0xff, 0x9e, 0x14,
-    0x56, 0xfc, 0xc5, 0xca, 0xeb, 0xff, 0xeb, 0xe7, 0x66, 0xc8, 0xe4, 0xff, 0xac, 0xde, 0xd3, 0xfe, 0x6f, 0x5e, 0x5b, 0x47,
-    0xfa, 0x0e, 0xd7, 0xff, 0x91, 0xfb, 0xff, 0xd1, 0x9a, 0xc7, 0xe3, 0xb3, 0x71, 0xff, 0xf1, 0x0a, 0xff, 0xcc, 0xb3, 0xf1,
-    0xf9, 0x47, 0x9c, 0xda, 0xeb, 0x7f, 0xf9, 0xdf, 0xf3, 0xdd, 0x2b, 0x6b, 0xe7, 0xee, 0xce, 0xff, 0x5c, 0xcf, 0x2a, 0x36,
-    0x23, 0x62, 0x6e, 0xc6, 0xe4, 0xe8, 0x35, 0x5d, 0x3b, 0x75, 0x4f, 0x6f, 0x17, 0xf4, 0xfe, 0xab, 0x67, 0xe4, 0x79, 0xe7,
-    0xfb, 0x50, 0xef, 0xf8, 0x06, 0x67, 0x1c, 0xcf, 0x7b, 0x61, 0xcf, 0x34, 0x7f, 0xff, 0x2f, 0x7e, 0xb4, 0x6a, 0x17, 0xd4,
-    0x20, 0x3e, 0xfb, 0x2f, 0xc6, 0x9f, 0x56, 0x20, 0xff, 0x6b, 0xf9, 0xdf, 0xdf, 0x4b, 0xaa, 0x7a, 0x87, 0xe1, 0xd3, 0xf6,
-    0x14, 0x2d, 0xf3, 0x29, 0xdb, 0x75, 0xfd, 0x4e, 0xef, 0x5b, 0x5a, 0xc2, 0x3e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x6b, 0xf4, 0x4f, 0xac, 0x9a, 0xc2, 0x6c, 0x2d, 0xab, 0xbe, 0x30, 0x3a, 0xb3, 0x0d,
-    0xeb, 0x33, 0x67, 0x3f, 0xe7, 0xeb, 0xcc, 0x05, 0x7d, 0xf0, 0x2f, 0x5a, 0x60, 0x4d, 0x7b, 0x78, 0xac, 0xf1, 0xfa, 0x3c,
-    0x0c, 0x5f, 0xd7, 0xb8, 0x25, 0x5a, 0x64, 0x3c, 0x92, 0x77, 0x7d, 0xc6, 0x86, 0xbd, 0xdf, 0xb9, 0xa6, 0x22, 0x7a, 0xa4,
-    0xb6, 0xdf, 0x6c, 0x85, 0x92, 0xb3, 0x5b, 0x25, 0x33, 0x62, 0xbb, 0x05, 0x8e, 0x0d, 0xa3, 0x7a, 0x42, 0x2b, 0xb5, 0xba,
-    0xd6, 0x8e, 0x4f, 0x73, 0x55, 0xf8, 0xd6, 0xc7, 0xa5, 0xcf, 0xd5, 0xf0, 0x6c, 0x1b, 0xeb, 0x5e, 0xaf, 0xef, 0xed, 0xf1,
-    0xa4, 0xe4, 0x96, 0xce, 0x8d, 0xc7, 0xdf, 0xf1, 0x9d, 0xe3, 0x35, 0x6b, 0xe7, 0x3f, 0x27, 0x73, 0xf6, 0x1b, 0xa7, 0x74,
-    0x4f, 0xab, 0xc4, 0xd2, 0x9f, 0xa9, 0x08, 0xb3, 0x9e, 0xff, 0x9a, 0xf5, 0x1e, 0xcf, 0x89, 0x10, 0x9b, 0x65, 0x63, 0xa6,
-    0x86, 0xf7, 0xfb, 0xaa, 0x07, 0xe4, 0xf3, 0xff, 0xa9, 0x35, 0x17, 0x9e, 0xd4, 0x02, 0x7d, 0x31, 0x61, 0x33, 0xbd, 0xf8,
-    0x9a, 0xfc, 0x8f, 0xe7, 0x4a, 0x3a, 0x3f, 0xff, 0x3d, 0xf4, 0x09, 0xf1, 0x9e, 0xdb, 0x1d, 0x97, 0xe6, 0xf2, 0x3f, 0xde,
-    0x83, 0xf6, 0x2c, 0xad, 0x9a, 0x29, 0x29, 0x57, 0x87, 0xbc, 0x05, 0xaf, 0x1e, 0x32, 0x4b, 0x23, 0xb5, 0x11, 0x7a, 0xe8,
-    0x6a, 0x64, 0xcf, 0xf9, 0x3f, 0x7f, 0xfd, 0x3f, 0xdf, 0x6f, 0x8b, 0xdf, 0x3f, 0xc8, 0xec, 0x4b, 0x3b, 0xfa, 0xe1, 0x67,
-    0x2c, 0x8d, 0xd4, 0x86, 0xbb, 0x6a, 0xe9, 0xee, 0xfc, 0xf7, 0xdf, 0xe6, 0x4a, 0x3c, 0x4a, 0xd4, 0xfa, 0xd1, 0x21, 0x77,
-    0x64, 0xd9, 0xdb, 0xd7, 0x59, 0xbd, 0xff, 0xb7, 0xba, 0x96, 0x75, 0x73, 0x99, 0x45, 0xab, 0x52, 0x7e, 0xfd, 0xfd, 0xba,
-    0xf3, 0xff, 0xbe, 0xad, 0xbe, 0x77, 0x69, 0xe6, 0xee, 0xde, 0x5b, 0xf3, 0x3f, 0xd7, 0x6e, 0xef, 0xc8, 0xff, 0xb8, 0x7e,
-    0x6b, 0x2f, 0xba, 0x4f, 0x71, 0xc6, 0x37, 0x9a, 0xad, 0xc0, 0x9f, 0x9b, 0x63, 0xf6, 0x4d, 0xf9, 0x6f, 0x45, 0xfd, 0xff,
-    0x33, 0x97, 0xde, 0xa3, 0xff, 0xdf, 0x5f, 0x90, 0xff, 0xec, 0x73, 0x9d, 0x8a, 0x19, 0x8e, 0xcf, 0xce, 0x7f, 0xf6, 0x98,
-    0x78, 0xaf, 0x6b, 0xe1, 0xec, 0xd2, 0x6c, 0xfe, 0x3f, 0xf5, 0xfc, 0xff, 0x86, 0xfc, 0xe7, 0x9f, 0x65, 0xaf, 0xdc, 0xff,
-    0x3b, 0xef, 0x1d, 0x88, 0xbe, 0x31, 0xff, 0xed, 0x43, 0xcf, 0xff, 0x35, 0xf3, 0xca, 0x3f, 0x2d, 0xff, 0x33, 0x77, 0x99,
-    0x9e, 0x9a, 0xff, 0x8a, 0x8c, 0x54, 0xdd, 0xff, 0xaf, 0x7f, 0x0b, 0x6a, 0x67, 0x75, 0xfa, 0xe7, 0x25, 0x7c, 0x9c, 0xff,
-    0xc8, 0xfb, 0x3f, 0xef, 0xce, 0xff, 0xdc, 0xbb, 0x31, 0xcf, 0xce, 0x7f, 0x4f, 0xce, 0x4a, 0xf3, 0xce, 0xe7, 0xc3, 0xb1,
-    0x39, 0xa6, 0x9f, 0x97, 0xff, 0xfc, 0x3b, 0x65, 0x6f, 0x7d, 0xfe, 0x97, 0x7b, 0x3b, 0xe0, 0x9a, 0xe7, 0x7f, 0x77, 0x7a,
-    0xaf, 0x84, 0xb7, 0xbf, 0x55, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0xec,
-    0xeb, 0xea, 0x88, 0x9d, 0xb9, 0x71, 0x62, 0xd7, 0x54, 0xbe, 0x8f, 0xd4, 0x29, 0x98, 0x59, 0x9f, 0x78, 0xf5, 0x83, 0x48,
-    0xad, 0xfd, 0xa3, 0x6d, 0x13, 0xad, 0x38, 0x9e, 0xa9, 0x64, 0xb4, 0xeb, 0x3b, 0xae, 0xd7, 0x84, 0x9f, 0xff, 0x0b, 0x73,
-    0x95, 0x1f, 0x63, 0xb9, 0xb8, 0xfb, 0xb6, 0x9e, 0x1b, 0xa5, 0xb9, 0xb3, 0x4e, 0x7c, 0x4f, 0xd6, 0x34, 0xaf, 0x5f, 0xab,
-    0x6c, 0x95, 0xfe, 0xd8, 0x3a, 0x47, 0x5a, 0xb8, 0x27, 0xe6, 0x61, 0x69, 0x13, 0x7b, 0x52, 0x75, 0x75, 0x9f, 0xcc, 0xbc,
-    0x1c, 0xf3, 0x47, 0xe4, 0xca, 0x8a, 0xfd, 0x2d, 0x51, 0xad, 0xff, 0x2e, 0xdb, 0xfa, 0xda, 0xf1, 0xb4, 0xe3, 0x75, 0x7e,
-    0xce, 0x78, 0xdf, 0xb9, 0xd1, 0xe3, 0xcf, 0xf8, 0x36, 0x33, 0xc7, 0xb2, 0xf5, 0xea, 0x3c, 0xef, 0xac, 0xd9, 0xf0, 0xd9,
-    0x63, 0x95, 0xb3, 0x95, 0x05, 0x46, 0xc7, 0xba, 0xe7, 0x54, 0xaf, 0xca, 0xd5, 0xbd, 0x9a, 0x69, 0xc5, 0xb3, 0x96, 0x1d,
-    0xf9, 0x2b, 0x30, 0x0f, 0xdb, 0x95, 0xdf, 0x71, 0x7f, 0xc5, 0x8e, 0xe3, 0x5a, 0x22, 0xf7, 0xde, 0xd6, 0xd9, 0x1a, 0x59,
-    0xd9, 0x4a, 0x30, 0xd1, 0xf3, 0xff, 0x53, 0xf3, 0x3f, 0x9a, 0x8b, 0xe0, 0xe7, 0x59, 0xc9, 0xce, 0x5b, 0x56, 0x31, 0x93,
-    0xc1, 0xea, 0x15, 0xd0, 0x8e, 0x65, 0x57, 0x56, 0xec, 0x3a, 0xfb, 0xbb, 0xc6, 0xdb, 0xa8, 0xaa, 0x9f, 0x18, 0x9d, 0xb3,
-    0x64, 0xb4, 0xec, 0xd3, 0xce, 0xff, 0xfd, 0xf2, 0x65, 0xf3, 0x47, 0xb1, 0xbb, 0xef, 0xdb, 0xfb, 0x67, 0xec, 0x78, 0x42,
-    0xc6, 0x33, 0xb3, 0x4b, 0xed, 0xcc, 0xff, 0x3d, 0xeb, 0x1d, 0xf7, 0xd4, 0xb9, 0x31, 0x5b, 0xab, 0xef, 0x3e, 0xb9, 0xc9,
-    0xcc, 0x64, 0x1c, 0x9b, 0xbf, 0xb9, 0x7a, 0x99, 0xfc, 0xdf, 0x3b, 0xff, 0x73, 0xf7, 0x56, 0xee, 0x57, 0xbd, 0x32, 0x3b,
-    0x4b, 0xef, 0xfb, 0xfb, 0x8b, 0x7d, 0xc3, 0xd3, 0x9a, 0xba, 0xe7, 0x89, 0xf2, 0x7f, 0x97, 0xfe, 0xbf, 0xfc, 0xbf, 0x6f,
-    0x7f, 0xe9, 0xa9, 0x4a, 0xe6, 0xfa, 0xff, 0xf2, 0xff, 0xe6, 0xfc, 0xf7, 0x47, 0x5c, 0xff, 0xef, 0xda, 0x5f, 0xde, 0x76,
-    0xff, 0x3f, 0xfa, 0xb4, 0xf7, 0x29, 0xcf, 0x7a, 0xce, 0x78, 0xfe, 0xb7, 0xe7, 0x93, 0x77, 0x56, 0x43, 0x7f, 0xff, 0xf3,
-    0xde, 0xa7, 0xd4, 0x83, 0xe7, 0xed, 0xfb, 0xa1, 0x36, 0x00, 0xf9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x76, 0xbe, 0xa9, 0x7f, 0x66, 0xc5, 0xf7, 0xc8, 0xa8, 0xcf, 0xb9, 0xcf, 0x04, 0x62, 0x23, 0x75, 0xce,
-    0xac, 0xf8, 0x9e, 0x1f, 0x9d, 0x6f, 0x5b, 0xc2, 0xfb, 0xc6, 0x8a, 0xcb, 0x36, 0xec, 0x49, 0x55, 0x7f, 0x48, 0x15, 0xa4,
-    0x77, 0xcc, 0xcd, 0x01, 0xf2, 0xff, 0x94, 0x0a, 0x69, 0x20, 0xff, 0xf2, 0x0f, 0xf2, 0x2f, 0xff, 0x20, 0xff, 0xf2, 0x0f,
-    0x6f, 0xbf, 0xff, 0x7f, 0xa7, 0x99, 0x6b, 0xf6, 0xd5, 0x29, 0x06, 0xcf, 0xfe, 0x63, 0x47, 0x87, 0xea, 0x65, 0x6d, 0x78,
-    0xdc, 0xf0, 0x8c, 0x10, 0xce, 0xca, 0xff, 0x35, 0xcf, 0xf8, 0x57, 0xf3, 0xaf, 0xff, 0x0f, 0x6f, 0xba, 0x1a, 0x89, 0xbc,
-    0xff, 0x27, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xdd, 0x5b, 0x92, 0xec, 0xb6, 0x0d, 0x00, 0x50, 0xee, 0x7f, 0xa1, 0xd9, 0x06, 0x53, 0xa9, 0x94, 0x2b, 0xf1, 0xf8, 0x8e,
+    0x48, 0x02, 0xa0, 0x9e, 0xc7, 0xa7, 0xfc, 0x33, 0xba, 0xdd, 0x52, 0x53, 0x82, 0xf8, 0x90, 0x08, 0xf6, 0x06, 0x00, 0x00,
+    0x00, 0x7c, 0xde, 0x7f, 0xfe, 0xfb, 0xf3, 0xdf, 0xfe, 0xb4, 0xe5, 0x78, 0xdb, 0x5f, 0xff, 0x62, 0xb4, 0xa5, 0xff, 0x7a,
+    0x24, 0xfd, 0x60, 0xdb, 0xdc, 0xbe, 0x62, 0xc7, 0xd5, 0x97, 0xca, 0xa6, 0x1f, 0x94, 0x5a, 0x4b, 0xff, 0xbd, 0x1d, 0x96,
+    0x7d, 0x0f, 0x94, 0x5e, 0x3b, 0x3c, 0xe6, 0xdf, 0x3f, 0x39, 0xde, 0x52, 0x79, 0x9c, 0x2b, 0x65, 0x5a, 0x79, 0x7e, 0x56,
+    0x4a, 0xb0, 0x2d, 0x6f, 0x3d, 0x2e, 0xa9, 0x36, 0x55, 0x8e, 0xe3, 0x6f, 0xee, 0x37, 0x89, 0xff, 0xe3, 0x5f, 0xf3, 0x57,
+    0x0c, 0x1e, 0x9d, 0xfd, 0xf9, 0x6b, 0xa3, 0x4d, 0xdf, 0x13, 0xfe, 0xb7, 0xef, 0xba, 0x08, 0xcd, 0x7e, 0x4b, 0x1f, 0xde,
+    0x09, 0x57, 0x4a, 0xe8, 0xb8, 0xf4, 0x5a, 0x28, 0x26, 0x46, 0xdf, 0x19, 0x39, 0x96, 0x99, 0x6d, 0x73, 0xc7, 0x17, 0xbb,
+    0xe6, 0xc7, 0xdf, 0x77, 0x7c, 0xa5, 0x1d, 0x9d, 0xe1, 0xd1, 0x95, 0x7b, 0xfc, 0xfb, 0xd6, 0xcf, 0x6a, 0x26, 0xea, 0xf7,
+    0xc4, 0x7f, 0xff, 0xbf, 0x38, 0xeb, 0xc1, 0x18, 0xcc, 0xd7, 0x0d, 0xeb, 0xb5, 0xc2, 0xf1, 0x3d, 0x6b, 0x5f, 0x09, 0x1f,
+    0x95, 0x53, 0x0f, 0x5c, 0xc3, 0xeb, 0xe7, 0x2c, 0xba, 0x9f, 0x1d, 0xf1, 0x5f, 0x11, 0xc5, 0x6d, 0xa2, 0x46, 0x8c, 0xb4,
+    0x29, 0x8e, 0x5b, 0x9c, 0xf9, 0x08, 0x1f, 0x1d, 0x4b, 0xa4, 0x3d, 0x93, 0x2f, 0xcb, 0xd5, 0x36, 0xc7, 0xbe, 0xf8, 0xaf,
+    0xa8, 0x6f, 0xd7, 0xeb, 0x92, 0x7d, 0xe5, 0x3b, 0x53, 0x5f, 0xdf, 0x3f, 0xfe, 0xd7, 0x7f, 0x5b, 0x45, 0xfc, 0xd7, 0x9c,
+    0x95, 0xf5, 0xf8, 0xef, 0xe2, 0x7f, 0xba, 0xfe, 0xff, 0xbd, 0xd4, 0x7b, 0xb0, 0xff, 0x95, 0xef, 0xb5, 0x57, 0xb5, 0xf3,
+    0xaf, 0x8d, 0xff, 0x51, 0x7f, 0xb0, 0x2d, 0xc7, 0x7f, 0xac, 0xf7, 0x19, 0xe9, 0x6d, 0x54, 0xb5, 0xff, 0xf7, 0xb6, 0x1e,
+    0x8e, 0x7b, 0x8f, 0x91, 0x08, 0x5f, 0x1b, 0xf3, 0xa8, 0xf9, 0xe6, 0x2b, 0xe2, 0xbf, 0x4d, 0x1c, 0x4d, 0x1f, 0xf6, 0xff,
+    0x67, 0xef, 0xf0, 0x6b, 0xf1, 0x5f, 0x57, 0x77, 0x5c, 0x19, 0xff, 0x3d, 0x38, 0x22, 0x56, 0xdd, 0x8f, 0x8f, 0xff, 0xb6,
+    0xb5, 0xf1, 0xb9, 0xf3, 0xfa, 0xff, 0xa3, 0x76, 0x60, 0x26, 0xfe, 0xbf, 0xd2, 0xfe, 0x9f, 0x69, 0x69, 0x8f, 0x4a, 0x71,
+    0xfe, 0x7e, 0x76, 0x45, 0x6d, 0x7e, 0x6d, 0xfc, 0xf7, 0xa9, 0x31, 0xec, 0x7b, 0xc7, 0x7f, 0x5b, 0xee, 0xe5, 0x55, 0x5e,
+    0xbb, 0xd1, 0x2b, 0x6a, 0x74, 0xe5, 0xce, 0xdc, 0xd5, 0xee, 0x19, 0xff, 0xb1, 0xeb, 0xb9, 0x0f, 0x5b, 0xf9, 0x3d, 0x11,
+    0xff, 0xed, 0x35, 0xf1, 0xdf, 0x83, 0xa3, 0x1d, 0xbf, 0xb7, 0xf7, 0x62, 0xe3, 0x71, 0x91, 0x96, 0x7c, 0xa6, 0x8d, 0x52,
+    0x15, 0xff, 0xf7, 0x38, 0x93, 0xea, 0xff, 0x8a, 0xf1, 0xff, 0x76, 0xd8, 0xc2, 0xff, 0x56, 0xfc, 0x1f, 0x3f, 0xff, 0x6b,
+    0xb7, 0x7f, 0x56, 0x17, 0x8d, 0xff, 0x9a, 0xf1, 0xff, 0xf3, 0xef, 0xd6, 0x33, 0x3d, 0xd7, 0x5c, 0xfc, 0xdf, 0xe9, 0xf9,
+    0xdf, 0xde, 0xf8, 0x1f, 0x3d, 0xf5, 0x7e, 0x53, 0xfb, 0xbf, 0x72, 0x1c, 0x3f, 0xfe, 0xce, 0xcd, 0xbe, 0x77, 0x8a, 0x5a,
+    0xe8, 0x4d, 0xae, 0x7b, 0x46, 0x7f, 0xf4, 0x39, 0x50, 0x6e, 0x94, 0xee, 0xea, 0xf7, 0x7f, 0xea, 0x4b, 0xf0, 0xbc, 0xe3,
+    0xe9, 0x37, 0x6e, 0x33, 0xf2, 0xae, 0xb7, 0x64, 0x5d, 0x5d, 0x67, 0x3e, 0x9f, 0x8d, 0xef, 0xcb, 0xf9, 0x61, 0x67, 0xcd,
+    0xa6, 0x24, 0x9e, 0x31, 0x66, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x9e, 0xbf,
+    0x10, 0x99, 0x6b, 0x18, 0xcd, 0x43, 0x50, 0x9b, 0x0f, 0xa1, 0xff, 0xc8, 0xc3, 0xba, 0xfa, 0xdd, 0xb3, 0x73, 0x2d, 0x33,
+    0xf3, 0x34, 0x6b, 0x3f, 0x5b, 0x95, 0x59, 0xa2, 0x76, 0xe6, 0xf9, 0x38, 0xdf, 0xcd, 0x6a, 0xb6, 0xe6, 0x58, 0x16, 0xb4,
+    0xf5, 0x9c, 0xe6, 0x99, 0x3c, 0x7c, 0xd5, 0x73, 0xab, 0x6b, 0xf2, 0xa3, 0xcd, 0xcf, 0x79, 0xaf, 0xc9, 0x34, 0x52, 0x17,
+    0xff, 0xeb, 0xe7, 0xa1, 0xff, 0x38, 0x8e, 0x7e, 0x41, 0x26, 0x86, 0xfa, 0xad, 0x73, 0x7f, 0xbf, 0x53, 0xfc, 0xcf, 0xde,
+    0x83, 0xb3, 0x57, 0x6f, 0x7c, 0xc6, 0xdd, 0x28, 0xfb, 0xc4, 0xf5, 0xb9, 0x55, 0x5a, 0x51, 0x7e, 0xd4, 0xfa, 0xf8, 0x6f,
+    0x27, 0xd5, 0xff, 0xd1, 0xf8, 0xef, 0xc3, 0xd5, 0x6c, 0xee, 0x1b, 0xff, 0xeb, 0x79, 0x27, 0xb2, 0x7b, 0xcd, 0xad, 0xe4,
+    0x10, 0xcf, 0x35, 0x9e, 0x8f, 0xff, 0x5c, 0xa6, 0xa0, 0x73, 0xeb, 0xd6, 0xeb, 0xe3, 0x3f, 0x5a, 0x22, 0x57, 0xc5, 0x7f,
+    0xfc, 0x2a, 0xe9, 0xc3, 0x6c, 0xd6, 0x77, 0x8c, 0xff, 0xfe, 0xf9, 0xf8, 0xaf, 0xcf, 0xe5, 0x1b, 0x8d, 0x80, 0x48, 0x1e,
+    0xf4, 0x99, 0x7e, 0xf5, 0x6a, 0xcf, 0x2e, 0xde, 0xef, 0x8a, 0xd6, 0xff, 0xa3, 0xcf, 0xcf, 0xfc, 0x92, 0xab, 0xe3, 0xbf,
+    0x0d, 0x23, 0xbc, 0x27, 0xa2, 0x34, 0x3e, 0x02, 0x92, 0xc9, 0x79, 0x75, 0x4d, 0xfc, 0xb7, 0xd0, 0x8a, 0x81, 0xf1, 0x7a,
+    0xfe, 0xee, 0xf1, 0x5f, 0xdd, 0x37, 0x88, 0x8e, 0x18, 0x54, 0x1f, 0xe3, 0xfd, 0xfa, 0xff, 0xbd, 0xa0, 0x95, 0xb8, 0x23,
+    0xfe, 0xb3, 0xe5, 0x13, 0x8d, 0xa6, 0x58, 0xfc, 0xcf, 0xd7, 0xee, 0xb1, 0xd5, 0x04, 0x62, 0xdb, 0xde, 0x1b, 0xff, 0xb5,
+    0xf9, 0x53, 0xd7, 0xc7, 0x8a, 0xdf, 0x14, 0xff, 0xd1, 0xfe, 0xff, 0x7c, 0x8f, 0xeb, 0x5e, 0xf1, 0xdf, 0x26, 0xd6, 0xe7,
+    0x39, 0x3b, 0xfe, 0x47, 0xd9, 0x56, 0xdf, 0x16, 0xff, 0xd1, 0xd8, 0x8a, 0xae, 0x67, 0xd4, 0xc2, 0x35, 0xdd, 0xdb, 0xeb,
+    0xff, 0xf6, 0xd2, 0xf8, 0x8f, 0xaf, 0x2f, 0xf3, 0xac, 0xf8, 0xaf, 0x6e, 0x35, 0x5c, 0x9f, 0x57, 0x2f, 0x3a, 0xda, 0x18,
+    0x1f, 0xa5, 0x7c, 0x77, 0xfb, 0xbf, 0x6f, 0x68, 0x85, 0x67, 0x9f, 0xff, 0x5f, 0x15, 0xff, 0xbb, 0x9e, 0xff, 0xb5, 0xe9,
+    0x35, 0xff, 0x76, 0x1d, 0x95, 0xf8, 0xaf, 0x8e, 0xff, 0xca, 0xb5, 0x13, 0xd7, 0xfe, 0x45, 0xf5, 0xfb, 0x3f, 0xf5, 0x23,
+    0x69, 0xfb, 0xdf, 0xff, 0xd9, 0x53, 0x3e, 0x6d, 0x6a, 0xc5, 0xb4, 0xf5, 0xbd, 0xb6, 0xc9, 0x55, 0x8d, 0x63, 0xc7, 0x5c,
+    0xff, 0xf6, 0xcd, 0xdd, 0xe3, 0x3f, 0xf6, 0xb6, 0x41, 0xf4, 0x93, 0xf1, 0x4f, 0xdc, 0x67, 0x2d, 0xb0, 0x6f, 0xbe, 0x45,
+    0xa9, 0x14, 0xaa, 0x4b, 0x48, 0xa9, 0xe2, 0x0e, 0xf0, 0xae, 0xf7, 0xcc, 0x77, 0xfd, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xef, 0xcd, 0x5e, 0x99, 0xcd, 0xb9, 0xfd, 0xcf, 0xbf, 0xf6, 0xd0, 0x7c, 0xd7,
+    0x9e, 0xfc, 0x5c, 0x5f, 0xce, 0x83, 0xb1, 0x36, 0xef, 0xb4, 0x22, 0x07, 0x43, 0x75, 0x1e, 0xa9, 0x71, 0xb9, 0xcc, 0x9e,
+    0xe9, 0xf1, 0x4c, 0xe2, 0xd5, 0x2b, 0x24, 0x32, 0xaf, 0x27, 0x93, 0x51, 0x27, 0xb3, 0x96, 0x40, 0x3c, 0x13, 0x62, 0x5b,
+    0xfc, 0xd6, 0xd8, 0x59, 0x9b, 0x99, 0x0f, 0xbe, 0xfa, 0x6d, 0x99, 0xf8, 0x8f, 0xe5, 0x96, 0xbc, 0x22, 0xd3, 0x5a, 0xfc,
+    0x6a, 0xaa, 0x3d, 0xc2, 0xfa, 0x52, 0x99, 0x3b, 0xda, 0xdc, 0xdf, 0x33, 0x73, 0xfa, 0x73, 0xb9, 0x07, 0x56, 0x4b, 0xa2,
+    0x4f, 0x65, 0x4b, 0x59, 0xfd, 0xe4, 0xef, 0x9f, 0x3b, 0xde, 0xd6, 0xa7, 0x32, 0x47, 0x44, 0xf6, 0x18, 0xcb, 0xbd, 0x52,
+    0x3f, 0xa3, 0xf5, 0x29, 0xf1, 0xdf, 0x02, 0xf7, 0xc5, 0x73, 0xe3, 0x3f, 0x7e, 0x9f, 0x6a, 0x85, 0x59, 0x7a, 0xd6, 0xd7,
+    0xc6, 0x88, 0xcc, 0xdc, 0xcd, 0xe7, 0x08, 0x3a, 0x23, 0xa3, 0xc6, 0x3f, 0xe3, 0x6d, 0xe5, 0xac, 0xcd, 0x45, 0xff, 0x9f,
+    0xef, 0x71, 0xed, 0xb0, 0xb5, 0xf5, 0xfb, 0x9d, 0xb1, 0x4f, 0xdc, 0xc5, 0xa2, 0xf5, 0xff, 0x7c, 0xfd, 0xf2, 0x9c, 0xf8,
+    0x9f, 0xe9, 0x6d, 0x9c, 0x17, 0xff, 0xe3, 0xbf, 0xd7, 0x65, 0xd5, 0xae, 0xcc, 0xb5, 0x33, 0xca, 0xb5, 0xdc, 0x42, 0x67,
+    0xa4, 0x07, 0xef, 0x2b, 0xbd, 0x38, 0x9f, 0x79, 0xff, 0xf1, 0xff, 0x6c, 0x4d, 0x3d, 0x1b, 0xff, 0xab, 0x7b, 0x8c, 0xe6,
+    0x64, 0xcc, 0x9e, 0xc9, 0xfe, 0xc2, 0xfa, 0xff, 0xf8, 0xba, 0x78, 0x4a, 0xfd, 0x5f, 0x99, 0x53, 0xab, 0x3e, 0xfe, 0x63,
+    0x11, 0x1e, 0xa9, 0xc9, 0xe7, 0x57, 0x3c, 0x58, 0x3b, 0x6f, 0xe3, 0x56, 0x7e, 0x4f, 0xb4, 0xff, 0xd7, 0xe3, 0x3f, 0x56,
+    0x32, 0x99, 0x75, 0x8a, 0xe2, 0x6b, 0x78, 0xec, 0x19, 0xe9, 0x8a, 0x8c, 0xff, 0xb5, 0x13, 0xfa, 0xff, 0xa3, 0x76, 0x62,
+    0xb4, 0x54, 0xea, 0xd7, 0xa6, 0xaa, 0xcc, 0xb6, 0xbd, 0x1a, 0xff, 0x99, 0xfa, 0x3f, 0x3a, 0x0e, 0x91, 0x69, 0x21, 0xb6,
+    0xc1, 0xc8, 0xc1, 0x68, 0x9f, 0xeb, 0x59, 0x43, 0x8f, 0xda, 0xff, 0x57, 0x8c, 0xff, 0xf7, 0xd3, 0xfa, 0xff, 0x2d, 0xb5,
+    0x8a, 0x51, 0x65, 0xfb, 0xbf, 0x25, 0x5a, 0x99, 0x99, 0xbb, 0x4d, 0xa4, 0xb4, 0xd7, 0xcb, 0xec, 0xca, 0xfa, 0x3f, 0xb7,
+    0xda, 0x5c, 0xdb, 0x96, 0xef, 0x34, 0xd2, 0xfe, 0xdf, 0x13, 0x85, 0x91, 0x3d, 0xf6, 0x44, 0x96, 0xd2, 0xda, 0xfa, 0xff,
+    0xcc, 0xbb, 0xd3, 0xce, 0xe3, 0xb9, 0x4f, 0xde, 0xb9, 0x3d, 0x79, 0xa4, 0xef, 0xd0, 0xff, 0x8f, 0x8c, 0xff, 0x47, 0x73,
+    0x1e, 0x8f, 0x6b, 0xe3, 0x3e, 0x18, 0x6f, 0xbb, 0x73, 0xfc, 0xef, 0x7d, 0xfe, 0x7f, 0x87, 0xdc, 0xcc, 0xdf, 0x8d, 0xff,
+    0x96, 0xca, 0x3f, 0x7d, 0x45, 0xfc, 0xcf, 0xb5, 0xac, 0x62, 0xfd, 0xd5, 0xdc, 0x8a, 0xc9, 0xd1, 0x3e, 0x5d, 0x3b, 0xf5,
+    0x4a, 0x6f, 0x17, 0xb4, 0xfe, 0xab, 0x57, 0xe4, 0x79, 0xe7, 0xfb, 0x50, 0xef, 0xf8, 0x05, 0x67, 0xdc, 0xcf, 0xfb, 0xa6,
+    0x96, 0x6a, 0x7c, 0x3d, 0x94, 0xd8, 0xdd, 0xaa, 0x5d, 0x90, 0x83, 0xf8, 0xec, 0x3d, 0xc6, 0x9f, 0x56, 0x20, 0xfe, 0x2b,
+    0xdf, 0x37, 0xa9, 0x68, 0x25, 0x55, 0xbd, 0xc3, 0xf0, 0xb5, 0x2b, 0x45, 0xc9, 0x7c, 0xe5, 0xbc, 0xae, 0x8f, 0xf4, 0xbe,
+    0xa5, 0x24, 0x5c, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xdb, 0x66, 0xff, 0x44,
+    0xf3, 0xa6, 0x45, 0x72, 0x35, 0x8d, 0x72, 0x0d, 0xb4, 0x92, 0xef, 0xf9, 0xb9, 0x42, 0x41, 0x1f, 0xfc, 0x8b, 0x16, 0x38,
+    0xd2, 0x1e, 0x9e, 0x53, 0xbc, 0xbe, 0xde, 0xc2, 0xcf, 0x23, 0x6e, 0x89, 0x12, 0x19, 0xcf, 0xd8, 0x5d, 0x5f, 0x99, 0x61,
+    0xef, 0x6f, 0xae, 0xc9, 0x7c, 0x1e, 0xc9, 0xe1, 0x37, 0x9b, 0x89, 0xa4, 0xdf, 0xea, 0x4a, 0x58, 0x9f, 0xb1, 0x19, 0xcb,
+    0xe3, 0xd0, 0x0f, 0x63, 0x28, 0x92, 0xa1, 0x61, 0x3e, 0x17, 0xf2, 0xec, 0x79, 0x9b, 0xb9, 0xae, 0xa2, 0x2b, 0x4d, 0xc4,
+    0xcf, 0x6b, 0x0b, 0x5d, 0xed, 0xf1, 0x48, 0xc9, 0x6d, 0x9d, 0x9b, 0x77, 0xbf, 0xe3, 0x37, 0xc7, 0x73, 0xd3, 0xce, 0x7f,
+    0x4f, 0xa6, 0xf6, 0x1b, 0xcf, 0xa8, 0xbc, 0xe2, 0x4a, 0xa8, 0xcc, 0x75, 0x11, 0x8f, 0xff, 0x9a, 0xf9, 0xe4, 0xe3, 0xb5,
+    0x10, 0x62, 0xab, 0x69, 0xcc, 0xe4, 0xea, 0x7e, 0x5f, 0x96, 0x80, 0x7c, 0xfc, 0x7f, 0x35, 0xb7, 0xc2, 0x5b, 0x4a, 0xa0,
+    0x2f, 0xb6, 0xfc, 0x6a, 0xe3, 0x7f, 0x7d, 0x05, 0x83, 0xfd, 0xf1, 0xdf, 0x43, 0xdf, 0x10, 0x6d, 0xb9, 0xdd, 0x73, 0x6b,
+    0x2e, 0xfe, 0xc7, 0x57, 0xd0, 0x9e, 0xad, 0x55, 0x2b, 0x22, 0xe5, 0xf2, 0x8d, 0xb7, 0x60, 0xef, 0x61, 0xdf, 0xd6, 0x68,
+    0xf6, 0x8f, 0xfd, 0xf1, 0x3f, 0x2e, 0xef, 0xd5, 0x73, 0x33, 0x6e, 0xb7, 0xc5, 0xc7, 0x0f, 0x32, 0xd7, 0xd2, 0x8e, 0x76,
+    0xf8, 0x19, 0x5b, 0x23, 0x39, 0xe0, 0xae, 0xda, 0xba, 0x3b, 0xfe, 0xfb, 0xdf, 0xd6, 0x44, 0x3c, 0xca, 0xa6, 0xb2, 0x7e,
+    0x77, 0xd8, 0xb7, 0x35, 0xdf, 0xd6, 0x59, 0x1d, 0xff, 0x6b, 0x81, 0x3b, 0xd1, 0x19, 0xed, 0xd9, 0xf9, 0x28, 0xad, 0xab,
+    0xff, 0xaf, 0x3a, 0xeb, 0xd9, 0xad, 0x99, 0xd1, 0xbd, 0xb7, 0xc6, 0xff, 0x5c, 0xb9, 0xbd, 0x23, 0xfe, 0xc7, 0x79, 0x5a,
+    0xa3, 0x19, 0x97, 0xaf, 0xe8, 0x4b, 0xce, 0x66, 0xda, 0xcf, 0xad, 0x25, 0xfb, 0xa6, 0xf8, 0x6f, 0x45, 0xed, 0xff, 0x33,
+    0xb7, 0xde, 0xa3, 0xfd, 0xdf, 0x5f, 0x10, 0xff, 0xd9, 0xe7, 0x3a, 0xf3, 0xc7, 0x71, 0xce, 0x38, 0x4a, 0x3c, 0x9b, 0x7e,
+    0xe6, 0x09, 0xc6, 0x95, 0x7d, 0xe1, 0xec, 0xd6, 0x6c, 0xfc, 0x7f, 0xb5, 0xfe, 0x7f, 0x43, 0xfc, 0xe7, 0x9f, 0x65, 0xf7,
+    0xc4, 0xea, 0x83, 0xfb, 0xde, 0x75, 0xe8, 0x1b, 0xe3, 0xbf, 0x7d, 0xb4, 0xfe, 0xaf, 0x59, 0x3f, 0xfe, 0x69, 0xf1, 0x3f,
+    0x33, 0xca, 0xf4, 0xd4, 0xf8, 0xaf, 0x88, 0x91, 0xaa, 0xf1, 0xff, 0xfa, 0xb7, 0x9d, 0x76, 0x66, 0xa1, 0x7f, 0x5e, 0x84,
+    0x8f, 0xe3, 0x3f, 0xf2, 0xfe, 0xcf, 0xbb, 0xe3, 0x7f, 0xee, 0xdd, 0x98, 0x67, 0xc7, 0x7f, 0x4f, 0xae, 0x3e, 0xf3, 0xce,
+    0xe7, 0xc3, 0xb1, 0xb5, 0xa4, 0x9f, 0x17, 0xff, 0xb9, 0x77, 0xc7, 0xde, 0xfc, 0xfc, 0x2f, 0xf7, 0x76, 0xc0, 0xbd, 0x9e,
+    0xff, 0x5d, 0xf1, 0x5e, 0x09, 0xef, 0x7f, 0x7b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x80, 0x33, 0xe6, 0xea, 0xcc, 0xcd, 0x10, 0xbb, 0x26, 0xe7, 0x7d, 0x24, 0x43, 0xc1, 0xcc, 0xf1, 0xc4, 0xf3, 0x1e, 0x44,
+    0xb2, 0xec, 0x1f, 0xe5, 0x51, 0x8a, 0xe6, 0x1a, 0xcf, 0xe4, 0x30, 0xda, 0xf5, 0x1b, 0xd7, 0xb3, 0xc1, 0xcf, 0xef, 0x61,
+    0x2e, 0xe7, 0xe3, 0x5a, 0xd9, 0x3f, 0xe5, 0x5c, 0x8f, 0x22, 0x30, 0x3b, 0x57, 0x6f, 0xee, 0x4a, 0xea, 0xe5, 0x59, 0x44,
+    0xf6, 0x64, 0xa6, 0x9e, 0x3b, 0xa7, 0xb1, 0x63, 0x8e, 0xdc, 0xad, 0x7a, 0x62, 0x05, 0x96, 0x36, 0x71, 0x25, 0x55, 0xe7,
+    0xf5, 0xc9, 0xac, 0xc8, 0x31, 0x7f, 0x47, 0xae, 0xcc, 0xd5, 0xdf, 0x12, 0xf9, 0xf2, 0xef, 0x72, 0xae, 0xf7, 0xc6, 0x7f,
+    0x7c, 0x8e, 0xe7, 0x71, 0xa6, 0xa3, 0xfb, 0xce, 0x57, 0xed, 0xa1, 0xac, 0xa6, 0xcf, 0xc9, 0x43, 0x10, 0xab, 0x73, 0xbf,
+    0xd7, 0xba, 0x7d, 0xcf, 0x0c, 0xec, 0x5c, 0xfe, 0x86, 0x71, 0x1d, 0xde, 0x02, 0xf1, 0x7f, 0xc7, 0xbc, 0x55, 0xb9, 0x8c,
+    0x57, 0x33, 0xb9, 0x17, 0xce, 0xda, 0x76, 0xe4, 0x5f, 0x81, 0x15, 0xd8, 0xae, 0xfc, 0x8d, 0xfb, 0x73, 0x75, 0x1c, 0x67,
+    0x11, 0xb9, 0xf7, 0xb9, 0x1e, 0x9f, 0xcb, 0xcc, 0x1d, 0x6e, 0xdc, 0xc3, 0x8f, 0xd6, 0xff, 0x4f, 0x8d, 0xff, 0xd1, 0x2a,
+    0x04, 0xbf, 0xaf, 0x47, 0x76, 0xde, 0xb6, 0x8a, 0x35, 0x0c, 0x56, 0x7b, 0x40, 0x3b, 0xb6, 0x5d, 0x99, 0xab, 0xeb, 0xec,
+    0xdf, 0x1a, 0x2f, 0xa3, 0x71, 0xeb, 0x66, 0x5f, 0xfc, 0xcf, 0xf4, 0xeb, 0xbe, 0x56, 0xff, 0xf7, 0xcb, 0xb7, 0xcd, 0xdf,
+    0xc5, 0xee, 0x7e, 0x6d, 0xef, 0x5f, 0xab, 0xe3, 0x09, 0x31, 0x9e, 0x5b, 0x57, 0x62, 0x5f, 0xfc, 0x3f, 0x33, 0xd3, 0x71,
+    0x26, 0xaf, 0x7c, 0x7b, 0xc8, 0x35, 0xd1, 0x93, 0x6b, 0x18, 0xc7, 0xda, 0x9a, 0xd5, 0xdb, 0xc4, 0xff, 0xbd, 0xe3, 0x3f,
+    0xd3, 0xfa, 0xb8, 0x32, 0x6f, 0x65, 0x76, 0x7d, 0xde, 0xb7, 0xb6, 0x17, 0x47, 0x63, 0x3a, 0xfb, 0x9e, 0xe4, 0xd4, 0x3c,
+    0xa7, 0xfd, 0x6a, 0xfc, 0x5f, 0xd7, 0xfe, 0x17, 0xff, 0xef, 0x8b, 0xff, 0x9e, 0xca, 0x61, 0xae, 0xfd, 0x7f, 0xa7, 0xf3,
+    0x99, 0x1d, 0xff, 0x17, 0xff, 0x7f, 0xea, 0x39, 0xdf, 0xbf, 0xff, 0xbf, 0xeb, 0x49, 0xe5, 0xdb, 0xc6, 0xff, 0xa3, 0x4f,
+    0x7b, 0x9f, 0xf2, 0xac, 0x27, 0xff, 0xec, 0xbf, 0xa7, 0xf6, 0x7d, 0x4d, 0x2e, 0xf3, 0xdc, 0xca, 0x94, 0x9e, 0xfb, 0xf2,
+    0xa6, 0x2b, 0xe1, 0xbb, 0x7b, 0x07, 0xc4, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+    0xe1, 0x1d, 0xfe, 0xf3, 0x32, 0xbe, 0x47, 0x66, 0x7d, 0xce, 0x7d, 0x27, 0x50, 0x7d, 0x07, 0xa8, 0xcf, 0xf8, 0x9e, 0x9f,
+    0x9d, 0xef, 0x7c, 0xc1, 0xd7, 0xda, 0x21, 0xc0, 0xae, 0x98, 0xbb, 0x4b, 0x16, 0xa4, 0x77, 0xac, 0xcd, 0x01, 0xe2, 0xff,
+    0x5e, 0x19, 0x2f, 0x01, 0xf1, 0x0f, 0x88, 0x7f, 0x40, 0xfc, 0x83, 0xf8, 0xbf, 0xc3, 0xca, 0x35, 0xb9, 0x9c, 0xbf, 0x40,
+    0xec, 0x0e, 0x70, 0x66, 0x56, 0xfb, 0x36, 0xbc, 0x6f, 0x78, 0x46, 0x08, 0xdf, 0x6d, 0x6f, 0x34, 0xcf, 0xff, 0xe0, 0xe5,
+    0xed, 0x8d, 0xc8, 0xfb, 0x7f, 0xa2, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x70, 0x95, 0x7f, 0xff, 0xd3, 0x0e, 0x20, 0xff, 0xc0, 0xc7, 0xe5, 0xff, 0x6f };
+    0x00, 0x00, 0x00, 0x00, 0xee, 0xe9, 0xbf, 0xff, 0x29, 0x07, 0x10, 0xff, 0xc0, 0xe7, 0xe2, 0xff, 0xdf };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle sunnyFontRecs[189] = {
+static const Rectangle sunnyFontRecs[188] = {
     { 4, 4, 4 , 16 },
     { 16, 4, 2 , 10 },
     { 26, 4, 5 , 3 },
@@ -289,92 +289,91 @@
     { 429, 52, 7 , 6 },
     { 444, 52, 6 , 3 },
     { 458, 52, 7 , 10 },
-    { 473, 52, 0 , 0 },
-    { 481, 52, 4 , 4 },
-    { 493, 52, 6 , 7 },
+    { 473, 52, 4 , 4 },
+    { 485, 52, 6 , 7 },
+    { 499, 52, 4 , 5 },
     { 4, 76, 4 , 5 },
-    { 16, 76, 4 , 5 },
-    { 28, 76, 7 , 11 },
-    { 43, 76, 6 , 9 },
-    { 57, 76, 7 , 12 },
-    { 72, 76, 2 , 2 },
-    { 82, 76, 6 , 10 },
-    { 96, 76, 3 , 5 },
-    { 107, 76, 4 , 5 },
-    { 119, 76, 7 , 6 },
-    { 134, 76, 9 , 10 },
-    { 151, 76, 8 , 7 },
-    { 167, 76, 6 , 11 },
-    { 181, 76, 6 , 11 },
-    { 195, 76, 7 , 11 },
-    { 210, 76, 7 , 11 },
-    { 225, 76, 7 , 11 },
-    { 240, 76, 7 , 11 },
-    { 255, 76, 7 , 11 },
-    { 270, 76, 7 , 11 },
-    { 285, 76, 9 , 10 },
-    { 302, 76, 7 , 12 },
-    { 317, 76, 7 , 11 },
-    { 332, 76, 7 , 11 },
-    { 347, 76, 7 , 11 },
-    { 362, 76, 7 , 11 },
-    { 377, 76, 3 , 11 },
-    { 388, 76, 3 , 11 },
-    { 399, 76, 5 , 11 },
-    { 412, 76, 5 , 11 },
-    { 425, 76, 8 , 10 },
-    { 441, 76, 7 , 11 },
-    { 456, 76, 7 , 11 },
-    { 471, 76, 7 , 11 },
-    { 486, 76, 7 , 11 },
+    { 16, 76, 7 , 11 },
+    { 31, 76, 6 , 9 },
+    { 45, 76, 7 , 12 },
+    { 60, 76, 2 , 2 },
+    { 70, 76, 6 , 10 },
+    { 84, 76, 3 , 5 },
+    { 95, 76, 4 , 5 },
+    { 107, 76, 7 , 6 },
+    { 122, 76, 9 , 10 },
+    { 139, 76, 8 , 7 },
+    { 155, 76, 6 , 11 },
+    { 169, 76, 6 , 11 },
+    { 183, 76, 7 , 11 },
+    { 198, 76, 7 , 11 },
+    { 213, 76, 7 , 11 },
+    { 228, 76, 7 , 11 },
+    { 243, 76, 7 , 11 },
+    { 258, 76, 7 , 11 },
+    { 273, 76, 9 , 10 },
+    { 290, 76, 7 , 12 },
+    { 305, 76, 7 , 11 },
+    { 320, 76, 7 , 11 },
+    { 335, 76, 7 , 11 },
+    { 350, 76, 7 , 11 },
+    { 365, 76, 3 , 11 },
+    { 376, 76, 3 , 11 },
+    { 387, 76, 5 , 11 },
+    { 400, 76, 5 , 11 },
+    { 413, 76, 8 , 10 },
+    { 429, 76, 7 , 11 },
+    { 444, 76, 7 , 11 },
+    { 459, 76, 7 , 11 },
+    { 474, 76, 7 , 11 },
+    { 489, 76, 7 , 11 },
     { 4, 100, 7 , 11 },
-    { 19, 100, 7 , 11 },
-    { 34, 100, 7 , 7 },
-    { 49, 100, 7 , 13 },
+    { 19, 100, 7 , 7 },
+    { 34, 100, 7 , 13 },
+    { 49, 100, 7 , 11 },
     { 64, 100, 7 , 11 },
     { 79, 100, 7 , 11 },
     { 94, 100, 7 , 11 },
-    { 109, 100, 7 , 11 },
-    { 124, 100, 6 , 11 },
+    { 109, 100, 6 , 11 },
+    { 123, 100, 7 , 10 },
     { 138, 100, 7 , 10 },
-    { 153, 100, 7 , 10 },
-    { 168, 100, 6 , 10 },
-    { 182, 100, 6 , 10 },
-    { 196, 100, 6 , 10 },
-    { 210, 100, 6 , 10 },
-    { 224, 100, 6 , 10 },
-    { 238, 100, 6 , 11 },
-    { 252, 100, 8 , 7 },
-    { 268, 100, 6 , 9 },
-    { 282, 100, 6 , 10 },
-    { 296, 100, 6 , 10 },
-    { 310, 100, 6 , 10 },
-    { 324, 100, 6 , 10 },
-    { 338, 100, 3 , 10 },
-    { 349, 100, 3 , 10 },
-    { 360, 100, 5 , 10 },
-    { 373, 100, 5 , 10 },
-    { 386, 100, 6 , 10 },
-    { 400, 100, 6 , 10 },
-    { 414, 100, 6 , 10 },
-    { 428, 100, 6 , 10 },
-    { 442, 100, 6 , 10 },
-    { 456, 100, 6 , 10 },
-    { 470, 100, 6 , 10 },
-    { 484, 100, 6 , 7 },
-    { 4, 124, 7 , 11 },
-    { 19, 124, 6 , 10 },
-    { 33, 124, 6 , 10 },
-    { 47, 124, 6 , 10 },
-    { 61, 124, 6 , 10 },
-    { 75, 124, 6 , 12 },
-    { 89, 124, 6 , 12 },
-    { 103, 124, 6 , 12 },
+    { 153, 100, 6 , 10 },
+    { 167, 100, 6 , 10 },
+    { 181, 100, 6 , 10 },
+    { 195, 100, 6 , 10 },
+    { 209, 100, 6 , 10 },
+    { 223, 100, 6 , 11 },
+    { 237, 100, 8 , 7 },
+    { 253, 100, 6 , 9 },
+    { 267, 100, 6 , 10 },
+    { 281, 100, 6 , 10 },
+    { 295, 100, 6 , 10 },
+    { 309, 100, 6 , 10 },
+    { 323, 100, 3 , 10 },
+    { 334, 100, 3 , 10 },
+    { 345, 100, 5 , 10 },
+    { 358, 100, 5 , 10 },
+    { 371, 100, 6 , 10 },
+    { 385, 100, 6 , 10 },
+    { 399, 100, 6 , 10 },
+    { 413, 100, 6 , 10 },
+    { 427, 100, 6 , 10 },
+    { 441, 100, 6 , 10 },
+    { 455, 100, 6 , 10 },
+    { 469, 100, 6 , 7 },
+    { 483, 100, 7 , 11 },
+    { 4, 124, 6 , 10 },
+    { 18, 124, 6 , 10 },
+    { 32, 124, 6 , 10 },
+    { 46, 124, 6 , 10 },
+    { 60, 124, 6 , 12 },
+    { 74, 124, 6 , 12 },
+    { 88, 124, 6 , 12 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo sunnyFontGlyphs[189] = {
+static const GlyphInfo sunnyFontGlyphs[188] = {
     { 32, 0, 0, 4, { 0 }},
     { 33, 0, 2, 3, { 0 }},
     { 34, 0, 2, 6, { 0 }},
@@ -483,7 +482,6 @@
     { 171, 0, 6, 8, { 0 }},
     { 172, 0, 7, 7, { 0 }},
     { 174, 0, 2, 8, { 0 }},
-    { 175, 0, 0, 0, { 0 }},
     { 176, 0, 2, 5, { 0 }},
     { 177, 0, 4, 7, { 0 }},
     { 178, 0, 2, 5, { 0 }},
@@ -584,29 +582,40 @@
 
     Font font = { 0 };
     font.baseSize = 16;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 188;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, sunnyFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, sunnyFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "GMSN.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/terminal/style_terminal.h b/raygui/styles/terminal/style_terminal.h
--- a/raygui/styles/terminal/style_terminal.h
+++ b/raygui/styles/terminal/style_terminal.h
@@ -7,7 +7,7 @@
 // more info and bugs-report:  github.com/raysan5/raygui                        //
 // feedback and support:       ray[at]raylibtech.com                            //
 //                                                                              //
-// Copyright (c) 2020-2025 raylib technologies (@raylibtech)                    //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
 //                                                                              //
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -15,127 +15,121 @@
 
 // Custom style name: Terminal
 static const GuiStyleProp terminalStyleProps[TERMINAL_STYLE_PROPS_COUNT] = {
-    { 0, 0, (int)0x1c8d00ff },    // DEFAULT_BORDER_COLOR_NORMAL 
-    { 0, 1, (int)0x161313ff },    // DEFAULT_BASE_COLOR_NORMAL 
-    { 0, 2, (int)0x38f620ff },    // DEFAULT_TEXT_COLOR_NORMAL 
-    { 0, 3, (int)0xc3fbc6ff },    // DEFAULT_BORDER_COLOR_FOCUSED 
-    { 0, 4, (int)0x43bf2eff },    // DEFAULT_BASE_COLOR_FOCUSED 
-    { 0, 5, (int)0xdcfadcff },    // DEFAULT_TEXT_COLOR_FOCUSED 
-    { 0, 6, (int)0x1f5b19ff },    // DEFAULT_BORDER_COLOR_PRESSED 
-    { 0, 7, (int)0x43ff28ff },    // DEFAULT_BASE_COLOR_PRESSED 
-    { 0, 8, (int)0x1e6f15ff },    // DEFAULT_TEXT_COLOR_PRESSED 
-    { 0, 9, (int)0x223b22ff },    // DEFAULT_BORDER_COLOR_DISABLED 
-    { 0, 10, (int)0x182c18ff },    // DEFAULT_BASE_COLOR_DISABLED 
-    { 0, 11, (int)0x244125ff },    // DEFAULT_TEXT_COLOR_DISABLED 
+    { 0, 0, (int)0x1c8d00ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x161313ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x38f620ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xc3fbc6ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x43bf2eff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xdcfadcff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x1f5b19ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0x43ff28ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x1e6f15ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x223b22ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x182c18ff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x244125ff },    // DEFAULT_TEXT_COLOR_DISABLED
     { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
     { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
     { 0, 18, (int)0xe6fce3ff },    // DEFAULT_LINE_COLOR 
     { 0, 19, (int)0x0c1505ff },    // DEFAULT_BACKGROUND_COLOR 
-    { 0, 20, (int)0x00000018 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
 };
 
 // WARNING: This style uses a custom font: "Mecha.ttf" (size: 16, spacing: 0)
 
-#define TERMINAL_STYLE_FONT_ATLAS_COMP_SIZE 1860
+#define TERMINAL_STYLE_FONT_ATLAS_COMP_SIZE 1731
 
 // Font atlas image pixels data: DEFLATE compressed
 static unsigned char terminalFontData[TERMINAL_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
-    0xdd, 0x41, 0x92, 0xa4, 0x36, 0x10, 0x05, 0x50, 0xee, 0x7f, 0xe9, 0xf4, 0x62, 0x62, 0x16, 0x76, 0xb8, 0x1b, 0x94, 0x4a,
-    0x89, 0x04, 0x9e, 0x5f, 0x78, 0xd3, 0xd5, 0x53, 0x4d, 0x01, 0xbf, 0x24, 0x84, 0x94, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x7c,
-    0x5e, 0xfc, 0xef, 0x4f, 0xe2, 0xc7, 0xdf, 0x8c, 0xcb, 0xef, 0xf3, 0xe7, 0xa7, 0xf1, 0xe3, 0x5f, 0xf9, 0xfb, 0xdf, 0x95,
-    0x77, 0xba, 0xfe, 0x5b, 0x31, 0xb4, 0x75, 0x73, 0x5b, 0x95, 0x7b, 0x9f, 0xd1, 0xdf, 0xfe, 0x7d, 0x7b, 0xaa, 0xde, 0xad,
-    0xf6, 0x95, 0xb1, 0xb3, 0x23, 0xbf, 0xe7, 0xae, 0x6e, 0x61, 0x6c, 0xdf, 0x2b, 0xc7, 0xa6, 0x7d, 0x1c, 0x0d, 0xf2, 0x7f,
-    0x7e, 0xcc, 0x46, 0xf2, 0x14, 0xe9, 0xf4, 0x8e, 0x7f, 0x3b, 0xad, 0xfc, 0x0e, 0x1d, 0xdd, 0xc6, 0xdc, 0x3e, 0x89, 0x92,
-    0xf7, 0x9f, 0xf9, 0x3b, 0x51, 0xb6, 0xd7, 0x72, 0xff, 0x26, 0x86, 0xdb, 0x88, 0xf9, 0x4f, 0x78, 0xbe, 0x8f, 0x63, 0xd1,
-    0x71, 0xef, 0x99, 0xff, 0xfc, 0x51, 0xcb, 0x9f, 0x29, 0x57, 0xb7, 0x3c, 0xd7, 0xa6, 0xaf, 0x3a, 0x27, 0xe5, 0xff, 0xec,
-    0x9b, 0xfa, 0xe7, 0x16, 0xb4, 0xa2, 0xdd, 0x90, 0xff, 0x5c, 0x06, 0x62, 0x22, 0x47, 0xbb, 0xf2, 0x5f, 0xdb, 0xd6, 0xc8,
-    0xff, 0x33, 0xda, 0xff, 0xb3, 0x6d, 0xff, 0xf7, 0x79, 0x2b, 0xff, 0xd9, 0xa3, 0x90, 0x6d, 0xff, 0x63, 0x7a, 0xfb, 0x3b,
-    0xe7, 0x7f, 0x74, 0xdc, 0x43, 0xfe, 0xcf, 0xaf, 0xe8, 0x73, 0xbf, 0x7d, 0xb6, 0x27, 0xe4, 0x7f, 0x5d, 0xfe, 0x7f, 0xeb,
-    0xb3, 0x9d, 0xf5, 0xf4, 0x76, 0xe4, 0xff, 0xd8, 0x9e, 0xff, 0xb3, 0xeb, 0xa8, 0xeb, 0xfb, 0x62, 0xc7, 0x08, 0xd4, 0x91,
-    0x1c, 0xdb, 0x89, 0xc1, 0x0c, 0xdf, 0xd3, 0x0b, 0x3b, 0xcb, 0x7f, 0x66, 0x4f, 0x66, 0xf2, 0x7f, 0x76, 0x5c, 0x8e, 0x5f,
-    0x7a, 0x30, 0xab, 0xf6, 0x7e, 0x45, 0xfe, 0x67, 0x46, 0xe4, 0x9e, 0x9d, 0xff, 0x38, 0xd9, 0x57, 0x31, 0x31, 0xbe, 0xb9,
-    0xb3, 0xcf, 0x30, 0xd3, 0x4f, 0xeb, 0x7b, 0x1c, 0xde, 0xd3, 0xff, 0x8f, 0xd6, 0xed, 0xbf, 0xfc, 0xcf, 0x5d, 0xff, 0xbf,
-    0x2d, 0xff, 0xb1, 0xfd, 0x58, 0xc5, 0x85, 0x33, 0x56, 0xfe, 0xe7, 0xf6, 0xf0, 0x79, 0x8f, 0x23, 0x16, 0x5d, 0xbf, 0x74,
-    0xcd, 0x7f, 0xee, 0xd3, 0x7d, 0xb1, 0xfd, 0x8f, 0x1b, 0x8f, 0x8f, 0xfc, 0xaf, 0xd8, 0x9b, 0x23, 0x77, 0xd8, 0x66, 0xe7,
-    0x2f, 0xc8, 0xbf, 0xfc, 0xcb, 0x7f, 0xef, 0xfe, 0x7f, 0x0c, 0x8e, 0xdc, 0xc6, 0xe3, 0xc7, 0xff, 0xe2, 0x52, 0x6f, 0x69,
-    0x7e, 0xb6, 0xe0, 0x78, 0x9f, 0x2b, 0xf7, 0x6e, 0xf9, 0xd9, 0x75, 0x4f, 0xb9, 0xfe, 0xdf, 0x39, 0x93, 0xf2, 0x28, 0x99,
-    0x87, 0xb2, 0x7e, 0xfe, 0xdf, 0x33, 0xe7, 0x28, 0x77, 0xcf, 0x3f, 0xb0, 0x7a, 0x95, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x65, 0x0d, 0x4d, 0x94, 0xad, 0x7b, 0x8c, 0x16, 0x95, 0xe7, 0xf7, 0xd4, 0x58,
-    0xbf, 0xb6, 0x87, 0xaa, 0xde, 0x71, 0xec, 0x59, 0x02, 0x63, 0xeb, 0x30, 0x73, 0x2b, 0xff, 0x56, 0xaf, 0x6e, 0x9b, 0x59,
-    0xdd, 0x58, 0xb3, 0x65, 0x15, 0xb5, 0x2d, 0xee, 0x49, 0xc7, 0xca, 0x75, 0xe2, 0x71, 0x69, 0x75, 0x70, 0x6d, 0x92, 0x56,
-    0xaf, 0xd8, 0xce, 0xac, 0x7d, 0xdf, 0x99, 0xff, 0xb1, 0x33, 0x70, 0xfc, 0x73, 0x46, 0x62, 0x35, 0x55, 0x6d, 0x0d, 0x98,
-    0x63, 0xe9, 0xb9, 0x19, 0x8b, 0xd6, 0x90, 0x8d, 0xef, 0x83, 0x3d, 0xe9, 0x90, 0xff, 0x2f, 0xe7, 0x3f, 0x57, 0x23, 0x7b,
-    0xc7, 0xb3, 0x50, 0xe4, 0x5f, 0xfe, 0xe5, 0xff, 0xad, 0xf9, 0x8f, 0xe2, 0xfe, 0x77, 0xbe, 0x5a, 0x47, 0xcd, 0x95, 0x55,
-    0x6d, 0x4a, 0xe4, 0x5f, 0xfe, 0x7f, 0xef, 0x6d, 0xc7, 0xc5, 0x56, 0x6c, 0xa4, 0xc5, 0xdb, 0x59, 0xb3, 0x64, 0x5f, 0x15,
-    0xad, 0xd1, 0x6f, 0x93, 0x28, 0x4c, 0xf0, 0x57, 0xf2, 0x9f, 0xaf, 0x7b, 0xbe, 0x67, 0xdc, 0x2b, 0xb3, 0xe5, 0x99, 0xda,
-    0x57, 0xf5, 0xf9, 0x3f, 0x7b, 0x1e, 0x42, 0xe6, 0xfb, 0xe9, 0x5b, 0xf9, 0x1f, 0xfd, 0x6c, 0xf2, 0x7f, 0x6c, 0x7e, 0xb6,
-    0xcc, 0xfd, 0x35, 0x16, 0x23, 0xd9, 0xd2, 0x57, 0x6d, 0x75, 0xa4, 0x46, 0xdb, 0xaa, 0x7e, 0x9e, 0xab, 0xd2, 0xf8, 0xde,
-    0xfc, 0x47, 0xc1, 0x7d, 0xae, 0xb9, 0x56, 0x52, 0xfe, 0xe5, 0xff, 0x98, 0xac, 0xc0, 0xdb, 0x3d, 0xff, 0x2b, 0xae, 0xbf,
-    0x2b, 0x9f, 0xe6, 0xfa, 0xcc, 0xf6, 0xff, 0x59, 0xf7, 0xff, 0xbe, 0x92, 0xff, 0xb3, 0x63, 0x79, 0x77, 0xfe, 0x3b, 0xd5,
-    0x4c, 0xcd, 0x8c, 0x30, 0xce, 0xfc, 0x9b, 0x8e, 0xf9, 0xdf, 0x35, 0x9f, 0x47, 0xfe, 0x77, 0xe5, 0xff, 0xe7, 0xa7, 0x8d,
-    0xcb, 0x7f, 0xaf, 0xfc, 0xaf, 0xeb, 0xff, 0x3f, 0x3b, 0xff, 0xeb, 0x7a, 0x5f, 0xab, 0xfb, 0x73, 0xb5, 0x5b, 0x9e, 0x99,
-    0x01, 0xf7, 0xdb, 0xfc, 0xbb, 0x48, 0x57, 0x6d, 0xaf, 0x98, 0x87, 0x37, 0x33, 0x3b, 0x68, 0xf7, 0x95, 0x41, 0xf5, 0xbf,
-    0xa9, 0x1f, 0xb3, 0xe8, 0x9b, 0x7f, 0x78, 0x46, 0xfe, 0xbf, 0xb0, 0xaf, 0x71, 0x3c, 0xee, 0x69, 0x59, 0x57, 0xfe, 0x3e,
-    0xce, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xd3, 0x2a, 0xac, 0xaa, 0xba, 0x8d, 0x3b,
-    0xab, 0x65, 0xe4, 0xd6, 0xf9, 0xc5, 0xe5, 0xba, 0x2e, 0x99, 0x55, 0xe4, 0x23, 0x6b, 0xf9, 0x6a, 0xd6, 0x34, 0xe6, 0xcf,
-    0x81, 0x48, 0xad, 0x96, 0x3b, 0x3f, 0x53, 0x32, 0x35, 0xec, 0xd7, 0xcd, 0xb6, 0xff, 0xbd, 0x7e, 0x43, 0xbe, 0x92, 0xc8,
-    0xaa, 0xf5, 0x05, 0x75, 0xf5, 0x9f, 0x8e, 0x82, 0xd5, 0x8a, 0xd9, 0x35, 0xf4, 0xf7, 0xe6, 0x7f, 0x74, 0xf5, 0xdb, 0xf5,
-    0x9f, 0x55, 0xd4, 0x5b, 0x89, 0xc4, 0xca, 0xbc, 0xca, 0xfc, 0x57, 0x9c, 0xe3, 0x51, 0xf6, 0xbe, 0xb1, 0xb8, 0x4e, 0xc1,
-    0x95, 0x56, 0xe2, 0xd9, 0x6b, 0xa2, 0xe2, 0xd5, 0xf9, 0xaf, 0xad, 0x96, 0x5b, 0xff, 0x9d, 0x90, 0xaf, 0x4f, 0x70, 0x5f,
-    0xfe, 0xff, 0x6e, 0x57, 0x75, 0xfe, 0x33, 0xef, 0x5b, 0x53, 0xd9, 0x6a, 0x2e, 0xff, 0x3d, 0x56, 0xf6, 0xc5, 0xf2, 0x9e,
-    0x47, 0x26, 0xff, 0x63, 0xfd, 0xb6, 0x15, 0xf9, 0xcf, 0x57, 0xe6, 0x39, 0x36, 0x65, 0xfd, 0x28, 0x4e, 0xf9, 0xfa, 0xfc,
-    0xd7, 0x9f, 0x69, 0xf1, 0x9f, 0xff, 0xbb, 0xac, 0xb6, 0x7d, 0x4b, 0xfe, 0x73, 0xd5, 0x69, 0x66, 0xf3, 0x9f, 0xbd, 0xe2,
-    0xbd, 0xbb, 0xfd, 0x5f, 0x73, 0x4d, 0xb0, 0x3e, 0xff, 0x91, 0xaa, 0x0c, 0xde, 0x27, 0xff, 0xb1, 0x20, 0xb9, 0xf2, 0x9f,
-    0x6d, 0x03, 0xdf, 0x90, 0xff, 0xea, 0xe7, 0x7c, 0x74, 0xc8, 0x7f, 0x6e, 0xc4, 0x2b, 0x4a, 0x73, 0x1a, 0xed, 0xdb, 0xff,
-    0x63, 0xdb, 0xf8, 0x5f, 0xff, 0xfc, 0x47, 0x49, 0xbf, 0xf0, 0xce, 0xfc, 0xd7, 0x57, 0xcb, 0xcd, 0x56, 0x0d, 0xbc, 0x3e,
-    0xd6, 0xd7, 0xa7, 0xfd, 0xaf, 0xbf, 0x1e, 0x5e, 0xd1, 0xfe, 0x1f, 0x0b, 0xee, 0x52, 0xac, 0xbf, 0xaa, 0xee, 0x9f, 0xff,
-    0xaa, 0xeb, 0xc2, 0xcc, 0x73, 0x93, 0x46, 0xef, 0xff, 0xc5, 0xe9, 0x59, 0x3c, 0x7a, 0xe7, 0x68, 0x3c, 0x4f, 0x31, 0xf8,
-    0xf4, 0xa2, 0xfe, 0xd7, 0xff, 0x95, 0xed, 0xff, 0x9a, 0x51, 0xef, 0xae, 0xa3, 0xe9, 0xd7, 0x9e, 0x2f, 0xde, 0x63, 0x8b,
-    0xf3, 0x4f, 0xdc, 0x8a, 0xed, 0x57, 0x56, 0x7d, 0x8e, 0xf1, 0xfc, 0x67, 0x5f, 0x93, 0xff, 0x8a, 0x8a, 0xd3, 0xf5, 0xed,
-    0xe1, 0xf7, 0xe6, 0xbc, 0xcc, 0xdc, 0x75, 0xef, 0xb1, 0xb5, 0xd5, 0xe7, 0xc5, 0x3b, 0xf2, 0x5f, 0xf7, 0xd9, 0x63, 0xc9,
-    0xb7, 0x4a, 0xa6, 0x96, 0x77, 0x2c, 0x9f, 0x0f, 0x23, 0xff, 0xcf, 0xcd, 0x7f, 0xdc, 0x70, 0xcf, 0xf0, 0x58, 0x3c, 0x1e,
-    0xdd, 0x61, 0x0f, 0xef, 0xcd, 0x3f, 0xfd, 0xce, 0x88, 0xee, 0xf9, 0x5f, 0x3f, 0x2f, 0xf4, 0xcb, 0xed, 0x81, 0x2a, 0xf9,
-    0x3c, 0xf1, 0x5a, 0x56, 0xfe, 0x73, 0xfd, 0x96, 0xd9, 0xf9, 0xff, 0x20, 0xff, 0xdf, 0xdd, 0xeb, 0xd0, 0x7f, 0x76, 0x03,
-    0xf2, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xfb, 0x67, 0xbb, 0x45, 0x6a, 0x7d, 0x5b, 0x0c, 0x56,
-    0x32, 0x88, 0x74, 0xa5, 0xf8, 0x6c, 0x7d, 0x8c, 0x18, 0x5c, 0xf7, 0x35, 0x5f, 0x37, 0xf8, 0xfa, 0xf3, 0x15, 0x66, 0xd6,
-    0x0f, 0xae, 0x3f, 0x8e, 0x75, 0x15, 0xd6, 0xeb, 0x8f, 0x52, 0xe6, 0xef, 0x47, 0x79, 0xed, 0xb5, 0xfe, 0x99, 0x99, 0xdf,
-    0xcf, 0x99, 0x95, 0xbe, 0xb5, 0x67, 0xd4, 0xb5, 0x63, 0x5b, 0xb7, 0xba, 0x33, 0x26, 0x92, 0x3e, 0x3e, 0x4f, 0xfb, 0xf7,
-    0xaa, 0x9f, 0x5d, 0x8f, 0x63, 0x2e, 0x4b, 0x51, 0xba, 0x06, 0x37, 0xf7, 0xd7, 0x9f, 0xb6, 0xaf, 0xaf, 0x57, 0x01, 0xd8,
-    0xdd, 0x5f, 0xc8, 0x3f, 0x35, 0x28, 0x6e, 0x9f, 0x8b, 0xbf, 0xae, 0xa2, 0x4e, 0x5d, 0xad, 0xe2, 0xbb, 0x8f, 0xe3, 0x71,
-    0xfa, 0x0c, 0x93, 0x68, 0xb8, 0xbe, 0xe5, 0xac, 0xff, 0x18, 0x2d, 0xf7, 0x75, 0x5c, 0xee, 0x23, 0xe6, 0xf3, 0x9f, 0x7f,
-    0x3e, 0x53, 0x14, 0x57, 0xe6, 0xcd, 0x57, 0xc7, 0xac, 0xde, 0xfa, 0x7c, 0xfb, 0x9f, 0xb9, 0x52, 0x88, 0xe5, 0x9f, 0xaa,
-    0xf6, 0x3b, 0x39, 0x4e, 0x6a, 0xb9, 0xae, 0x3e, 0x2b, 0x56, 0xbc, 0x12, 0x1b, 0xce, 0xad, 0xdc, 0xf5, 0xde, 0xb5, 0x33,
-    0x64, 0x26, 0xff, 0x7d, 0x8f, 0xcd, 0xd1, 0xe6, 0x95, 0xdd, 0xf9, 0x7f, 0xee, 0x2b, 0xef, 0xc9, 0x7f, 0x9f, 0xb3, 0xef,
-    0xb7, 0xcf, 0x33, 0xfb, 0xac, 0xc2, 0x0e, 0x47, 0xe0, 0xac, 0x4e, 0xec, 0x5b, 0xf3, 0x1f, 0x3f, 0x8e, 0x0c, 0xf6, 0xff,
-    0x4e, 0xfe, 0xb9, 0x5f, 0xf0, 0xb4, 0xfc, 0x57, 0xb6, 0xcb, 0x15, 0x6d, 0xf9, 0xde, 0x6b, 0x66, 0xed, 0xbf, 0xf6, 0xff,
-    0xdb, 0xf9, 0xbf, 0xff, 0x2a, 0x6c, 0x6f, 0x66, 0xfa, 0xed, 0xb3, 0x3e, 0xf9, 0x1f, 0x19, 0xf3, 0x92, 0xff, 0xb7, 0xe7,
-    0xff, 0x09, 0xdf, 0x4d, 0xb3, 0xf7, 0xff, 0xde, 0x31, 0xfe, 0x57, 0xf5, 0x8a, 0xf6, 0x7f, 0x6e, 0x8c, 0xfd, 0xee, 0x6d,
-    0xcb, 0x1f, 0xf3, 0xb7, 0x1c, 0x85, 0xd1, 0x3e, 0x80, 0xfe, 0xbf, 0xfc, 0xbf, 0x27, 0xff, 0x47, 0x7a, 0xf6, 0xc1, 0xb3,
-    0xae, 0x33, 0x46, 0x8e, 0xc7, 0x73, 0xf2, 0x5f, 0x79, 0xc7, 0xee, 0x29, 0xe3, 0x7f, 0x4f, 0xfb, 0x66, 0x78, 0x63, 0xfe,
-    0xef, 0xbd, 0xd7, 0xda, 0x63, 0xe6, 0xef, 0x33, 0xfb, 0x32, 0x4f, 0xce, 0xff, 0xb3, 0xfb, 0x64, 0xc7, 0x6d, 0x57, 0x85,
-    0x51, 0xb8, 0xa7, 0x79, 0x46, 0xfe, 0x63, 0x53, 0xfe, 0x47, 0xc6, 0x06, 0xde, 0x9d, 0xff, 0xf1, 0xd6, 0x2a, 0x6e, 0x1f,
-    0x63, 0x96, 0xff, 0xbb, 0xf3, 0xbf, 0x7f, 0xeb, 0x77, 0xf5, 0xc4, 0x62, 0x49, 0xd2, 0xc7, 0x8f, 0xc9, 0x13, 0xfb, 0xa4,
-    0x3b, 0xb7, 0x4d, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xef, 0xcc, 0x00, 0x1e, 0x7b, 0xb5,
-    0x43, 0x05, 0xfd, 0x23, 0x5d, 0x6d, 0xbd, 0xee, 0xf3, 0x1e, 0x89, 0xaa, 0xee, 0x99, 0x6d, 0xe8, 0x5c, 0x41, 0xdf, 0xac,
-    0xdb, 0xb7, 0x7e, 0x03, 0xf4, 0xae, 0xa0, 0x7f, 0x5e, 0xe5, 0x63, 0xfd, 0xe7, 0xad, 0x9c, 0x3f, 0xdf, 0xbb, 0x82, 0x7e,
-    0xbf, 0xb5, 0xab, 0xf4, 0xfb, 0x26, 0xd9, 0x59, 0x41, 0x7f, 0xbc, 0xbf, 0x71, 0x6c, 0xdc, 0xae, 0x6c, 0x35, 0x83, 0xae,
-    0x15, 0xf4, 0xbb, 0xaf, 0x05, 0xe3, 0xfe, 0xb5, 0x59, 0x63, 0xcf, 0xb4, 0xa8, 0xaa, 0xa0, 0xf1, 0xb4, 0x0a, 0xfa, 0x67,
-    0x19, 0x7b, 0x52, 0x9d, 0x6c, 0xf9, 0xb7, 0xfe, 0xf7, 0xbe, 0xfc, 0xf7, 0xad, 0x93, 0x91, 0xad, 0x52, 0xd3, 0xbb, 0x82,
-    0xa6, 0xfc, 0xcb, 0xbf, 0xfc, 0xaf, 0xaa, 0x91, 0x20, 0xff, 0x3c, 0x3d, 0xff, 0x3b, 0x2b, 0xe8, 0xa8, 0xa0, 0xb9, 0xbb,
-    0x22, 0xd0, 0x21, 0xff, 0xae, 0xff, 0x1f, 0xf1, 0x04, 0x3d, 0xf9, 0x5f, 0xf3, 0x8a, 0xfc, 0x7f, 0xfd, 0xde, 0x9f, 0x0a,
-    0xda, 0x2b, 0xf3, 0x1f, 0x4d, 0xc7, 0xff, 0xf6, 0xdf, 0xf1, 0xe1, 0x89, 0xf9, 0xd7, 0xff, 0xcf, 0xe7, 0xe2, 0xfe, 0x0a,
-    0x9a, 0xf9, 0x34, 0xcb, 0xbf, 0xfe, 0x7f, 0xc5, 0xfc, 0x9f, 0x9a, 0xb6, 0x47, 0x05, 0xcd, 0xb9, 0x6d, 0x93, 0x7f, 0xd0,
-    0x2b, 0xd4, 0xff, 0x07, 0xbd, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x9d, 0x4b, 0x96, 0xeb, 0x36, 0x0c, 0x44, 0xb9, 0xff, 0x4d, 0x57, 0x06, 0x39, 0x19, 0x24, 0x79, 0x96, 0x84, 0x2f, 0x41,
+    0xe9, 0xf6, 0x9d, 0x75, 0xdb, 0x6e, 0x4a, 0x25, 0x7e, 0x4c, 0x14, 0x40, 0x2d, 0x00, 0x00, 0x00, 0x80, 0xff, 0xa0, 0x3f,
+    0xfe, 0x46, 0x3f, 0x5f, 0xa9, 0xc7, 0x9f, 0xf3, 0xf7, 0x6f, 0xf5, 0xf3, 0xbf, 0xfc, 0xf3, 0xf3, 0xe4, 0x93, 0x9e, 0xbf,
+    0x4a, 0xa6, 0xd6, 0xc5, 0x5a, 0xe5, 0xfb, 0x1c, 0xeb, 0xab, 0xaf, 0xdb, 0xa3, 0x01, 0xfa, 0xdf, 0x5f, 0xad, 0xe5, 0x7e,
+    0xca, 0xad, 0x9e, 0xfd, 0xe9, 0xac, 0xec, 0x43, 0xd6, 0x36, 0xfa, 0xee, 0xc9, 0x0c, 0xfd, 0xad, 0xff, 0xc3, 0xd6, 0x6e,
+    0x85, 0x5a, 0xee, 0xeb, 0xd3, 0xb1, 0xd6, 0x9d, 0xac, 0xff, 0xfa, 0x39, 0x92, 0x7b, 0xef, 0x63, 0x97, 0xfe, 0xf1, 0xab,
+    0x44, 0xff, 0xbb, 0x57, 0xda, 0xb5, 0xbc, 0x56, 0x4f, 0x87, 0xeb, 0x6f, 0x5d, 0xf7, 0xbc, 0x53, 0xff, 0x5f, 0x23, 0xc3,
+    0xf5, 0x9c, 0xfc, 0xfb, 0x3d, 0x9d, 0xb3, 0x77, 0x8d, 0xfe, 0x77, 0xf3, 0xe8, 0xf3, 0x7b, 0x61, 0x5d, 0x19, 0xf6, 0xeb,
+    0x1f, 0x59, 0x91, 0x9d, 0xad, 0xbf, 0x6e, 0xee, 0x95, 0x02, 0xeb, 0xdb, 0xe8, 0x98, 0x81, 0xfe, 0xbb, 0xf5, 0x5f, 0x07,
+    0xe8, 0xbf, 0x12, 0xd6, 0x7f, 0x9e, 0x2b, 0x7b, 0x83, 0xfe, 0xbe, 0xab, 0x3b, 0x53, 0x7f, 0xef, 0xf7, 0xff, 0xdf, 0x7b,
+    0x1e, 0xe8, 0xff, 0xa6, 0xf1, 0x5f, 0x37, 0x63, 0x47, 0x64, 0xfd, 0x32, 0x53, 0x7f, 0x3d, 0x1a, 0x2d, 0xe3, 0xbb, 0x85,
+    0xd6, 0x31, 0xf7, 0x0b, 0x7b, 0xd4, 0xd3, 0xf5, 0x87, 0x8e, 0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x3b, 0xe8, 0x1e, 0x8f, 0x79, 0xee, 0x5f, 0x6c, 0xde, 0x39, 0xbf, 0x9f, 0xfe, 0x69, 0x0b, 0xd5, 0x7e,
+    0x57, 0xaa, 0x75, 0xa9, 0x89, 0x20, 0x5b, 0xa2, 0xf7, 0x51, 0x5f, 0xa2, 0xca, 0x1d, 0xb8, 0x2a, 0xbb, 0x42, 0x8f, 0x1f,
+    0x40, 0x4d, 0x31, 0xff, 0x33, 0xf4, 0x97, 0x23, 0x9e, 0x9e, 0x91, 0x4d, 0x82, 0xfe, 0x6f, 0xeb, 0xff, 0x77, 0x6d, 0xff,
+    0xf7, 0x13, 0x85, 0xfe, 0x53, 0xf4, 0x5f, 0xe6, 0x79, 0x4d, 0x21, 0xe7, 0xc0, 0x77, 0xf4, 0xb7, 0xaf, 0x40, 0x96, 0x33,
+    0xe3, 0x2f, 0xc3, 0x97, 0x5e, 0x9f, 0x9b, 0x73, 0xa7, 0xbf, 0x67, 0x2d, 0xe7, 0xd1, 0xff, 0x4e, 0x17, 0x9b, 0xbb, 0x3c,
+    0x37, 0x57, 0xd1, 0x9f, 0xbd, 0x33, 0xd7, 0x9d, 0xfd, 0x9e, 0xf1, 0xff, 0x2c, 0xfd, 0xfb, 0x3d, 0x5c, 0x7a, 0xe0, 0x63,
+    0x45, 0xff, 0x7d, 0xfd, 0x5f, 0x1b, 0x47, 0x05, 0xf4, 0x47, 0xff, 0x2f, 0xe9, 0xef, 0x5d, 0xb1, 0x29, 0xf5, 0xd3, 0x26,
+    0xce, 0xff, 0xd6, 0xfa, 0x1a, 0x7d, 0xfb, 0x7f, 0xcb, 0xb9, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5f, 0xf0, 0xff, 0xdb, 0x5d, 0xf8, 0x59, 0xb1, 0x4f, 0x8d, 0xc8, 0x3e, 0xa8, 0xc8, 0x65, 0xf0,
+    0xde, 0xa1, 0xac, 0x4f, 0xb4, 0xd7, 0x50, 0xcb, 0xa9, 0xc4, 0x6f, 0xff, 0x94, 0x8a, 0x38, 0x7b, 0x75, 0xd4, 0xde, 0xe3,
+    0x7f, 0xe8, 0xd4, 0xdf, 0xe3, 0xb5, 0x40, 0x7f, 0xf4, 0x47, 0x7f, 0xf4, 0x47, 0xff, 0x59, 0xfa, 0xdf, 0xd7, 0x8b, 0x57,
+    0xc8, 0x45, 0xe7, 0xf3, 0x19, 0x65, 0x7a, 0xdf, 0x3b, 0xd6, 0x3d, 0x11, 0x9f, 0xbd, 0x36, 0xeb, 0x7f, 0x97, 0xfd, 0x16,
+    0xf3, 0x50, 0xee, 0xee, 0xff, 0x53, 0xf2, 0xec, 0xe4, 0xec, 0xe9, 0x59, 0xad, 0x96, 0xb9, 0xff, 0xc7, 0xfb, 0x3e, 0xfa,
+    0xcf, 0xd7, 0x3f, 0xe2, 0xc2, 0x46, 0xff, 0x39, 0xfa, 0xdf, 0x29, 0x8c, 0xfe, 0x6f, 0xd7, 0xff, 0xf7, 0x39, 0x74, 0xa7,
+    0xe8, 0x9f, 0xed, 0x8a, 0xf7, 0xea, 0x9f, 0xe9, 0x8c, 0xf7, 0xee, 0xa2, 0xc9, 0x59, 0x8f, 0x40, 0xe6, 0x7d, 0x50, 0x8f,
+    0xfe, 0xe4, 0x01, 0x00, 0xcc, 0xcb, 0x3c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xda,
+    0x15, 0xb7, 0x39, 0xdf, 0xf2, 0xea, 0x81, 0xad, 0xe2, 0xc8, 0x9e, 0x2f, 0x8e, 0x19, 0x3f, 0xbd, 0x60, 0x99, 0x22, 0xaa,
+    0x9e, 0x56, 0x67, 0xd6, 0x57, 0x93, 0x39, 0x52, 0x62, 0xf5, 0x28, 0xd9, 0xe3, 0x31, 0x39, 0xd5, 0xf0, 0x32, 0xdd, 0x0a,
+    0x5e, 0x97, 0x68, 0xfe, 0x3d, 0x90, 0xdb, 0xc7, 0xb0, 0x92, 0x1c, 0x04, 0x15, 0xb5, 0xbd, 0xd1, 0x1f, 0xfd, 0xb3, 0x4e,
+    0x8f, 0xa9, 0x70, 0x03, 0xe7, 0xb8, 0x51, 0x14, 0x74, 0xdf, 0xf4, 0xe9, 0xbf, 0xa7, 0x82, 0x77, 0x9f, 0xe7, 0xcb, 0xfa,
+    0x34, 0x29, 0x51, 0x41, 0xf4, 0xdf, 0xaf, 0xbf, 0xf7, 0x6e, 0x7c, 0x47, 0xff, 0x0c, 0x6f, 0xf9, 0x9b, 0xf4, 0x57, 0x42,
+    0xe6, 0x73, 0x2c, 0x6f, 0xe6, 0x0b, 0xfa, 0x57, 0xcc, 0xbf, 0x39, 0xab, 0x89, 0xef, 0xf5, 0xff, 0x0c, 0x77, 0x71, 0xfd,
+    0xc8, 0x50, 0xf3, 0x9e, 0x89, 0xfa, 0xf7, 0xbb, 0x22, 0xd1, 0xbf, 0x7e, 0xfc, 0x9f, 0xac, 0xbf, 0x67, 0x77, 0xa8, 0x7b,
+    0x66, 0xc8, 0x7e, 0x4f, 0x65, 0xfd, 0x14, 0xf4, 0xc7, 0x81, 0x7e, 0xc2, 0xfe, 0x7f, 0xe6, 0xeb, 0x81, 0x9e, 0x03, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x22, 0x6b, 0x99, 0xe7, 0x59, 0x5b, 0x1d, 0x17, 0x9d, 0x75,
+    0x14, 0x7d, 0x15, 0xc0, 0xf4, 0xd8, 0xdf, 0x13, 0xf7, 0x39, 0x5f, 0xe7, 0x56, 0xc4, 0x22, 0x9f, 0x3d, 0x35, 0x93, 0xbd,
+    0xd5, 0xf5, 0xf6, 0xea, 0x6f, 0x8d, 0x82, 0x3e, 0xff, 0x9d, 0x2d, 0x32, 0x7d, 0x7d, 0x5e, 0x7d, 0x2c, 0xce, 0xf4, 0x15,
+    0xfd, 0xb3, 0xeb, 0x68, 0x67, 0x3f, 0x13, 0x7e, 0x4f, 0xdc, 0x19, 0xfa, 0x5f, 0xcf, 0x0c, 0x1d, 0xfa, 0xfb, 0x6b, 0x76,
+    0xae, 0x26, 0xad, 0xb3, 0x32, 0x5f, 0xe6, 0xe9, 0xef, 0x9d, 0xf1, 0x76, 0xf7, 0xff, 0x9a, 0x39, 0xa1, 0x5e, 0x7f, 0x25,
+    0xd6, 0x7f, 0x7f, 0x87, 0xfe, 0xd9, 0x57, 0x33, 0x41, 0x7f, 0xb5, 0xd4, 0xff, 0x9d, 0xa5, 0x7f, 0x7e, 0x1d, 0x6d, 0x6f,
+    0x6e, 0xd9, 0xf3, 0xb5, 0xde, 0xec, 0xfe, 0x5f, 0x71, 0xfe, 0x59, 0xfc, 0xfb, 0xdf, 0x75, 0xed, 0xe5, 0xec, 0x3a, 0xca,
+    0x9e, 0xef, 0x7f, 0xef, 0x98, 0xff, 0x57, 0x6a, 0x66, 0xed, 0xc9, 0x9e, 0x38, 0x95, 0xe4, 0xcd, 0xc7, 0xf5, 0x57, 0xe2,
+    0x99, 0x8b, 0xe8, 0xbf, 0x92, 0x2a, 0x27, 0x74, 0xe9, 0xef, 0xab, 0xad, 0x71, 0x4e, 0xfd, 0xf7, 0x53, 0xeb, 0xd4, 0xef,
+    0xd7, 0x1f, 0xde, 0xa7, 0x3f, 0x9c, 0x14, 0x37, 0x89, 0xee, 0xff, 0x03, 0xf9, 0x1d, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x7b, 0x56, 0x79, 0xf5, 0xe6, 0x63, 0xef, 0xcb, 0xf1, 0x6d, 0xca, 0x7c, 0xf2, 0x80,
+    0xdd, 0xbb, 0x2c, 0xd7, 0x5e, 0xa0, 0xaf, 0xde, 0x9e, 0x4c, 0xb1, 0xd3, 0xff, 0xff, 0x44, 0xfc, 0x5f, 0x2b, 0x50, 0xab,
+    0xdf, 0xea, 0x7d, 0x52, 0x92, 0x47, 0x5c, 0x2d, 0x31, 0x70, 0x5f, 0xed, 0x54, 0xa5, 0xc5, 0xc1, 0xbd, 0x8e, 0xf6, 0xe7,
+    0xfa, 0xff, 0xd3, 0x2a, 0xab, 0xfe, 0xf7, 0xef, 0xb3, 0xbb, 0xba, 0x7c, 0x8e, 0xbe, 0xd8, 0x3d, 0xd8, 0x1f, 0x3b, 0x88,
+    0xb8, 0xf0, 0x32, 0xf4, 0xf7, 0xf7, 0x63, 0x15, 0x3b, 0x91, 0xba, 0xf4, 0x57, 0x63, 0xde, 0x9c, 0x8a, 0xfd, 0xb9, 0xb6,
+    0x59, 0x24, 0xa2, 0xbf, 0xca, 0x9d, 0x68, 0xbb, 0xf5, 0xaf, 0xf0, 0x4d, 0xef, 0xd0, 0xff, 0x7a, 0xdd, 0xe1, 0x19, 0xc7,
+    0xb3, 0xfb, 0xff, 0x72, 0xaf, 0xff, 0xe2, 0xfa, 0xab, 0xd5, 0x37, 0x9f, 0x9d, 0xb7, 0x7a, 0xbf, 0xaa, 0x78, 0xb6, 0x4e,
+    0xf6, 0x7a, 0xd8, 0x55, 0x9a, 0x9f, 0xfc, 0x64, 0x15, 0x96, 0x93, 0x03, 0xfb, 0xcd, 0xfe, 0xaf, 0x60, 0xdd, 0xe5, 0xea,
+    0xd5, 0xf7, 0x93, 0x93, 0xdf, 0xe2, 0x73, 0xe0, 0x6e, 0xfd, 0xab, 0xd7, 0x7f, 0xe7, 0x78, 0x85, 0x3d, 0xfe, 0x74, 0x15,
+    0x39, 0x6f, 0xdf, 0xb3, 0xfe, 0x3b, 0xd5, 0xb7, 0xd4, 0xa9, 0xff, 0x59, 0xa3, 0xfc, 0x84, 0xef, 0xb3, 0x53, 0x9e, 0x90,
+    0xac, 0x39, 0xf0, 0x4c, 0xfd, 0x4f, 0x1d, 0xdb, 0xe7, 0x7b, 0x37, 0xe9, 0xe5, 0xe8, 0x8f, 0xfe, 0x3c, 0x2f, 0x68, 0x09,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0xf7, 0x31, 0xe5, 0x70, 0x3f, 0x2c, 0xa7, 0x5f, 0x5e, 0xa1,
+    0xc8, 0xfb, 0x73, 0xe7, 0xfe, 0x13, 0x67, 0xc8, 0x3c, 0x47, 0x7f, 0x5e, 0x25, 0xfa, 0xe7, 0x71, 0x0d, 0xb5, 0x39, 0xdc,
+    0x97, 0x33, 0x87, 0x20, 0x12, 0xcd, 0x95, 0xd1, 0x69, 0x3f, 0xd7, 0xd1, 0x2f, 0x57, 0xbd, 0x5f, 0x8d, 0xf1, 0x7e, 0xd4,
+    0xc5, 0xa2, 0xf3, 0x6a, 0x7a, 0xef, 0x76, 0xf4, 0xaf, 0xdb, 0xb3, 0x1e, 0xd4, 0x9a, 0xc3, 0xd2, 0x51, 0x19, 0x78, 0x25,
+    0x9c, 0x83, 0xb2, 0xca, 0xfd, 0x74, 0x3d, 0x8e, 0xae, 0xbb, 0x99, 0x41, 0x05, 0x31, 0x45, 0x6d, 0xff, 0x4b, 0xb7, 0xfe,
+    0xe7, 0xfe, 0x05, 0xfd, 0x9f, 0xeb, 0xaf, 0x9f, 0x2b, 0xc3, 0x13, 0x7d, 0x1b, 0xba, 0x58, 0xe9, 0xa2, 0xff, 0xbb, 0xdd,
+    0xf9, 0x6f, 0xd1, 0xdf, 0xb2, 0xe6, 0x41, 0xff, 0x09, 0xfa, 0xdf, 0xe5, 0x97, 0xdb, 0xfe, 0x42, 0xff, 0x8f, 0xe8, 0xaf,
+    0xa2, 0xff, 0xc3, 0xf8, 0xff, 0x75, 0xfd, 0x33, 0xcf, 0x97, 0x9b, 0xb5, 0xfe, 0x3b, 0xed, 0xc9, 0xd8, 0xa1, 0xbf, 0x2f,
+    0xf7, 0x69, 0xba, 0xfe, 0x6f, 0xf3, 0x6d, 0xe7, 0xe6, 0xa1, 0xfc, 0xf9, 0xd9, 0xea, 0x59, 0xff, 0x09, 0xfd, 0x5d, 0x39,
+    0xb5, 0x99, 0xd7, 0x13, 0x7f, 0xe6, 0x72, 0x4f, 0x9e, 0x51, 0x89, 0xd2, 0x2b, 0x50, 0x35, 0x62, 0xd7, 0x9d, 0xe8, 0x51,
+    0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x57, 0xcb, 0xc4, 0xe6, 0xb8, 0x56, 0xa1, 0xff, 0xa3,
+    0xd7, 0x77, 0x1f, 0xa9, 0xa4, 0x7f, 0x52, 0xfe, 0x44, 0x9e, 0x63, 0xdf, 0x1b, 0x33, 0x3c, 0xcd, 0x77, 0xff, 0x3c, 0xca,
+    0x32, 0x3f, 0x7f, 0x22, 0x2f, 0x52, 0xb2, 0x5c, 0x9e, 0xa1, 0x2e, 0xef, 0xbd, 0x0a, 0x22, 0x25, 0x2a, 0xbd, 0xd3, 0x3b,
+    0xf3, 0x27, 0xba, 0x1d, 0xcc, 0x6b, 0x7b, 0xdc, 0xcd, 0x76, 0x96, 0xc5, 0xbf, 0x3f, 0x4d, 0xdb, 0xf3, 0x27, 0x94, 0xdc,
+    0xff, 0xf7, 0xeb, 0x3f, 0xc7, 0x89, 0xe6, 0xa9, 0xa4, 0xb9, 0xbf, 0x42, 0xf4, 0x29, 0xfa, 0x67, 0xf6, 0xcb, 0x8c, 0xbe,
+    0x1c, 0xed, 0x75, 0xe8, 0xbf, 0xb3, 0xc2, 0xf9, 0x94, 0x4a, 0xda, 0x7d, 0xfa, 0xc7, 0xfd, 0x53, 0xa7, 0xf9, 0xe1, 0xe6,
+    0x9d, 0xa4, 0xb1, 0xff, 0xe9, 0x5d, 0x03, 0xf4, 0x5f, 0x01, 0xff, 0xff, 0x1b, 0xeb, 0xa5, 0x9f, 0xe2, 0x9f, 0xcd, 0xf4,
+    0x0f, 0x6a, 0xe8, 0x6c, 0x98, 0x3b, 0xcf, 0x58, 0xbc, 0xd9, 0xf3, 0xfd, 0xb3, 0xbb, 0xf5, 0xdf, 0x3b, 0x82, 0xce, 0xa9,
+    0xac, 0xb2, 0xcb, 0x3f, 0x5b, 0xaf, 0x3f, 0x9c, 0xba, 0xf7, 0xaf, 0xb4, 0x9a, 0x23, 0xf0, 0x96, 0xfa, 0x4f, 0x13, 0xea,
+    0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xa6, 0x5f, 0x56, 0xae, 0xb8, 0xcf, 0x54, 0x77,
+    0xbf, 0xa7, 0x0d, 0x3d, 0xde, 0x7d, 0x5f, 0x26, 0x45, 0xe6, 0xee, 0xbb, 0x8c, 0xd1, 0xc2, 0x6b, 0xe7, 0xc7, 0x4c, 0x77,
+    0xbf, 0x2f, 0xf6, 0xd1, 0xe3, 0xdd, 0xef, 0xb8, 0xce, 0x8e, 0x9c, 0xa0, 0xb9, 0x55, 0xf5, 0xef, 0x3c, 0x55, 0x1d, 0x35,
+    0x9a, 0x3c, 0x99, 0x14, 0xab, 0xe9, 0xa4, 0x68, 0x7b, 0x55, 0xc5, 0xd3, 0xaa, 0xea, 0xdf, 0xdd, 0xe3, 0xc9, 0x15, 0xdf,
+    0x67, 0xe9, 0x7f, 0xaa, 0x87, 0xef, 0x7a, 0xc5, 0x80, 0xfe, 0x6f, 0xd7, 0x7f, 0xa1, 0x3f, 0xfa, 0xff, 0x74, 0x6e, 0xce,
+    0x75, 0x9e, 0x2f, 0xf4, 0xff, 0xac, 0xfe, 0x79, 0x6b, 0x49, 0xf4, 0xb7, 0x7f, 0x67, 0x98, 0xda, 0xea, 0x7c, 0x7f, 0xf3,
+    0x5b, 0xf4, 0xdf, 0x5d, 0x55, 0xb9, 0x37, 0xf3, 0x40, 0xe5, 0xdf, 0xa8, 0xb3, 0xfa, 0xcb, 0x57, 0xaa, 0x2a, 0x47, 0xda,
+    0xb6, 0x53, 0x7f, 0x98, 0x5b, 0x81, 0x67, 0x0d, 0xce, 0x6f, 0x81, 0xb9, 0x55, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf9, 0xf3, 0x9f, 0xfd, 0x00, 0xf2, 0x0f, 0x7c, 0x2e, 0xff, 0xff, 0x00 };
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f,
+    0xea, 0x4d, 0xa3, 0x3f, 0xfa, 0x7f, 0x5c, 0xff, 0xbf, 0x00 };
 
 // Font glyphs rectangles data (on atlas)
-static const Rectangle terminalFontRecs[189] = {
+static const Rectangle terminalFontRecs[175] = {
     { 4, 4, 4 , 16 },
     { 16, 4, 1 , 11 },
     { 25, 4, 3 , 3 },
@@ -157,179 +151,165 @@
     { 210, 4, 5 , 11 },
     { 223, 4, 5 , 11 },
     { 236, 4, 5 , 11 },
-    { 249, 4, 5 , 11 },
-    { 262, 4, 5 , 11 },
-    { 275, 4, 5 , 11 },
-    { 288, 4, 5 , 11 },
-    { 301, 4, 5 , 11 },
-    { 314, 4, 1 , 8 },
-    { 323, 4, 1 , 10 },
-    { 332, 4, 4 , 5 },
-    { 344, 4, 5 , 3 },
-    { 357, 4, 4 , 5 },
-    { 369, 4, 5 , 11 },
-    { 382, 4, 11 , 11 },
-    { 401, 4, 5 , 11 },
-    { 414, 4, 5 , 11 },
-    { 427, 4, 5 , 11 },
-    { 440, 4, 5 , 11 },
-    { 453, 4, 5 , 11 },
-    { 466, 4, 5 , 11 },
-    { 479, 4, 5 , 11 },
-    { 492, 4, 5 , 11 },
-    { 4, 28, 1 , 11 },
-    { 13, 28, 5 , 11 },
-    { 26, 28, 5 , 11 },
-    { 39, 28, 5 , 11 },
-    { 52, 28, 7 , 11 },
-    { 67, 28, 5 , 11 },
-    { 80, 28, 5 , 11 },
-    { 93, 28, 5 , 11 },
-    { 106, 28, 5 , 13 },
-    { 119, 28, 5 , 11 },
-    { 132, 28, 5 , 11 },
-    { 145, 28, 5 , 11 },
-    { 158, 28, 5 , 11 },
-    { 171, 28, 5 , 11 },
-    { 184, 28, 7 , 11 },
-    { 199, 28, 5 , 11 },
-    { 212, 28, 5 , 11 },
-    { 225, 28, 5 , 11 },
-    { 238, 28, 2 , 13 },
-    { 248, 28, 6 , 12 },
-    { 262, 28, 2 , 13 },
-    { 272, 28, 5 , 4 },
-    { 285, 28, 5 , 1 },
-    { 298, 28, 2 , 2 },
-    { 308, 28, 5 , 8 },
-    { 321, 28, 5 , 11 },
-    { 334, 28, 5 , 8 },
-    { 347, 28, 5 , 11 },
-    { 360, 28, 5 , 8 },
-    { 373, 28, 4 , 11 },
-    { 385, 28, 5 , 10 },
-    { 398, 28, 5 , 11 },
-    { 411, 28, 1 , 11 },
-    { 420, 28, 1 , 13 },
-    { 429, 28, 5 , 11 },
-    { 442, 28, 1 , 11 },
-    { 451, 28, 7 , 8 },
-    { 466, 28, 5 , 8 },
-    { 479, 28, 5 , 8 },
-    { 492, 28, 5 , 10 },
-    { 4, 52, 5 , 10 },
-    { 17, 52, 4 , 8 },
-    { 29, 52, 5 , 8 },
-    { 42, 52, 3 , 11 },
-    { 53, 52, 5 , 8 },
-    { 66, 52, 5 , 8 },
-    { 79, 52, 7 , 8 },
-    { 94, 52, 5 , 8 },
-    { 107, 52, 5 , 10 },
-    { 120, 52, 5 , 8 },
-    { 133, 52, 3 , 13 },
-    { 144, 52, 1 , 15 },
-    { 153, 52, 3 , 13 },
-    { 164, 52, 5 , 3 },
-    { 177, 52, 1 , 11 },
-    { 186, 52, 5 , 11 },
-    { 199, 52, 5 , 10 },
-    { 212, 52, 5 , 10 },
-    { 225, 52, 5 , 10 },
-    { 238, 52, 0 , 0 },
-    { 246, 52, 0 , 0 },
-    { 254, 52, 0 , 0 },
-    { 262, 52, 7 , 8 },
-    { 277, 52, 0 , 0 },
-    { 285, 52, 0 , 0 },
-    { 293, 52, 5 , 3 },
-    { 306, 52, 7 , 8 },
-    { 321, 52, 5 , 1 },
-    { 334, 52, 3 , 3 },
-    { 345, 52, 5 , 7 },
-    { 358, 52, 0 , 0 },
-    { 366, 52, 0 , 0 },
-    { 374, 52, 0 , 0 },
-    { 382, 52, 5 , 10 },
-    { 395, 52, 7 , 11 },
-    { 410, 52, 1 , 1 },
-    { 419, 52, 0 , 0 },
-    { 427, 52, 0 , 0 },
-    { 435, 52, 0 , 0 },
-    { 443, 52, 0 , 0 },
-    { 451, 52, 0 , 0 },
-    { 459, 52, 0 , 0 },
-    { 467, 52, 5 , 13 },
-    { 480, 52, 5 , 11 },
-    { 493, 52, 5 , 14 },
-    { 4, 76, 5 , 14 },
-    { 17, 76, 5 , 14 },
-    { 30, 76, 5 , 14 },
-    { 43, 76, 5 , 13 },
-    { 56, 76, 5 , 13 },
-    { 69, 76, 9 , 11 },
-    { 86, 76, 5 , 13 },
-    { 99, 76, 5 , 14 },
-    { 112, 76, 5 , 14 },
-    { 125, 76, 5 , 14 },
-    { 138, 76, 5 , 13 },
-    { 151, 76, 2 , 14 },
-    { 161, 76, 2 , 14 },
-    { 171, 76, 3 , 14 },
-    { 182, 76, 3 , 13 },
-    { 193, 76, 5 , 11 },
-    { 206, 76, 5 , 14 },
-    { 219, 76, 5 , 14 },
-    { 232, 76, 5 , 14 },
-    { 245, 76, 5 , 14 },
-    { 258, 76, 5 , 14 },
-    { 271, 76, 5 , 13 },
-    { 284, 76, 5 , 5 },
-    { 297, 76, 5 , 13 },
-    { 310, 76, 5 , 14 },
-    { 323, 76, 5 , 14 },
-    { 336, 76, 5 , 14 },
-    { 349, 76, 5 , 13 },
-    { 362, 76, 5 , 14 },
-    { 375, 76, 5 , 11 },
-    { 388, 76, 5 , 11 },
-    { 401, 76, 5 , 11 },
-    { 414, 76, 5 , 11 },
-    { 427, 76, 5 , 11 },
-    { 440, 76, 5 , 11 },
-    { 453, 76, 5 , 10 },
-    { 466, 76, 5 , 10 },
-    { 479, 76, 9 , 8 },
-    { 496, 76, 5 , 10 },
-    { 4, 100, 5 , 11 },
-    { 17, 100, 5 , 11 },
-    { 30, 100, 5 , 11 },
-    { 43, 100, 5 , 10 },
-    { 56, 100, 2 , 11 },
-    { 66, 100, 2 , 11 },
-    { 76, 100, 3 , 11 },
-    { 87, 100, 3 , 10 },
-    { 98, 100, 5 , 11 },
-    { 111, 100, 5 , 11 },
-    { 124, 100, 5 , 11 },
-    { 137, 100, 5 , 11 },
-    { 150, 100, 5 , 11 },
-    { 163, 100, 5 , 11 },
-    { 176, 100, 5 , 10 },
-    { 189, 100, 5 , 5 },
-    { 202, 100, 5 , 10 },
-    { 215, 100, 5 , 11 },
-    { 228, 100, 5 , 11 },
-    { 241, 100, 5 , 11 },
-    { 254, 100, 5 , 10 },
-    { 267, 100, 5 , 13 },
-    { 280, 100, 4 , 8 },
-    { 292, 100, 5 , 12 },
+    { 4, 28, 5 , 11 },
+    { 17, 28, 5 , 11 },
+    { 30, 28, 5 , 11 },
+    { 43, 28, 5 , 11 },
+    { 56, 28, 5 , 11 },
+    { 69, 28, 1 , 8 },
+    { 78, 28, 1 , 10 },
+    { 87, 28, 4 , 5 },
+    { 99, 28, 5 , 3 },
+    { 112, 28, 4 , 5 },
+    { 124, 28, 5 , 11 },
+    { 137, 28, 11 , 11 },
+    { 156, 28, 5 , 11 },
+    { 169, 28, 5 , 11 },
+    { 182, 28, 5 , 11 },
+    { 195, 28, 5 , 11 },
+    { 208, 28, 5 , 11 },
+    { 221, 28, 5 , 11 },
+    { 234, 28, 5 , 11 },
+    { 4, 52, 5 , 11 },
+    { 17, 52, 1 , 11 },
+    { 26, 52, 5 , 11 },
+    { 39, 52, 5 , 11 },
+    { 52, 52, 5 , 11 },
+    { 65, 52, 7 , 11 },
+    { 80, 52, 5 , 11 },
+    { 93, 52, 5 , 11 },
+    { 106, 52, 5 , 11 },
+    { 119, 52, 5 , 13 },
+    { 132, 52, 5 , 11 },
+    { 145, 52, 5 , 11 },
+    { 158, 52, 5 , 11 },
+    { 171, 52, 5 , 11 },
+    { 184, 52, 5 , 11 },
+    { 197, 52, 7 , 11 },
+    { 212, 52, 5 , 11 },
+    { 225, 52, 5 , 11 },
+    { 238, 52, 5 , 11 },
+    { 4, 76, 2 , 13 },
+    { 14, 76, 6 , 12 },
+    { 28, 76, 2 , 13 },
+    { 38, 76, 5 , 4 },
+    { 51, 76, 5 , 1 },
+    { 64, 76, 2 , 2 },
+    { 74, 76, 5 , 8 },
+    { 87, 76, 5 , 11 },
+    { 100, 76, 5 , 8 },
+    { 113, 76, 5 , 11 },
+    { 126, 76, 5 , 8 },
+    { 139, 76, 4 , 11 },
+    { 151, 76, 5 , 10 },
+    { 164, 76, 5 , 11 },
+    { 177, 76, 1 , 11 },
+    { 186, 76, 1 , 13 },
+    { 195, 76, 5 , 11 },
+    { 208, 76, 1 , 11 },
+    { 217, 76, 7 , 8 },
+    { 232, 76, 5 , 8 },
+    { 4, 100, 5 , 8 },
+    { 17, 100, 5 , 10 },
+    { 30, 100, 5 , 10 },
+    { 43, 100, 4 , 8 },
+    { 55, 100, 5 , 8 },
+    { 68, 100, 3 , 11 },
+    { 79, 100, 5 , 8 },
+    { 92, 100, 5 , 8 },
+    { 105, 100, 7 , 8 },
+    { 120, 100, 5 , 8 },
+    { 133, 100, 5 , 10 },
+    { 146, 100, 5 , 8 },
+    { 159, 100, 3 , 13 },
+    { 170, 100, 1 , 15 },
+    { 179, 100, 3 , 13 },
+    { 190, 100, 5 , 3 },
+    { 203, 100, 1 , 11 },
+    { 212, 100, 5 , 11 },
+    { 225, 100, 5 , 10 },
+    { 238, 100, 5 , 10 },
+    { 4, 124, 5 , 10 },
+    { 17, 124, 7 , 8 },
+    { 32, 124, 5 , 3 },
+    { 45, 124, 7 , 8 },
+    { 60, 124, 5 , 1 },
+    { 73, 124, 3 , 3 },
+    { 84, 124, 5 , 7 },
+    { 97, 124, 5 , 10 },
+    { 110, 124, 7 , 11 },
+    { 125, 124, 1 , 1 },
+    { 134, 124, 5 , 13 },
+    { 147, 124, 5 , 11 },
+    { 160, 124, 5 , 14 },
+    { 173, 124, 5 , 14 },
+    { 186, 124, 5 , 14 },
+    { 199, 124, 5 , 14 },
+    { 212, 124, 5 , 13 },
+    { 225, 124, 5 , 13 },
+    { 238, 124, 9 , 11 },
+    { 4, 148, 5 , 13 },
+    { 17, 148, 5 , 14 },
+    { 30, 148, 5 , 14 },
+    { 43, 148, 5 , 14 },
+    { 56, 148, 5 , 13 },
+    { 69, 148, 2 , 14 },
+    { 79, 148, 2 , 14 },
+    { 89, 148, 3 , 14 },
+    { 100, 148, 3 , 13 },
+    { 111, 148, 5 , 11 },
+    { 124, 148, 5 , 14 },
+    { 137, 148, 5 , 14 },
+    { 150, 148, 5 , 14 },
+    { 163, 148, 5 , 14 },
+    { 176, 148, 5 , 14 },
+    { 189, 148, 5 , 13 },
+    { 202, 148, 5 , 5 },
+    { 215, 148, 5 , 13 },
+    { 228, 148, 5 , 14 },
+    { 241, 148, 5 , 14 },
+    { 4, 172, 5 , 14 },
+    { 17, 172, 5 , 13 },
+    { 30, 172, 5 , 14 },
+    { 43, 172, 5 , 11 },
+    { 56, 172, 5 , 11 },
+    { 69, 172, 5 , 11 },
+    { 82, 172, 5 , 11 },
+    { 95, 172, 5 , 11 },
+    { 108, 172, 5 , 11 },
+    { 121, 172, 5 , 10 },
+    { 134, 172, 5 , 10 },
+    { 147, 172, 9 , 8 },
+    { 164, 172, 5 , 10 },
+    { 177, 172, 5 , 11 },
+    { 190, 172, 5 , 11 },
+    { 203, 172, 5 , 11 },
+    { 216, 172, 5 , 10 },
+    { 229, 172, 2 , 11 },
+    { 239, 172, 2 , 11 },
+    { 4, 196, 3 , 11 },
+    { 15, 196, 3 , 10 },
+    { 26, 196, 5 , 11 },
+    { 39, 196, 5 , 11 },
+    { 52, 196, 5 , 11 },
+    { 65, 196, 5 , 11 },
+    { 78, 196, 5 , 11 },
+    { 91, 196, 5 , 11 },
+    { 104, 196, 5 , 10 },
+    { 117, 196, 5 , 5 },
+    { 130, 196, 5 , 10 },
+    { 143, 196, 5 , 11 },
+    { 156, 196, 5 , 11 },
+    { 169, 196, 5 , 11 },
+    { 182, 196, 5 , 10 },
+    { 195, 196, 5 , 13 },
+    { 208, 196, 4 , 8 },
+    { 220, 196, 5 , 12 },
 };
 
 // Font glyphs info data
 // NOTE: No glyphs.image data provided
-static const GlyphInfo terminalFontGlyphs[189] = {
+static const GlyphInfo terminalFontGlyphs[175] = {
     { 32, 0, 0, 4, { 0 }},
     { 33, 1, 3, 3, { 0 }},
     { 34, 1, 3, 5, { 0 }},
@@ -430,29 +410,15 @@
     { 163, 1, 3, 7, { 0 }},
     { 8364, 1, 3, 7, { 0 }},
     { 165, 1, 3, 7, { 0 }},
-    { 352, 0, 0, 0, { 0 }},
-    { 167, 0, 0, 0, { 0 }},
-    { 353, 0, 0, 0, { 0 }},
     { 169, 1, 3, 9, { 0 }},
-    { 170, 0, 0, 0, { 0 }},
-    { 171, 0, 0, 0, { 0 }},
     { 172, 1, 8, 7, { 0 }},
     { 174, 1, 3, 9, { 0 }},
     { 175, 1, 1, 7, { 0 }},
     { 176, 1, 0, 5, { 0 }},
     { 177, 1, 7, 7, { 0 }},
-    { 178, 0, 0, 0, { 0 }},
-    { 179, 0, 0, 0, { 0 }},
-    { 381, 0, 0, 0, { 0 }},
     { 181, 1, 6, 7, { 0 }},
     { 182, 1, 3, 9, { 0 }},
     { 183, 1, 8, 3, { 0 }},
-    { 382, 0, 0, 0, { 0 }},
-    { 185, 0, 0, 0, { 0 }},
-    { 186, 0, 0, 0, { 0 }},
-    { 187, 0, 0, 0, { 0 }},
-    { 338, 0, 0, 0, { 0 }},
-    { 339, 0, 0, 0, { 0 }},
     { 376, 1, 1, 7, { 0 }},
     { 191, 1, 3, 7, { 0 }},
     { 192, 1, 0, 7, { 0 }},
@@ -535,33 +501,44 @@
     // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
     int terminalFontDataSize = 0;
     unsigned char *data = DecompressData(terminalFontData, TERMINAL_STYLE_FONT_ATLAS_COMP_SIZE, &terminalFontDataSize);
-    Image imFont = { data, 512, 256, 1, 2 };
+    Image imFont = { data, 256, 256, 1, 2 };
 
     Font font = { 0 };
     font.baseSize = 16;
-    font.glyphCount = 189;
-
-    // Load texture from image
-    font.texture = LoadTextureFromImage(imFont);
-    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+    font.glyphCount = 175;
 
     // Copy char recs data from global fontRecs
     // NOTE: Required to avoid issues if trying to free font
-    font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
     memcpy(font.recs, terminalFontRecs, font.glyphCount*sizeof(Rectangle));
 
     // Copy font char info data from global fontChars
     // NOTE: Required to avoid issues if trying to free font
-    font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
     memcpy(font.glyphs, terminalFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
 
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
     GuiSetFont(font);
 
     // Setup a white rectangle on the font to be used on shapes drawing,
     // it makes possible to draw shapes and text (full UI) in a single draw call
-    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
     SetShapesTexture(font.texture, fontWhiteRec);
 
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "Mecha.ttf");
     //-----------------------------------------------------------------
 
     // TODO: Custom user style setup: Set specific properties here (if required)
diff --git a/raygui/styles/turbo/style_turbo.h b/raygui/styles/turbo/style_turbo.h
new file mode 100644
--- /dev/null
+++ b/raygui/styles/turbo/style_turbo.h
@@ -0,0 +1,612 @@
+//////////////////////////////////////////////////////////////////////////////////
+//                                                                              //
+// StyleAsCode exporter v2.0 - Style data exported as a values array            //
+//                                                                              //
+// USAGE: On init call: GuiLoadStyleTurbo();                                   //
+//                                                                              //
+// more info and bugs-report:  github.com/raysan5/raygui                        //
+// feedback and support:       ray[at]raylibtech.com                            //
+//                                                                              //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
+//                                                                              //
+//////////////////////////////////////////////////////////////////////////////////
+
+#define TURBO_STYLE_PROPS_COUNT  20
+
+// Custom style name: Turbo
+static const GuiStyleProp turboStyleProps[TURBO_STYLE_PROPS_COUNT] = {
+    { 0, 0, (int)0xb3b7a6ff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0x36372eff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0xe2eee1ff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xe7ca54ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0x73765fff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xffffffff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0xebd858ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xe7ab54ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x282620ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0x767868ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0x8c8e7fff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0x696a5dff },    // DEFAULT_TEXT_COLOR_DISABLED
+    { 0, 16, (int)0x00000010 },    // DEFAULT_TEXT_SIZE 
+    { 0, 18, (int)0xbbaf6cff },    // DEFAULT_LINE_COLOR 
+    { 0, 19, (int)0x60645fff },    // DEFAULT_BACKGROUND_COLOR 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 1, 8, (int)0xf0e4c4ff },    // LABEL_TEXT_COLOR_PRESSED
+    { 1, 11, (int)0x959680ff },    // LABEL_TEXT_COLOR_DISABLED
+    { 4, 8, (int)0xb4aa8dff },    // SLIDER_TEXT_COLOR_PRESSED
+    { 6, 8, (int)0xb5aa89ff },    // CHECKBOX_TEXT_COLOR_PRESSED
+};
+
+// WARNING: This style uses a custom font: "hello-world.ttf" (size: 16, spacing: 1)
+
+#define TURBO_STYLE_FONT_ATLAS_COMP_SIZE 2589
+
+// Font atlas image pixels data: DEFLATE compressed
+static unsigned char turboFontData[TURBO_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
+    0xdd, 0x8d, 0x8e, 0xac, 0xb8, 0x11, 0x06, 0x50, 0xf3, 0xfe, 0xef, 0xec, 0x8a, 0x94, 0xdd, 0x8d, 0x92, 0xe8, 0xda, 0xa6,
+    0xaa, 0xcd, 0x4f, 0xcf, 0x9c, 0x7b, 0x14, 0x45, 0x6a, 0xb6, 0xbb, 0xc1, 0x50, 0xd8, 0x30, 0xcd, 0xe7, 0x68, 0x00, 0x00,
+    0x00, 0x00, 0xd1, 0xa2, 0x0f, 0x5e, 0xcb, 0xbc, 0xde, 0x86, 0xaf, 0xf7, 0xbf, 0x5f, 0xef, 0x93, 0x65, 0x67, 0x3f, 0x6b,
+    0xbc, 0x4e, 0x2d, 0xf9, 0x39, 0x31, 0x7c, 0x47, 0xfc, 0xe1, 0x95, 0x7f, 0xfe, 0x65, 0x3e, 0x67, 0xb4, 0xbd, 0xf9, 0xd6,
+    0xcb, 0x2e, 0x99, 0x7f, 0x7b, 0x4f, 0xae, 0x59, 0xfd, 0x3d, 0x67, 0xdb, 0x3d, 0xd3, 0x86, 0xff, 0xfc, 0xeb, 0x89, 0x4f,
+    0x99, 0xaf, 0xcf, 0x9f, 0x3f, 0xad, 0x2d, 0xb6, 0x3a, 0xb7, 0xdd, 0x7d, 0xb9, 0xa4, 0xf6, 0xae, 0x3d, 0xf5, 0x3f, 0xda,
+    0x27, 0x99, 0xd7, 0xdb, 0xb0, 0x1d, 0xff, 0xaa, 0x9b, 0x51, 0xdd, 0x1e, 0x89, 0xe3, 0x64, 0x54, 0x23, 0xc7, 0xa4, 0xca,
+    0x23, 0xf5, 0xf9, 0xf3, 0xa3, 0x68, 0xc7, 0x39, 0x75, 0xb4, 0xb6, 0x7f, 0x3e, 0xbb, 0x8c, 0xdf, 0xd1, 0xa7, 0x5b, 0x5e,
+    0x3b, 0x57, 0x8d, 0xdb, 0xf1, 0xf8, 0xc3, 0x7b, 0x6b, 0xeb, 0x76, 0x7e, 0xbd, 0x22, 0xbd, 0x2f, 0x62, 0x7a, 0xd4, 0x1c,
+    0xc3, 0x73, 0x46, 0x6e, 0xeb, 0xa2, 0xb0, 0xdd, 0xb1, 0x58, 0xd2, 0x52, 0xbd, 0x5a, 0xdf, 0xdc, 0xff, 0xef, 0xa8, 0xff,
+    0xf8, 0x77, 0x2b, 0x1e, 0xa9, 0xfe, 0x36, 0x92, 0xeb, 0x94, 0xaf, 0xda, 0x63, 0xf0, 0xbd, 0xe3, 0xfe, 0xfc, 0xea, 0x36,
+    0x1d, 0x2d, 0x3b, 0x0a, 0xad, 0x31, 0x5a, 0xd2, 0x87, 0xdb, 0xdd, 0xca, 0x67, 0xbd, 0x48, 0x6c, 0x4d, 0x7c, 0x7c, 0x2e,
+    0x8d, 0xc9, 0x9e, 0x9e, 0xef, 0xbb, 0x48, 0xaf, 0x69, 0x14, 0xde, 0x33, 0x5f, 0xd2, 0xb6, 0xbe, 0xe7, 0xba, 0x3e, 0x2a,
+    0xff, 0x79, 0xf3, 0xd1, 0x57, 0x14, 0xeb, 0xe1, 0xf3, 0xf5, 0x3c, 0xd2, 0xe7, 0xc4, 0xb8, 0xf8, 0x9a, 0x2a, 0x5b, 0xff,
+    0x6d, 0x63, 0xfd, 0x47, 0xba, 0xbd, 0xef, 0xab, 0xff, 0x27, 0xfa, 0xff, 0xb6, 0xa8, 0xff, 0xa6, 0xfe, 0x53, 0xff, 0x6d,
+    0xee, 0xba, 0x60, 0xde, 0x6f, 0x47, 0x62, 0x3c, 0x13, 0x1b, 0xeb, 0x39, 0x6e, 0xaf, 0xfe, 0xd9, 0xd1, 0x56, 0x19, 0x09,
+    0x8e, 0xaf, 0xb7, 0xc6, 0x75, 0x36, 0xbb, 0x46, 0x8b, 0xf4, 0x88, 0x73, 0x76, 0x75, 0x95, 0xb9, 0x5f, 0x12, 0xdb, 0x8e,
+    0xcc, 0x56, 0xaa, 0xff, 0x48, 0xdd, 0xf3, 0x89, 0x45, 0xcb, 0x67, 0xeb, 0x3f, 0x26, 0xe7, 0xbf, 0xd9, 0x71, 0x14, 0x97,
+    0x5e, 0xff, 0x67, 0xeb, 0xbf, 0x2d, 0x46, 0x65, 0x2d, 0x75, 0xa4, 0x56, 0xd6, 0xb2, 0xbf, 0xe8, 0x8e, 0xea, 0xce, 0xfa,
+    0x8f, 0xe4, 0x56, 0xc7, 0x89, 0xbb, 0x61, 0xa3, 0xef, 0xa8, 0x5c, 0xbd, 0xf5, 0x0f, 0x8f, 0xab, 0x78, 0x70, 0x9f, 0x7c,
+    0xd2, 0x63, 0xf7, 0xc7, 0xfb, 0xff, 0x78, 0x6c, 0xfc, 0x1f, 0xe9, 0xb1, 0xc1, 0xf5, 0xf5, 0x1f, 0x2f, 0xaf, 0xfe, 0xda,
+    0xf8, 0x3f, 0x8a, 0xe3, 0xf2, 0xd8, 0x34, 0x96, 0xaf, 0x5e, 0xcd, 0xbc, 0x6b, 0x8f, 0xb4, 0xe5, 0xfd, 0x84, 0x6f, 0x1c,
+    0xff, 0xc7, 0x43, 0xed, 0x18, 0x85, 0x6b, 0x03, 0xf5, 0x5f, 0xa9, 0xff, 0xda, 0x98, 0x76, 0x75, 0x77, 0x33, 0xb6, 0x9e,
+    0x99, 0xbe, 0xbb, 0xfe, 0xeb, 0x15, 0xab, 0xfe, 0xcf, 0x8e, 0x6d, 0x63, 0x7a, 0x5f, 0x36, 0xb6, 0xec, 0xc3, 0xef, 0xe8,
+    0x6b, 0xf6, 0xd5, 0x7f, 0x7c, 0x70, 0xd5, 0xf0, 0x1b, 0xeb, 0xbf, 0xdd, 0x58, 0xff, 0xf1, 0x63, 0xc7, 0xff, 0x95, 0xeb,
+    0xff, 0x98, 0xfe, 0x45, 0x3a, 0x36, 0x8d, 0x00, 0xde, 0xdf, 0xfb, 0x57, 0xee, 0xf6, 0xcc, 0x7f, 0x79, 0x14, 0xe9, 0xbf,
+    0x0b, 0x54, 0xee, 0x36, 0xad, 0xc6, 0xce, 0x2d, 0xbd, 0x6e, 0xdf, 0xde, 0xff, 0xe7, 0xb7, 0x3b, 0x96, 0x4b, 0xa2, 0x70,
+    0x1c, 0xbd, 0xed, 0xfc, 0x1a, 0x8f, 0xf7, 0xac, 0xc0, 0xcf, 0xa5, 0xfe, 0xc1, 0x19, 0x40, 0xf5, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x33, 0xf5, 0xff, 0xfb, 0xff, 0xff, 0x5d, 0xd6, 0xff, 0x98, 0x66, 0xdc,
+    0x87, 0x4b, 0x46, 0x9f, 0xd5, 0x0b, 0xdf, 0x9f, 0x5f, 0xb3, 0xdd, 0x19, 0xec, 0x6d, 0xb2, 0xa5, 0xf5, 0x36, 0xb8, 0x7e,
+    0xc9, 0x7c, 0xad, 0x33, 0xfb, 0x66, 0xdc, 0x2e, 0x2d, 0xf5, 0x4c, 0x72, 0x2e, 0x27, 0xb0, 0x2f, 0x9e, 0x70, 0xcd, 0xce,
+    0xeb, 0xb0, 0xca, 0x30, 0xcc, 0x24, 0x1f, 0xf6, 0x53, 0xd5, 0xb4, 0x7e, 0x3d, 0xbb, 0x3e, 0x6d, 0x9a, 0x8a, 0x19, 0xe5,
+    0xdc, 0xbf, 0x5a, 0xf6, 0xf4, 0x91, 0x4c, 0x7e, 0x9a, 0x3d, 0x8f, 0xde, 0xd3, 0xe9, 0xcc, 0x77, 0x65, 0xb0, 0xcf, 0xda,
+    0xf3, 0x48, 0xa7, 0x5f, 0x54, 0x96, 0x1c, 0xc3, 0x79, 0x55, 0x56, 0x59, 0x0f, 0xc7, 0xe9, 0xbd, 0x30, 0xcb, 0x48, 0x3e,
+    0x86, 0x39, 0xe2, 0xb9, 0x63, 0x6d, 0x57, 0xf6, 0x7d, 0x2c, 0xd7, 0x38, 0x92, 0xef, 0xe9, 0xd3, 0xef, 0x89, 0xcb, 0x9e,
+    0x29, 0x8b, 0x64, 0x6b, 0xb5, 0xff, 0x64, 0x6c, 0xe4, 0xda, 0xf2, 0x93, 0xfa, 0xaf, 0xe4, 0x4b, 0xb7, 0x74, 0x02, 0xea,
+    0x31, 0xc8, 0xa5, 0xff, 0xe7, 0x7c, 0x76, 0x57, 0xd2, 0x4a, 0x76, 0x5f, 0xdf, 0x51, 0xff, 0xeb, 0xec, 0xb4, 0x48, 0xf5,
+    0x83, 0xf9, 0x63, 0xf1, 0x89, 0xec, 0x86, 0xbb, 0xf2, 0xc8, 0x3f, 0xd9, 0x8b, 0x57, 0xd6, 0x7f, 0x3e, 0x27, 0xb6, 0x9e,
+    0xfc, 0xb3, 0xbf, 0xfe, 0xf3, 0x79, 0x55, 0x31, 0xcc, 0x53, 0x51, 0xff, 0xd5, 0xfa, 0x8f, 0x2f, 0xa8, 0xff, 0x9d, 0x49,
+    0xda, 0xab, 0x4f, 0x8b, 0x54, 0xf2, 0xf9, 0x2a, 0xe5, 0xa7, 0x4f, 0xc6, 0xb2, 0xe7, 0xae, 0x3e, 0xe2, 0xc4, 0xf8, 0xe3,
+    0x9e, 0xfa, 0x5f, 0x25, 0xf7, 0xe6, 0x8e, 0xaf, 0xea, 0xe7, 0xec, 0x9a, 0x83, 0x61, 0x75, 0xe4, 0x64, 0xf7, 0x68, 0x24,
+    0x67, 0x0a, 0xdc, 0x5d, 0xff, 0xf3, 0xaa, 0xad, 0xad, 0x5b, 0xdb, 0xda, 0xe3, 0x7e, 0xda, 0x03, 0xc6, 0xd6, 0x2b, 0x83,
+    0x7b, 0xce, 0xe2, 0xc7, 0xc7, 0xb3, 0xc7, 0xc5, 0xf4, 0x0a, 0x73, 0xdf, 0xb1, 0x75, 0x6f, 0xff, 0x1f, 0x9b, 0xf3, 0xd4,
+    0xe3, 0xc6, 0xa4, 0xd5, 0xfc, 0x2c, 0x17, 0xd9, 0xf6, 0xac, 0x64, 0xa4, 0xe6, 0x53, 0x95, 0x7f, 0x4a, 0xfd, 0x5f, 0xbf,
+    0x64, 0x7f, 0xa5, 0xe5, 0xea, 0x3f, 0x6e, 0x18, 0x5b, 0x7e, 0xc3, 0xf8, 0xbf, 0x4d, 0xf3, 0xea, 0xef, 0xaa, 0xff, 0xea,
+    0xde, 0xb8, 0xb6, 0xfe, 0xa3, 0x30, 0x6e, 0xdf, 0x39, 0xce, 0x7f, 0x66, 0xfc, 0x3f, 0xef, 0x63, 0x22, 0xdd, 0xee, 0xd5,
+    0x0c, 0xd3, 0x2b, 0xeb, 0x3f, 0x6e, 0xb9, 0xb6, 0xbc, 0xbf, 0xfe, 0xf7, 0xd6, 0xe5, 0xde, 0xfa, 0xdf, 0x39, 0x5f, 0x85,
+    0xfa, 0xbf, 0x7f, 0x64, 0xb0, 0xf7, 0x3d, 0x95, 0xab, 0x83, 0x27, 0xfb, 0xff, 0xfb, 0xdb, 0xfa, 0xf9, 0xfa, 0xdf, 0x39,
+    0xfe, 0x8f, 0x87, 0xeb, 0xbf, 0x32, 0xff, 0xd7, 0x3d, 0xa3, 0x7c, 0xf5, 0xff, 0x44, 0xfd, 0xbf, 0xa1, 0xd5, 0xf3, 0xe3,
+    0xa6, 0xf5, 0xdd, 0xc2, 0xdc, 0xac, 0x89, 0xb5, 0xbb, 0xe2, 0x51, 0x9c, 0x39, 0x3c, 0x0a, 0x6b, 0x5d, 0x19, 0x39, 0xb6,
+    0x2d, 0xd7, 0xf2, 0xb5, 0xb3, 0x49, 0x25, 0x39, 0xbe, 0x3a, 0xcf, 0xd8, 0x9d, 0xd7, 0x05, 0xd7, 0xbc, 0x2b, 0xb7, 0x17,
+    0x63, 0xd9, 0xf6, 0x3b, 0xce, 0x23, 0xed, 0x85, 0x29, 0xfe, 0x7c, 0xbb, 0xb8, 0xe9, 0x3d, 0x68, 0x45, 0xd4, 0x3f, 0x5a,
+    0x91, 0x37, 0x1d, 0x85, 0x91, 0xbc, 0xa6, 0x36, 0x0a, 0xdd, 0xd3, 0xea, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xd8, 0xf5, 0xfb, 0xe4, 0x6c, 0xa6, 0xf8, 0x2c, 0x37, 0x31, 0xff, 0x79, 0xab, 0x14, 0xb4, 0xfe,
+    0xe0, 0x92, 0x59, 0x2b, 0xf4, 0x93, 0x5b, 0xd3, 0x93, 0x39, 0x6f, 0xe3, 0x36, 0x19, 0xe7, 0xcb, 0xf7, 0xe4, 0xb2, 0xca,
+    0xec, 0x0a, 0xf3, 0x7d, 0x38, 0x4e, 0x49, 0xcb, 0xb5, 0xeb, 0x38, 0x79, 0xbf, 0x27, 0x67, 0x24, 0x58, 0xb5, 0xd8, 0xb9,
+    0x57, 0x63, 0xd9, 0x52, 0x67, 0x8f, 0xe9, 0xdc, 0x6c, 0x0a, 0xf3, 0x6c, 0xe7, 0x3e, 0x7c, 0x57, 0x2f, 0x3c, 0x99, 0x54,
+    0xc9, 0x67, 0x3f, 0x52, 0xa9, 0x46, 0x9f, 0x64, 0x4f, 0xec, 0xcc, 0xd2, 0xdd, 0x95, 0xa5, 0x9f, 0xcb, 0x6e, 0x3c, 0xa6,
+    0xfb, 0x38, 0x3e, 0x3c, 0x53, 0xf7, 0xc9, 0x77, 0xf4, 0x74, 0xdb, 0xae, 0x66, 0x4a, 0xc8, 0xb4, 0xd1, 0x7c, 0xeb, 0xf6,
+    0xe5, 0xeb, 0xf7, 0x74, 0x22, 0xe7, 0x71, 0x7a, 0xc6, 0x8b, 0x55, 0x3e, 0xc4, 0x71, 0x3a, 0x89, 0x22, 0x37, 0x9b, 0xc2,
+    0xa8, 0xed, 0x7a, 0x61, 0x7e, 0x80, 0x75, 0xed, 0xdd, 0x91, 0xbf, 0xf3, 0x86, 0xfa, 0xdf, 0x95, 0xa5, 0x7d, 0x75, 0x2a,
+    0x4f, 0x1f, 0xae, 0x7d, 0xbf, 0xa9, 0x6d, 0xdb, 0x70, 0x74, 0x77, 0xf6, 0x29, 0xb7, 0x28, 0xe6, 0xf1, 0xe4, 0x9f, 0x98,
+    0x3b, 0xa6, 0x33, 0x12, 0x9d, 0x3f, 0x2f, 0x46, 0xa1, 0xfe, 0x33, 0xdb, 0x78, 0xbe, 0x6f, 0x68, 0xd3, 0xf4, 0xdb, 0x7c,
+    0x8e, 0xd4, 0xd3, 0xf5, 0xdf, 0x16, 0x19, 0xec, 0xb9, 0x14, 0xf6, 0xdd, 0x89, 0x39, 0xfb, 0xea, 0x7c, 0x57, 0x8e, 0x4e,
+    0xae, 0x9a, 0xe6, 0x29, 0x36, 0xf9, 0x3c, 0xf4, 0x9e, 0x38, 0x1e, 0x67, 0x23, 0xbf, 0xfc, 0x19, 0x20, 0x36, 0x3f, 0x31,
+    0x3b, 0x5e, 0xdf, 0xbe, 0xa9, 0xff, 0xff, 0xb4, 0xfe, 0x5b, 0xaa, 0xfa, 0xd7, 0xf5, 0x1f, 0x2f, 0xad, 0xff, 0x79, 0x2d,
+    0x67, 0xeb, 0x72, 0x67, 0x96, 0x66, 0x14, 0xd6, 0xed, 0xb9, 0xfa, 0xcf, 0xce, 0x60, 0x30, 0xfb, 0x86, 0xf1, 0x99, 0xa1,
+    0x6f, 0xaa, 0xcd, 0x28, 0x1e, 0xf5, 0xf1, 0x48, 0xf2, 0x46, 0x25, 0x8d, 0xf8, 0x9a, 0x74, 0x8f, 0x55, 0x95, 0xf7, 0x2d,
+    0x67, 0x5b, 0xf5, 0xff, 0xc9, 0x78, 0xe6, 0xde, 0xfa, 0x6f, 0x85, 0x79, 0x5a, 0xa2, 0x30, 0xea, 0x1a, 0x9f, 0x01, 0xe2,
+    0x96, 0xbb, 0xd1, 0xef, 0xbb, 0x3f, 0xbe, 0xda, 0xaf, 0x71, 0xfb, 0xfa, 0xc4, 0xc6, 0x73, 0xe7, 0xea, 0x08, 0xc9, 0x1c,
+    0x57, 0xb1, 0xf8, 0x96, 0xfc, 0xb5, 0x71, 0xe5, 0x98, 0x6f, 0xc5, 0x84, 0xf8, 0x4a, 0x6e, 0xe9, 0xe7, 0xd7, 0x0b, 0x9f,
+    0x9f, 0x45, 0xaa, 0xf3, 0x77, 0xc5, 0xd6, 0x63, 0x62, 0xe7, 0xdf, 0xa3, 0xde, 0x94, 0x99, 0xb3, 0x4e, 0x81, 0x7d, 0x4b,
+    0xfd, 0xdf, 0x3d, 0x72, 0x8a, 0x1f, 0x76, 0xce, 0x8f, 0x4d, 0x57, 0x96, 0x57, 0xf5, 0xff, 0x7b, 0xef, 0xad, 0xae, 0xea,
+    0xec, 0xfb, 0x53, 0xab, 0x62, 0xcb, 0xb9, 0x24, 0xb6, 0x5e, 0xdf, 0x5c, 0x5b, 0xff, 0xf7, 0x56, 0x83, 0xfa, 0xff, 0xde,
+    0xfa, 0xaf, 0xde, 0x0d, 0xfd, 0x8d, 0xbf, 0x8f, 0x51, 0xff, 0x57, 0xd7, 0xed, 0xb3, 0x23, 0xbe, 0xdd, 0xc9, 0xf1, 0x77,
+    0x9f, 0xe3, 0xe2, 0xc4, 0xb5, 0x5a, 0x7e, 0x6c, 0xa0, 0xf2, 0xdf, 0x59, 0xff, 0xfb, 0xff, 0x46, 0xc2, 0xde, 0xbf, 0x2c,
+    0xfd, 0xcc, 0xd1, 0x34, 0xa0, 0xfe, 0x81, 0xb6, 0x9c, 0x4f, 0xf0, 0xcc, 0xaf, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9c, 0x59, 0x0e, 0x7c, 0x36, 0x4b, 0xfc, 0x9a, 0xb5, 0xcb, 0x27, 0xbb, 0xcf, 0xd2,
+    0xdd, 0xfb, 0xc3, 0x6b, 0x7d, 0xe5, 0x37, 0xf4, 0xdb, 0xb6, 0x70, 0x6f, 0xab, 0x8c, 0x93, 0xae, 0xfb, 0x2d, 0xc7, 0x60,
+    0xfe, 0x5b, 0xfa, 0x74, 0x59, 0x4f, 0x1f, 0xb3, 0x95, 0x25, 0x7d, 0x5a, 0xb5, 0x3d, 0xf9, 0x14, 0xdb, 0xbe, 0x7c, 0x8a,
+    0x5a, 0x32, 0xd6, 0x9f, 0x97, 0x1d, 0x7f, 0xff, 0x6f, 0xb4, 0xec, 0x4f, 0xdb, 0x7e, 0x4c, 0xcf, 0x65, 0x47, 0x29, 0x27,
+    0x33, 0xb7, 0x64, 0xb6, 0xd6, 0x7b, 0xd2, 0x84, 0xff, 0xfc, 0x0d, 0x31, 0xd9, 0xc2, 0x28, 0x25, 0x93, 0xdd, 0xb5, 0x2f,
+    0x47, 0xf3, 0x2b, 0x1c, 0x85, 0x99, 0x53, 0xee, 0xd8, 0x5f, 0x51, 0x9a, 0x8b, 0xa1, 0x2d, 0x8e, 0xcd, 0xcc, 0xf1, 0xdc,
+    0x93, 0x39, 0xff, 0xb5, 0xfa, 0x1f, 0x7f, 0xc3, 0x78, 0x4b, 0x8e, 0xd2, 0x96, 0x1c, 0xc9, 0x73, 0x69, 0x9f, 0xcc, 0x80,
+    0x52, 0x79, 0x02, 0x77, 0xe7, 0xf6, 0xcc, 0xfa, 0xe1, 0x71, 0x1b, 0xe4, 0xbf, 0xe3, 0xfc, 0xbe, 0x9c, 0xb5, 0xf1, 0xf3,
+    0xfb, 0x32, 0x26, 0xd9, 0xab, 0x91, 0xae, 0xa4, 0xfc, 0x3a, 0x8f, 0x8f, 0xf5, 0xd1, 0xa7, 0xad, 0xe6, 0xc6, 0x79, 0xf6,
+    0x79, 0xef, 0x71, 0x1a, 0x74, 0xb6, 0xfe, 0xe7, 0x33, 0xbe, 0x9c, 0x7f, 0x75, 0x76, 0x96, 0x3d, 0x26, 0x7d, 0xf9, 0xa8,
+    0x95, 0xe7, 0x73, 0xd4, 0xd4, 0x9e, 0xc0, 0xdf, 0xb5, 0x3d, 0x95, 0xef, 0x39, 0xd2, 0x6d, 0x96, 0x4b, 0x38, 0x3d, 0xa6,
+    0x5b, 0xf2, 0xec, 0xbe, 0x9c, 0x1d, 0x99, 0x7d, 0xb0, 0xa5, 0x57, 0xec, 0xaf, 0x48, 0x7c, 0x5a, 0x75, 0xfe, 0x99, 0xd9,
+    0x7c, 0x7a, 0xbb, 0x96, 0x44, 0xb2, 0xa5, 0x63, 0x7a, 0x5d, 0xd6, 0x36, 0xf5, 0xcb, 0xd5, 0xbe, 0xbc, 0xa5, 0x13, 0xc8,
+    0x57, 0x33, 0x5e, 0x64, 0x7a, 0xec, 0xca, 0x92, 0x28, 0x5c, 0x1b, 0xf6, 0xf4, 0x1d, 0x8b, 0x59, 0x3e, 0x78, 0x24, 0xfb,
+    0xb8, 0x67, 0xf7, 0x65, 0x5b, 0x5c, 0x49, 0x64, 0xb6, 0xa6, 0xb2, 0x64, 0x35, 0x13, 0xda, 0x78, 0xfe, 0xc2, 0xdc, 0x2c,
+    0x97, 0x9f, 0xcc, 0xb4, 0xd7, 0x0b, 0x55, 0x1e, 0xc9, 0x76, 0xce, 0xd4, 0x4b, 0xbe, 0x5f, 0xae, 0xf6, 0xe5, 0xad, 0x30,
+    0x03, 0x41, 0x5c, 0x7e, 0xc5, 0x58, 0x9d, 0xe9, 0xec, 0x18, 0x5e, 0x1b, 0xe7, 0x5e, 0xaf, 0xce, 0x63, 0x10, 0x2f, 0xdc,
+    0x97, 0xf9, 0xfa, 0xbf, 0x66, 0xce, 0x8a, 0xbd, 0xf3, 0xdc, 0xf5, 0x07, 0x8f, 0xb6, 0x6c, 0x9e, 0x65, 0xb5, 0x5e, 0xae,
+    0x6f, 0xe5, 0x5a, 0x2e, 0xff, 0xd3, 0xf5, 0x1f, 0x1b, 0x67, 0x07, 0xd8, 0x55, 0xff, 0xfd, 0x25, 0x15, 0xf3, 0x5b, 0xea,
+    0x3f, 0x57, 0x97, 0x3b, 0x97, 0xd4, 0x5a, 0xba, 0xbd, 0xb8, 0x95, 0x7f, 0x4e, 0xff, 0xff, 0x5c, 0xfd, 0xc7, 0x17, 0xd6,
+    0xff, 0x7b, 0xd7, 0xf9, 0x0d, 0x7d, 0xe3, 0xde, 0x33, 0x6d, 0xbb, 0xbc, 0x5f, 0xae, 0xcf, 0xb1, 0xb3, 0xb7, 0xfe, 0x23,
+    0xd1, 0x63, 0xef, 0x4c, 0xd5, 0x7e, 0xb6, 0xfe, 0xdf, 0xdb, 0x97, 0xae, 0xda, 0xea, 0xc9, 0x35, 0x5b, 0xcd, 0x18, 0xff,
+    0xc6, 0xfa, 0xdf, 0x35, 0xfe, 0x9f, 0xcd, 0x02, 0xf5, 0xf6, 0xfe, 0x3f, 0x52, 0xf3, 0xe7, 0xfd, 0x9c, 0xfe, 0x3f, 0x16,
+    0xf3, 0xf0, 0x7e, 0xdf, 0xf8, 0xff, 0xc9, 0xe3, 0xaf, 0x72, 0x6f, 0x6c, 0x35, 0x47, 0x7a, 0xdc, 0x70, 0x65, 0x70, 0xfd,
+    0xdf, 0x17, 0xbf, 0x6f, 0x8c, 0xf3, 0xd9, 0x9d, 0x8e, 0xef, 0xa8, 0xff, 0x75, 0x4f, 0xfa, 0x7d, 0x7b, 0xac, 0x3d, 0x5a,
+    0xff, 0x72, 0xdb, 0x7f, 0x56, 0xfd, 0xb7, 0x5b, 0xfa, 0xff, 0xea, 0xac, 0xa5, 0xd9, 0xdf, 0x9f, 0x7d, 0x53, 0xfd, 0xef,
+    0x9c, 0x55, 0xe8, 0xce, 0x35, 0x53, 0xff, 0xed, 0x8b, 0x7a, 0x86, 0x37, 0xf4, 0xff, 0xed, 0x96, 0xfe, 0xff, 0xdb, 0xce,
+    0xd8, 0xef, 0x3d, 0xfe, 0xaa, 0xbf, 0x73, 0x57, 0xff, 0xdf, 0x57, 0xff, 0xd9, 0x1e, 0xbb, 0xb2, 0x64, 0xfd, 0x4d, 0x9f,
+    0xbf, 0xbe, 0xf3, 0x57, 0xde, 0xbb, 0xef, 0x7e, 0xde, 0x71, 0x4d, 0x7a, 0xdf, 0x9a, 0xa9, 0x7f, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x8d, 0x66, 0x19, 0xcb, 0xd9, 0x54, 0xc2, 0xbb, 0x32, 0xce, 0x77, 0xbd, 0x9e, 0x4f,
+    0x51, 0xaf, 0xac, 0xd3, 0x7d, 0xf9, 0xee, 0xe3, 0xe7, 0x08, 0x7a, 0x61, 0x96, 0x87, 0x3b, 0xf6, 0x58, 0x5f, 0x1c, 0x99,
+    0x6f, 0x9d, 0xcf, 0xe0, 0x37, 0xfc, 0xca, 0x3f, 0x0a, 0xd9, 0x83, 0xfb, 0x32, 0xce, 0xe7, 0xe6, 0x69, 0xce, 0x9f, 0x7e,
+    0x47, 0x2d, 0x77, 0xfd, 0x7d, 0xf9, 0xee, 0xff, 0xbd, 0xc7, 0xfa, 0xe5, 0x6b, 0x5d, 0xed, 0x65, 0x68, 0x8f, 0x3e, 0xfd,
+    0xd2, 0xa7, 0xe7, 0x80, 0xe7, 0xf6, 0x58, 0x26, 0xc9, 0xbc, 0xfa, 0x0d, 0xe3, 0xb3, 0xd8, 0xf1, 0xd2, 0xbe, 0x67, 0x9e,
+    0x3d, 0x3b, 0x4b, 0x45, 0xec, 0x37, 0x3d, 0x19, 0xd6, 0xd3, 0xcf, 0xf2, 0xf4, 0x4d, 0x9f, 0x46, 0x65, 0x8f, 0x1d, 0xd3,
+    0xe3, 0x29, 0x53, 0xff, 0x77, 0x25, 0x99, 0x8f, 0x3f, 0x2b, 0xf7, 0x7a, 0x4b, 0x66, 0xb5, 0xc4, 0x4d, 0x29, 0xee, 0xfb,
+    0xf2, 0xdd, 0xdb, 0xa9, 0xfc, 0x9f, 0xbe, 0x75, 0x49, 0xfe, 0x7b, 0xde, 0x3a, 0x97, 0xc6, 0x6f, 0x7b, 0xa6, 0x77, 0xd5,
+    0xf7, 0x9f, 0x79, 0x2a, 0x7e, 0x6f, 0xc6, 0x79, 0xbb, 0x34, 0x49, 0x63, 0x96, 0x08, 0x72, 0x0c, 0x8f, 0xe3, 0xeb, 0x53,
+    0xdc, 0xf7, 0xb6, 0xca, 0x37, 0x64, 0xe9, 0xbe, 0xf1, 0xc9, 0xf0, 0xdf, 0x32, 0xfe, 0x8f, 0x97, 0x66, 0x46, 0x5e, 0x9f,
+    0xa4, 0xd3, 0xbe, 0x32, 0xe1, 0xb0, 0x95, 0x13, 0xc0, 0xd4, 0x3f, 0xd7, 0x25, 0x43, 0x5c, 0x93, 0xff, 0xdb, 0xd4, 0xff,
+    0x87, 0x55, 0xf1, 0x7c, 0x96, 0xe6, 0xfa, 0x2c, 0xdf, 0xd4, 0xff, 0xcb, 0xea, 0x3f, 0x5f, 0x7d, 0xd7, 0x24, 0x69, 0xea,
+    0xff, 0xaf, 0xab, 0x8a, 0x6f, 0x9d, 0x4b, 0x83, 0xab, 0xc7, 0xff, 0x95, 0x33, 0xc0, 0x1b, 0x92, 0x19, 0xf3, 0xaf, 0x7f,
+    0x5b, 0x95, 0xef, 0xcc, 0xd8, 0xba, 0x2b, 0x7b, 0xbe, 0x52, 0xff, 0x4f, 0x66, 0x5c, 0xd3, 0x8a, 0xa3, 0xef, 0xfb, 0x92,
+    0xd9, 0x62, 0xcb, 0xeb, 0x2d, 0x79, 0x85, 0xb3, 0xf3, 0x7a, 0xe9, 0xf9, 0x24, 0xbd, 0xfb, 0xb2, 0xe7, 0x6b, 0x57, 0x79,
+    0xfa, 0x7f, 0xf8, 0xf9, 0xfd, 0x86, 0xfa, 0x07, 0xf5, 0x6f, 0xf4, 0x0f, 0xee, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x5e, 0x7f, 0xfd, 0xd3, 0x0e,
+    0xa0, 0xfe, 0x81, 0x5f, 0x57, 0xff, 0xff, 0x02 };
+
+// Font glyphs rectangles data (on atlas)
+static const Rectangle turboFontRecs[185] = {
+    { 4, 4, 5 , 16 },
+    { 17, 4, 2 , 10 },
+    { 27, 4, 4 , 4 },
+    { 39, 4, 5 , 10 },
+    { 52, 4, 5 , 11 },
+    { 65, 4, 5 , 10 },
+    { 78, 4, 5 , 10 },
+    { 91, 4, 2 , 4 },
+    { 101, 4, 4 , 13 },
+    { 113, 4, 5 , 13 },
+    { 126, 4, 4 , 4 },
+    { 138, 4, 5 , 6 },
+    { 151, 4, 3 , 2 },
+    { 162, 4, 5 , 2 },
+    { 175, 4, 2 , 1 },
+    { 185, 4, 5 , 10 },
+    { 198, 4, 5 , 10 },
+    { 211, 4, 4 , 10 },
+    { 223, 4, 5 , 10 },
+    { 236, 4, 5 , 10 },
+    { 249, 4, 5 , 10 },
+    { 262, 4, 5 , 10 },
+    { 275, 4, 5 , 10 },
+    { 288, 4, 5 , 10 },
+    { 301, 4, 5 , 10 },
+    { 314, 4, 5 , 10 },
+    { 327, 4, 2 , 6 },
+    { 337, 4, 2 , 6 },
+    { 347, 4, 5 , 6 },
+    { 360, 4, 5 , 4 },
+    { 373, 4, 5 , 6 },
+    { 386, 4, 5 , 10 },
+    { 399, 4, 5 , 7 },
+    { 412, 4, 5 , 10 },
+    { 425, 4, 5 , 10 },
+    { 438, 4, 5 , 10 },
+    { 451, 4, 5 , 10 },
+    { 464, 4, 5 , 10 },
+    { 477, 4, 5 , 10 },
+    { 490, 4, 5 , 10 },
+    { 4, 28, 5 , 10 },
+    { 17, 28, 4 , 10 },
+    { 29, 28, 5 , 10 },
+    { 42, 28, 5 , 10 },
+    { 55, 28, 5 , 10 },
+    { 68, 28, 5 , 10 },
+    { 81, 28, 5 , 10 },
+    { 94, 28, 5 , 10 },
+    { 107, 28, 5 , 10 },
+    { 120, 28, 5 , 10 },
+    { 133, 28, 5 , 10 },
+    { 146, 28, 5 , 10 },
+    { 159, 28, 5 , 10 },
+    { 172, 28, 5 , 10 },
+    { 185, 28, 5 , 10 },
+    { 198, 28, 5 , 10 },
+    { 211, 28, 5 , 10 },
+    { 224, 28, 5 , 10 },
+    { 237, 28, 5 , 10 },
+    { 250, 28, 3 , 13 },
+    { 261, 28, 5 , 10 },
+    { 274, 28, 3 , 13 },
+    { 285, 28, 4 , 3 },
+    { 297, 28, 5 , 1 },
+    { 310, 28, 3 , 3 },
+    { 321, 28, 5 , 7 },
+    { 334, 28, 5 , 10 },
+    { 347, 28, 5 , 7 },
+    { 360, 28, 5 , 10 },
+    { 373, 28, 5 , 7 },
+    { 386, 28, 5 , 10 },
+    { 399, 28, 5 , 10 },
+    { 412, 28, 5 , 10 },
+    { 425, 28, 4 , 10 },
+    { 437, 28, 3 , 13 },
+    { 448, 28, 5 , 10 },
+    { 461, 28, 5 , 10 },
+    { 474, 28, 5 , 7 },
+    { 487, 28, 5 , 7 },
+    { 4, 52, 5 , 7 },
+    { 17, 52, 5 , 10 },
+    { 30, 52, 5 , 10 },
+    { 43, 52, 5 , 7 },
+    { 56, 52, 5 , 7 },
+    { 69, 52, 5 , 10 },
+    { 82, 52, 5 , 7 },
+    { 95, 52, 5 , 7 },
+    { 108, 52, 5 , 7 },
+    { 121, 52, 5 , 7 },
+    { 134, 52, 5 , 10 },
+    { 147, 52, 5 , 7 },
+    { 160, 52, 4 , 13 },
+    { 172, 52, 2 , 13 },
+    { 182, 52, 4 , 13 },
+    { 194, 52, 5 , 4 },
+    { 207, 52, 2 , 9 },
+    { 217, 52, 5 , 7 },
+    { 230, 52, 5 , 10 },
+    { 243, 52, 5 , 10 },
+    { 256, 52, 5 , 10 },
+    { 269, 52, 5 , 10 },
+    { 282, 52, 5 , 7 },
+    { 295, 52, 3 , 5 },
+    { 306, 52, 5 , 5 },
+    { 319, 52, 5 , 3 },
+    { 332, 52, 5 , 7 },
+    { 345, 52, 5 , 2 },
+    { 358, 52, 4 , 4 },
+    { 370, 52, 5 , 8 },
+    { 383, 52, 3 , 5 },
+    { 394, 52, 3 , 6 },
+    { 405, 52, 5 , 10 },
+    { 418, 52, 5 , 10 },
+    { 431, 52, 2 , 3 },
+    { 441, 52, 3 , 5 },
+    { 452, 52, 4 , 4 },
+    { 464, 52, 5 , 5 },
+    { 477, 52, 5 , 10 },
+    { 490, 52, 5 , 7 },
+    { 4, 76, 5 , 10 },
+    { 17, 76, 5 , 10 },
+    { 30, 76, 5 , 14 },
+    { 43, 76, 5 , 14 },
+    { 56, 76, 5 , 14 },
+    { 69, 76, 5 , 14 },
+    { 82, 76, 5 , 12 },
+    { 95, 76, 5 , 12 },
+    { 108, 76, 5 , 10 },
+    { 121, 76, 5 , 13 },
+    { 134, 76, 5 , 14 },
+    { 147, 76, 5 , 14 },
+    { 160, 76, 5 , 14 },
+    { 173, 76, 5 , 12 },
+    { 186, 76, 4 , 14 },
+    { 198, 76, 4 , 14 },
+    { 210, 76, 4 , 14 },
+    { 222, 76, 4 , 12 },
+    { 234, 76, 5 , 10 },
+    { 247, 76, 5 , 14 },
+    { 260, 76, 5 , 14 },
+    { 273, 76, 5 , 14 },
+    { 286, 76, 5 , 14 },
+    { 299, 76, 5 , 14 },
+    { 312, 76, 5 , 12 },
+    { 325, 76, 4 , 3 },
+    { 337, 76, 5 , 10 },
+    { 350, 76, 5 , 14 },
+    { 363, 76, 5 , 14 },
+    { 376, 76, 5 , 14 },
+    { 389, 76, 5 , 12 },
+    { 402, 76, 5 , 14 },
+    { 415, 76, 5 , 10 },
+    { 428, 76, 5 , 10 },
+    { 441, 76, 5 , 10 },
+    { 454, 76, 5 , 10 },
+    { 467, 76, 5 , 10 },
+    { 480, 76, 5 , 10 },
+    { 493, 76, 5 , 9 },
+    { 4, 100, 5 , 9 },
+    { 17, 100, 5 , 7 },
+    { 30, 100, 5 , 10 },
+    { 43, 100, 5 , 10 },
+    { 56, 100, 5 , 10 },
+    { 69, 100, 5 , 10 },
+    { 82, 100, 5 , 9 },
+    { 95, 100, 4 , 10 },
+    { 107, 100, 4 , 10 },
+    { 119, 100, 4 , 10 },
+    { 131, 100, 4 , 9 },
+    { 143, 100, 5 , 10 },
+    { 156, 100, 5 , 10 },
+    { 169, 100, 5 , 10 },
+    { 182, 100, 5 , 10 },
+    { 195, 100, 5 , 10 },
+    { 208, 100, 5 , 10 },
+    { 221, 100, 5 , 9 },
+    { 234, 100, 5 , 6 },
+    { 247, 100, 5 , 7 },
+    { 260, 100, 5 , 10 },
+    { 273, 100, 5 , 10 },
+    { 286, 100, 5 , 10 },
+    { 299, 100, 5 , 9 },
+    { 312, 100, 5 , 13 },
+    { 325, 100, 5 , 10 },
+    { 338, 100, 5 , 12 },
+};
+
+// Font glyphs info data
+// NOTE: No glyphs.image data provided
+static const GlyphInfo turboFontGlyphs[185] = {
+    { 32, 0, 0, 5, { 0 }},
+    { 33, 1, 3, 5, { 0 }},
+    { 34, 0, 3, 5, { 0 }},
+    { 35, 0, 3, 5, { 0 }},
+    { 36, 0, 3, 5, { 0 }},
+    { 37, 0, 3, 5, { 0 }},
+    { 38, 0, 3, 5, { 0 }},
+    { 39, 1, 4, 5, { 0 }},
+    { 40, 0, 3, 5, { 0 }},
+    { 41, 0, 3, 5, { 0 }},
+    { 42, 0, 3, 5, { 0 }},
+    { 43, 0, 7, 5, { 0 }},
+    { 44, 0, 12, 5, { 0 }},
+    { 45, 0, 9, 5, { 0 }},
+    { 46, 1, 12, 5, { 0 }},
+    { 47, 0, 3, 5, { 0 }},
+    { 48, 0, 3, 5, { 0 }},
+    { 49, 0, 3, 5, { 0 }},
+    { 50, 0, 3, 5, { 0 }},
+    { 51, 0, 3, 5, { 0 }},
+    { 52, 0, 3, 5, { 0 }},
+    { 53, 0, 3, 5, { 0 }},
+    { 54, 0, 3, 5, { 0 }},
+    { 55, 0, 3, 5, { 0 }},
+    { 56, 0, 3, 5, { 0 }},
+    { 57, 0, 3, 5, { 0 }},
+    { 58, 0, 7, 5, { 0 }},
+    { 59, 0, 7, 5, { 0 }},
+    { 60, 0, 7, 5, { 0 }},
+    { 61, 0, 8, 5, { 0 }},
+    { 62, 0, 7, 5, { 0 }},
+    { 63, 0, 3, 5, { 0 }},
+    { 64, 0, 6, 5, { 0 }},
+    { 65, 0, 3, 5, { 0 }},
+    { 66, 0, 3, 5, { 0 }},
+    { 67, 0, 3, 5, { 0 }},
+    { 68, 0, 3, 5, { 0 }},
+    { 69, 0, 3, 5, { 0 }},
+    { 70, 0, 3, 5, { 0 }},
+    { 71, 0, 3, 5, { 0 }},
+    { 72, 0, 3, 5, { 0 }},
+    { 73, 0, 3, 5, { 0 }},
+    { 74, 0, 3, 5, { 0 }},
+    { 75, 0, 3, 5, { 0 }},
+    { 76, 0, 3, 5, { 0 }},
+    { 77, 0, 3, 5, { 0 }},
+    { 78, 0, 3, 5, { 0 }},
+    { 79, 0, 3, 5, { 0 }},
+    { 80, 0, 3, 5, { 0 }},
+    { 81, 0, 3, 5, { 0 }},
+    { 82, 0, 3, 5, { 0 }},
+    { 83, 0, 3, 5, { 0 }},
+    { 84, 0, 3, 5, { 0 }},
+    { 85, 0, 3, 5, { 0 }},
+    { 86, 0, 3, 5, { 0 }},
+    { 87, 0, 3, 5, { 0 }},
+    { 88, 0, 3, 5, { 0 }},
+    { 89, 0, 3, 5, { 0 }},
+    { 90, 0, 3, 5, { 0 }},
+    { 91, 0, 3, 5, { 0 }},
+    { 92, 0, 3, 5, { 0 }},
+    { 93, 0, 3, 5, { 0 }},
+    { 94, 0, 3, 5, { 0 }},
+    { 95, 0, 12, 5, { 0 }},
+    { 96, 1, 4, 5, { 0 }},
+    { 97, 0, 6, 5, { 0 }},
+    { 98, 0, 3, 5, { 0 }},
+    { 99, 0, 6, 5, { 0 }},
+    { 100, 0, 3, 5, { 0 }},
+    { 101, 0, 6, 5, { 0 }},
+    { 102, 0, 3, 5, { 0 }},
+    { 103, 0, 6, 5, { 0 }},
+    { 104, 0, 3, 5, { 0 }},
+    { 105, 0, 3, 5, { 0 }},
+    { 106, 0, 3, 5, { 0 }},
+    { 107, 0, 3, 5, { 0 }},
+    { 108, 0, 3, 5, { 0 }},
+    { 109, 0, 6, 5, { 0 }},
+    { 110, 0, 6, 5, { 0 }},
+    { 111, 0, 6, 5, { 0 }},
+    { 112, 0, 6, 5, { 0 }},
+    { 113, 0, 6, 5, { 0 }},
+    { 114, 0, 6, 5, { 0 }},
+    { 115, 0, 6, 5, { 0 }},
+    { 116, 0, 3, 5, { 0 }},
+    { 117, 0, 6, 5, { 0 }},
+    { 118, 0, 6, 5, { 0 }},
+    { 119, 0, 6, 5, { 0 }},
+    { 120, 0, 6, 5, { 0 }},
+    { 121, 0, 6, 5, { 0 }},
+    { 122, 0, 6, 5, { 0 }},
+    { 123, 0, 3, 5, { 0 }},
+    { 124, 1, 3, 5, { 0 }},
+    { 125, 0, 3, 5, { 0 }},
+    { 126, 0, 8, 5, { 0 }},
+    { 161, 1, 4, 5, { 0 }},
+    { 162, 0, 6, 5, { 0 }},
+    { 163, 0, 3, 5, { 0 }},
+    { 8364, 0, 3, 5, { 0 }},
+    { 165, 0, 3, 5, { 0 }},
+    { 167, 0, 3, 5, { 0 }},
+    { 169, 0, 6, 5, { 0 }},
+    { 170, 2, 3, 5, { 0 }},
+    { 171, 0, 8, 5, { 0 }},
+    { 172, 0, 6, 5, { 0 }},
+    { 174, 0, 6, 5, { 0 }},
+    { 175, 0, 3, 5, { 0 }},
+    { 176, 1, 3, 5, { 0 }},
+    { 177, 0, 5, 5, { 0 }},
+    { 178, 2, 3, 5, { 0 }},
+    { 179, 2, 3, 5, { 0 }},
+    { 181, 0, 6, 5, { 0 }},
+    { 182, 0, 3, 5, { 0 }},
+    { 183, 1, 6, 5, { 0 }},
+    { 185, 0, 3, 5, { 0 }},
+    { 186, 0, 3, 5, { 0 }},
+    { 187, 0, 8, 5, { 0 }},
+    { 338, 0, 3, 5, { 0 }},
+    { 339, 0, 6, 5, { 0 }},
+    { 376, 0, 3, 5, { 0 }},
+    { 191, 0, 3, 5, { 0 }},
+    { 192, 0, -1, 5, { 0 }},
+    { 193, 0, -1, 5, { 0 }},
+    { 194, 0, -1, 5, { 0 }},
+    { 195, 0, -1, 5, { 0 }},
+    { 196, 0, 1, 5, { 0 }},
+    { 197, 0, 1, 5, { 0 }},
+    { 198, 0, 3, 5, { 0 }},
+    { 199, 0, 3, 5, { 0 }},
+    { 200, 0, -1, 5, { 0 }},
+    { 201, 0, -1, 5, { 0 }},
+    { 202, 0, -1, 5, { 0 }},
+    { 203, 0, 1, 5, { 0 }},
+    { 204, 0, -1, 5, { 0 }},
+    { 205, 0, -1, 5, { 0 }},
+    { 206, 0, -1, 5, { 0 }},
+    { 207, 0, 1, 5, { 0 }},
+    { 208, 0, 3, 5, { 0 }},
+    { 209, 0, -1, 5, { 0 }},
+    { 210, 0, -1, 5, { 0 }},
+    { 211, 0, -1, 5, { 0 }},
+    { 212, 0, -1, 5, { 0 }},
+    { 213, 0, -1, 5, { 0 }},
+    { 214, 0, 1, 5, { 0 }},
+    { 215, 0, 10, 5, { 0 }},
+    { 216, 0, 3, 5, { 0 }},
+    { 217, 0, -1, 5, { 0 }},
+    { 218, 0, -1, 5, { 0 }},
+    { 219, 0, -1, 5, { 0 }},
+    { 220, 0, 1, 5, { 0 }},
+    { 221, 0, -1, 5, { 0 }},
+    { 222, 0, 3, 5, { 0 }},
+    { 223, 0, 3, 5, { 0 }},
+    { 224, 0, 3, 5, { 0 }},
+    { 225, 0, 3, 5, { 0 }},
+    { 226, 0, 3, 5, { 0 }},
+    { 227, 0, 3, 5, { 0 }},
+    { 228, 0, 4, 5, { 0 }},
+    { 229, 0, 4, 5, { 0 }},
+    { 230, 0, 6, 5, { 0 }},
+    { 231, 0, 6, 5, { 0 }},
+    { 232, 0, 3, 5, { 0 }},
+    { 233, 0, 3, 5, { 0 }},
+    { 234, 0, 3, 5, { 0 }},
+    { 235, 0, 4, 5, { 0 }},
+    { 236, 0, 3, 5, { 0 }},
+    { 237, 0, 3, 5, { 0 }},
+    { 238, 0, 3, 5, { 0 }},
+    { 239, 0, 4, 5, { 0 }},
+    { 240, 0, 3, 5, { 0 }},
+    { 241, 0, 3, 5, { 0 }},
+    { 242, 0, 3, 5, { 0 }},
+    { 243, 0, 3, 5, { 0 }},
+    { 244, 0, 3, 5, { 0 }},
+    { 245, 0, 3, 5, { 0 }},
+    { 246, 0, 4, 5, { 0 }},
+    { 247, 0, 7, 5, { 0 }},
+    { 248, 0, 6, 5, { 0 }},
+    { 249, 0, 3, 5, { 0 }},
+    { 250, 0, 3, 5, { 0 }},
+    { 251, 0, 3, 5, { 0 }},
+    { 252, 0, 4, 5, { 0 }},
+    { 253, 0, 3, 5, { 0 }},
+    { 254, 0, 3, 5, { 0 }},
+    { 255, 0, 4, 5, { 0 }},
+};
+
+// Style loading function: Turbo
+static void GuiLoadStyleTurbo(void)
+{
+    // Load style properties provided
+    // NOTE: Default properties are propagated
+    for (int i = 0; i < TURBO_STYLE_PROPS_COUNT; i++)
+    {
+        GuiSetStyle(turboStyleProps[i].controlId, turboStyleProps[i].propertyId, turboStyleProps[i].propertyValue);
+    }
+
+    // Custom font loading
+    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
+    int turboFontDataSize = 0;
+    unsigned char *data = DecompressData(turboFontData, TURBO_STYLE_FONT_ATLAS_COMP_SIZE, &turboFontDataSize);
+    Image imFont = { data, 512, 256, 1, 2 };
+
+    Font font = { 0 };
+    font.baseSize = 16;
+    font.glyphCount = 185;
+
+    // Copy char recs data from global fontRecs
+    // NOTE: Required to avoid issues if trying to free font
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+    memcpy(font.recs, turboFontRecs, font.glyphCount*sizeof(Rectangle));
+
+    // Copy font char info data from global fontChars
+    // NOTE: Required to avoid issues if trying to free font
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+    memcpy(font.glyphs, turboFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
+
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 510, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
+    GuiSetFont(font);
+
+    // Setup a white rectangle on the font to be used on shapes drawing,
+    // it makes possible to draw shapes and text (full UI) in a single draw call
+    SetShapesTexture(font.texture, fontWhiteRec);
+
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "hello-world.ttf");
+    //-----------------------------------------------------------------
+
+    // TODO: Custom user style setup: Set specific properties here (if required)
+    // i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
+}
diff --git a/raygui/styles/wisteria/style_wisteria.h b/raygui/styles/wisteria/style_wisteria.h
new file mode 100644
--- /dev/null
+++ b/raygui/styles/wisteria/style_wisteria.h
@@ -0,0 +1,580 @@
+//////////////////////////////////////////////////////////////////////////////////
+//                                                                              //
+// StyleAsCode exporter v2.0 - Style data exported as a values array            //
+//                                                                              //
+// USAGE: On init call: GuiLoadStyleWisteria();                                   //
+//                                                                              //
+// more info and bugs-report:  github.com/raysan5/raygui                        //
+// feedback and support:       ray[at]raylibtech.com                            //
+//                                                                              //
+// Copyright (c) 2020-2026 raylib technologies (@raylibtech)                    //
+//                                                                              //
+//////////////////////////////////////////////////////////////////////////////////
+
+#define WISTERIA_STYLE_PROPS_COUNT  20
+
+// Custom style name: Wisteria
+static const GuiStyleProp wisteriaStyleProps[WISTERIA_STYLE_PROPS_COUNT] = {
+    { 0, 0, (int)0x6f748cff },    // DEFAULT_BORDER_COLOR_NORMAL
+    { 0, 1, (int)0xcfd0e1ff },    // DEFAULT_BASE_COLOR_NORMAL
+    { 0, 2, (int)0x8c91afff },    // DEFAULT_TEXT_COLOR_NORMAL
+    { 0, 3, (int)0xced9e3ff },    // DEFAULT_BORDER_COLOR_FOCUSED
+    { 0, 4, (int)0xe6edfcff },    // DEFAULT_BASE_COLOR_FOCUSED
+    { 0, 5, (int)0xc2d3e1ff },    // DEFAULT_TEXT_COLOR_FOCUSED
+    { 0, 6, (int)0x574695ff },    // DEFAULT_BORDER_COLOR_PRESSED
+    { 0, 7, (int)0xc3a5e6ff },    // DEFAULT_BASE_COLOR_PRESSED
+    { 0, 8, (int)0x825fb7ff },    // DEFAULT_TEXT_COLOR_PRESSED
+    { 0, 9, (int)0xb9bbc3ff },    // DEFAULT_BORDER_COLOR_DISABLED
+    { 0, 10, (int)0xcfd2daff },    // DEFAULT_BASE_COLOR_DISABLED
+    { 0, 11, (int)0xb5b8c2ff },    // DEFAULT_TEXT_COLOR_DISABLED
+    { 0, 16, (int)0x0000000c },    // DEFAULT_TEXT_SIZE 
+    { 0, 17, (int)0x00000000 },    // DEFAULT_TEXT_SPACING 
+    { 0, 18, (int)0x9b74d2ff },    // DEFAULT_LINE_COLOR 
+    { 0, 19, (int)0xe9eaf6ff },    // DEFAULT_BACKGROUND_COLOR 
+    { 0, 20, (int)0x00000008 },    // DEFAULT_TEXT_LINE_SPACING 
+    { 4, 3, (int)0xa9bdcfff },    // SLIDER_BORDER_COLOR_FOCUSED
+    { 4, 5, (int)0xacc4d8ff },    // SLIDER_TEXT_COLOR_FOCUSED
+    { 5, 3, (int)0xb5c7d9ff },    // PROGRESSBAR_BORDER_COLOR_FOCUSED
+};
+
+// WARNING: This style uses a custom font: "PixelIntv.otf" (size: 12, spacing: 0)
+
+#define WISTERIA_STYLE_FONT_ATLAS_COMP_SIZE 1995
+
+// Font atlas image pixels data: DEFLATE compressed
+static unsigned char wisteriaFontData[WISTERIA_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
+    0x9d, 0x3b, 0x8e, 0x25, 0x35, 0x14, 0x86, 0x8d, 0xe9, 0x8c, 0x10, 0x11, 0x80, 0x84, 0x98, 0x04, 0x89, 0x84, 0x84, 0xd1,
+    0x48, 0x90, 0xcd, 0x02, 0x88, 0x11, 0x22, 0x40, 0x44, 0x24, 0xc0, 0x1e, 0x98, 0x95, 0x4d, 0x42, 0xce, 0x06, 0xd8, 0x05,
+    0x0b, 0x38, 0x68, 0x5e, 0x4d, 0xf7, 0xdc, 0x2a, 0xdb, 0xe7, 0xe5, 0xf2, 0xad, 0xfb, 0xf5, 0xa7, 0x1e, 0x69, 0xca, 0xb7,
+    0xaa, 0x5c, 0xfe, 0x7d, 0xec, 0xea, 0xf6, 0xdf, 0xc7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x78, 0xf5, 0xb5, 0x7d, 0x6c,
+    0xab, 0xa4, 0xbc, 0x2d, 0x19, 0xbf, 0xd6, 0xbb, 0xe3, 0x6f, 0x4a, 0xea, 0xee, 0x27, 0xb6, 0xaf, 0x58, 0x77, 0xea, 0xb0,
+    0x57, 0xeb, 0xfd, 0x9a, 0x15, 0x55, 0xc9, 0xfe, 0xf5, 0xf7, 0xdb, 0xab, 0x28, 0x9e, 0xe1, 0xf1, 0x57, 0x51, 0x3c, 0x4b,
+    0xfb, 0xbc, 0x6c, 0xfd, 0xdb, 0x6d, 0xb0, 0x5f, 0xf6, 0xe6, 0xfb, 0x55, 0x4b, 0x54, 0xc5, 0x35, 0xf7, 0x3f, 0x5f, 0x54,
+    0x3d, 0x50, 0xdf, 0x33, 0x74, 0xad, 0xdb, 0xfa, 0x74, 0xef, 0x19, 0x44, 0x59, 0x83, 0x77, 0xc7, 0x33, 0xf5, 0x2f, 0xf7,
+    0xf7, 0x18, 0x8f, 0xff, 0x9e, 0x2a, 0x22, 0x77, 0x9b, 0x2d, 0x51, 0x9a, 0xda, 0x54, 0xc3, 0x9d, 0x22, 0x7a, 0x73, 0x09,
+    0x6a, 0xdd, 0xda, 0x7c, 0x06, 0x31, 0xe8, 0x6f, 0xeb, 0xa1, 0x51, 0xd7, 0xb1, 0xc5, 0xff, 0x2b, 0xee, 0x5e, 0xf7, 0x80,
+    0xf6, 0x55, 0xfd, 0x35, 0x8e, 0x8a, 0xff, 0x92, 0xaa, 0xbe, 0x47, 0xff, 0x19, 0xe3, 0x7f, 0xfb, 0xf3, 0xed, 0x36, 0xdb,
+    0xbe, 0x5e, 0x7d, 0x1b, 0xff, 0xfa, 0xd9, 0x33, 0x42, 0x7f, 0xfd, 0xfc, 0x9f, 0xab, 0x7e, 0xc4, 0xf8, 0xbf, 0xe2, 0x7b,
+    0x64, 0x6f, 0x1e, 0xdf, 0xee, 0x3b, 0x92, 0x1e, 0xff, 0x47, 0xd0, 0x52, 0xbf, 0xf7, 0xfe, 0x27, 0x8e, 0x71, 0x36, 0x3b,
+    0xfe, 0x2d, 0xd7, 0x7a, 0xd7, 0x12, 0x62, 0x88, 0xcf, 0x6b, 0xd5, 0xbf, 0xa5, 0x3e, 0x44, 0x8c, 0x35, 0x9a, 0x59, 0x1e,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9c, 0x2b, 0x26, 0xed, 0xf5, 0xf7, 0xc8, 0x95,
+    0xc8, 0xac, 0xb2, 0x71, 0xb7, 0x81, 0xc6, 0xb9, 0x52, 0x0d, 0x2d, 0x76, 0x54, 0xbb, 0x64, 0xb9, 0xfd, 0x8a, 0xda, 0x9b,
+    0x31, 0x52, 0x1b, 0xeb, 0xfd, 0x3c, 0xfa, 0x57, 0xe5, 0xda, 0x6b, 0xdb, 0xa1, 0xb7, 0xe7, 0x67, 0xdc, 0x5f, 0xb9, 0xf6,
+    0x3e, 0x9f, 0xb6, 0x4c, 0x37, 0x02, 0x94, 0x29, 0xf1, 0x3f, 0xe6, 0x61, 0xca, 0x71, 0x37, 0x6e, 0xfb, 0xcc, 0x5a, 0x75,
+    0xbd, 0x53, 0x3b, 0x0a, 0xff, 0x5f, 0x6d, 0xce, 0xed, 0xdf, 0xd1, 0xae, 0x4f, 0xab, 0xa3, 0xc4, 0xd2, 0x27, 0x2d, 0x0e,
+    0xd6, 0x88, 0xf1, 0x3f, 0x26, 0xfe, 0x5b, 0xfd, 0x54, 0xde, 0xfb, 0x8e, 0x19, 0xc7, 0x8f, 0xd2, 0x3f, 0x63, 0xac, 0x2e,
+    0x03, 0xa3, 0x82, 0xb5, 0x2e, 0xb6, 0xf9, 0xdf, 0xe2, 0xd4, 0x69, 0xb9, 0x95, 0xec, 0xef, 0x53, 0x47, 0xc4, 0xbf, 0x27,
+    0xc6, 0x6d, 0xe3, 0x7f, 0x5b, 0xff, 0x38, 0x77, 0x9b, 0x1c, 0xf2, 0x36, 0x3d, 0x12, 0x63, 0x6b, 0xcd, 0xff, 0x10, 0xe9,
+    0x67, 0x3c, 0xee, 0xe7, 0x29, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5c,
+    0x3f, 0xde, 0x2c, 0x4f, 0x89, 0x0c, 0x66, 0xf1, 0xd9, 0xf7, 0x6b, 0xcd, 0x72, 0xeb, 0xcd, 0x6f, 0xef, 0x68, 0xdf, 0x47,
+    0xc4, 0x9a, 0xb4, 0x25, 0x83, 0x99, 0xdf, 0x8b, 0x28, 0x4b, 0x38, 0xf2, 0x32, 0xda, 0xed, 0x48, 0xfd, 0x2d, 0xf5, 0xb1,
+    0xeb, 0x2f, 0xc6, 0x0c, 0x83, 0xbd, 0xcc, 0x30, 0x6b, 0xe9, 0x6f, 0x71, 0x1d, 0x78, 0xf4, 0xef, 0x8f, 0x55, 0xa5, 0xa1,
+    0x87, 0x7e, 0x8c, 0xb7, 0xea, 0x2f, 0xc6, 0xbc, 0x8f, 0x39, 0xb3, 0x58, 0x8e, 0xfe, 0x96, 0x76, 0x3b, 0xcb, 0xf8, 0xdf,
+    0xbf, 0x66, 0x35, 0x8e, 0xff, 0xd2, 0x1d, 0x55, 0x24, 0xdc, 0x8d, 0xaa, 0x8f, 0xa9, 0xd1, 0xf6, 0xb9, 0x5d, 0xfd, 0x4b,
+    0x8a, 0xfe, 0x39, 0x77, 0xbc, 0x9e, 0xf9, 0xdf, 0x92, 0xbd, 0xfa, 0x08, 0x9f, 0x9b, 0xcf, 0x1b, 0xde, 0x2b, 0x9d, 0xd1,
+    0x32, 0x79, 0xe3, 0x3f, 0x2e, 0xc0, 0xeb, 0x71, 0x89, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xcc, 0x58, 0xa3, 0xb0, 0xaf, 0x9d, 0x65, 0xac, 0x00, 0x5e, 0x1e, 0xaf, 0x03, 0x6b, 0x98, 0xef, 0x1f, 0xaf, 0x3b,
+    0x8e, 0x11, 0x51, 0xe6, 0xfc, 0xb3, 0xed, 0xc7, 0x3b, 0x9a, 0x07, 0xcd, 0xee, 0x20, 0x8c, 0x58, 0x07, 0x9c, 0xaf, 0x7f,
+    0x19, 0x5a, 0x8f, 0xbd, 0x54, 0xb2, 0x1a, 0x3c, 0x43, 0x55, 0x99, 0xf1, 0xa9, 0x95, 0x21, 0x4a, 0xef, 0x66, 0xea, 0xb7,
+    0x82, 0x25, 0xd7, 0x5d, 0xef, 0x6a, 0xb6, 0x1d, 0x8a, 0x5b, 0xee, 0x98, 0x9e, 0x97, 0x45, 0xff, 0xe4, 0x55, 0xfd, 0x6c,
+    0x75, 0x60, 0x0c, 0xc8, 0xf7, 0x48, 0x17, 0x75, 0x3c, 0xfa, 0x7c, 0x77, 0xf9, 0xfa, 0x97, 0x01, 0x8f, 0x5f, 0xb4, 0x23,
+    0x45, 0x3a, 0xbb, 0xdf, 0x5a, 0x7a, 0x40, 0xb6, 0xfe, 0xbd, 0x67, 0xb5, 0xbb, 0x84, 0x4a, 0x68, 0xbf, 0x89, 0xd6, 0x7f,
+    0xa4, 0x9f, 0x46, 0xf7, 0x60, 0x4b, 0x0f, 0x98, 0x13, 0xff, 0xa2, 0xd6, 0xbf, 0x3d, 0x36, 0xc4, 0xb7, 0x9e, 0xc5, 0x05,
+    0x64, 0x1b, 0x51, 0xbc, 0x6e, 0x35, 0x8b, 0x8a, 0xd5, 0x34, 0x72, 0xcc, 0x78, 0x83, 0xb6, 0xed, 0x55, 0x1d, 0xed, 0xd8,
+    0xb4, 0xb5, 0xc4, 0x7c, 0xfd, 0xc5, 0xbc, 0xe3, 0x77, 0x5d, 0x6e, 0xf7, 0x6b, 0x5b, 0xd4, 0xd9, 0x1d, 0x7b, 0xf1, 0xf1,
+    0xbf, 0xde, 0x5f, 0xa3, 0xcd, 0x38, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x36,
+    0x73, 0x14, 0xe8, 0x33, 0xd5, 0xf4, 0xcf, 0xb0, 0xee, 0x9d, 0x35, 0x73, 0xef, 0xdc, 0xac, 0xfd, 0xed, 0xec, 0x79, 0xc1,
+    0x24, 0x65, 0x07, 0xb8, 0xf8, 0x75, 0x33, 0x5f, 0x16, 0xb3, 0x5e, 0x0b, 0x59, 0x33, 0x6e, 0x69, 0x3d, 0x18, 0x1e, 0x5f,
+    0x8f, 0xd5, 0xf3, 0x11, 0xef, 0xc3, 0x8b, 0xf1, 0xb6, 0xd9, 0xe2, 0xdf, 0xe6, 0x0b, 0x59, 0x4d, 0xff, 0x32, 0xc9, 0x9f,
+    0xe7, 0xd1, 0xdf, 0xbb, 0xfb, 0xb3, 0xdd, 0x91, 0xa5, 0x6f, 0xd5, 0x33, 0xe8, 0x3f, 0xe6, 0xde, 0xb5, 0xf8, 0x08, 0xa3,
+    0x7d, 0x78, 0x47, 0xe9, 0x2f, 0xa6, 0xbd, 0x73, 0x3d, 0xfa, 0xfb, 0xfc, 0xf2, 0xf3, 0xe2, 0xdf, 0x7e, 0xc7, 0x92, 0xb2,
+    0x33, 0xba, 0x37, 0x5a, 0x75, 0x99, 0x1a, 0x8f, 0x70, 0x6a, 0xc5, 0xfb, 0xe5, 0xb2, 0x9c, 0x5d, 0xc7, 0xba, 0x17, 0xa3,
+    0xfc, 0xab, 0xde, 0xec, 0xdf, 0x47, 0xe8, 0x8f, 0x77, 0xec, 0xdc, 0xbd, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xe0, 0xd6, 0xd6, 0x71, 0xe2, 0xf6, 0xa3, 0xd2, 0x66, 0x75, 0x93, 0xcd, 0x8c, 0x1e, 0xd6, 0xdc,
+    0x31, 0x5a, 0x6f, 0x85, 0x75, 0xad, 0xb2, 0x3e, 0x28, 0xbb, 0xf4, 0x39, 0x7c, 0x2b, 0x4f, 0xee, 0x79, 0x2a, 0x9f, 0xec,
+    0x66, 0x31, 0xd9, 0x7a, 0xf2, 0xde, 0xb9, 0xde, 0x3b, 0xeb, 0x1d, 0x00, 0xba, 0x5c, 0x6d, 0xba, 0xa3, 0xb5, 0xe9, 0x14,
+    0x89, 0x71, 0x5d, 0x58, 0x33, 0xf4, 0xb5, 0xcb, 0xea, 0x23, 0x25, 0x1f, 0xf3, 0xec, 0x51, 0xeb, 0x3d, 0xdd, 0x6c, 0xd1,
+    0xba, 0x93, 0xcb, 0xa8, 0x77, 0xae, 0xef, 0xce, 0x5a, 0xfd, 0xab, 0x3a, 0x57, 0x9b, 0x5e, 0x9d, 0x18, 0x5f, 0xa1, 0x2d,
+    0x2b, 0x8e, 0x67, 0x57, 0x71, 0x79, 0xe0, 0x58, 0x7a, 0xcc, 0x93, 0xc6, 0xff, 0xde, 0x9c, 0x7d, 0x77, 0xff, 0xaf, 0xfe,
+    0x5c, 0xcf, 0x9d, 0xf5, 0x4e, 0x1e, 0x9b, 0x8b, 0xcb, 0xdb, 0x03, 0x22, 0xb3, 0x29, 0x5a, 0x1d, 0x59, 0xed, 0x7e, 0x53,
+    0x1a, 0x3b, 0x47, 0xf6, 0x54, 0x68, 0xc5, 0xff, 0x98, 0xfe, 0xd6, 0x3b, 0x17, 0xa3, 0x3f, 0x4e, 0x16, 0x89, 0xff, 0x8c,
+    0xac, 0x78, 0xb6, 0xdd, 0x68, 0x7d, 0x51, 0xb8, 0x3f, 0xff, 0xcf, 0xd7, 0xdf, 0xea, 0x82, 0x9b, 0xad, 0x7f, 0x31, 0xfb,
+    0x54, 0xbd, 0x6f, 0x8d, 0xda, 0xf9, 0xdf, 0xae, 0xc2, 0x88, 0xfe, 0xd1, 0x77, 0x8e, 0xcd, 0x1a, 0x99, 0xab, 0x7f, 0x71,
+    0x38, 0x6b, 0x23, 0x77, 0xa3, 0x6f, 0xbf, 0x85, 0x67, 0xea, 0x9f, 0x77, 0xe7, 0x18, 0x67, 0xa5, 0x2d, 0xab, 0xe3, 0xca,
+    0x7f, 0x19, 0xa7, 0xaf, 0xfd, 0xcf, 0x0f, 0x7e, 0x0a, 0x7b, 0x26, 0xdf, 0x4d, 0x3b, 0xd7, 0x7b, 0x36, 0x1c, 0xed, 0x55,
+    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe2, 0xd3, 0x4d, 0x8f, 0x47, 0xcf, 0x49, 0xe6,
+    0x2d, 0xef, 0xb9, 0xce, 0xbe, 0x94, 0xaf, 0xe5, 0xf3, 0x8b, 0xa3, 0x2f, 0xe5, 0xa5, 0xfc, 0x92, 0x50, 0x97, 0xba, 0xbb,
+    0xc7, 0xf0, 0xd6, 0x97, 0xe5, 0x33, 0xfd, 0x75, 0xe8, 0x7d, 0x17, 0x5c, 0xed, 0x78, 0xf3, 0xaa, 0xca, 0x5b, 0xf9, 0x98,
+    0xef, 0xe5, 0xb9, 0xfc, 0xbe, 0x71, 0xbc, 0xe7, 0x24, 0xf3, 0x96, 0xb7, 0xf4, 0xff, 0x4c, 0xfe, 0x91, 0xbf, 0xe5, 0x85,
+    0x7c, 0xb1, 0x79, 0xd6, 0x9f, 0xe1, 0x75, 0x69, 0xf9, 0x71, 0x34, 0x3b, 0x19, 0x7b, 0x32, 0x31, 0x55, 0x53, 0xdf, 0xd8,
+    0xdf, 0xe1, 0x78, 0xd4, 0x5b, 0xf9, 0x93, 0x7c, 0x20, 0x3f, 0x6c, 0x38, 0xd1, 0x7a, 0x2b, 0xc9, 0xde, 0xf2, 0x96, 0xfe,
+    0x7f, 0x88, 0xc8, 0x5f, 0xf2, 0xab, 0x7c, 0x78, 0x51, 0xf2, 0x5c, 0x9e, 0x27, 0xd4, 0xa5, 0xc8, 0xdd, 0xeb, 0x7a, 0xdc,
+    0x39, 0x77, 0xb2, 0xf6, 0xc4, 0xff, 0x51, 0x7c, 0x2c, 0x3f, 0xca, 0x37, 0x06, 0x1f, 0x42, 0xa6, 0xfe, 0x5f, 0xc9, 0xbf,
+    0x3b, 0xfa, 0xdb, 0x3c, 0x13, 0x1e, 0x3f, 0xde, 0xa5, 0xb6, 0xc5, 0xdc, 0x47, 0xac, 0x3b, 0x62, 0x46, 0x97, 0xcd, 0x68,
+    0xd3, 0x11, 0xfd, 0xf7, 0xeb, 0xf7, 0x91, 0xbc, 0x98, 0xa8, 0x7f, 0x6f, 0xfe, 0x2f, 0x8a, 0x9c, 0xaf, 0xd6, 0xbd, 0xc0,
+    0x4b, 0xf0, 0x2e, 0xfb, 0xbe, 0xac, 0x80, 0xb3, 0xe2, 0x7f, 0x9f, 0xdf, 0x26, 0xea, 0x9f, 0xe3, 0x02, 0x3a, 0x56, 0x63,
+    0xf4, 0x8f, 0xd3, 0x7f, 0xe4, 0xdd, 0xde, 0xe3, 0x26, 0x5a, 0x71, 0xfc, 0xef, 0x39, 0xc9, 0xbc, 0xe5, 0x3d, 0x34, 0xfa,
+    0x67, 0xd7, 0xe5, 0x48, 0xa7, 0xe1, 0x51, 0xf1, 0x0f, 0xe8, 0x0f, 0xe8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xe7, 0xfc, 0xdd, 0x63, 0x19, 0xd8, 0xad, 0xd0, 0xb3, 0x06, 0x15, 0xed, 0x79, 0xeb, 0x3f, 0xcb, 0xbc, 0xfb,
+    0xb5, 0x9e, 0xbc, 0xe7, 0xcd, 0x8b, 0xae, 0x67, 0x96, 0xfe, 0x1e, 0x5f, 0x43, 0x8e, 0xe7, 0x6d, 0x9d, 0xfb, 0xf5, 0xb2,
+    0x07, 0xb6, 0xb4, 0x8a, 0xae, 0xe7, 0x51, 0xd9, 0x51, 0x6e, 0x79, 0xed, 0x41, 0xba, 0x0e, 0xe7, 0xf5, 0xb3, 0x9c, 0xe8,
+    0x3c, 0xcf, 0x45, 0xed, 0x79, 0x5a, 0xc5, 0x0f, 0x91, 0x55, 0x56, 0x1a, 0xd9, 0xe3, 0x8a, 0x21, 0xcb, 0x5d, 0x86, 0xdf,
+    0x23, 0x73, 0x7d, 0x71, 0xa5, 0xb2, 0xd9, 0xf7, 0xbc, 0x16, 0xbf, 0xd7, 0x0c, 0xfd, 0xad, 0x7e, 0xc8, 0x33, 0xeb, 0x2f,
+    0x0b, 0xe9, 0xef, 0x1d, 0xdf, 0x7c, 0xe3, 0x55, 0x99, 0x52, 0x76, 0x84, 0xfe, 0x23, 0xfb, 0xb9, 0x5f, 0x6b, 0xfc, 0x6b,
+    0xaf, 0x7f, 0x6b, 0xf1, 0xdf, 0xaf, 0xc7, 0x2d, 0xe8, 0x2f, 0xe8, 0xbf, 0xb8, 0xdf, 0xeb, 0x28, 0x0f, 0xd9, 0xd9, 0xdf,
+    0xff, 0xc7, 0xfa, 0xe1, 0x3a, 0x7e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1f, 0x2d, 0x2f,
+    0x9a, 0xe7, 0x77, 0xd1, 0x2b, 0xf9, 0xfe, 0xaa, 0x29, 0x1f, 0x57, 0xfb, 0x19, 0x6c, 0x1e, 0x2d, 0x5b, 0xbe, 0x3e, 0xab,
+    0x47, 0x6f, 0xec, 0x77, 0xd1, 0xd6, 0x76, 0xb5, 0xe7, 0xc3, 0x9a, 0xed, 0xfb, 0x6b, 0xed, 0x60, 0x6b, 0x59, 0x87, 0xb5,
+    0xf7, 0x61, 0x5b, 0xbe, 0xbe, 0x4c, 0xfd, 0x23, 0x3c, 0x80, 0x5b, 0xc7, 0xeb, 0x15, 0xac, 0x45, 0x90, 0x3f, 0xc1, 0xb3,
+    0xa6, 0xd4, 0x2b, 0xa9, 0x4b, 0x78, 0x9f, 0x7c, 0x65, 0xf3, 0xfc, 0x29, 0x59, 0x9e, 0x97, 0xd5, 0xd6, 0xa2, 0xcf, 0x50,
+    0xb6, 0x9e, 0xbb, 0x71, 0xbe, 0xfe, 0x67, 0xe9, 0x53, 0x56, 0x1f, 0xd6, 0xad, 0xc7, 0xbf, 0x67, 0x4e, 0x59, 0xad, 0x6f,
+    0xd8, 0x3c, 0x5a, 0xad, 0x77, 0xdf, 0x35, 0xca, 0x56, 0x7c, 0x07, 0x5a, 0x29, 0xc6, 0xcf, 0xee, 0x5d, 0x42, 0x7f, 0xfe,
+    0x0e, 0x29, 0xef, 0xfd, 0xff, 0x3a, 0x62, 0x07, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdf,
+    0xff, 0x92, 0xc5, 0x4f, 0xe7, 0x72, 0xe9, 0x65, 0xf1, 0x5b, 0xc9, 0x21, 0x98, 0xb9, 0x0a, 0x74, 0xe6, 0x2c, 0x7e, 0xa5,
+    0xd9, 0x33, 0xda, 0x59, 0xfc, 0x56, 0x72, 0x08, 0x7a, 0xe3, 0x9f, 0xd1, 0xf1, 0xac, 0x6d, 0xd0, 0xf7, 0x0f, 0xac, 0x94,
+    0xc5, 0xaf, 0x74, 0xf3, 0x3b, 0xc5, 0x96, 0x8d, 0xb9, 0x00, 0xaf, 0xd9, 0x05, 0xe0, 0x9b, 0xff, 0x57, 0x5b, 0xcd, 0xcf,
+    0xc9, 0xe2, 0xa6, 0x2f, 0xbd, 0xb6, 0xdd, 0x5e, 0x3d, 0x4e, 0xef, 0x95, 0x56, 0xf3, 0xd1, 0x5f, 0xd2, 0x66, 0xc1, 0x55,
+    0xbc, 0xac, 0xab, 0x64, 0xf1, 0xbb, 0xa5, 0xf8, 0xbf, 0x76, 0x27, 0x5c, 0xde, 0xdc, 0x59, 0x4e, 0xe1, 0x02, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf3, 0x79, 0x40, 0x2c, 0xde, 0x97, 0x68, 0x7f, 0x9b, 0x27,
+    0x8b, 0x9f, 0x18, 0x7c, 0x6d, 0xd0, 0x5f, 0xdd, 0xaa, 0xe1, 0xbe, 0xcf, 0xf8, 0x2c, 0x7e, 0x05, 0xfd, 0x43, 0x56, 0x70,
+    0xb7, 0x4b, 0xea, 0x15, 0xb4, 0x1d, 0x6b, 0x9f, 0x99, 0x9e, 0x9f, 0x55, 0x32, 0x20, 0x59, 0xce, 0xbc, 0x96, 0x5d, 0x98,
+    0xaf, 0x6d, 0xfe, 0x9f, 0x9f, 0xc9, 0xea, 0xa8, 0xfc, 0x58, 0x50, 0x26, 0xc6, 0x38, 0xfa, 0xa3, 0xbf, 0xc7, 0x89, 0x8d,
+    0xfe, 0xe7, 0xf4, 0xfd, 0x8d, 0x68, 0xcc, 0xbb, 0xe1, 0xed, 0xbc, 0x93, 0x6a, 0xff, 0x42, 0x09, 0xfd, 0xcf, 0xfb, 0x73,
+    0x2a, 0x3f, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xc0, 0x6a, 0x90, 0x0d, 0x11, 0xfd, 0xd1, 0xff, 0xc6, 0xf5, 0xff, 0x0f };
+
+// Font glyphs rectangles data (on atlas)
+static const Rectangle wisteriaFontRecs[184] = {
+    { 4, 4, 5 , 12 },
+    { 17, 4, 2 , 7 },
+    { 27, 4, 5 , 3 },
+    { 40, 4, 5 , 5 },
+    { 53, 4, 6 , 7 },
+    { 67, 4, 7 , 7 },
+    { 82, 4, 5 , 7 },
+    { 95, 4, 3 , 3 },
+    { 106, 4, 4 , 8 },
+    { 118, 4, 4 , 8 },
+    { 130, 4, 5 , 5 },
+    { 143, 4, 5 , 5 },
+    { 156, 4, 2 , 3 },
+    { 166, 4, 5 , 1 },
+    { 179, 4, 2 , 2 },
+    { 189, 4, 7 , 7 },
+    { 204, 4, 7 , 6 },
+    { 219, 4, 6 , 6 },
+    { 233, 4, 6 , 6 },
+    { 4, 24, 6 , 6 },
+    { 18, 24, 6 , 6 },
+    { 32, 24, 6 , 6 },
+    { 46, 24, 6 , 6 },
+    { 60, 24, 6 , 6 },
+    { 74, 24, 6 , 6 },
+    { 88, 24, 6 , 6 },
+    { 102, 24, 2 , 5 },
+    { 112, 24, 2 , 6 },
+    { 122, 24, 3 , 5 },
+    { 133, 24, 5 , 3 },
+    { 146, 24, 3 , 5 },
+    { 157, 24, 6 , 7 },
+    { 171, 24, 7 , 7 },
+    { 186, 24, 6 , 7 },
+    { 200, 24, 6 , 7 },
+    { 214, 24, 6 , 7 },
+    { 228, 24, 6 , 7 },
+    { 4, 44, 6 , 7 },
+    { 18, 44, 6 , 7 },
+    { 32, 44, 6 , 7 },
+    { 46, 44, 6 , 7 },
+    { 60, 44, 6 , 7 },
+    { 74, 44, 6 , 7 },
+    { 88, 44, 6 , 7 },
+    { 102, 44, 6 , 7 },
+    { 116, 44, 7 , 7 },
+    { 131, 44, 6 , 7 },
+    { 145, 44, 6 , 7 },
+    { 159, 44, 6 , 7 },
+    { 173, 44, 7 , 8 },
+    { 188, 44, 6 , 7 },
+    { 202, 44, 6 , 7 },
+    { 216, 44, 6 , 7 },
+    { 230, 44, 6 , 7 },
+    { 4, 64, 6 , 7 },
+    { 18, 64, 7 , 7 },
+    { 33, 64, 6 , 7 },
+    { 47, 64, 6 , 7 },
+    { 61, 64, 6 , 7 },
+    { 75, 64, 4 , 8 },
+    { 87, 64, 7 , 7 },
+    { 102, 64, 4 , 8 },
+    { 114, 64, 4 , 2 },
+    { 126, 64, 6 , 1 },
+    { 140, 64, 2 , 2 },
+    { 150, 64, 6 , 5 },
+    { 164, 64, 6 , 7 },
+    { 178, 64, 6 , 5 },
+    { 192, 64, 6 , 7 },
+    { 206, 64, 6 , 5 },
+    { 220, 64, 6 , 7 },
+    { 234, 64, 6 , 7 },
+    { 4, 84, 6 , 7 },
+    { 18, 84, 6 , 7 },
+    { 32, 84, 5 , 8 },
+    { 45, 84, 6 , 7 },
+    { 59, 84, 6 , 7 },
+    { 73, 84, 7 , 5 },
+    { 88, 84, 6 , 5 },
+    { 102, 84, 6 , 5 },
+    { 116, 84, 6 , 7 },
+    { 130, 84, 6 , 7 },
+    { 144, 84, 6 , 5 },
+    { 158, 84, 6 , 5 },
+    { 172, 84, 6 , 6 },
+    { 186, 84, 6 , 5 },
+    { 200, 84, 6 , 5 },
+    { 214, 84, 7 , 5 },
+    { 229, 84, 6 , 5 },
+    { 4, 104, 6 , 7 },
+    { 18, 104, 6 , 5 },
+    { 32, 104, 4 , 8 },
+    { 44, 104, 2 , 8 },
+    { 54, 104, 4 , 8 },
+    { 66, 104, 5 , 2 },
+    { 79, 104, 2 , 7 },
+    { 89, 104, 6 , 6 },
+    { 103, 104, 6 , 7 },
+    { 117, 104, 6 , 7 },
+    { 131, 104, 6 , 7 },
+    { 145, 104, 6 , 9 },
+    { 159, 104, 7 , 7 },
+    { 174, 104, 8 , 8 },
+    { 190, 104, 6 , 5 },
+    { 204, 104, 8 , 8 },
+    { 220, 104, 7 , 7 },
+    { 235, 104, 8 , 8 },
+    { 4, 124, 4 , 4 },
+    { 16, 124, 8 , 8 },
+    { 32, 124, 8 , 8 },
+    { 48, 124, 8 , 8 },
+    { 64, 124, 6 , 7 },
+    { 78, 124, 5 , 8 },
+    { 91, 124, 3 , 3 },
+    { 102, 124, 8 , 8 },
+    { 118, 124, 8 , 8 },
+    { 134, 124, 6 , 5 },
+    { 148, 124, 10 , 7 },
+    { 166, 124, 10 , 5 },
+    { 184, 124, 6 , 7 },
+    { 198, 124, 6 , 10 },
+    { 212, 124, 6 , 10 },
+    { 226, 124, 6 , 10 },
+    { 240, 124, 6 , 10 },
+    { 4, 144, 6 , 10 },
+    { 18, 144, 6 , 10 },
+    { 32, 144, 10 , 7 },
+    { 50, 144, 6 , 9 },
+    { 64, 144, 6 , 10 },
+    { 78, 144, 6 , 10 },
+    { 92, 144, 6 , 10 },
+    { 106, 144, 6 , 10 },
+    { 120, 144, 6 , 10 },
+    { 134, 144, 6 , 10 },
+    { 148, 144, 6 , 10 },
+    { 162, 144, 6 , 10 },
+    { 176, 144, 6 , 7 },
+    { 190, 144, 6 , 10 },
+    { 204, 144, 6 , 10 },
+    { 218, 144, 6 , 10 },
+    { 232, 144, 6 , 10 },
+    { 4, 164, 6 , 10 },
+    { 18, 164, 6 , 10 },
+    { 32, 164, 6 , 5 },
+    { 46, 164, 6 , 7 },
+    { 60, 164, 6 , 10 },
+    { 74, 164, 6 , 10 },
+    { 88, 164, 6 , 10 },
+    { 102, 164, 6 , 10 },
+    { 116, 164, 6 , 10 },
+    { 130, 164, 6 , 7 },
+    { 144, 164, 6 , 7 },
+    { 158, 164, 6 , 8 },
+    { 172, 164, 6 , 8 },
+    { 186, 164, 6 , 8 },
+    { 200, 164, 6 , 8 },
+    { 214, 164, 6 , 8 },
+    { 228, 164, 6 , 8 },
+    { 4, 184, 9 , 5 },
+    { 21, 184, 6 , 7 },
+    { 35, 184, 6 , 8 },
+    { 49, 184, 6 , 8 },
+    { 63, 184, 6 , 8 },
+    { 77, 184, 6 , 8 },
+    { 91, 184, 6 , 8 },
+    { 105, 184, 6 , 8 },
+    { 119, 184, 6 , 8 },
+    { 133, 184, 6 , 8 },
+    { 147, 184, 6 , 7 },
+    { 161, 184, 6 , 8 },
+    { 175, 184, 6 , 8 },
+    { 189, 184, 6 , 8 },
+    { 203, 184, 6 , 8 },
+    { 217, 184, 6 , 8 },
+    { 231, 184, 6 , 8 },
+    { 4, 204, 5 , 5 },
+    { 17, 204, 6 , 5 },
+    { 31, 204, 6 , 8 },
+    { 45, 204, 6 , 8 },
+    { 59, 204, 6 , 8 },
+    { 73, 204, 6 , 8 },
+    { 87, 204, 6 , 10 },
+    { 101, 204, 6 , 9 },
+    { 115, 204, 6 , 10 },
+};
+
+// Font glyphs info data
+// NOTE: No glyphs.image data provided
+static const GlyphInfo wisteriaFontGlyphs[184] = {
+    { 32, 0, 0, 5, { 0 }},
+    { 33, 0, 2, 3, { 0 }},
+    { 34, 0, 2, 6, { 0 }},
+    { 35, 0, 3, 6, { 0 }},
+    { 36, 0, 2, 7, { 0 }},
+    { 37, 0, 2, 8, { 0 }},
+    { 38, 0, 2, 6, { 0 }},
+    { 39, 0, 2, 4, { 0 }},
+    { 40, 0, 2, 5, { 0 }},
+    { 41, 0, 2, 5, { 0 }},
+    { 42, 0, 2, 6, { 0 }},
+    { 43, 0, 3, 6, { 0 }},
+    { 44, 0, 7, 3, { 0 }},
+    { 45, 0, 5, 6, { 0 }},
+    { 46, 0, 7, 3, { 0 }},
+    { 47, 0, 2, 8, { 0 }},
+    { 48, 0, 3, 8, { 0 }},
+    { 49, 0, 3, 7, { 0 }},
+    { 50, 0, 3, 7, { 0 }},
+    { 51, 0, 3, 7, { 0 }},
+    { 52, 0, 3, 7, { 0 }},
+    { 53, 0, 3, 7, { 0 }},
+    { 54, 0, 3, 7, { 0 }},
+    { 55, 0, 3, 7, { 0 }},
+    { 56, 0, 3, 7, { 0 }},
+    { 57, 0, 3, 7, { 0 }},
+    { 58, 0, 4, 3, { 0 }},
+    { 59, 0, 4, 3, { 0 }},
+    { 60, 0, 3, 4, { 0 }},
+    { 61, 0, 4, 6, { 0 }},
+    { 62, 0, 3, 4, { 0 }},
+    { 63, 0, 2, 7, { 0 }},
+    { 64, 0, 2, 8, { 0 }},
+    { 65, 0, 2, 7, { 0 }},
+    { 66, 0, 2, 7, { 0 }},
+    { 67, 0, 2, 7, { 0 }},
+    { 68, 0, 2, 7, { 0 }},
+    { 69, 0, 2, 7, { 0 }},
+    { 70, 0, 2, 7, { 0 }},
+    { 71, 0, 2, 7, { 0 }},
+    { 72, 0, 2, 7, { 0 }},
+    { 73, 0, 2, 7, { 0 }},
+    { 74, 0, 2, 7, { 0 }},
+    { 75, 0, 2, 7, { 0 }},
+    { 76, 0, 2, 7, { 0 }},
+    { 77, 0, 2, 8, { 0 }},
+    { 78, 0, 2, 7, { 0 }},
+    { 79, 0, 2, 7, { 0 }},
+    { 80, 0, 2, 7, { 0 }},
+    { 81, 0, 2, 7, { 0 }},
+    { 82, 0, 2, 7, { 0 }},
+    { 83, 0, 2, 7, { 0 }},
+    { 84, 0, 2, 7, { 0 }},
+    { 85, 0, 2, 7, { 0 }},
+    { 86, 0, 2, 7, { 0 }},
+    { 87, 0, 2, 8, { 0 }},
+    { 88, 0, 2, 7, { 0 }},
+    { 89, 0, 2, 7, { 0 }},
+    { 90, 0, 2, 7, { 0 }},
+    { 91, 0, 2, 5, { 0 }},
+    { 92, 0, 2, 8, { 0 }},
+    { 93, 0, 2, 5, { 0 }},
+    { 94, 0, -1, 5, { 0 }},
+    { 95, 0, 10, 7, { 0 }},
+    { 96, 0, -1, 3, { 0 }},
+    { 97, 0, 4, 7, { 0 }},
+    { 98, 0, 2, 7, { 0 }},
+    { 99, 0, 4, 7, { 0 }},
+    { 100, 0, 2, 7, { 0 }},
+    { 101, 0, 4, 7, { 0 }},
+    { 102, 0, 2, 7, { 0 }},
+    { 103, 0, 4, 7, { 0 }},
+    { 104, 0, 2, 7, { 0 }},
+    { 105, 0, 2, 7, { 0 }},
+    { 106, 0, 2, 6, { 0 }},
+    { 107, 0, 2, 7, { 0 }},
+    { 108, 0, 2, 7, { 0 }},
+    { 109, 0, 4, 8, { 0 }},
+    { 110, 0, 4, 7, { 0 }},
+    { 111, 0, 4, 7, { 0 }},
+    { 112, 0, 4, 7, { 0 }},
+    { 113, 0, 4, 7, { 0 }},
+    { 114, 0, 4, 7, { 0 }},
+    { 115, 0, 4, 7, { 0 }},
+    { 116, 0, 3, 7, { 0 }},
+    { 117, 0, 4, 7, { 0 }},
+    { 118, 0, 4, 7, { 0 }},
+    { 119, 0, 4, 8, { 0 }},
+    { 120, 0, 4, 7, { 0 }},
+    { 121, 0, 4, 7, { 0 }},
+    { 122, 0, 4, 7, { 0 }},
+    { 123, 0, 2, 5, { 0 }},
+    { 124, 0, 2, 3, { 0 }},
+    { 125, 0, 2, 5, { 0 }},
+    { 126, 0, -1, 6, { 0 }},
+    { 161, 0, 2, 3, { 0 }},
+    { 162, 0, 3, 7, { 0 }},
+    { 163, 0, 2, 7, { 0 }},
+    { 8364, 0, 2, 7, { 0 }},
+    { 165, 0, 2, 7, { 0 }},
+    { 167, 0, 1, 7, { 0 }},
+    { 169, 0, 2, 8, { 0 }},
+    { 170, 0, 1, 8, { 0 }},
+    { 171, 0, 3, 7, { 0 }},
+    { 172, 0, 1, 8, { 0 }},
+    { 174, 0, 2, 8, { 0 }},
+    { 175, 0, 1, 8, { 0 }},
+    { 176, 0, 1, 2, { 0 }},
+    { 177, 0, 1, 8, { 0 }},
+    { 178, 0, 1, 8, { 0 }},
+    { 179, 0, 1, 8, { 0 }},
+    { 181, 0, 4, 7, { 0 }},
+    { 182, 0, 1, 4, { 0 }},
+    { 183, 0, 4, 4, { 0 }},
+    { 185, 0, 1, 8, { 0 }},
+    { 186, 0, 1, 8, { 0 }},
+    { 187, 0, 3, 7, { 0 }},
+    { 338, 0, 2, 11, { 0 }},
+    { 339, 0, 4, 11, { 0 }},
+    { 191, 0, 2, 7, { 0 }},
+    { 192, 0, -1, 7, { 0 }},
+    { 193, 0, -1, 7, { 0 }},
+    { 194, 0, -1, 7, { 0 }},
+    { 195, 0, -1, 7, { 0 }},
+    { 196, 0, -1, 7, { 0 }},
+    { 197, 0, -1, 7, { 0 }},
+    { 198, 0, 2, 11, { 0 }},
+    { 199, 0, 2, 7, { 0 }},
+    { 200, 0, -1, 7, { 0 }},
+    { 201, 0, -1, 7, { 0 }},
+    { 202, 0, -1, 7, { 0 }},
+    { 203, 0, -1, 7, { 0 }},
+    { 204, 0, -1, 7, { 0 }},
+    { 205, 0, -1, 7, { 0 }},
+    { 206, 0, -1, 7, { 0 }},
+    { 207, 0, -1, 7, { 0 }},
+    { 208, 0, 2, 7, { 0 }},
+    { 209, 0, -1, 7, { 0 }},
+    { 210, 0, -1, 7, { 0 }},
+    { 211, 0, -1, 7, { 0 }},
+    { 212, 0, -1, 7, { 0 }},
+    { 213, 0, -1, 7, { 0 }},
+    { 214, 0, -1, 7, { 0 }},
+    { 215, 0, 3, 7, { 0 }},
+    { 216, 0, 2, 7, { 0 }},
+    { 217, 0, -1, 7, { 0 }},
+    { 218, 0, -1, 7, { 0 }},
+    { 219, 0, -1, 7, { 0 }},
+    { 220, 0, -1, 7, { 0 }},
+    { 221, 0, -1, 7, { 0 }},
+    { 222, 0, 2, 7, { 0 }},
+    { 223, 0, 2, 7, { 0 }},
+    { 224, 0, 1, 7, { 0 }},
+    { 225, 0, 1, 7, { 0 }},
+    { 226, 0, 1, 7, { 0 }},
+    { 227, 0, 1, 7, { 0 }},
+    { 228, 0, 1, 7, { 0 }},
+    { 229, 0, 1, 7, { 0 }},
+    { 230, 0, 4, 10, { 0 }},
+    { 231, 0, 4, 7, { 0 }},
+    { 232, 0, 1, 7, { 0 }},
+    { 233, 0, 1, 7, { 0 }},
+    { 234, 0, 1, 7, { 0 }},
+    { 235, 0, 1, 7, { 0 }},
+    { 236, 0, 1, 7, { 0 }},
+    { 237, 0, 1, 7, { 0 }},
+    { 238, 0, 1, 7, { 0 }},
+    { 239, 0, 1, 7, { 0 }},
+    { 240, 0, 2, 7, { 0 }},
+    { 241, 0, 1, 7, { 0 }},
+    { 242, 0, 1, 7, { 0 }},
+    { 243, 0, 1, 7, { 0 }},
+    { 244, 0, 1, 7, { 0 }},
+    { 245, 0, 1, 7, { 0 }},
+    { 246, 0, 1, 7, { 0 }},
+    { 247, 0, 3, 6, { 0 }},
+    { 248, 0, 4, 7, { 0 }},
+    { 249, 0, 1, 7, { 0 }},
+    { 250, 0, 1, 7, { 0 }},
+    { 251, 0, 1, 7, { 0 }},
+    { 252, 0, 1, 7, { 0 }},
+    { 253, 0, 1, 7, { 0 }},
+    { 254, 0, 2, 7, { 0 }},
+    { 255, 0, 1, 7, { 0 }},
+};
+
+// Style loading function: Wisteria
+static void GuiLoadStyleWisteria(void)
+{
+    // Load style properties provided
+    // NOTE: Default properties are propagated
+    for (int i = 0; i < WISTERIA_STYLE_PROPS_COUNT; i++)
+    {
+        GuiSetStyle(wisteriaStyleProps[i].controlId, wisteriaStyleProps[i].propertyId, wisteriaStyleProps[i].propertyValue);
+    }
+
+    // Custom font loading
+    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
+    int wisteriaFontDataSize = 0;
+    unsigned char *data = DecompressData(wisteriaFontData, WISTERIA_STYLE_FONT_ATLAS_COMP_SIZE, &wisteriaFontDataSize);
+    Image imFont = { data, 256, 256, 1, 2 };
+
+    Font font = { 0 };
+    font.baseSize = 12;
+    font.glyphCount = 184;
+
+    // Copy char recs data from global fontRecs
+    // NOTE: Required to avoid issues if trying to free font
+    font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+    memcpy(font.recs, wisteriaFontRecs, font.glyphCount*sizeof(Rectangle));
+
+    // Copy font char info data from global fontChars
+    // NOTE: Required to avoid issues if trying to free font
+    font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+    memcpy(font.glyphs, wisteriaFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
+
+    // Define font white rectangle to be used on shapes drawing
+    // WARNING: It can be updated if icons are baked into font atlas image
+    Rectangle fontWhiteRec = { 254, 254, 1, 1 };
+
+#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
+    // Load texture from image
+    font.texture = LoadTextureFromImage(imFont);
+    UnloadImage(imFont);  // Uncompressed image data can be unloaded from memory
+
+    GuiSetFont(font);
+
+    // Setup a white rectangle on the font to be used on shapes drawing,
+    // it makes possible to draw shapes and text (full UI) in a single draw call
+    SetShapesTexture(font.texture, fontWhiteRec);
+
+    // Set font name in raygui internal variable (requires raygui 5.0)
+    snprintf(guiFontName, 32, "%s", "PixelIntv.otf");
+    //-----------------------------------------------------------------
+
+    // TODO: Custom user style setup: Set specific properties here (if required)
+    // i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
+}
diff --git a/raylib/examples/audio/audio_amp_envelope.c b/raylib/examples/audio/audio_amp_envelope.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/audio/audio_amp_envelope.c
@@ -0,0 +1,238 @@
+/*******************************************************************************************
+*
+*   raylib [audio] example - amp envelope
+*
+*   Example complexity rating: [★☆☆☆] 1/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by Arbinda Rizki Muhammad (@arbipink) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Arbinda Rizki Muhammad (@arbipink)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+#include <math.h>           // Required for: sinf()
+
+#define BUFFER_SIZE      4096
+#define SAMPLE_RATE     44100
+
+// Wave state
+typedef enum {
+    IDLE,
+    ATTACK,
+    DECAY,
+    SUSTAIN,
+    RELEASE
+} ADSRState;
+
+// Grouping all ADSR parameters and state into a struct
+typedef struct {
+    float attackTime;
+    float decayTime;
+    float sustainLevel;
+    float releaseTime;
+    float currentValue;
+    ADSRState state;
+} Envelope;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void FillAudioBuffer(int i, float *buffer, float envelopeValue, float *audioTime);
+static void UpdateEnvelope(Envelope *env);
+static void DrawADSRGraph(Envelope *env, Rectangle bounds);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [audio] example - amp envelope");
+
+    InitAudioDevice();
+
+    // Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
+    SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
+    float buffer[BUFFER_SIZE] = { 0 };
+
+    // Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
+    AudioStream stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
+
+    // Init Phase
+    float audioTime = 0.0f;
+
+    // Initialize the struct
+    Envelope env = {
+        .attackTime = 1.0f,
+        .decayTime = 1.0f,
+        .sustainLevel = 0.5f,
+        .releaseTime = 1.0f,
+        .currentValue = 0.0f,
+        .state = IDLE
+    };
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_SPACE)) env.state = ATTACK;
+
+        if (IsKeyReleased(KEY_SPACE) && (env.state != IDLE)) env.state = RELEASE;
+
+        if (IsAudioStreamProcessed(stream))
+        {
+            if ((env.state != IDLE) || (env.currentValue > 0.0f))
+            {
+                for (int i = 0; i < BUFFER_SIZE; i++)
+                {
+                    UpdateEnvelope(&env);
+                    FillAudioBuffer(i, buffer, env.currentValue, &audioTime);
+                }
+            }
+            else
+            {
+                // Clear buffer if silent to avoid looping noise
+                for (int i = 0; i < BUFFER_SIZE; i++) buffer[i] = 0;
+                audioTime = 0.0f;
+            }
+
+            UpdateAudioStream(stream, buffer, BUFFER_SIZE);
+        }
+
+        if (!IsAudioStreamPlaying(stream)) PlayAudioStream(stream);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            GuiSliderBar((Rectangle){ 100, 60, 400, 30 }, "Attack (s)", TextFormat("%2.2fs", env.attackTime), &env.attackTime, 0.1f, 3.0f);
+            GuiSliderBar((Rectangle){ 100, 100, 400, 30 }, "Decay (s)", TextFormat("%2.2fs", env.decayTime), &env.decayTime, 0.1f, 3.0f);
+            GuiSliderBar((Rectangle){ 100, 140, 400, 30 }, "Sustain", TextFormat("%2.2f", env.sustainLevel), &env.sustainLevel, 0.0f, 1.0f);
+            GuiSliderBar((Rectangle){ 100, 180, 400, 30 }, "Release (s)", TextFormat("%2.2fs", env.releaseTime), &env.releaseTime, 0.1f, 3.0f);
+
+            DrawADSRGraph(&env, (Rectangle){ 100, 250, 400, 100 });
+
+            DrawCircleV((Vector2){ 520, 350 - (env.currentValue * 100) }, 5, MAROON);
+            DrawText(TextFormat("Current Gain: %2.2f", env.currentValue), 535, 345 - (env.currentValue * 100), 10, MAROON);
+
+            DrawText("Press SPACE to PLAY the sound!", 200, 400, 20, LIGHTGRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadAudioStream(stream);
+    CloseAudioDevice();
+
+    CloseWindow();
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Module Functions Definition
+//------------------------------------------------------------------------------------
+static void FillAudioBuffer(int i, float *buffer, float envelopeValue, float *audioTime)
+{
+    int frequency = 440;
+    buffer[i] = envelopeValue*sinf(2.0f*PI*frequency*(*audioTime));
+    *audioTime += (1.0f/SAMPLE_RATE);
+}
+
+static void UpdateEnvelope(Envelope *env)
+{
+    // Calculate the time delta for ONE sample (1/44100)
+    float sampleTime = 1.0f/SAMPLE_RATE;
+
+    switch(env->state)
+    {
+        case ATTACK:
+        {
+            env->currentValue += (1.0f/env->attackTime)*sampleTime;
+            if (env->currentValue >= 1.0f)
+            {
+                env->currentValue = 1.0f;
+                env->state = DECAY;
+            }
+
+        } break;
+        case DECAY:
+        {
+            env->currentValue -= ((1.0f - env->sustainLevel)/env->decayTime)*sampleTime;
+            if (env->currentValue <= env->sustainLevel)
+            {
+                env->currentValue = env->sustainLevel;
+                env->state = SUSTAIN;
+            }
+
+        } break;
+        case SUSTAIN:
+        {
+            env->currentValue = env->sustainLevel;
+
+        } break;
+        case RELEASE:
+        {
+            env->currentValue -= (env->sustainLevel/env->releaseTime)*sampleTime;
+            if (env->currentValue <= 0.001f) // Use a small threshold to avoid infinite tail
+            {
+                env->currentValue = 0.0f;
+                env->state = IDLE;
+            }
+
+        } break;
+        default: break;
+    }
+}
+
+static void DrawADSRGraph(Envelope *env, Rectangle bounds)
+{
+    DrawRectangleRec(bounds, Fade(LIGHTGRAY, 0.3f));
+    DrawRectangleLinesEx(bounds, 1, GRAY);
+
+    // Fixed visual width for sustain stage since it's an amplitude not a time value
+    float sustainWidth = 1.0f;
+
+    // Total time to visualize (sum of A, D, R + a padding for Sustain)
+    float totalTime = env->attackTime + env->decayTime + sustainWidth + env->releaseTime;
+
+    float scaleX = bounds.width/totalTime;
+    float scaleY = bounds.height;
+
+    Vector2 start = { bounds.x, bounds.y + bounds.height };
+    Vector2 peak = { start.x + (env->attackTime*scaleX), bounds.y };
+    Vector2 sustain = { peak.x + (env->decayTime*scaleX), bounds.y + (1.0f - env->sustainLevel)*scaleY };
+    Vector2 rel = { sustain.x + (sustainWidth*scaleX), sustain.y };
+    Vector2 end = { rel.x + (env->releaseTime*scaleX), bounds.y + bounds.height };
+
+    DrawLineV(start, peak, SKYBLUE);
+    DrawLineV(peak, sustain, BLUE);
+    DrawLineV(sustain, rel, DARKBLUE);
+    DrawLineV(rel, end, ORANGE);
+
+    DrawText("ADSR Visualizer", bounds.x, bounds.y - 20, 10, DARKGRAY);
+}
diff --git a/raylib/examples/audio/audio_raw_stream.c b/raylib/examples/audio/audio_raw_stream.c
--- a/raylib/examples/audio/audio_raw_stream.c
+++ b/raylib/examples/audio/audio_raw_stream.c
@@ -4,53 +4,22 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 1.6, last time updated with raylib 4.2
+*   Example originally created with raylib 1.6, last time updated with raylib 6.0
 *
 *   Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
 *
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
 *
-*   Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
+*   Copyright (c) 2015-2026 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
 *
 ********************************************************************************************/
 
 #include "raylib.h"
-
-#include <stdlib.h>         // Required for: malloc(), free()
-#include <math.h>           // Required for: sinf()
-#include <string.h>         // Required for: memcpy()
-
-#define MAX_SAMPLES               512
-#define MAX_SAMPLES_PER_UPDATE   4096
-
-// Cycles per second (hz)
-float frequency = 440.0f;
-
-// Audio frequency, for smoothing
-float audioFrequency = 440.0f;
-
-// Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
-float oldFrequency = 1.0f;
-
-// Index for audio rendering
-float sineIdx = 0.0f;
-
-// Audio input processing callback
-void AudioInputCallback(void *buffer, unsigned int frames)
-{
-    audioFrequency = frequency + (audioFrequency - frequency)*0.95f;
-
-    float incr = audioFrequency/44100.0f;
-    short *d = (short *)buffer;
+#include <math.h>
 
-    for (unsigned int i = 0; i < frames; i++)
-    {
-        d[i] = (short)(32000.0f*sinf(2*PI*sineIdx));
-        sineIdx += incr;
-        if (sineIdx > 1.0f) sineIdx -= 1.0f;
-    }
-}
+#define BUFFER_SIZE 4096
+#define SAMPLE_RATE 44100
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -64,43 +33,24 @@
 
     InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw stream");
 
-    InitAudioDevice();              // Initialize audio device
-
-    SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
-
-    // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
-    AudioStream stream = LoadAudioStream(44100, 16, 1);
-
-    SetAudioStreamCallback(stream, AudioInputCallback);
-
-    // Buffer for the single cycle waveform we are synthesizing
-    short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
-
-    // Frame buffer, describing the waveform when repeated over the course of a frame
-    short *writeBuf = (short *)malloc(sizeof(short)*MAX_SAMPLES_PER_UPDATE);
-
-    PlayAudioStream(stream);        // Start processing stream buffer (no data loaded currently)
-
-    // Position read in to determine next frequency
-    Vector2 mousePosition = { -100.0f, -100.0f };
-
-    /*
-    // Cycles per second (hz)
-    float frequency = 440.0f;
-
-    // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
-    float oldFrequency = 1.0f;
+    InitAudioDevice();
 
-    // Cursor to read and copy the samples of the sine wave buffer
-    int readCursor = 0;
-    */
+    // Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
+    SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
+    float buffer[BUFFER_SIZE] = {};
 
-    // Computed size in samples of the sine wave
-    int waveLength = 1;
+    // Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
+    AudioStream stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
+    float pan = 0.0f;
+    SetAudioStreamPan(stream, pan);
+    PlayAudioStream(stream);
 
-    Vector2 position = { 0, 0 };
+    int sineFrequency = 440;
+    int newSineFrequency = 440;
+    int sineIndex = 0;
+    double sineStartTime = 0.0;
 
-    SetTargetFPS(30);               // Set our game to run at 30 frames-per-second
+    SetTargetFPS(30);
     //--------------------------------------------------------------------------------------
 
     // Main game loop
@@ -108,91 +58,76 @@
     {
         // Update
         //----------------------------------------------------------------------------------
-        mousePosition = GetMousePosition();
 
-        if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
+        if (IsKeyDown(KEY_UP))
         {
-            float fp = (float)(mousePosition.y);
-            frequency = 40.0f + (float)(fp);
-
-            float pan = (float)(mousePosition.x)/(float)screenWidth;
-            SetAudioStreamPan(stream, pan);
+            newSineFrequency += 10;
+            if (newSineFrequency > 12500) newSineFrequency = 12500;
         }
 
-        // Rewrite the sine wave
-        // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
-        if (frequency != oldFrequency)
+        if (IsKeyDown(KEY_DOWN))
         {
-            // Compute wavelength. Limit size in both directions
-            //int oldWavelength = waveLength;
-            waveLength = (int)(22050/frequency);
-            if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
-            if (waveLength < 1) waveLength = 1;
+            newSineFrequency -= 10;
+            if (newSineFrequency < 20) newSineFrequency = 20;
+        }
 
-            // Write sine wave
-            for (int i = 0; i < waveLength*2; i++)
-            {
-                data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
-            }
-            // Make sure the rest of the line is flat
-            for (int j = waveLength*2; j < MAX_SAMPLES; j++)
-            {
-                data[j] = (short)0;
-            }
+        if (IsKeyDown(KEY_LEFT))
+        {
+            pan -= 0.01f;
+            if (pan < -1.0f) pan = -1.0f;
+            SetAudioStreamPan(stream, pan);
+        }
 
-            // Scale read cursor's position to minimize transition artifacts
-            //readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength));
-            oldFrequency = frequency;
+        if (IsKeyDown(KEY_RIGHT))
+        {
+            pan += 0.01f;
+            if (pan > 1.0f) pan = 1.0f;
+            SetAudioStreamPan(stream, pan);
         }
 
-        /*
-        // Refill audio stream if required
         if (IsAudioStreamProcessed(stream))
         {
-            // Synthesize a buffer that is exactly the requested size
-            int writeCursor = 0;
-
-            while (writeCursor < MAX_SAMPLES_PER_UPDATE)
+            for (int i = 0; i < BUFFER_SIZE; i++)
             {
-                // Start by trying to write the whole chunk at once
-                int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;
-
-                // Limit to the maximum readable size
-                int readLength = waveLength-readCursor;
-
-                if (writeLength > readLength) writeLength = readLength;
-
-                // Write the slice
-                memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
-
-                // Update cursors and loop audio
-                readCursor = (readCursor + writeLength)%waveLength;
+                int wavelength = SAMPLE_RATE/sineFrequency;
+                buffer[i] = sinf(2*PI*sineIndex/wavelength);
+                sineIndex++;
 
-                writeCursor += writeLength;
+                if (sineIndex >= wavelength)
+                {
+                    sineFrequency = newSineFrequency;
+                    sineIndex = 0;
+                    sineStartTime = GetTime();
+                }
             }
 
-            // Copy finished frame to audio stream
-            UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
+            UpdateAudioStream(stream, buffer, BUFFER_SIZE);
         }
-        */
+
         //----------------------------------------------------------------------------------
 
         // Draw
         //----------------------------------------------------------------------------------
         BeginDrawing();
-
             ClearBackground(RAYWHITE);
 
-            DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED);
-            DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY);
+            DrawText(TextFormat("sine frequency: %i", sineFrequency), screenWidth - 220, 10, 20, RED);
+            DrawText(TextFormat("pan: %.2f", pan), screenWidth - 220, 30, 20, RED);
+            DrawText("Up/down to change frequency", 10, 10, 20, DARKGRAY);
+            DrawText("Left/right to pan", 10, 30, 20, DARKGRAY);
 
-            // Draw the current buffer state proportionate to the screen
+            int windowStart = (int)((GetTime() - sineStartTime)*SAMPLE_RATE);
+            int windowSize = SAMPLE_RATE/10;
+            int wavelength = SAMPLE_RATE/sineFrequency;
+
+            // Draw a sine wave with the same frequency as the one being sent to the audio stream
             for (int i = 0; i < screenWidth; i++)
             {
-                position.x = (float)i;
-                position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000.0f;
-
-                DrawPixelV(position, RED);
+                int t0 = windowStart + i*windowSize/screenWidth;
+                int t1 = windowStart + (i + 1)*windowSize/screenWidth;
+                Vector2 startPos = { (float)i, 250 + 50*sinf(2*PI*t0/wavelength) };
+                Vector2 endPos = { (float)i + 1, 250 + 50*sinf(2*PI*t1/wavelength) };
+                DrawLineV(startPos, endPos, RED);
             }
 
         EndDrawing();
@@ -201,9 +136,6 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    free(data);                 // Unload sine wave data
-    free(writeBuf);             // Unload write buffer
-
     UnloadAudioStream(stream);   // Close raw audio stream and delete buffers from RAM
     CloseAudioDevice();         // Close audio device (music streaming is automatically stopped)
 
diff --git a/raylib/examples/audio/audio_sound_positioning.c b/raylib/examples/audio/audio_sound_positioning.c
--- a/raylib/examples/audio/audio_sound_positioning.c
+++ b/raylib/examples/audio/audio_sound_positioning.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.5
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *
 *   Example contributed by Le Juez Victor (@Bigfoot71) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -68,7 +68,7 @@
             .z = 5.0f*sinf(th)
         };
 
-        SetSoundPosition(camera, sound, spherePos, 20.0f);
+        SetSoundPosition(camera, sound, spherePos, 1.0f);
 
         if (!IsSoundPlaying(sound)) PlaySound(sound);
         //----------------------------------------------------------------------------------
@@ -116,14 +116,14 @@
     // Calculate normalized vectors for spatial positioning
     Vector3 normalizedDirection = Vector3Normalize(direction);
     Vector3 forward = Vector3Normalize(Vector3Subtract(listener.target, listener.position));
-    Vector3 right = Vector3Normalize(Vector3CrossProduct(listener.up, forward));
+    Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, listener.up));
 
     // Reduce volume for sounds behind the listener
     float dotProduct = Vector3DotProduct(forward, normalizedDirection);
     if (dotProduct < 0.0f) attenuation *= (1.0f + dotProduct*0.5f);
 
     // Set stereo panning based on sound position relative to listener
-    float pan = 0.5f + 0.5f*Vector3DotProduct(normalizedDirection, right);
+    float pan = Vector3DotProduct(normalizedDirection, right);
 
     // Apply final sound properties
     SetSoundVolume(sound, attenuation);
diff --git a/raylib/examples/audio/audio_spectrum_visualizer.c b/raylib/examples/audio/audio_spectrum_visualizer.c
--- a/raylib/examples/audio/audio_spectrum_visualizer.c
+++ b/raylib/examples/audio/audio_spectrum_visualizer.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 6.0, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Inspired by Inigo Quilez's https://www.shadertoy.com/
 *   Resources/specification: https://gist.github.com/soulthreads/2efe50da4be1fb5f7ab60ff14ca434b8
@@ -115,7 +115,7 @@
         .tapbackPos = 0.01f
     };
 
-    int wavCursor = 0;
+    unsigned int wavCursor = 0;
     const short *wavPCM16 = wav.data;
 
     short chunkSamples[AUDIO_STREAM_RING_BUFFER_SIZE] = { 0 };
@@ -274,8 +274,8 @@
 
 static void RenderFrame(const FFTData *fftData, Image *fftImage)
 {
-    double framesSinceTapback = floor(fftData->tapbackPos/WINDOW_TIME);
-    framesSinceTapback = Clamp(framesSinceTapback, 0.0, fftData->fftHistoryLen - 1);
+    float framesSinceTapback = floorf((float)(fftData->tapbackPos/WINDOW_TIME));
+    framesSinceTapback = Clamp(framesSinceTapback, 0.0f, (float)(fftData->fftHistoryLen - 1));
 
     int historyPosition = (fftData->historyPos - 1 - (int)framesSinceTapback)%fftData->fftHistoryLen;
     if (historyPosition < 0) historyPosition += fftData->fftHistoryLen;
diff --git a/raylib/examples/audio/audio_stream_callback.c b/raylib/examples/audio/audio_stream_callback.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/audio/audio_stream_callback.c
@@ -0,0 +1,246 @@
+/*******************************************************************************************
+*
+*   raylib [audio] example - stream callback
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example created by Dan Hoang (@dan-hoang) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   NOTE: Example sends a wave to the audio device,
+*     user gets the choice of four waves: sine, square, triangle, and sawtooth
+*     A stream is set up to play to the audio device; stream is hooked to a callback that
+*     generates a wave, that is determined by user choice
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Dan Hoang (@dan-hoang)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#define BUFFER_SIZE 4096
+#define SAMPLE_RATE 44100
+
+// Wave type
+typedef enum {
+    SINE,
+    SQUARE,
+    TRIANGLE,
+    SAWTOOTH
+} WaveType;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void SineCallback(void *framesOut, unsigned int frameCount);
+static void SquareCallback(void *framesOut, unsigned int frameCount);
+static void TriangleCallback(void *framesOut, unsigned int frameCount);
+static void SawtoothCallback(void *framesOut, unsigned int frameCount);
+
+static int waveFrequency = 440;
+static int newWaveFrequency = 440;
+static int waveIndex = 0;
+
+// Buffer to keep the last second of uploaded audio,
+// part of which will be drawn on the screen
+static float buffer[SAMPLE_RATE] = { 0 };
+static AudioCallback waveCallbacks[] = { SineCallback, SquareCallback, TriangleCallback, SawtoothCallback };
+static char *waveTypesAsString[] = { "sine", "square", "triangle", "sawtooth" };
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream callback");
+
+    InitAudioDevice();
+
+    // Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
+    SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
+
+    // Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
+    AudioStream stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
+    PlayAudioStream(stream);
+
+    // Configure it so that waveCallbacks[waveType] is called whenever stream is out of samples
+    WaveType waveType = SINE;
+    SetAudioStreamCallback(stream, waveCallbacks[waveType]);
+
+    SetTargetFPS(30);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyDown(KEY_UP))
+        {
+            newWaveFrequency += 10;
+            if (newWaveFrequency > 12500) newWaveFrequency = 12500;
+        }
+
+        if (IsKeyDown(KEY_DOWN))
+        {
+            newWaveFrequency -= 10;
+            if (newWaveFrequency < 20) newWaveFrequency = 20;
+        }
+
+        if (IsKeyPressed(KEY_LEFT))
+        {
+            if (waveType == SINE) waveType = SAWTOOTH;
+            else if (waveType == SQUARE) waveType = SINE;
+            else if (waveType == TRIANGLE) waveType = SQUARE;
+            else waveType = TRIANGLE;
+
+            SetAudioStreamCallback(stream, waveCallbacks[waveType]);
+        }
+
+        if (IsKeyPressed(KEY_RIGHT))
+        {
+            if (waveType == SINE) waveType = SQUARE;
+            else if (waveType == SQUARE) waveType = TRIANGLE;
+            else if (waveType == TRIANGLE) waveType = SAWTOOTH;
+            else waveType = SINE;
+
+            SetAudioStreamCallback(stream, waveCallbacks[waveType]);
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+            DrawText(TextFormat("frequency: %i", newWaveFrequency), screenWidth - 220, 10, 20, RED);
+            DrawText(TextFormat("wave type: %s", waveTypesAsString[waveType]), screenWidth - 220, 30, 20, RED);
+            DrawText("Up/down to change frequency", 10, 10, 20, DARKGRAY);
+            DrawText("Left/right to change wave type", 10, 30, 20, DARKGRAY);
+
+            // Draw the last 10 ms of uploaded audio
+            for (int i = 0; i < screenWidth; i++)
+            {
+                Vector2 startPos = {(float)i, 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + i*SAMPLE_RATE/100/screenWidth] };
+                Vector2 endPos = { (float)(i + 1), 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + (i + 1)*SAMPLE_RATE/100/screenWidth] };
+                DrawLineV(startPos, endPos, RED);
+            }
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadAudioStream(stream);  // Close raw audio stream and delete buffers from RAM
+    CloseAudioDevice();         // Close audio device (music streaming is automatically stopped)
+
+    CloseWindow();              // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Module Functions Definition
+//------------------------------------------------------------------------------------
+static void SineCallback(void *framesOut, unsigned int frameCount)
+{
+    int wavelength = SAMPLE_RATE/waveFrequency;
+
+    // Synthesize the sine wave
+    for (unsigned int i = 0; i < frameCount; i++)
+    {
+        ((float *)framesOut)[i] = sinf(2*PI*waveIndex/wavelength);
+
+        waveIndex++;
+
+        if (waveIndex >= wavelength)
+        {
+            waveFrequency = newWaveFrequency;
+            waveIndex = 0;
+        }
+    }
+
+    // Save the synthesized samples for later drawing
+    for (unsigned int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount];
+    for (unsigned int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i];
+}
+
+static void SquareCallback(void *framesOut, unsigned int frameCount)
+{
+    int wavelength = SAMPLE_RATE/waveFrequency;
+
+    // Synthesize the square wave
+    for (unsigned int i = 0; i < frameCount; i++)
+    {
+        ((float *)framesOut)[i] = (waveIndex < wavelength/2)? 1.0f : -1.0f;
+        waveIndex++;
+
+        if (waveIndex >= wavelength)
+        {
+            waveFrequency = newWaveFrequency;
+            waveIndex = 0;
+        }
+    }
+
+    // Save the synthesized samples for later drawing
+    for (unsigned int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount];
+    for (unsigned int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i];
+}
+
+static void TriangleCallback(void *framesOut, unsigned int frameCount)
+{
+    int wavelength = SAMPLE_RATE/waveFrequency;
+
+    // Synthesize the triangle wave
+    for (unsigned int i = 0; i < frameCount; i++)
+    {
+        ((float *)framesOut)[i] = (waveIndex < wavelength/2)? (-1 + 2.0f*waveIndex/(wavelength/2)) : (1 - 2.0f*(waveIndex - wavelength/2)/(wavelength/2));
+        waveIndex++;
+
+        if (waveIndex >= wavelength)
+        {
+            waveFrequency = newWaveFrequency;
+            waveIndex = 0;
+        }
+    }
+
+    // Save the synthesized samples for later drawing
+    for (unsigned int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount];
+    for (unsigned int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i];
+}
+
+static void SawtoothCallback(void *framesOut, unsigned int frameCount)
+{
+    int wavelength = SAMPLE_RATE/waveFrequency;
+
+    // Synthesize the sawtooth wave
+    for (unsigned int i = 0; i < frameCount; i++)
+    {
+        ((float *)framesOut)[i] = -1 + 2.0f*waveIndex/wavelength;
+        waveIndex++;
+
+        if (waveIndex >= wavelength)
+        {
+            waveFrequency = newWaveFrequency;
+            waveIndex = 0;
+        }
+    }
+
+    // Save the synthesized samples for later drawing
+    for (unsigned int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount];
+    for (unsigned int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float*)framesOut)[i];
+}
diff --git a/raylib/examples/audio/raygui.h b/raylib/examples/audio/raygui.h
new file mode 100644
--- /dev/null
+++ b/raylib/examples/audio/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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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/raylib/examples/core/core_2d_camera_platformer.c b/raylib/examples/core/core_2d_camera_platformer.c
--- a/raylib/examples/core/core_2d_camera_platformer.c
+++ b/raylib/examples/core/core_2d_camera_platformer.c
@@ -148,10 +148,11 @@
             DrawText("Controls:", 20, 20, 10, BLACK);
             DrawText("- Right/Left to move", 40, 40, 10, DARKGRAY);
             DrawText("- Space to jump", 40, 60, 10, DARKGRAY);
-            DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, DARKGRAY);
-            DrawText("- C to change camera mode", 40, 100, 10, DARKGRAY);
-            DrawText("Current camera mode:", 20, 120, 10, BLACK);
-            DrawText(cameraDescriptions[cameraOption], 40, 140, 10, DARKGRAY);
+            DrawText("- Mouse Wheel to Zoom in-out", 40, 80, 10, DARKGRAY);
+            DrawText("- R to reset position + zoom", 40, 100, 10, DARKGRAY);
+            DrawText("- C to change camera mode", 40, 120, 10, DARKGRAY);
+            DrawText("Current camera mode:", 20, 140, 10, BLACK);
+            DrawText(cameraDescriptions[cameraOption], 40, 160, 10, DARKGRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -226,10 +227,10 @@
     Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera);
     Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera);
 
-    if (max.x < width) camera->offset.x = width - (max.x - width/2);
-    if (max.y < height) camera->offset.y = height - (max.y - height/2);
-    if (min.x > 0) camera->offset.x = width/2 - min.x;
-    if (min.y > 0) camera->offset.y = height/2 - min.y;
+    if (max.x < width) camera->offset.x = width - (max.x - (float)width/2);
+    if (max.y < height) camera->offset.y = height - (max.y - (float)height/2);
+    if (min.x > 0) camera->offset.x = (float)width/2 - min.x;
+    if (min.y > 0) camera->offset.y = (float)height/2 - min.y;
 }
 
 void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
diff --git a/raylib/examples/core/core_automation_events.c b/raylib/examples/core/core_automation_events.c
--- a/raylib/examples/core/core_automation_events.c
+++ b/raylib/examples/core/core_automation_events.c
@@ -225,10 +225,10 @@
         Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, camera);
         Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, camera);
 
-        if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - screenWidth/2);
-        if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - screenHeight/2);
-        if (min.x > 0) camera.offset.x = screenWidth/2 - min.x;
-        if (min.y > 0) camera.offset.y = screenHeight/2 - min.y;
+        if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - (float)screenWidth/2);
+        if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - (float)screenHeight/2);
+        if (min.x > 0) camera.offset.x = (float)screenWidth/2 - min.x;
+        if (min.y > 0) camera.offset.y = (float)screenHeight/2 - min.y;
         //----------------------------------------------------------------------------------
 
         // Events management
diff --git a/raylib/examples/core/core_basic_window.c b/raylib/examples/core/core_basic_window.c
--- a/raylib/examples/core/core_basic_window.c
+++ b/raylib/examples/core/core_basic_window.c
@@ -22,7 +22,7 @@
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
 *
-*   Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+*   Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
 *
 ********************************************************************************************/
 
diff --git a/raylib/examples/core/core_clipboard_text.c b/raylib/examples/core/core_clipboard_text.c
--- a/raylib/examples/core/core_clipboard_text.c
+++ b/raylib/examples/core/core_clipboard_text.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Ananth S (@Ananth1839) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/core/core_compute_hash.c b/raylib/examples/core/core_compute_hash.c
--- a/raylib/examples/core/core_compute_hash.c
+++ b/raylib/examples/core/core_compute_hash.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
@@ -60,7 +60,7 @@
         //----------------------------------------------------------------------------------
         if (btnComputeHashes)
         {
-            int textInputLen = strlen(textInput);
+            int textInputLen = (int)strlen(textInput);
 
             // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
             base64Text = EncodeDataBase64((unsigned char *)textInput, textInputLen, &base64TextSize);
diff --git a/raylib/examples/core/core_delta_time.c b/raylib/examples/core/core_delta_time.c
--- a/raylib/examples/core/core_delta_time.c
+++ b/raylib/examples/core/core_delta_time.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/core/core_directory_files.c b/raylib/examples/core/core_directory_files.c
--- a/raylib/examples/core/core_directory_files.c
+++ b/raylib/examples/core/core_directory_files.c
@@ -21,6 +21,7 @@
 #include "raygui.h"                 // Required for GUI controls
 
 #define MAX_FILEPATH_SIZE       1024
+#define FILE_FILTER             "DIRS*;.png;.c"
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -37,10 +38,18 @@
     char directory[MAX_FILEPATH_SIZE] = { 0 };
     strcpy(directory, GetWorkingDirectory());
 
-    FilePathList files = LoadDirectoryFiles(directory);
+    // Load file-paths on current working directory
+    // NOTE: LoadDirectoryFiles() loads files and directories by default,
+    // use LoadDirectoryFilesEx() for custom filters and recursive directories loading
+    //FilePathList files = LoadDirectoryFiles(directory);
+    FilePathList files = LoadDirectoryFilesEx(directory, FILE_FILTER, false);
 
     int btnBackPressed = false;
 
+    int listScrollIndex = 0;
+    int listItemActive = -1;
+    int listItemFocused = -1;
+
     SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
 
@@ -53,8 +62,23 @@
         {
             TextCopy(directory, GetPrevDirectoryPath(directory));
             UnloadDirectoryFiles(files);
-            files = LoadDirectoryFiles(directory);
+            files = LoadDirectoryFilesEx(directory, FILE_FILTER, false);
+
+            listScrollIndex = 0;
+            listItemActive = -1;
+            listItemFocused = -1;
         }
+
+        if ((listItemActive >= 0) && (listItemActive < (int)files.count) && DirectoryExists(files.paths[listItemActive]))
+        {
+            TextCopy(directory, files.paths[listItemActive]);
+            UnloadDirectoryFiles(files);
+            files = LoadDirectoryFilesEx(directory, FILE_FILTER, false);
+
+            listScrollIndex = 0;
+            listItemActive = -1;
+            listItemFocused = -1;
+        }
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -62,28 +86,16 @@
         BeginDrawing();
             ClearBackground(RAYWHITE);
 
-            DrawText(directory, 100, 40, 20, DARKGRAY);
-
-            btnBackPressed = GuiButton((Rectangle){ 40.0f, 38.0f, 48, 24 }, "<");
-
-            for (int i = 0; i < (int)files.count; i++)
-            {
-                Color color = Fade(LIGHTGRAY, 0.3f);
+            btnBackPressed = GuiButton((Rectangle){ 40.0f, 10.0f, 48, 28 }, "<");
 
-                if (!IsPathFile(files.paths[i]) && DirectoryExists(files.paths[i]))
-                {
-                    if (GuiButton((Rectangle){0.0f, 85.0f + 40.0f*(float)i, screenWidth, 40}, ""))
-                    {
-                        TextCopy(directory, files.paths[i]);
-                        UnloadDirectoryFiles(files);
-                        files = LoadDirectoryFiles(directory);
-                        continue;
-                    }
-                }
+            GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize*2);
+            GuiLabel((Rectangle){ 40 + 48 + 10, 10, 700, 28 }, directory);
+            GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize);
 
-                DrawRectangle(0, 85 + 40*i, screenWidth, 40, color);
-                DrawText(GetFileName(files.paths[i]), 120, 100 + 40*i, 10, GRAY);
-            }
+            GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+            GuiSetStyle(LISTVIEW, TEXT_PADDING, 40);
+            GuiListViewEx((Rectangle){ 0, 50, (float)GetScreenWidth(), (float)GetScreenHeight() - 50 },
+                files.paths, files.count, &listScrollIndex, &listItemActive, &listItemFocused);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
diff --git a/raylib/examples/core/core_highdpi_testbed.c b/raylib/examples/core/core_highdpi_testbed.c
--- a/raylib/examples/core/core_highdpi_testbed.c
+++ b/raylib/examples/core/core_highdpi_testbed.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Ramon Santamaria (@raysan5) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -73,12 +73,12 @@
             }
 
             // Draw UI info
-            DrawText(TextFormat("CURRENT MONITOR: %i/%i (%ix%i)", currentMonitor + 1, GetMonitorCount(), 
+            DrawText(TextFormat("CURRENT MONITOR: %i/%i (%ix%i)", currentMonitor + 1, GetMonitorCount(),
                 GetMonitorWidth(currentMonitor), GetMonitorHeight(currentMonitor)), 50, 50, 20, DARKGRAY);
             DrawText(TextFormat("WINDOW POSITION: %ix%i", (int)windowPos.x, (int)windowPos.y), 50, 90, 20, DARKGRAY);
             DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 50, 130, 20, DARKGRAY);
             DrawText(TextFormat("RENDER SIZE: %ix%i", GetRenderWidth(), GetRenderHeight()), 50, 170, 20, DARKGRAY);
-            DrawText(TextFormat("SCALE FACTOR: %.1fx%.1f", scaleDpi.x, scaleDpi.y), 50, 210, 20, GRAY);
+            DrawText(TextFormat("SCALE FACTOR: %.2fx%.2f", scaleDpi.x, scaleDpi.y), 50, 210, 20, GRAY);
 
             // Draw reference rectangles, top-left and bottom-right corners
             DrawRectangle(0, 0, 30, 60, RED);
@@ -86,10 +86,10 @@
 
             // Draw mouse position
             DrawCircleV(GetMousePosition(), 20, MAROON);
-            DrawRectangle(mousePos.x - 25, mousePos.y, 50, 2, BLACK);
-            DrawRectangle(mousePos.x, mousePos.y - 25, 2, 50, BLACK);
-            DrawText(TextFormat("[%i,%i]", GetMouseX(), GetMouseY()), mousePos.x - 44,
-                (mousePos.y > GetScreenHeight() - 60)? mousePos.y - 46 : mousePos.y + 30, 20, BLACK);
+            DrawRectangleRec((Rectangle) { mousePos.x - 25, mousePos.y, 50, 2 }, BLACK);
+            DrawRectangleRec((Rectangle) { mousePos.x, mousePos.y - 25, 2, 50 }, BLACK);
+            DrawText(TextFormat("[%i,%i]", GetMouseX(), GetMouseY()), (int)mousePos.x - 44,
+                (mousePos.y > GetScreenHeight() - 60)? (int)mousePos.y - 46 : (int)mousePos.y + 30, 20, BLACK);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -97,9 +97,6 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-
-    // TODO: Unload all loaded resources at this point
-
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/examples/core/core_input_actions.c b/raylib/examples/core/core_input_actions.c
--- a/raylib/examples/core/core_input_actions.c
+++ b/raylib/examples/core/core_input_actions.c
@@ -117,7 +117,7 @@
 
             DrawRectangleV(position, size, releaseAction? BLUE : RED);
 
-            DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Cursor", 10, 10, 20, WHITE);
+            DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Arrow keys", 10, 10, 20, WHITE);
             DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, GREEN);
 
         EndDrawing();
diff --git a/raylib/examples/core/core_input_gamepad.c b/raylib/examples/core/core_input_gamepad.c
--- a/raylib/examples/core/core_input_gamepad.c
+++ b/raylib/examples/core/core_input_gamepad.c
@@ -24,7 +24,8 @@
 // NOTE: Gamepad name ID depends on drivers and OS
 #define XBOX_ALIAS_1 "xbox"
 #define XBOX_ALIAS_2 "x-box"
-#define PS_ALIAS     "playstation"
+#define PS_ALIAS_1   "playstation"
+#define PS_ALIAS_2   "sony"
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -148,7 +149,8 @@
                     //DrawText(TextFormat("Xbox axis LT: %02.02f", GetGamepadAxisMovement(gamepad, GAMEPAD_AXIS_LEFT_TRIGGER)), 10, 40, 10, BLACK);
                     //DrawText(TextFormat("Xbox axis RT: %02.02f", GetGamepadAxisMovement(gamepad, GAMEPAD_AXIS_RIGHT_TRIGGER)), 10, 60, 10, BLACK);
                 }
-                else if (TextFindIndex(TextToLower(GetGamepadName(gamepad)), PS_ALIAS) > -1)
+                else if ((TextFindIndex(TextToLower(GetGamepadName(gamepad)), PS_ALIAS_1) > -1) ||
+                         (TextFindIndex(TextToLower(GetGamepadName(gamepad)), PS_ALIAS_2) > -1))
                 {
                     DrawTexture(texPs3Pad, 0, 0, DARKGRAY);
 
diff --git a/raylib/examples/core/core_input_gestures_testbed.c b/raylib/examples/core/core_input_gestures_testbed.c
--- a/raylib/examples/core/core_input_gestures_testbed.c
+++ b/raylib/examples/core/core_input_gestures_testbed.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.0, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 5.0, last time updated with raylib 6.0
 *
 *   Example contributed by ubkp (@ubkp) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/core/core_input_virtual_controls.c b/raylib/examples/core/core_input_virtual_controls.c
--- a/raylib/examples/core/core_input_virtual_controls.c
+++ b/raylib/examples/core/core_input_virtual_controls.c
@@ -51,11 +51,31 @@
         { padPosition.x, padPosition.y + buttonRadius*1.5f }  // Down
     };
 
-    const char *buttonLabels[BUTTON_MAX] = {
-        "Y",    // Up
-        "X",    // Left
-        "B",    // Right
-        "A"     // Down
+    Vector2 arrowTris[4][3] = {
+        // Up
+        {
+            { buttonPositions[0].x,     buttonPositions[0].y - 12 },
+            { buttonPositions[0].x - 9, buttonPositions[0].y + 9  },
+            { buttonPositions[0].x + 9, buttonPositions[0].y + 9  }
+        },
+        // Left
+        {
+            { buttonPositions[1].x + 9,  buttonPositions[1].y - 9 },
+            { buttonPositions[1].x - 12, buttonPositions[1].y     },
+            { buttonPositions[1].x + 9,  buttonPositions[1].y + 9 }
+        },
+        // Right
+        {
+            { buttonPositions[2].x + 12, buttonPositions[2].y     },
+            { buttonPositions[2].x - 9,  buttonPositions[2].y - 9 },
+            { buttonPositions[2].x - 9,  buttonPositions[2].y + 9 }
+        },
+        // Down
+        {
+            { buttonPositions[3].x - 9, buttonPositions[3].y - 9  },
+            { buttonPositions[3].x,     buttonPositions[3].y + 12 },
+            { buttonPositions[3].x + 9, buttonPositions[3].y - 9  }
+        }
     };
 
     Color buttonLabelColors[BUTTON_MAX] = {
@@ -128,9 +148,12 @@
             {
                 DrawCircleV(buttonPositions[i], buttonRadius, (i == pressedButton)? DARKGRAY : BLACK);
 
-                DrawText(buttonLabels[i],
-                    (int)buttonPositions[i].x - 7, (int)buttonPositions[i].y - 8,
-                    20, buttonLabelColors[i]);
+                DrawTriangle(
+                    arrowTris[i][0],
+                    arrowTris[i][1],
+                    arrowTris[i][2],
+                    buttonLabelColors[i]
+                );
             }
 
             DrawText("move the player with D-Pad buttons", 10, 10, 20, DARKGRAY);
diff --git a/raylib/examples/core/core_keyboard_testbed.c b/raylib/examples/core/core_keyboard_testbed.c
--- a/raylib/examples/core/core_keyboard_testbed.c
+++ b/raylib/examples/core/core_keyboard_testbed.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   NOTE: raylib defined keys refer to ENG-US Keyboard layout, 
+*   NOTE: raylib defined keys refer to ENG-US Keyboard layout,
 *   mapping to other layouts is up to the user
 *
 *   Example originally created with raylib 5.6, last time updated with raylib 5.6
@@ -43,20 +43,20 @@
     int line01KeyWidths[15] = { 0 };
     for (int i = 0; i < 15; i++) line01KeyWidths[i] = 45;
     line01KeyWidths[13] = 62;   // PRINTSCREEN
-    int line01Keys[15] = { 
-        KEY_ESCAPE, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, 
-        KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, 
-        KEY_F12, KEY_PRINT_SCREEN, KEY_PAUSE 
+    int line01Keys[15] = {
+        KEY_ESCAPE, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+        KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
+        KEY_F12, KEY_PRINT_SCREEN, KEY_PAUSE
     };
-    
+
     // Keyboard line 02
     int line02KeyWidths[15] = { 0 };
     for (int i = 0; i < 15; i++) line02KeyWidths[i] = 45;
     line02KeyWidths[0] = 25;    // GRAVE
     line02KeyWidths[13] = 82;   // BACKSPACE
-    int line02Keys[15] = { 
-        KEY_GRAVE, KEY_ONE, KEY_TWO, KEY_THREE, KEY_FOUR, 
-        KEY_FIVE, KEY_SIX, KEY_SEVEN, KEY_EIGHT, KEY_NINE, 
+    int line02Keys[15] = {
+        KEY_GRAVE, KEY_ONE, KEY_TWO, KEY_THREE, KEY_FOUR,
+        KEY_FIVE, KEY_SIX, KEY_SEVEN, KEY_EIGHT, KEY_NINE,
         KEY_ZERO, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_DELETE };
 
     // Keyboard line 03
@@ -103,7 +103,7 @@
         KEY_SPACE, KEY_RIGHT_ALT, 162, KEY_NULL,
         KEY_RIGHT_CONTROL, KEY_LEFT, KEY_DOWN, KEY_RIGHT
     };
-    
+
     Vector2 keyboardOffset = { 26, 80 };
 
     SetTargetFPS(60);
@@ -128,28 +128,28 @@
             ClearBackground(RAYWHITE);
 
             DrawText("KEYBOARD LAYOUT: ENG-US", 26, 38, 20, LIGHTGRAY);
-            
+
             // Keyboard line 01 - 15 keys
             // ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, IMP, CLOSE
-            for (int i = 0, recOffsetX = 0; i < 15; i++) 
+            for (int i = 0, recOffsetX = 0; i < 15; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y, line01KeyWidths[i], 30 }, line01Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y, (float)line01KeyWidths[i], 30.0f }, line01Keys[i]);
                 recOffsetX += line01KeyWidths[i] + KEY_REC_SPACING;
             }
- 
+
             // Keyboard line 02 - 15 keys
             // `, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -, =, BACKSPACE, DEL
-            for (int i = 0, recOffsetX = 0; i < 15; i++) 
+            for (int i = 0, recOffsetX = 0; i < 15; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + KEY_REC_SPACING, line02KeyWidths[i], 38 }, line02Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + KEY_REC_SPACING, (float)line02KeyWidths[i], 38.0f }, line02Keys[i]);
                 recOffsetX += line02KeyWidths[i] + KEY_REC_SPACING;
             }
-            
+
             // Keyboard line 03 - 15 keys
             // TAB, Q, W, E, R, T, Y, U, I, O, P, [, ], \, INS
             for (int i = 0, recOffsetX = 0; i < 15; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38 + KEY_REC_SPACING*2, line03KeyWidths[i], 38 }, line03Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38 + KEY_REC_SPACING*2, (float)line03KeyWidths[i], 38.0f }, line03Keys[i]);
                 recOffsetX += line03KeyWidths[i] + KEY_REC_SPACING;
             }
 
@@ -157,7 +157,7 @@
             // MAYUS, A, S, D, F, G, H, J, K, L, ;, ', ENTER, REPAG
             for (int i = 0, recOffsetX = 0; i < 14; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*2 + KEY_REC_SPACING*3, line04KeyWidths[i], 38 }, line04Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*2 + KEY_REC_SPACING*3, (float)line04KeyWidths[i], 38.0f }, line04Keys[i]);
                 recOffsetX += line04KeyWidths[i] + KEY_REC_SPACING;
             }
 
@@ -165,7 +165,7 @@
             // LSHIFT, Z, X, C, V, B, N, M, ,, ., /, RSHIFT, UP, AVPAG
             for (int i = 0, recOffsetX = 0; i < 14; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*3 + KEY_REC_SPACING*4, line05KeyWidths[i], 38 }, line05Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*3 + KEY_REC_SPACING*4, (float)line05KeyWidths[i], 38.0f }, line05Keys[i]);
                 recOffsetX += line05KeyWidths[i] + KEY_REC_SPACING;
             }
 
@@ -173,7 +173,7 @@
             // LCTRL, WIN, LALT, SPACE, ALTGR, \, FN, RCTRL, LEFT, DOWN, RIGHT
             for (int i = 0, recOffsetX = 0; i < 11; i++)
             {
-                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*4 + KEY_REC_SPACING*5, line06KeyWidths[i], 38 }, line06Keys[i]);
+                GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*4 + KEY_REC_SPACING*5, (float)line06KeyWidths[i], 38.0f }, line06Keys[i]);
                 recOffsetX += line06KeyWidths[i] + KEY_REC_SPACING;
             }
 
@@ -316,16 +316,16 @@
         if (IsKeyDown(key))
         {
             DrawRectangleLinesEx(bounds, 2.0f, MAROON);
-            DrawText(GetKeyText(key), bounds.x + 4, bounds.y + 4, 10, MAROON);
+            DrawText(GetKeyText(key), (int)(bounds.x + 4), (int)(bounds.y + 4), 10, MAROON);
         }
         else
         {
             DrawRectangleLinesEx(bounds, 2.0f, DARKGRAY);
-            DrawText(GetKeyText(key), bounds.x + 4, bounds.y + 4, 10, DARKGRAY);
+            DrawText(GetKeyText(key), (int)(bounds.x + 4), (int)(bounds.y + 4), 10, DARKGRAY);
         }
     }
-    
-    if (CheckCollisionPointRec(GetMousePosition(), bounds)) 
+
+    if (CheckCollisionPointRec(GetMousePosition(), bounds))
     {
         DrawRectangleRec(bounds, Fade(RED, 0.2f));
         DrawRectangleLinesEx(bounds, 3.0f, RED);
diff --git a/raylib/examples/core/core_random_sequence.c b/raylib/examples/core/core_random_sequence.c
--- a/raylib/examples/core/core_random_sequence.c
+++ b/raylib/examples/core/core_random_sequence.c
@@ -96,8 +96,6 @@
             {
                 DrawRectangleRec(rectangles[i].rect, rectangles[i].color);
 
-                DrawText("Press SPACE to shuffle the sequence", 10, screenHeight - 96, 20, BLACK);
-
                 DrawText("Press SPACE to shuffle the current sequence", 10, screenHeight - 96, 20, BLACK);
                 DrawText("Press UP to add a rectangle and generate a new sequence", 10, screenHeight - 64, 20, BLACK);
                 DrawText("Press DOWN to remove a rectangle and generate a new sequence", 10, screenHeight - 32, 20, BLACK);
@@ -113,7 +111,7 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    free(rectangles);
+    RL_FREE(rectangles);
     CloseWindow(); // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/examples/core/core_render_texture.c b/raylib/examples/core/core_render_texture.c
--- a/raylib/examples/core/core_render_texture.c
+++ b/raylib/examples/core/core_render_texture.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
diff --git a/raylib/examples/core/core_screen_recording.c b/raylib/examples/core/core_screen_recording.c
--- a/raylib/examples/core/core_screen_recording.c
+++ b/raylib/examples/core/core_screen_recording.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
diff --git a/raylib/examples/core/core_smooth_pixelperfect.c b/raylib/examples/core/core_smooth_pixelperfect.c
--- a/raylib/examples/core/core_smooth_pixelperfect.c
+++ b/raylib/examples/core/core_smooth_pixelperfect.c
@@ -52,7 +52,7 @@
 
     // The target's height is flipped (in the source Rectangle), due to OpenGL reasons
     Rectangle sourceRec = { 0.0f, 0.0f, (float)target.texture.width, -(float)target.texture.height };
-    Rectangle destRec = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) };
+    Rectangle destRec = { (screenWidth - screenWidth/1.25f)/2.0f, (screenHeight - screenHeight/1.25f)/2.0f, screenWidth/1.25f, screenHeight/1.25f };
 
     Vector2 origin = { 0.0f, 0.0f };
 
@@ -61,6 +61,9 @@
     float cameraX = 0.0f;
     float cameraY = 0.0f;
 
+    bool smoothOn = true;
+    bool overscan = false;
+
     SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
 
@@ -86,6 +89,18 @@
         worldSpaceCamera.target.y = truncf(screenSpaceCamera.target.y);
         screenSpaceCamera.target.y -= worldSpaceCamera.target.y;
         screenSpaceCamera.target.y *= virtualRatio;
+
+        if (IsKeyPressed(KEY_S)) smoothOn = !smoothOn;
+        if (IsKeyPressed(KEY_O)) overscan = !overscan;
+
+        if (overscan)
+        {
+            destRec = (Rectangle) { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) };
+        }
+        else
+        {
+            destRec = (Rectangle) { (screenWidth - screenWidth/1.25f)/2.0f, (screenHeight - screenHeight/1.25f)/2.0f, screenWidth/1.25f, screenHeight/1.25f };
+        }
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -101,14 +116,23 @@
         EndTextureMode();
 
         BeginDrawing();
-            ClearBackground(RED);
+            ClearBackground(LIGHTGRAY);
 
-            BeginMode2D(screenSpaceCamera);
+            if (smoothOn)
+            {
+                BeginMode2D(screenSpaceCamera);
+                   DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE);
+                EndMode2D();
+            }
+            else
+            {
                 DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE);
-            EndMode2D();
+            }
 
             DrawText(TextFormat("Screen resolution: %ix%i", screenWidth, screenHeight), 10, 10, 20, DARKBLUE);
             DrawText(TextFormat("World resolution: %ix%i", virtualScreenWidth, virtualScreenHeight), 10, 40, 20, DARKGREEN);
+            DrawText(TextFormat("Smooth: %s", (smoothOn ? "ON" : "OFF")), 10, screenHeight - 60, 20, RED);
+            DrawText(TextFormat("Overscan: %s", (overscan ? "ON" : "OFF")), 10, screenHeight - 30, 20, RED);
             DrawFPS(GetScreenWidth() - 95, 10);
         EndDrawing();
         //----------------------------------------------------------------------------------
diff --git a/raylib/examples/core/core_viewport_scaling.c b/raylib/examples/core/core_viewport_scaling.c
--- a/raylib/examples/core/core_viewport_scaling.c
+++ b/raylib/examples/core/core_viewport_scaling.c
@@ -177,10 +177,10 @@
             DrawRectangleRec(increaseTypeButton, SKYBLUE);
             DrawRectangleRec(decreaseResolutionButton, SKYBLUE);
             DrawRectangleRec(increaseResolutionButton, SKYBLUE);
-            DrawText("<", decreaseTypeButton.x + 3, decreaseTypeButton.y + 1, 10, BLACK);
-            DrawText(">", increaseTypeButton.x + 3, increaseTypeButton.y + 1, 10, BLACK);
-            DrawText("<", decreaseResolutionButton.x + 3, decreaseResolutionButton.y + 1, 10, BLACK);
-            DrawText(">", increaseResolutionButton.x + 3, increaseResolutionButton.y + 1, 10, BLACK);
+            DrawText("<", (int)decreaseTypeButton.x + 3, (int)decreaseTypeButton.y + 1, 10, BLACK);
+            DrawText(">", (int)increaseTypeButton.x + 3, (int)increaseTypeButton.y + 1, 10, BLACK);
+            DrawText("<", (int)decreaseResolutionButton.x + 3, (int)decreaseResolutionButton.y + 1, 10, BLACK);
+            DrawText(">", (int)increaseResolutionButton.x + 3, (int)increaseResolutionButton.y + 1, 10, BLACK);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -216,7 +216,7 @@
 
 static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
 {
-    const float resizeRatio = (float)(screenHeight/gameHeight);
+    const float resizeRatio = (float)screenHeight/gameHeight;
     sourceRect->x = 0.0f;
     sourceRect->y = 0.0f;
     sourceRect->width = (float)(int)(screenWidth/resizeRatio);
@@ -230,7 +230,7 @@
 
 static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
 {
-    const float resizeRatio = (float)(screenWidth/gameWidth);
+    const float resizeRatio = (float)screenWidth/gameWidth;
     sourceRect->x = 0.0f;
     sourceRect->y = 0.0f;
     sourceRect->width = (float)gameWidth;
@@ -308,7 +308,7 @@
     }
 
     UnloadRenderTexture(*target);
-    *target = LoadRenderTexture(sourceRect->width, -sourceRect->height);
+    *target = LoadRenderTexture((int)sourceRect->width, -(int)sourceRect->height);
 }
 
 // Example how to calculate position on RenderTexture
diff --git a/raylib/examples/core/core_window_web.c b/raylib/examples/core/core_window_web.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/core/core_window_web.c
@@ -0,0 +1,86 @@
+/*******************************************************************************************
+*
+*   raylib [core] example - window web
+*
+*   Example complexity rating: [★☆☆☆] 1/4
+*
+*   Example originally created with raylib 1.3, last time updated with raylib 5.5
+*
+*   This example has been adapted to compile for PLATFORM_WEB and PLATFORM_DESKTOP
+*   As you will notice, code structure is slightly different to the other examples
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#if defined(PLATFORM_WEB)
+    #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+int screenWidth = 800;
+int screenHeight = 450;
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+void UpdateDrawFrame(void);     // Update and Draw one frame
+
+//----------------------------------------------------------------------------------
+// Program main entry point
+//----------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    InitWindow(screenWidth, screenHeight, "raylib [core] example - window web");
+
+#if defined(PLATFORM_WEB)
+    emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
+#else
+    SetTargetFPS(60);   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        UpdateDrawFrame();
+    }
+#endif
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+void UpdateDrawFrame(void)
+{
+    // Update
+    //----------------------------------------------------------------------------------
+    // TODO: Update your variables here
+    //----------------------------------------------------------------------------------
+
+    // Draw
+    //----------------------------------------------------------------------------------
+    BeginDrawing();
+
+        ClearBackground(RAYWHITE);
+
+        DrawText("Welcome to raylib web structure!", 220, 200, 20, SKYBLUE);
+
+    EndDrawing();
+    //----------------------------------------------------------------------------------
+}
diff --git a/raylib/examples/core/msf_gif.h b/raylib/examples/core/msf_gif.h
--- a/raylib/examples/core/msf_gif.h
+++ b/raylib/examples/core/msf_gif.h
@@ -413,7 +413,7 @@
 
     //generate palette
     typedef struct { uint8_t r, g, b; } Color3;
-    Color3 table[256] = { {0} };
+    Color3 table[256] = { { 0 } };
     int tableIdx = 1; //we start counting at 1 because 0 is the transparent color
     //transparent is always last in the table
     tlb[tlbSize-1] = 0;
@@ -550,7 +550,7 @@
 
 int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc
     //NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`.
-    MsfCookedFrame empty = {0}; //god I hate MSVC...
+    MsfCookedFrame empty = { 0 }; //god I hate MSVC...
     handle->previousFrame = empty;
     handle->currentFrame = empty;
     handle->width = width;
@@ -614,7 +614,7 @@
 }
 
 MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc
-    if (!handle->listHead) { MsfGifResult empty = {0}; return empty; }
+    if (!handle->listHead) { MsfGifResult empty = { 0 }; return empty; }
 
     //first pass: determine total size
     size_t total = 1; //1 byte for trailing marker
diff --git a/raylib/examples/core/raygui.h b/raylib/examples/core/raygui.h
--- a/raylib/examples/core/raygui.h
+++ b/raylib/examples/core/raygui.h
@@ -1,5949 +1,6422 @@
 /*******************************************************************************************
 *
-*   raygui v4.5-dev - 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        --> 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 set we have the EXTENDED properties (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_DEBUG_RECS_BOUNDS
-*           Draw control bounds rectangles for debug
-*
-*       #define RAYGUI_DEBUG_TEXT_BOUNDS
-*           Draw text bounds rectangles for debug
-*
-*   VERSIONS HISTORY:
-*       5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
-*                         ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
-*                         ADDED: GuiValueBoxFloat()
-*                         ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
-*                         ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
-*                         ADDED: GuiLoadIconsFromMemory()
-*                         ADDED: Multiple new icons
-*                         REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
-*                         REMOVED: GuiSliderPro(), functionality was redundant
-*                         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
-*                         REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
-*
-*       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 5.6-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-2025 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 4
-#define RAYGUI_VERSION_MINOR 5
-#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION  "5.0-dev"
-
-#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)     // We are building the library as a Win32 shared library (.dll)
-    #elif defined(USE_LIBTYPE_SHARED)
-        #define RAYGUIAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
-    #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
-
-//----------------------------------------------------------------------------------
-// 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;
-
-    // Rectangle type
-    typedef struct Rectangle {
-        float x;
-        float y;
-        float width;
-        float height;
-    } Rectangle;
-
-    // TODO: 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;
-
-    // TODO: 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 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
-typedef enum {
-    // Default -> populates to all controls when set
-    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
-} GuiControl;
-
-// Gui base properties for every control
-// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
-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
-} 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)
-//----------------------------------------------------------------------------------
-// DEFAULT extended properties
-// NOTE: Those properties are common to all controls or global
-// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
-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
-} GuiDefaultProperty;
-
-// Other possible text properties:
-// TEXT_WEIGHT                  // Normal, Italic, Bold -> Requires specific font change
-// TEXT_INDENT                  // Text indentation -> Now using TEXT_PADDING...
-
-// Label
-//typedef enum { } GuiLabelProperty;
-
-// Button/Spinner
-//typedef enum { } GuiButtonProperty;
-
-// Toggle/ToggleGroup
-typedef enum {
-    GROUP_PADDING = 16,         // ToggleGroup separation between toggles
-} 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
-} 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 (default rolls down)
-} GuiDropdownBoxProperty;
-
-// TextBox/TextBoxMulti/ValueBox/Spinner
-typedef enum {
-    TEXT_READONLY = 16,         // TextBox in read-only mode: 0-text editable, 1-text no-editable
-} GuiTextBoxProperty;
-
-// ValueBox/Spinner
-typedef enum {
-    SPINNER_BUTTON_WIDTH = 16,  // Spinner left/right buttons width
-    SPINNER_BUTTON_SPACING,     // Spinner buttons separation
-} GuiValueBoxProperty;
-
-// Control11
-//typedef enum { } GuiControl11Property;
-
-// ListView
-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)
-    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,
-    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
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// 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 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 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 GuiTabBar(Rectangle bounds, const 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
-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, const 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 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()
-//----------------------------------------------------------------------------------------------------------
-
-#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_250                      = 250,
-    ICON_251                      = 251,
-    ICON_252                      = 252,
-    ICON_253                      = 253,
-    ICON_254                      = 254,
-    ICON_255                      = 255
-} GuiIconName;
-#endif
-
-#endif
-
-#if defined(__cplusplus)
-}            // Prevents name mangling of functions
-#endif
-
-#endif // RAYGUI_H
-
-/***********************************************************************************
-*
-*   RAYGUI IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RAYGUI_IMPLEMENTATION)
-
-#include <ctype.h>              // required for: isspace() [GuiTextBox()]
-#include <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
-#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
-#include <math.h>               // Required for: roundf() [GuiColorPicker()]
-
-// 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 <stdlib.h>             // 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         256          // Maximum number of icons
-#define RAYGUI_ICON_MAX_NAME_LENGTH    32          // Maximum length of icon name id
-
-// 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: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 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
-    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
-};
-
-// 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 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 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()
-//-------------------------------------------------------------------------------
-
-// raylib functions already implemented in raygui
-//-------------------------------------------------------------------------------
-static Color GetColor(int hexValue);                // Returns a Color struct from hexadecimal value
-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 const 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
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize);    // Load style from memory (binary only)
-
-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 const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow);   // 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 Color GuiFade(Color color, float alpha);         // Fade color by an alpha factor
-
-//----------------------------------------------------------------------------------
-// Gui Setup Functions Definition
-//----------------------------------------------------------------------------------
-// Enable gui global state
-// NOTE: We check 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: We check 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 we try to setup a font but default style has not been
-        // lazily loaded before, it will be overwritten, so we need to force
-        // default style loading 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 = 0;
-    //GuiState state = guiState;
-
-    int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
-
-    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 - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
-    Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 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
-    //--------------------------------------------------------------------
-    GuiStatusBar(statusBar, title); // Draw window header as status bar
-    GuiPanel(windowPanel, NULL);    // Draw window base
-
-    // Draw window close button
-    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)
-    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;      // Window close button clicked: result = 1
-}
-
-// 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 = 0;
-    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 = 0;
-    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 = 0;
-    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) 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;
-}
-
-// Tab Bar control
-// NOTE: Using GuiToggle() for the TABS
-int GuiTabBar(Rectangle bounds, const 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(GetMousePosition(), 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)
-{
-    #define RAYGUI_MIN_SCROLLBAR_WIDTH     40
-    #define RAYGUI_MIN_SCROLLBAR_HEIGHT    40
-    #define RAYGUI_MIN_MOUSE_WHEEL_SPEED   20
-
-    int result = 0;
-    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 = hasVerticalScrollBar? 0.0f : -1.0f;
-    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 = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
-            if (hasHorizontalScrollBar)
-            {
-                if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-
-            if (hasVerticalScrollBar)
-            {
-                if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-#endif
-            float wheelMove = GetMouseWheelMove();
-
-            // Set scrolling speed with mouse wheel based on ratio between bounds and content
-            Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
-            if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-            if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-
-            // Horizontal and vertical scrolling with mouse wheel
-            if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
-            else scrollPos.y += wheelMove*mouseWheelSpeed.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) 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Button pressed: result = 1
-}
-
-// Label button control
-int GuiLabelButton(Rectangle bounds, const char *text)
-{
-    GuiState state = guiState;
-    bool pressed = false;
-
-    // NOTE: We 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 = GetMousePosition();
-
-        // Check checkbox state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
-    //--------------------------------------------------------------------
-
-    return pressed;
-}
-
-// Toggle Button control
-int GuiToggle(Rectangle bounds, const char *text, bool *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    bool temp = false;
-    if (active == NULL) active = &temp;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check toggle button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                state = STATE_NORMAL;
-                *active = !(*active);
-            }
-            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)
-{
-    #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
-        #define RAYGUI_TOGGLEGROUP_MAX_ITEMS    32
-    #endif
-
-    int result = 0;
-    float initBoundsX = bounds.x;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, rows);
-
-    int prevRow = rows[0];
-
-    for (int i = 0; i < itemCount; i++)
-    {
-        if (prevRow != rows[i])
-        {
-            bounds.x = initBoundsX;
-            bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
-            prevRow = rows[i];
-        }
-
-        if (i == (*active))
-        {
-            toggle = true;
-            GuiToggle(bounds, items[i], &toggle);
-        }
-        else
-        {
-            toggle = false;
-            GuiToggle(bounds, items[i], &toggle);
-            if (toggle) *active = i;
-        }
-
-        bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
-    }
-
-    return result;
-}
-
-// Toggle Slider control extended
-int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    if (active == NULL) active = &temp;
-
-    //bool toggle = false;    // Required for individual toggles
-
-    // Get substrings items from text (items pointers)
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = GetMousePosition();
-
-        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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                *checked = !(*checked);
-                result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds) ||
-            CheckCollisionPointRec(mousePoint, selector))
-        {
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                *active += 1;
-                if (*active >= itemCount) *active = 0;      // Cyclic combobox
-            }
-
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            // Check if mouse has been pressed or released outside limits
-            if (!CheckCollisionPointRec(mousePoint, boundsOpen))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-
-            // Check if already selected item has been pressed again
-            if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) 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 (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-                    {
-                        itemSelected = i;
-                        result = 1;         // Item selected
-                    }
-                    break;
-                }
-            }
-
-            itemBounds = bounds;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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? "#121#" : "#120#", 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;
-
-    // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
-    return result;   // Mouse click: result = 1
-}
-
-// 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 = 0;
-    GuiState state = guiState;
-
-    bool multiline = false;     // TODO: Consider multiline text input
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            // GLOBAL: Auto-cursor movement logic
-            // NOTE: Keystrokes are handled repeatedly when button is held down for some time
-            if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(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,
-            // we add 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 = GetCharPressed();       // Get Unicode codepoint
-            if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
-
-            // Encode codepoint as UTF-8
-            int codepointSize = 0;
-            const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
-
-            // Handle text paste action
-            if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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';
-                    }
-                }
-            }
-            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';
-            }
-
-            // Move cursor to start
-            if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
-
-            // Move cursor to end
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
-
-            // Delete related codepoints from text, after current cursor position
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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;
-            }
-
-            else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(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;
-            }
-
-            // Delete related codepoints from text, before current cursor position
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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;
-            }
-
-            else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(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;
-            }
-
-            // Move cursor position with keys
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                //int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
-            {
-                int prevCodepointSize = 0;
-                GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
-
-                textBoxCursorIndex -= prevCodepointSize;
-            }
-            else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
-            {
-                int nextCodepointSize = 0;
-                GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
-                textBoxCursorIndex += nextCodepointSize;
-            }
-
-            // Move cursor position with mouse
-            if (CheckCollisionPointRec(mousePosition, textBounds))     // Mouse hover text
-            {
-                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 (GetMousePosition().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) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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 && IsKeyPressed(KEY_ENTER)) ||
-                (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                textBoxCursorIndex = 0;     // GLOBAL: Reset the shared cursor index
-                autoCursorCounter = 0;      // GLOBAL: Reset counter for repeated keystrokes
-                result = 1;
-            }
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePosition, bounds))
-            {
-                state = STATE_FOCUSED;
-
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    textBoxCursorIndex = textLength;   // GLOBAL: Place cursor index to the end of current text
-                    autoCursorCounter = 0;             // GLOBAL: Reset counter for repeated keystrokes
-                    result = 1;
-                }
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Mouse button pressed: result = 1
-}
-
-/*
-// 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 = GetMousePosition();
-
-        // Check spinner state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) 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))));
-    //--------------------------------------------------------------------
-
-    *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;
-    GuiState state = guiState;
-
-    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 = GetMousePosition();
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                
-                // Only allow keys in range [48..57]
-                if ((key >= 48) && (key <= 57))
-                {
-                    textValue[keyCount] = (char)key;
-                    keyCount++;
-                    valueHasChanged = true;
-                }
-            }
-
-            // Delete text
-            if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
-            {
-                keyCount--;
-                textValue[keyCount] = '\0';
-                valueHasChanged = true;
-            }
-
-            if (valueHasChanged) *value = TextToInteger(textValue);
-
-            // NOTE: We are not clamp values until user input finishes
-            //if (*value > maxValue) *value = maxValue;
-            //else if (*value < minValue) *value = minValue;
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                if (*value > maxValue) *value = maxValue;
-                else if (*value < minValue) *value = minValue;
-
-                result = 1;
-            }
-        }
-        else
-        {
-            if (*value > maxValue) *value = maxValue;
-            else if (*value < minValue) *value = minValue;
-
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-// 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;
-    GuiState state = guiState;
-
-    //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
-    //snprintf(textValue, sizeof(textValue), "%2.2f", *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 = GetMousePosition();
-
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                    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 (IsKeyPressed(KEY_BACKSPACE))
-            {
-                if (keyCount > 0)
-                {
-                    keyCount--;
-                    textValue[keyCount] = '\0';
-                    valueHasChanged = true;
-                }
-            }
-
-            if (valueHasChanged) *value = TextToFloat(textValue);
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-    float oldValue = *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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    }
-
-    // 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
-    {
-        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);
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-
-    // 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));
-    //--------------------------------------------------------------------
-
-    // 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)
-        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 = 0;
-    GuiState state = guiState;
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
-
-    return result;
-}
-
-// List View control with extended parameters
-int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int itemFocused = (focus == NULL)? -1 : *focus;
-    int itemSelected = (active == NULL)? -1 : *active;
-
-    // Check if we need a scroll bar
-    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 = GetMousePosition();
-
-        // 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 (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                    {
-                        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)
-            {
-                int wheelMove = (int)GetMouseWheelMove();
-                startIndex -= wheelMove;
-
-                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(DEFAULT, 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
-            }
-            else if (((startIndex + i) == itemFocused)) // && (focus != NULL))  // NOTE: We want 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
-            }
-            else
-            {
-                // Draw item normal (no rectangle)
-                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, 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;
-
-    return result;
-}
-
-// Color Panel control - Color (RGBA) variant
-int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
-{
-    int result = 0;
-
-    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
-
-    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)
-    {
-        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 };
-    }
-    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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_UP))
-            {
-                hue -= 2.0f;
-                if (hue <= 0.0f) hue = 0.0f;
-            }
-            else if (IsKeyDown(KEY_DOWN))
-            {
-                hue += 2.0f;
-                if (hue >= 360.0f) hue = 360.0f;
-            }*/
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    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));
-    }
-    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);
-
-    // 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 = 0;
-
-    Color temp = { 200, 0, 0, 255 };
-    if (color == NULL) color = &temp;
-
-    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 });
-
-    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 = 0;
-
-    Vector3 tempHsv = { 0 };
-
-    if (colorHsv == NULL)
-    {
-        const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
-        tempHsv = ConvertRGBtoHSV(tempColor);
-        colorHsv = &tempHsv;
-    }
-
-    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 };
-
-    GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
-
-    return result;
-}
-
-// Color Panel control - HSV variant
-int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
-{
-    int result = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
-{
-    #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 = -1;    // Returns clicked button from buttons list, 0 refers to closed window button
-
-    int buttonCount = 0;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    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, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
-    //--------------------------------------------------------------------
-
-    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)
-{
-    #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
-
-    // 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;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    // 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);
-    }
-
-    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, textMaxSize, textEditMode)) 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);
-    }
-    else
-    {
-        if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
-    }
-
-    int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
-
-    for (int i = 0; i < buttonCount; i++)
-    {
-        if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    if (result >= 0) textEditMode = false;
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
-    //--------------------------------------------------------------------
-
-    return result;      // Result is the pressed button index
-}
-
-// Grid control
-// NOTE: Returns grid mouse-hover selected cell
-// About drawing lines at subpixel spacing, simple put, not easy solution:
-// 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 = 0;
-    GuiState state = guiState;
-
-    Vector2 mousePoint = GetMousePosition();
-    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);
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;
-
-            while (!feof(rgsFile))
-            {
-                switch (buffer[0])
-                {
-                    case 'p':
-                    {
-                        // Style property: p <control_id> <property_id> <property_value> <property_name>
-
-                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
-                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
-
-                    } break;
-                    case 'f':
-                    {
-                        // Style font: f <gen_font_size> <charmap_file> <font_file>
-
-                        int fontSize = 0;
-                        char charmapFileName[256] = { 0 };
-                        char fontFileName[256] = { 0 };
-                        sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, 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));
-                fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
-
-                GuiLoadStyleFromMemory(fileData, fileDataSize);
-
-                RAYGUI_FREE(fileData);
-            }
-
-            fclose(rgsFile);
-        }
-    }
-}
-
-// Load style default over global style
-void GuiLoadStyleDefault(void)
-{
-    // We set this variable 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, 15);        // DEFAULT, 15 pixels between lines
-    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);
-
-    // 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: We set 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 });
-    }
-}
-
-// 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)
-// 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;
-
-        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);
-
-        if ((signature[0] == 'r') &&
-            (signature[1] == 'G') &&
-            (signature[2] == 'I') &&
-            (signature[3] == ' '))
-        {
-            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);
-
-            // Read icons data directly over internal icons array
-            fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
-        }
-
-        fclose(rgiFile);
-    }
-
-    return guiIconsName;
-}
-
-// Load icons from memory
-// WARNING: Binary files only
-char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
-{
-    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)
-        {
-            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));
-                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)
-{
-    #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))
-            {
-            #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
-            }
-
-            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)
-int GuiGetTextWidth(const char *text)
-{
-    #if !defined(ICON_TEXT_PADDING)
-        #define ICON_TEXT_PADDING   4
-    #endif
-
-    Vector2 textSize = { 0 };
-    int textIconOffset = 0;
-
-    if ((text != NULL) && (text[0] != '\0'))
-    {
-        if (text[0] == '#')
-        {
-            for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
-            {
-                if (text[i] == '#')
-                {
-                    textIconOffset = i;
-                    break;
-                }
-            }
-        }
-
-        text += textIconOffset;
-
-        // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
-        float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
-        // Custom MeasureText() implementation
-        if ((guiFont.texture.id > 0) && (text != NULL))
-        {
-            // Get size in bytes of text, 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 + 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)
-{
-    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 CONTROL11:
-            // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
-        default:
-        {
-            // TODO: 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: We support up to 999 values for iconId
-static const char *GetTextIcon(const char *text, int *iconId)
-{
-#if !defined(RAYGUI_NO_ICONS)
-    *iconId = -1;
-    if (text[0] == '#')     // Maybe we have an icon!
-    {
-        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] == '#')
-        {
-            *iconId = TextToInteger(iconValue);
-
-            // 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 textSize = (int)strlen(text);
-
-    lines[0] = text;
-    *count = 1;
-
-    for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
-    {
-        if (text[i] == '\n')
-        {
-            k++;
-            lines[k] = &text[i + 1]; // WARNING: next value is valid?
-            *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(ICON_TEXT_PADDING)
-        #define 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: We can't use GuiTextSplit() function because it can be already 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_SIZE)/2);
-    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: We get text size after icon has been processed
-        // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
-        int textSizeX = GuiGetTextWidth(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 += 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 we get pixel-perfect coordinates,
-        // In case of decimals we got weird text positioning
-        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: We consider 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);
-        }
-#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 we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
-            // but we need to draw all of the bad bytes using the '?' symbol moving one byte
-            if (codepoint == 0x3f) codepointSize = 1; // TODO: Review 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_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_LINE_SPACING);
-                }
-            }
-
-            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,
-                // 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_LINE_SPACING);
-        else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
-        //---------------------------------------------------------------------------------
-    }
-
-#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(GuiGetFont(), 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);
-
-        GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, 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, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
-        GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
-        GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
-    }
-}
-
-// Split controls text into multiple strings
-// Also check for multiple columns (required by GuiToggleGroup())
-static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
-{
-    // 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
-
-    // 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
-    #endif
-
-    static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };   // 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;
-
-    // Count how many substrings we have on text and point to every one
-    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'))
-        {
-            result[counter] = buffer + i + 1;
-
-            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;
-        }
-    }
-
-    *count = counter;
-
-    return result;
-}
-
-// 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;
-}
-
-// 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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
-                !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
-            int wheel = (int)GetMouseWheelMove();
-            if (wheel != 0) value += wheel;
-
-            // Handle mouse button down
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_DOWN)) value += 5;
-                else if (IsKeyDown(KEY_UP)) value -= 5;
-            }
-            else
-            {
-                if (IsKeyDown(KEY_RIGHT)) value += 5;
-                else if (IsKeyDown(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
-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;
-}
-
-// 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];
-
-    va_list args;
-    va_start(args, text);
-    vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
-    va_end(args);
-
-    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
-const 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 we have on text and point to every one
-        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)
-{
-    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 we exit as soon as possible and a '?'(0x3f) codepoint is returned
-// Total number of bytes processed are returned as a parameter
-// NOTE: the standard says U+FFFD should be returned in case of errors
+*   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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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)
 {
diff --git a/raylib/examples/models/models_animation_blend_custom.c b/raylib/examples/models/models_animation_blend_custom.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_animation_blend_custom.c
@@ -0,0 +1,331 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - animation blend custom
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
+*
+*   Example contributed by dmitrii-brand (@dmitrii-brand) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   DETAILS: Example demonstrates per-bone animation blending, allowing smooth transitions
+*   between two animations by interpolating bone transforms. This is useful for:
+*    - Blending movement animations (walk/run) with action animations (jump/attack)
+*    - Creating smooth animation transitions
+*    - Layering animations (e.g., upper body attack while lower body walks)
+*
+*   WARNING: GPU skinning must be enabled in raylib with a compilation flag,
+*   if not enabled, CPU skinning will be used instead
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 dmitrii-brand (@dmitrii-brand)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#include "rlgl.h"       // Requried for: rlUpdateVertexBuffer() (CPU-skinning)
+
+#include <string.h>     // Required for: memcpy()
+#include <stdlib.h>     // Required for: NULL
+
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static bool IsUpperBodyBone(const char *boneName);
+static void UpdateModelAnimationBones(Model *model, ModelAnimation *anim1, int frame1,
+    ModelAnimation *anim2, int frame2, float blend, bool upperBodyBlend);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blend custom");
+
+    // Define the camera to look into our 3d world
+    Camera camera = { 0 };
+    camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; // Camera position
+    camera.target = (Vector3){ 0.0f, 1.0f, 0.0f };  // Camera looking at point
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };      // Camera up vector (rotation towards target)
+    camera.fovy = 45.0f;                            // Camera field-of-view Y
+    camera.projection = CAMERA_PERSPECTIVE;         // Camera projection type
+
+    // Load gltf model
+    Model model = LoadModel("resources/models/gltf/greenman.glb");
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
+
+    // Load skinning shader
+    // WARNING: GPU skinning must be enabled in raylib with a compilation flag,
+    // if not enabled, CPU skinning will be used instead
+    Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION),
+                                       TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION));
+    model.materials[1].shader = skinningShader;
+
+    // Load gltf model animations
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/gltf/greenman.glb", &animCount);
+
+    // Use specific animation indices: 2-walk/move, 3-attack
+    int animIndex0 = 2; // Walk/Move animation (index 2)
+    int animIndex1 = 3; // Attack animation (index 3)
+    int animCurrentFrame0 = 0;
+    int animCurrentFrame1 = 0;
+
+    // Validate indices
+    if (animIndex0 >= animCount) animIndex0 = 0;
+    if (animIndex1 >= animCount) animIndex1 = (animCount > 1) ? 1 : 0;
+
+    bool upperBodyBlend = true;     // Toggle: true = upper/lower body blending, false = uniform blending (50/50)
+
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())        // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        // Toggle upper/lower body blending mode (SPACE key)
+        if (IsKeyPressed(KEY_SPACE)) upperBodyBlend = !upperBodyBlend;
+
+        // Update animation frames
+        ModelAnimation anim0 = anims[animIndex0];
+        ModelAnimation anim1 = anims[animIndex1];
+
+        animCurrentFrame0 = (animCurrentFrame0 + 1)%anim0.keyframeCount;
+        animCurrentFrame1 = (animCurrentFrame1 + 1)%anim1.keyframeCount;
+
+        // Blend the two animations
+        // When upperBodyBlend is ON: upper body = attack (1.0), lower body = walk (0.0)
+        // When upperBodyBlend is OFF: uniform blend at 0.5 (50% walk, 50% attack)
+        float blendFactor = (upperBodyBlend? 1.0f : 0.5f);
+        UpdateModelAnimationBones(&model, &anim0, animCurrentFrame0,
+            &anim1, animCurrentFrame1, blendFactor, upperBodyBlend);
+
+        // raylib provided animation blending function
+        //UpdateModelAnimationEx(model, anim0, (float)animCurrentFrame0,
+        //    anim1, (float)animCurrentFrame1, blendFactor);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                DrawModel(model, position, 1.0f, WHITE);
+
+                DrawGrid(10, 1.0f);
+
+            EndMode3D();
+
+            // Draw UI
+            DrawText(TextFormat("ANIM 0: %s", anim0.name), 10, 10, 20, GRAY);
+            DrawText(TextFormat("ANIM 1: %s", anim1.name), 10, 40, 20, GRAY);
+            DrawText(TextFormat("[SPACE] Toggle blending mode: %s",
+                upperBodyBlend? "Upper/Lower Body Blending" : "Uniform Blending"),
+                10, GetScreenHeight() - 30, 20, DARKGRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModelAnimations(anims, animCount); // Unload model animation
+    UnloadModel(model);    // Unload model and meshes/material
+    UnloadShader(skinningShader);   // Unload GPU skinning shader
+
+    CloseWindow();                  // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Check if a bone is part of upper body (for selective blending)
+static bool IsUpperBodyBone(const char *boneName)
+{
+    // Common upper body bone names (adjust based on your model)
+    if (TextIsEqual(boneName, "spine") || TextIsEqual(boneName, "spine1") || TextIsEqual(boneName, "spine2") ||
+        TextIsEqual(boneName, "chest") || TextIsEqual(boneName, "upperChest") ||
+        TextIsEqual(boneName, "neck") || TextIsEqual(boneName, "head") ||
+        TextIsEqual(boneName, "shoulder") || TextIsEqual(boneName, "shoulder_L") || TextIsEqual(boneName, "shoulder_R") ||
+        TextIsEqual(boneName, "upperArm") || TextIsEqual(boneName, "upperArm_L") || TextIsEqual(boneName, "upperArm_R") ||
+        TextIsEqual(boneName, "lowerArm") || TextIsEqual(boneName, "lowerArm_L") || TextIsEqual(boneName, "lowerArm_R") ||
+        TextIsEqual(boneName, "hand") || TextIsEqual(boneName, "hand_L") || TextIsEqual(boneName, "hand_R") ||
+        TextIsEqual(boneName, "clavicle") || TextIsEqual(boneName, "clavicle_L") || TextIsEqual(boneName, "clavicle_R"))
+    {
+        return true;
+    }
+
+    // Check if bone name contains upper body keywords
+    if (strstr(boneName, "spine") != NULL || strstr(boneName, "chest") != NULL ||
+        strstr(boneName, "neck") != NULL || strstr(boneName, "head") != NULL ||
+        strstr(boneName, "shoulder") != NULL || strstr(boneName, "arm") != NULL ||
+        strstr(boneName, "hand") != NULL || strstr(boneName, "clavicle") != NULL)
+    {
+        return true;
+    }
+
+    return false;
+}
+
+// Blend two animations per-bone with selective upper/lower body blending
+static void UpdateModelAnimationBones(Model *model, ModelAnimation *anim0, int frame0,
+    ModelAnimation *anim1, int frame1, float blend, bool upperBodyBlend)
+{
+    // Validate inputs
+    if ((anim0->boneCount != 0) && (anim0->keyframePoses != NULL) &&
+        (anim1->boneCount != 0) && (anim1->keyframePoses != NULL) &&
+        (model->skeleton.boneCount != 0) && (model->skeleton.bindPose != NULL))
+    {
+        // Clamp blend factor to [0, 1]
+        blend = fminf(1.0f, fmaxf(0.0f, blend));
+
+        // Ensure frame indices are valid
+        if (frame0 >= anim0->keyframeCount) frame0 = anim0->keyframeCount - 1;
+        if (frame1 >= anim1->keyframeCount) frame1 = anim1->keyframeCount - 1;
+        if (frame0 < 0) frame0 = 0;
+        if (frame1 < 0) frame1 = 0;
+
+        // Get bone count (use minimum of all to be safe)
+        unsigned int boneCount = model->skeleton.boneCount;
+        if (anim0->boneCount < boneCount) boneCount = anim0->boneCount;
+        if (anim1->boneCount < boneCount) boneCount = anim1->boneCount;
+
+        // Blend each bone
+        for (unsigned int boneIndex = 0; boneIndex < boneCount; boneIndex++)
+        {
+            // Determine blend factor for this bone
+            float boneBlendFactor = blend;
+
+            // If upper body blending is enabled, use different blend factors for upper vs lower body
+            if (upperBodyBlend)
+            {
+                const char *boneName = model->skeleton.bones[boneIndex].name;
+                bool isUpperBody = IsUpperBodyBone(boneName);
+
+                // Upper body: use anim1 (attack), Lower body: use anim0 (walk)
+                // blend = 0.0 means full anim0 (walk), 1.0 means full anim1 (attack)
+                if (isUpperBody) boneBlendFactor = blend; // Upper body: blend towards anim1 (attack)
+                else boneBlendFactor = 1.0f - blend; // Lower body: blend towards anim0 (walk) - invert the blend
+            }
+
+            // Get transforms from both animations
+            Transform *bindTransform = &model->skeleton.bindPose[boneIndex];
+            Transform *animTransform0 = &anim0->keyframePoses[frame0][boneIndex];
+            Transform *animTransform1 = &anim1->keyframePoses[frame1][boneIndex];
+
+            // Blend the transforms
+            Transform blended = { 0 };
+            blended.translation = Vector3Lerp(animTransform0->translation, animTransform1->translation, boneBlendFactor);
+            blended.rotation = QuaternionSlerp(animTransform0->rotation, animTransform1->rotation, boneBlendFactor);
+            blended.scale = Vector3Lerp(animTransform0->scale, animTransform1->scale, boneBlendFactor);
+
+            // Convert bind pose to matrix
+            Matrix bindMatrix = MatrixMultiply(MatrixMultiply(
+                MatrixScale(bindTransform->scale.x, bindTransform->scale.y, bindTransform->scale.z),
+                QuaternionToMatrix(bindTransform->rotation)),
+                MatrixTranslate(bindTransform->translation.x, bindTransform->translation.y, bindTransform->translation.z));
+
+            // Convert blended transform to matrix
+            Matrix blendedMatrix = MatrixMultiply(MatrixMultiply(
+                MatrixScale(blended.scale.x, blended.scale.y, blended.scale.z),
+                QuaternionToMatrix(blended.rotation)),
+                MatrixTranslate(blended.translation.x, blended.translation.y, blended.translation.z));
+
+            // Calculate final bone matrix (similar to UpdateModelAnimationBones)
+            model->boneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindMatrix), blendedMatrix);
+        }
+
+        // CPU skinning, updates CPU buffers and uploads them to GPU (if available)
+        // NOTE: Fallback in case GPU skinning is not supported or enabled
+        for (int m = 0; m < model->meshCount; m++)
+        {
+            Mesh mesh = model->meshes[m];
+            Vector3 animVertex = { 0 };
+            Vector3 animNormal = { 0 };
+            const int vertexValuesCount = mesh.vertexCount*3;
+
+            int boneIndex = 0;
+            int boneCounter = 0;
+            float boneWeight = 0.0f;
+            bool bufferUpdateRequired = false; // Flag to check when anim vertex information is updated
+
+            // Skip if missing bone data or missing anim buffers initialization
+            if ((mesh.boneWeights == NULL) || (mesh.boneIndices == NULL) ||
+                (mesh.animVertices == NULL) || (mesh.animNormals == NULL)) continue;
+
+            for (int vCounter = 0; vCounter < vertexValuesCount; vCounter += 3)
+            {
+                mesh.animVertices[vCounter] = 0;
+                mesh.animVertices[vCounter + 1] = 0;
+                mesh.animVertices[vCounter + 2] = 0;
+                if (mesh.animNormals != NULL)
+                {
+                    mesh.animNormals[vCounter] = 0;
+                    mesh.animNormals[vCounter + 1] = 0;
+                    mesh.animNormals[vCounter + 2] = 0;
+                }
+
+                // Iterates over 4 bones per vertex
+                for (int j = 0; j < 4; j++, boneCounter++)
+                {
+                    boneWeight = mesh.boneWeights[boneCounter];
+                    boneIndex = mesh.boneIndices[boneCounter];
+
+                    // Early stop when no transformation will be applied
+                    if (boneWeight == 0.0f) continue;
+                    animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
+                    animVertex = Vector3Transform(animVertex, model->boneMatrices[boneIndex]);
+                    mesh.animVertices[vCounter] += animVertex.x*boneWeight;
+                    mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
+                    mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
+                    bufferUpdateRequired = true;
+
+                    // Normals processing
+                    // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
+                    if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
+                    {
+                        animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
+                        animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model->boneMatrices[boneIndex])));
+                        mesh.animNormals[vCounter] += animNormal.x*boneWeight;
+                        mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
+                        mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
+                    }
+                }
+            }
+
+            if (bufferUpdateRequired)
+            {
+                // Update GPU vertex buffers with updated data (position + normals)
+                rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_POSITION], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0);
+                if (mesh.normals != NULL) rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_NORMAL], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0);
+            }
+        }
+    }
+}
+
diff --git a/raylib/examples/models/models_animation_blending.c b/raylib/examples/models/models_animation_blending.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_animation_blending.c
@@ -0,0 +1,292 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - animation blending
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
+*
+*   Example contributed by Kirandeep (@Kirandeep-Singh-Khehra) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   WARNING: GPU skinning must be enabled in raylib with a compilation flag,
+*   if not enabled, CPU skinning will be used instead
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2024-2026 Kirandeep (@Kirandeep-Singh-Khehra) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"             // Required for: UI controls
+
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blending");
+
+    // Define the camera to look into our 3d world
+    Camera camera = { 0 };
+    camera.position = (Vector3){ 6.0f, 6.0f, 6.0f }; // Camera position
+    camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };  // Camera looking at point
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };      // Camera up vector (rotation towards target)
+    camera.fovy = 45.0f;                            // Camera field-of-view Y
+    camera.projection = CAMERA_PERSPECTIVE;         // Camera projection type
+
+    // Load model
+    Model model = LoadModel("resources/models/gltf/robot.glb"); // Load character model
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model world position
+
+#if SUPPORT_GPU_SKINNING
+    // WARNING: SUPPORT_GPU_SKINNING is required to be enabled at raylib compile time (disabled by default)
+    // It will skip loading CPU required buffers to store animation updated data, so, both modes are exclusive
+     
+    // Load skinning shader
+    // NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
+    Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION),
+                                       TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION));
+
+    // Skinning shader could be required to be assigned to all materials shaders, just to make
+    // sure required uniforms are being updated for the mesh using that material (and shader)
+    for (int i = 0; i < model.materialCount; i++) model.materials[i].shader = skinningShader;
+#endif
+
+    // Load model animations
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/gltf/robot.glb", &animCount);
+
+    // Animation playing variables
+    // NOTE: Two animations are played with a smooth transition between them
+    int currentAnimPlaying = 0;         // Current animation playing (0 o 1)
+    int nextAnimToPlay = 1;             // Next animation to play (to transition)
+    bool animTransition = false;        // Flag to register anim transition state
+
+    int animIndex0 = 10;                // Current animation playing (walking)
+    float animCurrentFrame0 = 0.0f;     // Current animation frame (supporting interpolated frames)
+    float animFrameSpeed0 = 0.5f;       // Current animation play speed
+    int animIndex1 = 6;                 // Next animation to play (running)
+    float animCurrentFrame1 = 0.0f;     // Next animation frame (supporting interpolated frames)
+    float animFrameSpeed1 = 0.5f;       // Next animation play speed
+
+    float animBlendFactor = 0.0f;       // Blend factor from anim0[frame0] --> anim1[frame1], [0.0f..1.0f]
+                                        // NOTE: 0.0f results in full anim0[] and 1.0f in full anim1[]
+
+    float animBlendTime = 2.0f;         // Time to blend from one playing animation to another (in seconds)
+    float animBlendTimeCounter = 0.0f;  // Time counter (delta time)
+
+    bool animPause = false;             // Pause animation
+
+    // UI required variables
+    char *animNames[64] = { 0 };        // Pointers to animation names for dropdown box
+    for (int i = 0; i < animCount; i++) animNames[i] = anims[i].name;
+
+    bool dropdownEditMode0 = false;
+    bool dropdownEditMode1 = false;
+    float animFrameProgress0 = 0.0f;
+    float animFrameProgress1 = 0.0f;
+    float animBlendProgress = 0.0f;
+
+    SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())        // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        if (IsKeyPressed(KEY_P)) animPause = !animPause;
+
+        if (!animPause)
+        {
+            // Start transition from anim0[] to anim1[]
+            if (IsKeyPressed(KEY_SPACE) && !animTransition)
+            {
+                if (currentAnimPlaying == 0)
+                {
+                    // Transition anim0 --> anim1
+                    nextAnimToPlay = 1;
+                    animCurrentFrame1 = 0.0f;
+                }
+                else
+                {
+                    // Transition anim1 --> anim0
+                    nextAnimToPlay = 0;
+                    animCurrentFrame0 = 0.0f;
+                }
+
+                // Set animation transition
+                animTransition = true;
+                animBlendTimeCounter = 0.0f;
+                animBlendFactor = 0.0f;
+            }
+
+            if (animTransition)
+            {
+                // Playing anim0 and anim1 at the same time
+                animCurrentFrame0 += animFrameSpeed0;
+                if (animCurrentFrame0 >= anims[animIndex0].keyframeCount) animCurrentFrame0 = 0.0f;
+                animCurrentFrame1 += animFrameSpeed1;
+                if (animCurrentFrame1 >= anims[animIndex1].keyframeCount) animCurrentFrame1 = 0.0f;
+
+                // Increment blend factor over time to transition from anim0 --> anim1 over time
+                // NOTE: Time blending could be other than linear, using some easing
+                animBlendFactor = animBlendTimeCounter/animBlendTime;
+                animBlendTimeCounter += GetFrameTime();
+                animBlendProgress = animBlendFactor;
+
+                // Update model with animations blending
+                if (nextAnimToPlay == 1)
+                {
+                    // Blend anim0 --> anim1
+                    UpdateModelAnimationEx(model, anims[animIndex0], animCurrentFrame0,
+                        anims[animIndex1], animCurrentFrame1, animBlendFactor);
+                }
+                else
+                {
+                    // Blend anim1 --> anim0
+                    UpdateModelAnimationEx(model, anims[animIndex1], animCurrentFrame1,
+                        anims[animIndex0], animCurrentFrame0, animBlendFactor);
+                }
+
+                // Check if transition completed
+                if (animBlendFactor > 1.0f)
+                {
+                    // Reset frame states
+                    if (currentAnimPlaying == 0) animCurrentFrame0 = 0.0f;
+                    else if (currentAnimPlaying == 1) animCurrentFrame1 = 0.0f;
+                    currentAnimPlaying = nextAnimToPlay; // Update current animation playing
+
+                    animBlendFactor = 0.0f; // Reset blend factor
+                    animTransition = false; // Exit transition mode
+                    animBlendTimeCounter = 0.0f;
+                }
+            }
+            else
+            {
+                // Play only one anim, the current one
+                if (currentAnimPlaying == 0)
+                {
+                    // Playing anim0 at defined speed
+                    animCurrentFrame0 += animFrameSpeed0;
+                    if (animCurrentFrame0 >= anims[animIndex0].keyframeCount) animCurrentFrame0 = 0.0f;
+                    UpdateModelAnimation(model, anims[animIndex0], animCurrentFrame0);
+                    //UpdateModelAnimationEx(model, anims[animIndex0], animCurrentFrame0,
+                    //    anims[animIndex1], animCurrentFrame1, 0.0f); // Same as above, first animation frame blend
+                }
+                else if (currentAnimPlaying == 1)
+                {
+                    // Playing anim1 at defined speed
+                    animCurrentFrame1 += animFrameSpeed1;
+                    if (animCurrentFrame1 >= anims[animIndex1].keyframeCount) animCurrentFrame1 = 0.0f;
+                    UpdateModelAnimation(model, anims[animIndex1], animCurrentFrame1);
+                    //UpdateModelAnimationEx(model, anims[animIndex0], animCurrentFrame0,
+                    //    anims[animIndex1], animCurrentFrame1, 1.0f); // Same as above, second animation frame blend
+                }
+            }
+        }
+
+        // Update progress bars values with current frame for each animation
+        animFrameProgress0 = animCurrentFrame0;
+        animFrameProgress1 = animCurrentFrame1;
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                DrawModel(model, position, 1.0f, WHITE); // Draw animated model
+
+                DrawGrid(10, 1.0f);
+
+            EndMode3D();
+
+            if (animTransition) DrawText("ANIM TRANSITION BLENDING!", 170, 50, 30, BLUE);
+
+            // Draw UI elements
+            //---------------------------------------------------------------------------------------------
+            if (dropdownEditMode0) GuiDisable();
+            GuiSlider((Rectangle){ 10, 38, 160, 12 },
+                NULL, TextFormat("x%.1f", animFrameSpeed0), &animFrameSpeed0, 0.1f, 2.0f);
+            GuiEnable();
+            if (dropdownEditMode1) GuiDisable();
+            GuiSlider((Rectangle){ GetScreenWidth() - 170.0f, 38, 160, 12 },
+                TextFormat("%.1fx", animFrameSpeed1), NULL, &animFrameSpeed1, 0.1f, 2.0f);
+            GuiEnable();
+
+            // Draw animation selectors for blending transition
+            // NOTE: Transition does not start until requested
+            GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 1);
+            if (GuiDropdownBox((Rectangle){ 10, 10, 160, 24 }, TextJoin(animNames, animCount, ";"),
+                &animIndex0, dropdownEditMode0)) dropdownEditMode0 = !dropdownEditMode0;
+
+            // Blending process progress bar
+            if (nextAnimToPlay == 1) GuiSetStyle(PROGRESSBAR, PROGRESS_SIDE, 0); // Left-->Right
+            else GuiSetStyle(PROGRESSBAR, PROGRESS_SIDE, 1); // Right-->Left
+            GuiProgressBar((Rectangle){ 180, 14, 440, 16 }, NULL, NULL, &animBlendProgress, 0.0f, 1.0f);
+            GuiSetStyle(PROGRESSBAR, PROGRESS_SIDE, 0); // Reset to Left-->Right
+
+            if (GuiDropdownBox((Rectangle){ GetScreenWidth() - 170.0f, 10, 160, 24 }, TextJoin(animNames, animCount, ";"),
+                &animIndex1, dropdownEditMode1)) dropdownEditMode1 = !dropdownEditMode1;
+
+            GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+            GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize*2);
+            GuiLabel((Rectangle){ 0, GetScreenHeight() - 100.0f, (float)GetScreenWidth(), 40 }, "PRESS SPACE to START BLENDING");
+            GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetFont().baseSize);
+            GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+
+            // Draw playing timeline with keyframes for anim0[]
+            GuiProgressBar((Rectangle){ 60, GetScreenHeight() - 60.0f, GetScreenWidth() - 180.0f, 20 }, "ANIM 0",
+                TextFormat("FRAME: %.2f / %i", animFrameProgress0, anims[animIndex0].keyframeCount),
+                &animFrameProgress0, 0.0f, (float)anims[animIndex0].keyframeCount);
+            for (int i = 0; i < anims[animIndex0].keyframeCount; i++)
+                DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180)/(float)anims[animIndex0].keyframeCount)*(float)i),
+                    GetScreenHeight() - 60, 1, 20, BLUE);
+
+            // Draw playing timeline with keyframes for anim1[]
+            GuiProgressBar((Rectangle){ 60, GetScreenHeight() - 30.0f, GetScreenWidth() - 180.0f, 20 }, "ANIM 1",
+                TextFormat("FRAME: %.2f / %i", animFrameProgress1, anims[animIndex1].keyframeCount),
+                &animFrameProgress1, 0.0f, (float)anims[animIndex1].keyframeCount);
+            for (int i = 0; i < anims[animIndex1].keyframeCount; i++)
+                DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180)/(float)anims[animIndex1].keyframeCount)*(float)i),
+                    GetScreenHeight() - 30, 1, 20, BLUE);
+            //---------------------------------------------------------------------------------------------
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModelAnimations(anims, animCount); // Unload model animation
+    UnloadModel(model);             // Unload model and meshes/material
+#if SUPPORT_GPU_SKINNING
+    UnloadShader(skinningShader);   // Unload GPU skinning shader
+#endif
+
+    CloseWindow();                  // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/models/models_animation_gpu_skinning.c b/raylib/examples/models/models_animation_gpu_skinning.c
--- a/raylib/examples/models/models_animation_gpu_skinning.c
+++ b/raylib/examples/models/models_animation_gpu_skinning.c
@@ -8,13 +8,14 @@
 *
 *   Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5)
 *
+*   WARNING: GPU skinning must be enabled in raylib with a compilation flag,
+*   if not enabled, CPU skinning will be used instead
+*
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
 *
 *   Copyright (c) 2024-2025 Daniel Holden (@orangeduck)
 *
-*   Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS
-*
 ********************************************************************************************/
 
 #include "raylib.h"
@@ -42,29 +43,36 @@
     // Define the camera to look into our 3d world
     Camera camera = { 0 };
     camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
-    camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };  // Camera looking at point
+    camera.target = (Vector3){ 0.0f, 1.0f, 0.0f };  // Camera looking at point
     camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };      // Camera up vector (rotation towards target)
     camera.fovy = 45.0f;                            // Camera field-of-view Y
     camera.projection = CAMERA_PERSPECTIVE;         // Camera projection type
 
     // Load gltf model
-    Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
+    Model model = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
 
+#if SUPPORT_GPU_SKINNING
+    // WARNING: SUPPORT_GPU_SKINNING is required to be enabled at raylib compile time (disabled by default)
+    // It will skip loading CPU required buffers to store animation updated data, so, both modes are exclusive
+
     // Load skinning shader
+    // NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
     Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION),
-                                       TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION));
+        TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION));
 
-    characterModel.materials[1].shader = skinningShader;
+    // Skinning shader could be required to be assigned to all materials shaders, just to make
+    // sure required uniforms are being updated for the mesh using that material (and shader)
+    model.materials[1].shader = skinningShader; // Just assigning to materials[1] for this model
+#endif
 
     // Load gltf model animations
-    int animsCount = 0;
-    unsigned int animIndex = 0;
-    unsigned int animCurrentFrame = 0;
-    ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount);
-
-    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/gltf/greenman.glb", &animCount);
 
-    DisableCursor();                    // Limit cursor to relative movement inside the window
+    // Animation playing variables
+    unsigned int animIndex = 0;         // Current animation playing
+    unsigned int animCurrentFrame = 0;  // Current animation frame
 
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -74,17 +82,15 @@
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Select current animation
-        if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount;
-        else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount;
+        if (IsKeyPressed(KEY_RIGHT)) animIndex = (animIndex + 1)%animCount;
+        else if (IsKeyPressed(KEY_LEFT)) animIndex = (animIndex + animCount - 1)%animCount;
 
         // Update model animation
-        ModelAnimation anim = modelAnimations[animIndex];
-        animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
-        characterModel.transform = MatrixTranslate(position.x, position.y, position.z);
-        UpdateModelAnimationBones(characterModel, anim, animCurrentFrame);
+        animCurrentFrame = (animCurrentFrame + 1)%anims[animIndex].keyframeCount;
+        UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -95,14 +101,14 @@
 
             BeginMode3D(camera);
 
-                // Draw character mesh, pose calculation is done in shader (GPU skinning)
-                DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform);
+                DrawModel(model, position, 1.0f, WHITE);
 
                 DrawGrid(10, 1.0f);
 
             EndMode3D();
 
-            DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY);
+            DrawText(TextFormat("Current animation: %s", anims[animIndex].name), 10, 40, 20, MAROON);
+            DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, GRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -110,9 +116,11 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    UnloadModelAnimations(modelAnimations, animsCount); // Unload model animation
-    UnloadModel(characterModel);    // Unload model and meshes/material
+    UnloadModelAnimations(anims, animCount); // Unload model animation
+    UnloadModel(model);             // Unload model and meshes/material
+#if SUPPORT_GPU_SKINNING
     UnloadShader(skinningShader);   // Unload GPU skinning shader
+#endif
 
     CloseWindow();                  // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
diff --git a/raylib/examples/models/models_animation_playing.c b/raylib/examples/models/models_animation_playing.c
deleted file mode 100644
--- a/raylib/examples/models/models_animation_playing.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [models] example - animation playing
-*
-*   Example complexity rating: [★★☆☆] 2/4
-*
-*   Example originally created with raylib 2.5, last time updated with raylib 3.5
-*
-*   Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5)
-*
-*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
-*   BSD-like license that allows static linking with closed source software
-*
-*   Copyright (c) 2019-2025 Culacant (@culacant) and Ramon Santamaria (@raysan5)
-*
-********************************************************************************************
-*
-*   NOTE: To export a model from blender, make sure it is not posed, the vertices need to be
-*         in the same position as they would be in edit mode and the scale of your models is
-*         set to 0. Scaling can be done from the export menu
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-//------------------------------------------------------------------------------------
-// Program main entry point
-//------------------------------------------------------------------------------------
-int main(void)
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    const int screenWidth = 800;
-    const int screenHeight = 450;
-
-    InitWindow(screenWidth, screenHeight, "raylib [models] example - animation playing");
-
-    // Define the camera to look into our 3d world
-    Camera camera = { 0 };
-    camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
-    camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };      // Camera looking at point
-    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target)
-    camera.fovy = 45.0f;                                // Camera field-of-view Y
-    camera.projection = CAMERA_PERSPECTIVE;             // Camera mode type
-
-    Model model = LoadModel("resources/models/iqm/guy.iqm");                    // Load the animated model mesh and basic data
-    Texture2D texture = LoadTexture("resources/models/iqm/guytex.png");         // Load model texture and set material
-    SetMaterialTexture(&model.materials[0], MATERIAL_MAP_DIFFUSE, texture);     // Set model material map texture
-
-    Vector3 position = { 0.0f, 0.0f, 0.0f };            // Set model position
-
-    // Load animation data
-    int animsCount = 0;
-    ModelAnimation *anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", &animsCount);
-    int animFrameCounter = 0;
-
-    DisableCursor();                    // Catch cursor
-    SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
-    //--------------------------------------------------------------------------------------
-
-    // Main game loop
-    while (!WindowShouldClose())        // Detect window close button or ESC key
-    {
-        // Update
-        //----------------------------------------------------------------------------------
-        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
-
-        // Play animation when spacebar is held down
-        if (IsKeyDown(KEY_SPACE))
-        {
-            animFrameCounter++;
-            UpdateModelAnimation(model, anims[0], animFrameCounter);
-            if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0;
-        }
-        //----------------------------------------------------------------------------------
-
-        // Draw
-        //----------------------------------------------------------------------------------
-        BeginDrawing();
-
-            ClearBackground(RAYWHITE);
-
-            BeginMode3D(camera);
-
-                DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
-
-                for (int i = 0; i < model.boneCount; i++)
-                {
-                    DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED);
-                }
-
-                DrawGrid(10, 1.0f);         // Draw a grid
-
-            EndMode3D();
-
-            DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON);
-            DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY);
-
-        EndDrawing();
-        //----------------------------------------------------------------------------------
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    UnloadTexture(texture);                     // Unload texture
-    UnloadModelAnimations(anims, animsCount);   // Unload model animations data
-    UnloadModel(model);                         // Unload model
-
-    CloseWindow();                  // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-
-    return 0;
-}
diff --git a/raylib/examples/models/models_animation_timing.c b/raylib/examples/models/models_animation_timing.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_animation_timing.c
@@ -0,0 +1,133 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - animation timing
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"             // Required for: UI controls
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - animation timing");
+
+    // Define the camera to look into our 3d world
+    Camera camera = { 0 };
+    camera.position = (Vector3){ 6.0f, 6.0f, 6.0f };    // Camera position
+    camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };      // Camera looking at point
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target)
+    camera.fovy = 45.0f;                                // Camera field-of-view Y
+    camera.projection = CAMERA_PERSPECTIVE;             // Camera projection type
+
+    // Load model
+    Model model = LoadModel("resources/models/gltf/robot.glb");
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model world position
+
+    // Load model animations
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/gltf/robot.glb", &animCount);
+
+    // Animation playing variables
+    int animIndex = 10;                  // Current animation playing
+    float animCurrentFrame = 0.0f;      // Current animation frame (supporting interpolated frames)
+    float animFrameSpeed = 0.5f;        // Animation play speed
+    bool animPause = false;             // Pause animation
+
+    // UI required variables
+    char *animNames[64] = { 0 };
+    for (int i = 0; i < animCount; i++) animNames[i] = anims[i].name;
+
+    bool dropdownEditMode = false;
+    float animFrameProgress = 0.0f;
+
+    SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())        // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        if (IsKeyPressed(KEY_P)) animPause = !animPause;
+
+        if (!animPause && (animIndex < animCount))
+        {
+            // Update model animation
+            animCurrentFrame += animFrameSpeed;
+            if (animCurrentFrame >= anims[animIndex].keyframeCount) animCurrentFrame = 0.0f;
+            UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
+        }
+
+        // NOTE: Animation and playing speed selected through UI
+
+        // Update progressbar value with current frame
+        animFrameProgress = animCurrentFrame;
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                DrawModel(model, position, 1.0f, WHITE);
+
+                DrawGrid(10, 1.0f);
+
+            EndMode3D();
+
+            // Draw UI, select anim and playing speed
+            GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 1);
+            if (GuiDropdownBox((Rectangle){ 10, 10, 140, 24 }, TextJoin(animNames, animCount, ";"),
+                &animIndex, dropdownEditMode)) dropdownEditMode = !dropdownEditMode;
+
+            GuiSlider((Rectangle){ 260, 10, 500, 24 }, "FRAME SPEED: ", TextFormat("x%.1f", animFrameSpeed),
+                &animFrameSpeed, 0.1f, 2.0f);
+
+            // Draw playing timeline with keyframes
+            GuiLabel((Rectangle){ 10, GetScreenHeight() - 64.0f, GetScreenWidth() - 20.0f, 24 },
+                TextFormat("CURRENT FRAME: %.2f / %i", animFrameProgress, anims[animIndex].keyframeCount));
+            GuiProgressBar((Rectangle){ 10, GetScreenHeight() - 40.0f, GetScreenWidth() - 20.0f, 24 }, NULL, NULL,
+                &animFrameProgress, 0.0f, (float)anims[animIndex].keyframeCount);
+            for (int i = 0; i < anims[animIndex].keyframeCount; i++)
+                DrawRectangle(10 + (int)(((float)(GetScreenWidth() - 20)/(float)anims[animIndex].keyframeCount)*(float)i),
+                    GetScreenHeight() - 40, 1, 24, BLUE);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModelAnimations(anims, animCount); // Unload model animation
+    UnloadModel(model);         // Unload model and meshes/material
+
+    CloseWindow();              // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
diff --git a/raylib/examples/models/models_basic_voxel.c b/raylib/examples/models/models_basic_voxel.c
--- a/raylib/examples/models/models_basic_voxel.c
+++ b/raylib/examples/models/models_basic_voxel.c
@@ -16,6 +16,7 @@
 ********************************************************************************************/
 
 #include "raylib.h"
+
 #include "raymath.h"
 
 #define WORLD_SIZE 8   // Size of our voxel world (8x8x8 cubes)
@@ -32,7 +33,7 @@
 
     InitWindow(screenWidth, screenHeight, "raylib [models] example - basic voxel");
 
-    DisableCursor();                    // Lock mouse to window center
+    DisableCursor(); // Lock mouse to window center
 
     // Define the camera to look into our 3d world (first person)
     Camera3D camera = { 0 };
@@ -71,19 +72,22 @@
         UpdateCamera(&camera, CAMERA_FIRST_PERSON);
 
         // Handle voxel removal with mouse click
+        // This method is quite inefficient. Ray marching through the voxel grid using DDA would be faster, but more complex.
         if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
         {
             // Cast a ray from the screen center (where crosshair would be)
-            Vector2 screenCenter = { screenWidth/2.0f, screenHeight/2.0f };
-            Ray ray = GetMouseRay(screenCenter, camera);
+            Vector2 screenCenter = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
+            Ray ray = GetScreenToWorldRay(screenCenter, camera);
 
             // Check ray collision with all voxels
-            bool voxelRemoved = false;
-            for (int x = 0; (x < WORLD_SIZE) && !voxelRemoved; x++)
+            float closestDistance = 99999.0f;
+            Vector3 closestVoxelPosition = { -1, -1, -1 };
+            bool voxelFound = false;
+            for (int x = 0; x < WORLD_SIZE; x++)
             {
-                for (int y = 0; (y < WORLD_SIZE) && !voxelRemoved; y++)
+                for (int y = 0; y < WORLD_SIZE; y++)
                 {
-                    for (int z = 0; (z < WORLD_SIZE) && !voxelRemoved; z++)
+                    for (int z = 0; z < WORLD_SIZE; z++)
                     {
                         if (!voxels[x][y][z]) continue; // Skip empty voxels
 
@@ -96,14 +100,23 @@
 
                         // Check ray-box collision
                         RayCollision collision = GetRayCollisionBox(ray, box);
-                        if (collision.hit)
+                        if (collision.hit && (collision.distance < closestDistance))
                         {
-                            voxels[x][y][z] = false;    // Remove this voxel
-                            voxelRemoved = true;        // Exit all loops
+                            closestDistance = collision.distance;
+                            closestVoxelPosition = (Vector3){ (float)x, (float)y, (float)z };
+                            voxelFound = true;
                         }
                     }
                 }
             }
+
+            // Remove the closest voxel if one was hit
+            if (voxelFound)
+            {
+                voxels[(int)closestVoxelPosition.x]
+                      [(int)closestVoxelPosition.y]
+                      [(int)closestVoxelPosition.z] = false;
+            }
         }
         //----------------------------------------------------------------------------------
 
@@ -135,6 +148,9 @@
 
             EndMode3D();
 
+            // Draw reference point for raycasting to delete blocks
+            DrawCircle(GetScreenWidth()/2, GetScreenHeight()/2, 4, RED);
+
             DrawText("Left-click a voxel to remove it!", 10, 10, 20, DARKGRAY);
             DrawText("WASD to move, mouse to look around", 10, 35, 10, GRAY);
 
@@ -145,6 +161,7 @@
     // De-Initialization
     //--------------------------------------------------------------------------------------
     UnloadModel(cubeModel);
+
     CloseWindow();
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/examples/models/models_bone_socket.c b/raylib/examples/models/models_bone_socket.c
--- a/raylib/examples/models/models_bone_socket.c
+++ b/raylib/examples/models/models_bone_socket.c
@@ -60,25 +60,25 @@
     unsigned int animCurrentFrame = 0;
     ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount);
 
-    // indices of bones for sockets
+    // Indices of bones for sockets
     int boneSocketIndex[BONE_SOCKETS] = { -1, -1, -1 };
 
-    // search bones for sockets
-    for (int i = 0; i < characterModel.boneCount; i++)
+    // Search bones for sockets
+    for (unsigned int i = 0; i < characterModel.skeleton.boneCount; i++)
     {
-        if (TextIsEqual(characterModel.bones[i].name, "socket_hat"))
+        if (TextIsEqual(characterModel.skeleton.bones[i].name, "socket_hat"))
         {
             boneSocketIndex[BONE_SOCKET_HAT] = i;
             continue;
         }
 
-        if (TextIsEqual(characterModel.bones[i].name, "socket_hand_R"))
+        if (TextIsEqual(characterModel.skeleton.bones[i].name, "socket_hand_R"))
         {
             boneSocketIndex[BONE_SOCKET_HAND_R] = i;
             continue;
         }
 
-        if (TextIsEqual(characterModel.bones[i].name, "socket_hand_L"))
+        if (TextIsEqual(characterModel.skeleton.bones[i].name, "socket_hand_L"))
         {
             boneSocketIndex[BONE_SOCKET_HAND_L] = i;
             continue;
@@ -115,8 +115,8 @@
 
         // Update model animation
         ModelAnimation anim = modelAnimations[animIndex];
-        animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
-        UpdateModelAnimation(characterModel, anim, animCurrentFrame);
+        animCurrentFrame = (animCurrentFrame + 1)%anim.keyframeCount;
+        UpdateModelAnimation(characterModel, anim, (float)animCurrentFrame);
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -129,7 +129,7 @@
                 // Draw character
                 Quaternion characterRotate = QuaternionFromAxisAngle((Vector3){ 0.0f, 1.0f, 0.0f }, angle*DEG2RAD);
                 characterModel.transform = MatrixMultiply(QuaternionToMatrix(characterRotate), MatrixTranslate(position.x, position.y, position.z));
-                UpdateModelAnimation(characterModel, anim, animCurrentFrame);
+                UpdateModelAnimation(characterModel, anim, (float)animCurrentFrame);
                 DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform);
 
                 // Draw equipments (hat, sword, shield)
@@ -137,8 +137,8 @@
                 {
                     if (!showEquip[i]) continue;
 
-                    Transform *transform = &anim.framePoses[animCurrentFrame][boneSocketIndex[i]];
-                    Quaternion inRotation = characterModel.bindPose[boneSocketIndex[i]].rotation;
+                    Transform *transform = &anim.keyframePoses[animCurrentFrame][boneSocketIndex[i]];
+                    Quaternion inRotation = characterModel.skeleton.bindPose[boneSocketIndex[i]].rotation;
                     Quaternion outRotation = transform->rotation;
 
                     // Calculate socket rotation (angle between bone in initial pose and same bone in current animation frame)
diff --git a/raylib/examples/models/models_decals.c b/raylib/examples/models/models_decals.c
--- a/raylib/examples/models/models_decals.c
+++ b/raylib/examples/models/models_decals.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★★] 4/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
 *   Based on previous work by @mrdoob
@@ -108,7 +108,7 @@
     decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE;
 
     bool showModel = true;
-    Model decalModels[MAX_DECALS] = { 0 };
+    static Model decalModels[MAX_DECALS] = { 0 };
     int decalCount = 0;
 
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
@@ -183,7 +183,7 @@
                 if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE);
 
                 // Draw the decal models
-                for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE);
+                for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){ 0 }, 1.0f, WHITE);
 
                 // If we hit the mesh, draw the box for the decal
                 if (collision.hit)
@@ -191,7 +191,7 @@
                     Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
                     Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0});
                     placementCube.transform = MatrixInvert(splat);
-                    DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f));
+                    DrawModel(placementCube, (Vector3){ 0 }, 1.0f, Fade(WHITE, 0.5f));
                 }
 
                 DrawGrid(10, 10.0f);
@@ -249,7 +249,7 @@
             DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY);
 
             // UI elements
-            if (GuiButton((Rectangle){ 10, screenHeight - 1000.f, 100, 60 }, showModel ? "Hide Model" : "Show Model")) showModel = !showModel;
+            if (GuiButton((Rectangle){ 10, screenHeight - 100.0f, 100, 60 }, showModel ? "Hide Model" : "Show Model")) showModel = !showModel;
 
             if (GuiButton((Rectangle){ 10 + 110, screenHeight - 100.0f, 100, 60 }, "Clear Decals"))
             {
diff --git a/raylib/examples/models/models_directional_billboard.c b/raylib/examples/models/models_directional_billboard.c
--- a/raylib/examples/models/models_directional_billboard.c
+++ b/raylib/examples/models/models_directional_billboard.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -17,7 +17,9 @@
 ********************************************************************************************/
 
 #include "raylib.h"
+
 #include "raymath.h"
+
 #include <stdlib.h>
 
 //------------------------------------------------------------------------------------
diff --git a/raylib/examples/models/models_loading.c b/raylib/examples/models/models_loading.c
--- a/raylib/examples/models/models_loading.c
+++ b/raylib/examples/models/models_loading.c
@@ -7,11 +7,11 @@
 *   NOTE: raylib supports multiple models file formats:
 *
 *     - OBJ  > Text file format. Must include vertex position-texcoords-normals information,
-*              if files references some .mtl materials file, it will be loaded (or try to)
-*     - GLTF > Text/binary file format. Includes lot of information and it could
-*              also reference external files, raylib will try loading mesh and materials data
+*              if .obj references some .mtl materials file, it will be tried to be loaded
+*     - GLTF/GLB > Text/binary file formats. Includes lot of information and it could
+*              also reference external files, mesh and materials data will be tried to be loaded
 *     - IQM  > Binary file format. Includes mesh vertex data but also animation data,
-*              raylib can load .iqm animations
+*              meshes and animation data can be loaded
 *     - VOX  > Binary file format. MagikaVoxel mesh format:
 *              https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt
 *     - M3D  > Binary file format. Model 3D format:
@@ -43,10 +43,10 @@
     // Define the camera to look into our 3d world
     Camera camera = { 0 };
     camera.position = (Vector3){ 50.0f, 50.0f, 50.0f }; // Camera position
-    camera.target = (Vector3){ 0.0f, 10.0f, 0.0f };     // Camera looking at point
+    camera.target = (Vector3){ 0.0f, 12.0f, 0.0f };     // Camera looking at point
     camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target)
     camera.fovy = 45.0f;                                // Camera field-of-view Y
-    camera.projection = CAMERA_PERSPECTIVE;                   // Camera mode type
+    camera.projection = CAMERA_PERSPECTIVE;             // Camera mode type
 
     Model model = LoadModel("resources/models/obj/castle.obj");                 // Load model
     Texture2D texture = LoadTexture("resources/models/obj/castle_diffuse.png"); // Load model texture
@@ -61,8 +61,6 @@
 
     bool selected = false;          // Selected object flag
 
-    DisableCursor();                // Limit cursor to relative movement inside the window
-
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -71,7 +69,7 @@
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Load new models/textures on drag&drop
         if (IsFileDropped())
@@ -93,7 +91,10 @@
 
                     bounds = GetMeshBoundingBox(model.meshes[0]);
 
-                    // TODO: Move camera position from target enough distance to visualize model properly
+                    // Move camera position from target enough distance to visualize model properly
+                    camera.position.x = bounds.max.x + 10.0f;
+                    camera.position.y = bounds.max.y + 10.0f;
+                    camera.position.z = bounds.max.z + 10.0f;
                 }
                 else if (IsFileExtension(droppedFiles.paths[0], ".png"))  // Texture file formats supported
                 {
diff --git a/raylib/examples/models/models_loading_gltf.c b/raylib/examples/models/models_loading_gltf.c
--- a/raylib/examples/models/models_loading_gltf.c
+++ b/raylib/examples/models/models_loading_gltf.c
@@ -42,16 +42,18 @@
     camera.fovy = 45.0f;                                // Camera field-of-view Y
     camera.projection = CAMERA_PERSPECTIVE;             // Camera projection type
 
-    // Load gltf model
+    // Load model
     Model model = LoadModel("resources/models/gltf/robot.glb");
-    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model world position
 
-    // Load gltf model animations
-    int animsCount = 0;
-    unsigned int animIndex = 0;
-    unsigned int animCurrentFrame = 0;
-    ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/robot.glb", &animsCount);
+    // Load model animations
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/gltf/robot.glb", &animCount);
 
+    // Animation playing variables
+    unsigned int animIndex = 0;         // Current animation playing
+    unsigned int animCurrentFrame = 0;  // Current animation frame
+
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -63,13 +65,12 @@
         UpdateCamera(&camera, CAMERA_ORBITAL);
 
         // Select current animation
-        if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) animIndex = (animIndex + 1)%animsCount;
-        else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) animIndex = (animIndex + animsCount - 1)%animsCount;
+        if (IsKeyPressed(KEY_RIGHT)) animIndex = (animIndex + 1)%animCount;
+        else if (IsKeyPressed(KEY_LEFT)) animIndex = (animIndex + animCount - 1)%animCount;
 
         // Update model animation
-        ModelAnimation anim = modelAnimations[animIndex];
-        animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
-        UpdateModelAnimation(model, anim, animCurrentFrame);
+        animCurrentFrame = (animCurrentFrame + 1)%anims[animIndex].keyframeCount;
+        UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -79,12 +80,15 @@
             ClearBackground(RAYWHITE);
 
             BeginMode3D(camera);
-                DrawModel(model, position, 1.0f, WHITE);    // Draw animated model
+
+                DrawModel(model, position, 1.0f, WHITE);
+
                 DrawGrid(10, 1.0f);
+
             EndMode3D();
 
-            DrawText("Use the LEFT/RIGHT mouse buttons to switch animation", 10, 10, 20, GRAY);
-            DrawText(TextFormat("Animation: %s", anim.name), 10, GetScreenHeight() - 20, 10, DARKGRAY);
+            DrawText(TextFormat("Current animation: %s", anims[animIndex].name), 10, 40, 20, MAROON);
+            DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, GRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -92,7 +96,8 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    UnloadModel(model);         // Unload model and meshes/material
+    UnloadModelAnimations(anims, animCount); // Unload model animations data
+    UnloadModel(model);         // Unload model
 
     CloseWindow();              // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
diff --git a/raylib/examples/models/models_loading_iqm.c b/raylib/examples/models/models_loading_iqm.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_loading_iqm.c
@@ -0,0 +1,104 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - loading iqm
+*
+*   Example complexity rating: [★★☆☆] 2/4
+*
+*   Example originally created with raylib 2.5, last time updated with raylib 3.5
+*
+*   Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   NOTES: To export an IQM model from blender, make sure it is not posed, the vertices need
+*   to be in the same position as they would be in edit mode and the scale of the models is
+*   set to 0; scaling can be set from the export menu
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2019-2025 Culacant (@culacant) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - loading iqm");
+
+    // Define the camera to look into our 3d world
+    Camera camera = { 0 };
+    camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
+    camera.target = (Vector3){ 0.0f, 4.0f, 0.0f };      // Camera looking at point
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target)
+    camera.fovy = 45.0f;                                // Camera field-of-view Y
+    camera.projection = CAMERA_PERSPECTIVE;             // Camera mode type
+
+    Model model = LoadModel("resources/models/iqm/guy.iqm");                    // Load the animated model mesh and basic data
+    Texture2D texture = LoadTexture("resources/models/iqm/guytex.png");         // Load model texture and set material
+    SetMaterialTexture(&model.materials[0], MATERIAL_MAP_DIFFUSE, texture);     // Set model material map texture
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
+
+    // Load animation data
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", &animCount);
+
+    // Animation playing variables
+    unsigned int animIndex = 0;         // Current animation playing
+    float animCurrentFrame = 0.0f;      // Current animation frame (supporting interpolated frames)
+
+    SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())        // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        // Play animation when spacebar is held down
+        animCurrentFrame += 1.0f;
+        UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
+        if (animCurrentFrame >= anims[animIndex].keyframeCount) animCurrentFrame = 0;
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
+
+                DrawGrid(10, 1.0f);
+
+            EndMode3D();
+
+            DrawText(TextFormat("Current animation: %s", anims[animIndex].name), 10, 10, 20, MAROON);
+            DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadTexture(texture);                    // Unload texture
+    UnloadModelAnimations(anims, animCount);   // Unload model animations data
+    UnloadModel(model);                        // Unload model
+
+    CloseWindow();                  // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/models/models_loading_m3d.c b/raylib/examples/models/models_loading_m3d.c
--- a/raylib/examples/models/models_loading_m3d.c
+++ b/raylib/examples/models/models_loading_m3d.c
@@ -21,6 +21,8 @@
 
 #include "raylib.h"
 
+static void DrawModelSkeleton(ModelSkeleton skeleton, ModelAnimPose pose, float scale, Color color);
+
 //------------------------------------------------------------------------------------
 // Program main entry point
 //------------------------------------------------------------------------------------
@@ -41,22 +43,17 @@
     camera.fovy = 45.0f;                                // Camera field-of-view Y
     camera.projection = CAMERA_PERSPECTIVE;             // Camera projection type
 
-    Vector3 position = { 0.0f, 0.0f, 0.0f };            // Set model position
-
-    char modelFileName[128] = "resources/models/m3d/cesium_man.m3d";
-    bool drawMesh = 1;
-    bool drawSkeleton = 1;
-    bool animPlaying = false;   // Store anim state, what to draw
-
     // Load model
-    Model model = LoadModel(modelFileName); // Load the bind-pose model mesh and basic data
+    Model model = LoadModel("resources/models/m3d/cesium_man.m3d");             // Load the animated model mesh and basic data
+    Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
 
-    // Load animations
-    int animsCount = 0;
-    int animFrameCounter = 0, animId = 0;
-    ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data
+    // Load animation data
+    int animCount = 0;
+    ModelAnimation *anims = LoadModelAnimations("resources/models/m3d/cesium_man.m3d", &animCount);
 
-    DisableCursor();                    // Limit cursor to relative movement inside the window
+    // Animation playing variables
+    unsigned int animIndex = 0;         // Current animation playing
+    float animCurrentFrame = 0.0f;      // Current animation frame (supporting interpolated frames)
 
     SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -66,38 +63,16 @@
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera, CAMERA_FIRST_PERSON);
-
-        if (animsCount)
-        {
-            // Play animation when spacebar is held down (or step one frame with N)
-            if (IsKeyDown(KEY_SPACE) || IsKeyPressed(KEY_N))
-            {
-                animFrameCounter++;
-
-                if (animFrameCounter >= anims[animId].frameCount) animFrameCounter = 0;
-
-                UpdateModelAnimation(model, anims[animId], animFrameCounter);
-                animPlaying = true;
-            }
-
-            // Select animation by pressing C
-            if (IsKeyPressed(KEY_C))
-            {
-                animFrameCounter = 0;
-                animId++;
-
-                if (animId >= (int)animsCount) animId = 0;
-                UpdateModelAnimation(model, anims[animId], 0);
-                animPlaying = true;
-            }
-        }
+        UpdateCamera(&camera, CAMERA_ORBITAL);
 
-        // Toggle skeleton drawing
-        if (IsKeyPressed(KEY_B)) drawSkeleton ^= 1;
+        // Select current animation
+        if (IsKeyPressed(KEY_RIGHT)) animIndex = (animIndex + 1)%animCount;
+        else if (IsKeyPressed(KEY_LEFT)) animIndex = (animIndex + animCount - 1)%animCount;
 
-        // Toggle mesh drawing
-        if (IsKeyPressed(KEY_M)) drawMesh ^= 1;
+        // Update model animation
+        animCurrentFrame += 1.0f;
+        if (animCurrentFrame >= anims[animIndex].keyframeCount) animCurrentFrame = 0.0f;
+        UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -109,52 +84,19 @@
             BeginMode3D(camera);
 
                 // Draw 3d model with texture
-                if (drawMesh) DrawModel(model, position, 1.0f, WHITE);
-
-                // Draw the animated skeleton
-                if (drawSkeleton)
+                if (!IsKeyDown(KEY_SPACE)) DrawModel(model, position, 1.0f, WHITE);
+                else
                 {
-                    // Loop to (boneCount - 1) because the last one is a special "no bone" bone,
-                    // needed to workaround buggy models
-                    // without a -1, we would always draw a cube at the origin
-                    for (int i = 0; i < model.boneCount - 1; i++)
-                    {
-                        // By default the model is loaded in bind-pose by LoadModel()
-                        // But if UpdateModelAnimation() has been called at least once
-                        // then the model is already in animation pose, so we need the animated skeleton
-                        if (!animPlaying || !animsCount)
-                        {
-                            // Display the bind-pose skeleton
-                            DrawCube(model.bindPose[i].translation, 0.04f, 0.04f, 0.04f, RED);
-
-                            if (model.bones[i].parent >= 0)
-                            {
-                                DrawLine3D(model.bindPose[i].translation,
-                                    model.bindPose[model.bones[i].parent].translation, RED);
-                            }
-                        }
-                        else
-                        {
-                            // Display the frame-pose skeleton
-                            DrawCube(anims[animId].framePoses[animFrameCounter][i].translation, 0.05f, 0.05f, 0.05f, RED);
-
-                            if (anims[animId].bones[i].parent >= 0)
-                            {
-                                DrawLine3D(anims[animId].framePoses[animFrameCounter][i].translation,
-                                    anims[animId].framePoses[animFrameCounter][anims[animId].bones[i].parent].translation, RED);
-                            }
-                        }
-                    }
+                    // Draw the animated skeleton
+                    DrawModelSkeleton(model.skeleton, anims[animIndex].keyframePoses[(int)animCurrentFrame], 1.0f, RED);
                 }
 
-                DrawGrid(10, 1.0f);         // Draw a grid
+                DrawGrid(10, 1.0f);
 
             EndMode3D();
 
-            DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, GetScreenHeight() - 80, 10, MAROON);
-            DrawText("PRESS N to STEP ONE ANIMATION FRAME", 10, GetScreenHeight() - 60, 10, DARKGRAY);
-            DrawText("PRESS C to CYCLE THROUGH ANIMATIONS", 10, GetScreenHeight() - 40, 10, DARKGRAY);
-            DrawText("PRESS M to toggle MESH, B to toggle SKELETON DRAWING", 10, GetScreenHeight() - 20, 10, DARKGRAY);
+            DrawText(TextFormat("Current animation: %s", anims[animIndex].name), 10, 10, 20, LIGHTGRAY);
+            DrawText("Press SPACE to draw skeleton", 10, 40, 20, MAROON);
             DrawText("(c) CesiumMan model by KhronosGroup", GetScreenWidth() - 210, GetScreenHeight() - 20, 10, GRAY);
 
         EndDrawing();
@@ -163,14 +105,28 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-
-    // Unload model animations data
-    UnloadModelAnimations(anims, animsCount);
-
-    UnloadModel(model);         // Unload model
+    UnloadModelAnimations(anims, animCount);   // Unload model animations data
+    UnloadModel(model);                        // Unload model
 
     CloseWindow();              // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
     return 0;
+}
+
+// Draw model skeleton
+static void DrawModelSkeleton(ModelSkeleton skeleton, ModelAnimPose pose, float scale, Color color)
+{
+    // Loop to (boneCount - 1) because the last one is a special "no bone" bone,
+    // needed to workaround buggy models without a -1, a cube is always drawn at the origin
+    for (unsigned int i = 0; i < skeleton.boneCount - 1; i++)
+    {
+        // Display the frame-pose skeleton
+        DrawCube(pose[i].translation, scale*0.05f, scale*0.05f, scale*0.05f, color);
+
+        if (skeleton.bones[i].parent >= 0)
+        {
+            DrawLine3D(pose[i].translation, pose[skeleton.bones[i].parent].translation, color);
+        }
+    }
 }
diff --git a/raylib/examples/models/models_loading_vox.c b/raylib/examples/models/models_loading_vox.c
--- a/raylib/examples/models/models_loading_vox.c
+++ b/raylib/examples/models/models_loading_vox.c
@@ -25,9 +25,9 @@
 #include "rlights.h"
 
 #if defined(PLATFORM_DESKTOP)
-#define GLSL_VERSION            330
+    #define GLSL_VERSION            330
 #else   // PLATFORM_ANDROID, PLATFORM_WEB
-#define GLSL_VERSION            100
+    #define GLSL_VERSION            100
 #endif
 
 //------------------------------------------------------------------------------------
@@ -130,6 +130,7 @@
             camerarot.y = 0;
         }
 
+        // Update camere movement, custom controls
         UpdateCameraPro(&camera,
             (Vector3){ (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, // Move forward-backward
                        (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, // Move right-left
@@ -173,7 +174,7 @@
             DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, BLUE);
             DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, BLUE);
             DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, BLUE);
-            DrawText(TextFormat("Model file: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
+            DrawText(TextFormat("VOX model file: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
diff --git a/raylib/examples/models/models_mesh_uv_painting.c b/raylib/examples/models/models_mesh_uv_painting.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_mesh_uv_painting.c
@@ -0,0 +1,323 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - mesh uv painting
+*
+*   Example demonstrates painting directly onto a mesh's texture: a ray is cast from the
+*   mouse into the scene, the hit triangle is found, and the hit point is converted into
+*   UV space using barycentric interpolation so a brush stroke can be drawn on the texture
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2025 PanicTitan (@PanicTitan)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+#include <math.h>       // Required for: fabsf(), floorf()
+#include <stddef.h>     // Required for: NULL
+
+//--------------------------------------------------------------------------------------
+// Global Definitions
+//--------------------------------------------------------------------------------------
+#define CANVAS_SIZE     512
+#define PALETTE_COUNT   8
+
+//--------------------------------------------------------------------------------------
+// Types and Structures Definition
+//--------------------------------------------------------------------------------------
+typedef enum { TOOL_PAINT = 0, TOOL_PICKER } ToolMode;
+typedef enum { SHAPE_SPHERE = 0, SHAPE_CUBE, SHAPE_CYLINDER, SHAPE_TORUS } ShapeType;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void ChangeShape(Model *model, BoundingBox *bbox, ShapeType *currentShape, ShapeType newShape, Texture2D canvasTexture);
+static bool GetMeshHitUV(Ray ray, Model model, BoundingBox bbox, Vector2 *outUV);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh uv painting");
+
+    Camera3D camera = { 0 };
+    camera.position = (Vector3){ 0.0f, 3.5f, 6.5f };
+    camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    // CPU-side canvas plus the GPU texture it gets pushed to after every stroke
+    Image canvasImage = GenImageColor(CANVAS_SIZE, CANVAS_SIZE, RAYWHITE);
+    Texture2D canvasTexture = LoadTextureFromImage(canvasImage);
+    SetTextureFilter(canvasTexture, TEXTURE_FILTER_BILINEAR);
+
+    Model model = { 0 };
+    BoundingBox modelBBox = { 0 };
+    ShapeType currentShape = SHAPE_SPHERE;
+    ChangeShape(&model, &modelBBox, &currentShape, SHAPE_SPHERE, canvasTexture);
+
+    ToolMode currentTool = TOOL_PAINT;
+    Color activeColor = RED;
+    int brushRadius = 12;
+    Vector2 lastHitUV = { 0 };
+    bool hasLastHit = false;
+
+    Color palette[PALETTE_COUNT] = { RED, ORANGE, GOLD, LIME, SKYBLUE, PURPLE, DARKGRAY, WHITE };
+    Rectangle uiPanelRec = { 10.0f, 10.0f, 230.0f, 490.0f };
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        Vector2 mousePos = GetMousePosition();
+        bool isMouseOverUI = CheckCollisionPointRec(mousePos, uiPanelRec);
+
+        if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+        if (!isMouseOverUI && IsMouseButtonDown(MOUSE_BUTTON_LEFT))
+        {
+            Ray ray = GetScreenToWorldRay(mousePos, camera);
+            Vector2 hitUV = { 0 };
+
+            if (GetMeshHitUV(ray, model, modelBBox, &hitUV))
+            {
+                int px = (int)(hitUV.x * CANVAS_SIZE);
+                int py = (int)(hitUV.y * CANVAS_SIZE);
+
+                if (currentTool == TOOL_PAINT)
+                {
+                    // Stroke from the last hit to this one, guarding against jumps across a UV seam
+                    if (hasLastHit && (fabsf(hitUV.x - lastHitUV.x) < 0.25f) && (fabsf(hitUV.y - lastHitUV.y) < 0.25f))
+                    {
+                        int lastPx = (int)(lastHitUV.x * CANVAS_SIZE);
+                        int lastPy = (int)(lastHitUV.y * CANVAS_SIZE);
+                        float dist = Vector2Distance((Vector2){ (float)lastPx, (float)lastPy }, (Vector2){ (float)px, (float)py });
+                        int steps = (int)(dist / 2.0f) + 1;
+
+                        for (int i = 0; i <= steps; i++)
+                        {
+                            float t = (float)i / (float)steps;
+                            ImageDrawCircle(&canvasImage, (int)Lerp((float)lastPx, (float)px, t),
+                                (int)Lerp((float)lastPy, (float)py, t), brushRadius, activeColor);
+                        }
+                    }
+                    else ImageDrawCircle(&canvasImage, px, py, brushRadius, activeColor);
+
+                    UpdateTexture(canvasTexture, canvasImage.data);
+                    lastHitUV = hitUV;
+                    hasLastHit = true;
+                }
+                else
+                {
+                    activeColor = GetImageColor(canvasImage, px, py);
+                    currentTool = TOOL_PAINT;
+                    hasLastHit = false;
+                }
+            }
+            else hasLastHit = false;
+        }
+        else hasLastHit = false;
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground((Color){ 30, 32, 40, 255 });
+
+            BeginMode3D(camera);
+                DrawModel(model, Vector3Zero(), 1.0f, WHITE);
+                DrawGrid(10, 1.0f);
+            EndMode3D();
+
+            // Side panel
+            DrawRectangleRec(uiPanelRec, Fade(BLACK, 0.8f));
+            DrawRectangleLinesEx(uiPanelRec, 2.0f, DARKGRAY);
+            DrawText("MESH UV PAINTER", 25, 22, 20, GOLD);
+
+            // Tool selection toggles
+            bool paintActive = (currentTool == TOOL_PAINT);
+            bool pickerActive = (currentTool == TOOL_PICKER);
+            if (GuiToggle((Rectangle){ 25, 55, 95, 32 }, "PAINT", &paintActive)) currentTool = TOOL_PAINT;
+            if (GuiToggle((Rectangle){ 125, 55, 95, 32 }, "PICKER", &pickerActive)) currentTool = TOOL_PICKER;
+
+            // Shape selection toggles
+            DrawText("Mesh Shape:", 25, 100, 10, LIGHTGRAY);
+            bool sphereActive = (currentShape == SHAPE_SPHERE);
+            bool cubeActive = (currentShape == SHAPE_CUBE);
+            bool cylinderActive = (currentShape == SHAPE_CYLINDER);
+            bool torusActive = (currentShape == SHAPE_TORUS);
+
+            if (GuiToggle((Rectangle){ 25, 120, 95, 28 }, "SPHERE", &sphereActive))
+                ChangeShape(&model, &modelBBox, &currentShape, SHAPE_SPHERE, canvasTexture);
+            if (GuiToggle((Rectangle){ 125, 120, 95, 28 }, "CUBE", &cubeActive))
+                ChangeShape(&model, &modelBBox, &currentShape, SHAPE_CUBE, canvasTexture);
+            if (GuiToggle((Rectangle){ 25, 153, 95, 28 }, "CYLINDER", &cylinderActive))
+                ChangeShape(&model, &modelBBox, &currentShape, SHAPE_CYLINDER, canvasTexture);
+            if (GuiToggle((Rectangle){ 125, 153, 95, 28 }, "TORUS", &torusActive))
+                ChangeShape(&model, &modelBBox, &currentShape, SHAPE_TORUS, canvasTexture);
+
+            // Color display
+            DrawText("Active Color:", 25, 195, 10, LIGHTGRAY);
+            DrawRectangle(125, 193, 95, 20, activeColor);
+            DrawRectangleLines(125, 193, 95, 20, WHITE);
+
+            // Color swatches
+            DrawText("Palette Swatches:", 25, 225, 10, LIGHTGRAY);
+            for (int i = 0; i < PALETTE_COUNT; i++)
+            {
+                Rectangle swatchRec = { 25.0f + (i%4)*48, 245.0f + (i/4)*45, 40.0f, 38.0f };
+                DrawRectangleRec(swatchRec, palette[i]);
+                DrawRectangleLinesEx(swatchRec, 1.0f, WHITE);
+                if (CheckCollisionPointRec(mousePos, swatchRec) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) activeColor = palette[i];
+            }
+
+            // Brush size buttons
+            DrawText(TextFormat("Brush Size: %dpx", brushRadius), 25, 345, 10, LIGHTGRAY);
+            if (GuiButton((Rectangle){ 25, 365, 95, 30 }, "SIZE -") && (brushRadius > 2)) brushRadius -= 2;
+            if (GuiButton((Rectangle){ 125, 365, 95, 30 }, "SIZE +") && (brushRadius < 64)) brushRadius += 2;
+
+            // Canvas action buttons
+            if (GuiButton((Rectangle){ 25, 410, 95, 30 }, "CLEAR"))
+            {
+                ImageClearBackground(&canvasImage, RAYWHITE);
+                UpdateTexture(canvasTexture, canvasImage.data);
+            }
+            if (GuiButton((Rectangle){ 125, 410, 95, 30 }, "FILL"))
+            {
+                ImageClearBackground(&canvasImage, activeColor);
+                UpdateTexture(canvasTexture, canvasImage.data);
+            }
+
+            DrawText("Left click: paint / pick color   |   Right drag: orbit camera", 260, screenHeight - 25, 10, RAYWHITE);
+            DrawFPS(screenWidth - 90, 15);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModel(model);
+    UnloadImage(canvasImage);
+    UnloadTexture(canvasTexture);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Unloads the current model and builds a new primitive shape in its place, sharing the
+// same canvas texture, and recomputes the transformed bounding box used for ray testing
+static void ChangeShape(Model *model, BoundingBox *bbox, ShapeType *currentShape, ShapeType newShape, Texture2D canvasTexture)
+{
+    UnloadModel(*model);
+
+    Mesh mesh = { 0 };
+
+    switch (newShape)
+    {
+        case SHAPE_SPHERE:   mesh = GenMeshSphere(1.5f, 32, 32); break;
+        case SHAPE_CUBE:     mesh = GenMeshCube(2.2f, 2.2f, 2.2f); break;
+        case SHAPE_CYLINDER: mesh = GenMeshCylinder(1.2f, 2.5f, 24); break;
+        case SHAPE_TORUS:    mesh = GenMeshTorus(0.6f, 1.6f, 24, 36); break;
+        default:             mesh = GenMeshSphere(1.5f, 32, 32); break;
+    }
+
+    *model = LoadModelFromMesh(mesh);
+
+    // GenMeshCylinder builds upward from y = 0; shift it down to center on the origin
+    if (newShape == SHAPE_CYLINDER) model->transform = MatrixTranslate(0.0f, -1.25f, 0.0f);
+
+    model->materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = canvasTexture;
+
+    BoundingBox box = GetMeshBoundingBox(model->meshes[0]);
+    box.min = Vector3Transform(box.min, model->transform);
+    box.max = Vector3Transform(box.max, model->transform);
+    *bbox = box;
+
+    *currentShape = newShape;
+}
+
+// Raycasts against the model's mesh triangles and returns the UV coordinate of the
+// closest hit, interpolated from the hit triangle's vertices with barycentric weights
+static bool GetMeshHitUV(Ray ray, Model model, BoundingBox bbox, Vector2 *outUV)
+{
+    if (!GetRayCollisionBox(ray, bbox).hit) return false; // Fast reject
+
+    Mesh mesh = model.meshes[0];
+    float closestDistance = 1e9f;
+    bool found = false;
+    Vector2 hitUV = { 0 };
+
+    for (int tri = 0; tri < mesh.triangleCount; tri++)
+    {
+        int i0, i1, i2;
+
+        if (mesh.indices != NULL)
+        {
+            i0 = mesh.indices[3*tri + 0];
+            i1 = mesh.indices[3*tri + 1];
+            i2 = mesh.indices[3*tri + 2];
+        }
+        else { i0 = 3*tri; i1 = 3*tri + 1; i2 = 3*tri + 2; }
+
+        Vector3 a = Vector3Transform((Vector3){ mesh.vertices[3*i0], mesh.vertices[3*i0 + 1], mesh.vertices[3*i0 + 2] }, model.transform);
+        Vector3 b = Vector3Transform((Vector3){ mesh.vertices[3*i1], mesh.vertices[3*i1 + 1], mesh.vertices[3*i1 + 2] }, model.transform);
+        Vector3 c = Vector3Transform((Vector3){ mesh.vertices[3*i2], mesh.vertices[3*i2 + 1], mesh.vertices[3*i2 + 2] }, model.transform);
+
+        RayCollision hit = GetRayCollisionTriangle(ray, a, b, c);
+
+        if (hit.hit && (hit.distance < closestDistance))
+        {
+            closestDistance = hit.distance;
+            found = true;
+
+            Vector2 uvA = { mesh.texcoords[2*i0], mesh.texcoords[2*i0 + 1] };
+            Vector2 uvB = { mesh.texcoords[2*i1], mesh.texcoords[2*i1 + 1] };
+            Vector2 uvC = { mesh.texcoords[2*i2], mesh.texcoords[2*i2 + 1] };
+
+            Vector3 w = Vector3Barycenter(hit.point, a, b, c);
+
+            hitUV.x = w.x*uvA.x + w.y*uvB.x + w.z*uvC.x;
+            hitUV.y = w.x*uvA.y + w.y*uvB.y + w.z*uvC.y;
+
+            // Wrap into [0, 1] in case of minor floating point drift at UV seams
+            hitUV.x -= floorf(hitUV.x);
+            hitUV.y -= floorf(hitUV.y);
+        }
+    }
+
+    if (found && (outUV != NULL)) *outUV = hitUV;
+
+    return found;
+}
diff --git a/raylib/examples/models/models_point_rendering.c b/raylib/examples/models/models_point_rendering.c
--- a/raylib/examples/models/models_point_rendering.c
+++ b/raylib/examples/models/models_point_rendering.c
@@ -16,6 +16,7 @@
 ********************************************************************************************/
 
 #include "raylib.h"
+#include "rlgl.h"
 
 #include <stdlib.h>             // Required for: rand()
 #include <math.h>               // Required for: cosf(), sinf()
@@ -26,8 +27,9 @@
 //------------------------------------------------------------------------------------
 // Module Functions Declaration
 //------------------------------------------------------------------------------------
-// Generate mesh using points
-static Mesh GenMeshPoints(int numPoints);
+static Mesh GenMeshPoints(int numPoints); // Generate mesh using points
+void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
+void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -183,4 +185,31 @@
     UploadMesh(&mesh, false);
 
     return mesh;
+}
+
+
+// Draw a model points
+// WARNING: OpenGL ES 2.0 does not support point mode drawing
+void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
+{
+    rlEnablePointMode();
+    rlDisableBackfaceCulling();
+
+    DrawModel(model, position, scale, tint);
+
+    rlEnableBackfaceCulling();
+    rlDisablePointMode();
+}
+
+// Draw a model points
+// WARNING: OpenGL ES 2.0 does not support point mode drawing
+void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
+{
+    rlEnablePointMode();
+    rlDisableBackfaceCulling();
+
+    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
+
+    rlEnableBackfaceCulling();
+    rlDisablePointMode();
 }
diff --git a/raylib/examples/models/models_procedural_decals.c b/raylib/examples/models/models_procedural_decals.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/models_procedural_decals.c
@@ -0,0 +1,504 @@
+/*******************************************************************************************
+*
+*   raylib [models] example - procedural decals
+*
+*   Example demonstrates projecting decals onto a 3D mesh surface by transforming the
+*   mesh's own triangles into the decal's local space and clipping them against a box,
+*   using only procedurally generated geometry and textures (no external resource files)
+*
+*   NOTE: This is the same clip-space decal projection idea used by models_decals.c
+*   (in turn based on three.js' DecalGeometry), applied here to a generated mesh and
+*   generated textures instead of a loaded model, so the example is fully self-contained
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2025 PanicTitan (@PanicTitan)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+#include "raymath.h"
+
+#include <stddef.h>     // Required for: NULL
+#include <string.h>     // Required for: memcpy()
+#include <math.h>       // Required for: fabsf(), fminf()
+
+//--------------------------------------------------------------------------------------
+// Global Definitions
+//--------------------------------------------------------------------------------------
+#define MAX_DECALS  256
+
+//--------------------------------------------------------------------------------------
+// Types and Structures Definition
+//--------------------------------------------------------------------------------------
+
+// Growable triangle-soup buffer used while building a clipped decal mesh
+typedef struct MeshBuilder {
+    int vertexCount;
+    int vertexCapacity;
+    Vector3 *vertices;
+    Vector2 *uvs;
+} MeshBuilder;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 v0, Vector3 v1, Vector3 v2);
+static void FreeMeshBuilder(MeshBuilder *mb);
+static Mesh BuildMesh(MeshBuilder *mb);
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s);
+static Mesh GenMeshDecal(Model model, Matrix projection, float decalSize, float decalOffset);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    SetConfigFlags(FLAG_MSAA_4X_HINT);
+    InitWindow(screenWidth, screenHeight, "raylib [models] example - procedural decals");
+
+    Camera3D camera = { 0 };
+    camera.position = (Vector3){ 0.0f, 2.5f, 5.0f };
+    camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    // Target model: a procedurally generated knot with a checkerboard skin
+    Model model = LoadModelFromMesh(GenMeshTorus(0.8f, 1.8f, 32, 64));
+
+    Image checkerImage = GenImageChecked(512, 512, 32, 32, LIGHTGRAY, GRAY);
+    Texture2D modelTexture = LoadTextureFromImage(checkerImage);
+    UnloadImage(checkerImage);
+    SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR);
+    model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture;
+
+    BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]);
+    camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f);
+
+    float modelSize = fminf(fminf(fabsf(modelBBox.max.x - modelBBox.min.x),
+        fabsf(modelBBox.max.y - modelBBox.min.y)), fabsf(modelBBox.max.z - modelBBox.min.z));
+
+    float decalSize = modelSize*0.35f;
+    float decalOffset = 0.01f;
+
+    // Translucent cube previewing where the next decal will land
+    Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
+    placementCube.materials[0].maps[0].color = LIME;
+
+    // Decal texture: a procedurally drawn target/bullseye, no image file needed
+    Image decalImage = GenImageColor(128, 128, BLANK);
+    ImageDrawCircle(&decalImage, 64, 64, 60, RED);
+    ImageDrawCircle(&decalImage, 64, 64, 45, WHITE);
+    ImageDrawCircle(&decalImage, 64, 64, 30, RED);
+    ImageDrawCircle(&decalImage, 64, 64, 15, YELLOW);
+
+    Texture2D decalTexture = LoadTextureFromImage(decalImage);
+    UnloadImage(decalImage);
+    SetTextureFilter(decalTexture, TEXTURE_FILTER_BILINEAR);
+
+    Material decalMaterial = LoadMaterialDefault();
+    decalMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = decalTexture;
+    decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE;
+
+    bool showModel = true;
+    Model decals[MAX_DECALS] = { 0 };
+    int decalCount = 0;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+        // Cast a ray from the mouse and keep the closest point it hits on the model
+        Ray ray = GetScreenToWorldRay(GetMousePosition(), camera);
+        RayCollision collision = { 0 };
+
+        if (GetRayCollisionBox(ray, modelBBox).hit && (decalCount < MAX_DECALS))
+        {
+            for (int m = 0; m < model.meshCount; m++)
+            {
+                RayCollision meshHit = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
+                if (meshHit.hit && (!collision.hit || (meshHit.distance < collision.distance))) collision = meshHit;
+            }
+        }
+
+        // Project a new decal at the hit point, facing along the surface normal
+        if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (decalCount < MAX_DECALS))
+        {
+            Vector3 lookTarget = Vector3Add(collision.point, collision.normal);
+            Matrix splat = MatrixLookAt(collision.point, lookTarget, (Vector3){ 0.0f, 1.0f, 0.0f });
+            splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD*(float)GetRandomValue(-180, 180)));
+
+            Mesh decalMesh = GenMeshDecal(model, splat, decalSize, decalOffset);
+
+            if (decalMesh.vertexCount > 0)
+            {
+                decals[decalCount] = LoadModelFromMesh(decalMesh);
+                decals[decalCount].materials[0].maps[0] = decalMaterial.maps[0];
+                decalCount++;
+            }
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                if (showModel) DrawModel(model, Vector3Zero(), 1.0f, WHITE);
+
+                for (int i = 0; i < decalCount; i++) DrawModel(decals[i], Vector3Zero(), 1.0f, WHITE);
+
+                // Preview cube at the surface point currently under the mouse
+                if (collision.hit)
+                {
+                    Vector3 lookTarget = Vector3Add(collision.point, collision.normal);
+                    Matrix splat = MatrixLookAt(collision.point, lookTarget, (Vector3){ 0.0f, 1.0f, 0.0f });
+                    placementCube.transform = MatrixInvert(splat);
+                    DrawModel(placementCube, Vector3Zero(), 1.0f, Fade(WHITE, 0.5f));
+                }
+
+                DrawGrid(10, 1.0f);
+
+            EndMode3D();
+
+            // Vertex/triangle counts: base model vs total once decal geometry is added
+            int baseVertices = 0, baseTriangles = 0;
+            for (int i = 0; i < model.meshCount; i++)
+            {
+                baseVertices += model.meshes[i].vertexCount;
+                baseTriangles += model.meshes[i].triangleCount;
+            }
+
+            int totalVertices = baseVertices, totalTriangles = baseTriangles;
+            for (int i = 0; i < decalCount; i++)
+            {
+                totalVertices += decals[i].meshes[0].vertexCount;
+                totalTriangles += decals[i].meshes[0].triangleCount;
+            }
+
+            int statX = screenWidth - 280;
+            DrawText("Vertices", statX + 90, 10, 10, LIME);
+            DrawText("Triangles", statX + 180, 10, 10, LIME);
+            DrawText("Base Model", statX, 25, 10, LIME);
+            DrawText(TextFormat("%d", baseVertices), statX + 90, 25, 10, LIME);
+            DrawText(TextFormat("%d", baseTriangles), statX + 180, 25, 10, LIME);
+            DrawText("TOTAL", statX, 40, 10, LIME);
+            DrawText(TextFormat("%d", totalVertices), statX + 90, 40, 10, LIME);
+            DrawText(TextFormat("%d", totalTriangles), statX + 180, 40, 10, LIME);
+
+            if (GuiButton((Rectangle){ 10, screenHeight - 80.0f, 100, 40 }, showModel ? "Hide Model" : "Show Model"))
+                showModel = !showModel;
+
+            if (GuiButton((Rectangle){ 120, screenHeight - 80.0f, 100, 40 }, "Clear Decals"))
+            {
+                for (int i = 0; i < decalCount; i++) UnloadModel(decals[i]);
+                decalCount = 0;
+            }
+
+            DrawText("Left click: place decal   |   Right drag: orbit camera", 10, screenHeight - 25, 10, DARKGRAY);
+            DrawFPS(10, 10);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    for (int i = 0; i < decalCount; i++) UnloadModel(decals[i]);
+
+    UnloadModel(placementCube);
+    UnloadTexture(decalTexture);
+    UnloadTexture(modelTexture);
+    UnloadModel(model);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Appends a triangle to a growable mesh builder buffer, growing it in fixed-size chunks
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 v0, Vector3 v1, Vector3 v2)
+{
+    if (mb->vertexCapacity <= (mb->vertexCount + 3))
+    {
+        int newVertexCapacity = (1 + (mb->vertexCapacity/256))*256;
+        Vector3 *newVertices = (Vector3 *)MemAlloc(newVertexCapacity*sizeof(Vector3));
+
+        if (mb->vertexCapacity > 0)
+        {
+            memcpy(newVertices, mb->vertices, mb->vertexCount*sizeof(Vector3));
+            MemFree(mb->vertices);
+        }
+
+        mb->vertices = newVertices;
+        mb->vertexCapacity = newVertexCapacity;
+    }
+
+    int index = mb->vertexCount;
+    mb->vertexCount += 3;
+
+    mb->vertices[index + 0] = v0;
+    mb->vertices[index + 1] = v1;
+    mb->vertices[index + 2] = v2;
+}
+
+// Frees a mesh builder's backing buffers
+static void FreeMeshBuilder(MeshBuilder *mb)
+{
+    if (mb->vertices != NULL) MemFree(mb->vertices);
+    if (mb->uvs != NULL) MemFree(mb->uvs);
+    *mb = (MeshBuilder){ 0 };
+}
+
+// Converts a mesh builder's triangle soup into a standard uploaded raylib Mesh
+static Mesh BuildMesh(MeshBuilder *mb)
+{
+    Mesh outMesh = { 0 };
+
+    outMesh.vertexCount = mb->vertexCount;
+    outMesh.triangleCount = mb->vertexCount/3;
+    outMesh.vertices = (float *)MemAlloc(outMesh.vertexCount*3*sizeof(float));
+    if (mb->uvs != NULL) outMesh.texcoords = (float *)MemAlloc(outMesh.vertexCount*2*sizeof(float));
+
+    for (int i = 0; i < mb->vertexCount; i++)
+    {
+        outMesh.vertices[3*i + 0] = mb->vertices[i].x;
+        outMesh.vertices[3*i + 1] = mb->vertices[i].y;
+        outMesh.vertices[3*i + 2] = mb->vertices[i].z;
+
+        if (mb->uvs != NULL)
+        {
+            outMesh.texcoords[2*i + 0] = mb->uvs[i].x;
+            outMesh.texcoords[2*i + 1] = mb->uvs[i].y;
+        }
+    }
+
+    UploadMesh(&outMesh, false);
+
+    return outMesh;
+}
+
+// Clips the segment [v0, v1] against the plane p.x = s, returning the intersection point
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
+{
+    float d0 = Vector3DotProduct(v0, p) - s;
+    float d1 = Vector3DotProduct(v1, p) - s;
+    float t = d0/(d0 - d1);
+
+    return Vector3Lerp(v0, v1, t);
+}
+
+// Builds a decal mesh: the model's triangles are transformed into the decal's local space
+// (so the decal sits at the origin, facing +Z) and clipped against a decalSize-sided box,
+// following the same clip-space projection idea used by engines' decal systems (and by
+// three.js' DecalGeometry, which the technique is commonly traced back to). What's left
+// after clipping becomes the decal's own small mesh, UV-mapped from its local coordinates
+static Mesh GenMeshDecal(Model model, Matrix projection, float decalSize, float decalOffset)
+{
+    Matrix invProj = MatrixInvert(projection);
+    MeshBuilder meshBuilders[2] = { 0 };
+    int mbIndex = 0;
+
+    // Gather triangles that land anywhere near the decal box; this is a loose, cheap
+    // pre-filter meant to skip most of the model, the precise clip happens below
+    for (int meshIndex = 0; meshIndex < model.meshCount; meshIndex++)
+    {
+        Mesh mesh = model.meshes[meshIndex];
+
+        for (int tri = 0; tri < mesh.triangleCount; tri++)
+        {
+            Vector3 vertices[3] = { 0 };
+
+            if (mesh.indices == NULL)
+            {
+                for (int v = 0; v < 3; v++)
+                {
+                    vertices[v] = (Vector3){
+                        mesh.vertices[3*3*tri + 3*v + 0],
+                        mesh.vertices[3*3*tri + 3*v + 1],
+                        mesh.vertices[3*3*tri + 3*v + 2]
+                    };
+                }
+            }
+            else
+            {
+                for (int v = 0; v < 3; v++)
+                {
+                    int idx = mesh.indices[3*tri + v];
+                    vertices[v] = (Vector3){
+                        mesh.vertices[3*idx + 0],
+                        mesh.vertices[3*idx + 1],
+                        mesh.vertices[3*idx + 2]
+                    };
+                }
+            }
+
+            int insideCount = 0;
+            for (int i = 0; i < 3; i++)
+            {
+                Vector3 v = Vector3Transform(vertices[i], projection);
+                if ((fabsf(v.x) < decalSize) || (fabsf(v.y) <= decalSize) || (fabsf(v.z) <= decalSize)) insideCount++;
+                vertices[i] = v;
+            }
+
+            if (insideCount > 0) AddTriangleToMeshBuilder(&meshBuilders[mbIndex], vertices[0], vertices[1], vertices[2]);
+        }
+    }
+
+    // Clip the surviving triangles against each of the decal box's 6 faces in turn
+    Vector3 planes[6] = {
+        {  1,  0,  0 }, { -1,  0,  0 },
+        {  0,  1,  0 }, {  0, -1,  0 },
+        {  0,  0,  1 }, {  0,  0, -1 }
+    };
+
+    for (int face = 0; face < 6; face++)
+    {
+        mbIndex = 1 - mbIndex;
+
+        MeshBuilder *inMesh = &meshBuilders[1 - mbIndex];
+        MeshBuilder *outMesh = &meshBuilders[mbIndex];
+
+        outMesh->vertexCount = 0;
+        float s = 0.5f*decalSize;
+
+        for (int i = 0; i < inMesh->vertexCount; i += 3)
+        {
+            Vector3 nV1, nV2, nV3, nV4;
+
+            float d1 = Vector3DotProduct(inMesh->vertices[i + 0], planes[face]) - s;
+            float d2 = Vector3DotProduct(inMesh->vertices[i + 1], planes[face]) - s;
+            float d3 = Vector3DotProduct(inMesh->vertices[i + 2], planes[face]) - s;
+
+            int v1Out = (d1 > 0);
+            int v2Out = (d2 > 0);
+            int v3Out = (d3 > 0);
+            int total = v1Out + v2Out + v3Out;
+
+            switch (total)
+            {
+                case 0:
+                    // Whole triangle is inside this face, keep it as-is
+                    AddTriangleToMeshBuilder(outMesh, inMesh->vertices[i], inMesh->vertices[i + 1], inMesh->vertices[i + 2]);
+                    break;
+                case 1:
+                    // One corner is outside; clip it off, turning the triangle into a quad
+                    if (v1Out)
+                    {
+                        nV1 = inMesh->vertices[i + 1];
+                        nV2 = inMesh->vertices[i + 2];
+                        nV3 = ClipSegment(inMesh->vertices[i], nV1, planes[face], s);
+                        nV4 = ClipSegment(inMesh->vertices[i], nV2, planes[face], s);
+                    }
+
+                    if (v2Out)
+                    {
+                        nV1 = inMesh->vertices[i];
+                        nV2 = inMesh->vertices[i + 2];
+                        nV3 = ClipSegment(inMesh->vertices[i + 1], nV1, planes[face], s);
+                        nV4 = ClipSegment(inMesh->vertices[i + 1], nV2, planes[face], s);
+
+                        AddTriangleToMeshBuilder(outMesh, nV3, nV2, nV1);
+                        AddTriangleToMeshBuilder(outMesh, nV2, nV3, nV4);
+                        break;
+                    }
+
+                    if (v3Out)
+                    {
+                        nV1 = inMesh->vertices[i];
+                        nV2 = inMesh->vertices[i + 1];
+                        nV3 = ClipSegment(inMesh->vertices[i + 2], nV1, planes[face], s);
+                        nV4 = ClipSegment(inMesh->vertices[i + 2], nV2, planes[face], s);
+                    }
+
+                    AddTriangleToMeshBuilder(outMesh, nV1, nV2, nV3);
+                    AddTriangleToMeshBuilder(outMesh, nV4, nV3, nV2);
+                    break;
+                case 2:
+                    // Two corners are outside; only the small corner near the surviving vertex remains
+                    if (!v1Out)
+                    {
+                        nV1 = inMesh->vertices[i];
+                        nV2 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+                        nV3 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+                        AddTriangleToMeshBuilder(outMesh, nV1, nV2, nV3);
+                    }
+
+                    if (!v2Out)
+                    {
+                        nV1 = inMesh->vertices[i + 1];
+                        nV2 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+                        nV3 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+                        AddTriangleToMeshBuilder(outMesh, nV1, nV2, nV3);
+                    }
+
+                    if (!v3Out)
+                    {
+                        nV1 = inMesh->vertices[i + 2];
+                        nV2 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+                        nV3 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+                        AddTriangleToMeshBuilder(outMesh, nV1, nV2, nV3);
+                    }
+                    break;
+                default:
+                    // All 3 corners are outside this face, the triangle is fully clipped away
+                    break;
+            }
+        }
+    }
+
+    MeshBuilder *finalMesh = &meshBuilders[mbIndex];
+    Mesh decalMesh = { 0 };
+
+    if (finalMesh->vertexCount > 0)
+    {
+        finalMesh->uvs = (Vector2 *)MemAlloc(sizeof(Vector2)*finalMesh->vertexCount);
+
+        for (int i = 0; i < finalMesh->vertexCount; i++)
+        {
+            // Clipped coordinates run roughly (-decalSize/2 .. decalSize/2); remap to (0..1)
+            finalMesh->uvs[i].x = (finalMesh->vertices[i].x/decalSize + 0.5f);
+            finalMesh->uvs[i].y = (finalMesh->vertices[i].y/decalSize + 0.5f);
+
+            // Nudge slightly along the normal so the decal doesn't z-fight with the surface
+            finalMesh->vertices[i].z -= decalOffset;
+            finalMesh->vertices[i] = Vector3Transform(finalMesh->vertices[i], invProj);
+        }
+
+        decalMesh = BuildMesh(finalMesh);
+    }
+
+    FreeMeshBuilder(&meshBuilders[0]);
+    FreeMeshBuilder(&meshBuilders[1]);
+
+    return decalMesh;
+}
diff --git a/raylib/examples/models/models_rlgl_solar_system.c b/raylib/examples/models/models_rlgl_solar_system.c
--- a/raylib/examples/models/models_rlgl_solar_system.c
+++ b/raylib/examples/models/models_rlgl_solar_system.c
@@ -66,8 +66,6 @@
     {
         // Update
         //----------------------------------------------------------------------------------
-        UpdateCamera(&camera, CAMERA_ORBITAL);
-
         earthRotation += (5.0f*rotationSpeed);
         earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed);
         moonRotation += (2.0f*rotationSpeed);
@@ -148,25 +146,25 @@
         {
             for (int j = 0; j < slices; j++)
             {
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360.0f/slices)));
 
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*(i))),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices)));
-                rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
-                           sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
-                           cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i))),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
+                rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
+                           sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
+                           cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
             }
         }
     rlEnd();
diff --git a/raylib/examples/models/models_rotating_cube.c b/raylib/examples/models/models_rotating_cube.c
--- a/raylib/examples/models/models_rotating_cube.c
+++ b/raylib/examples/models/models_rotating_cube.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jopestpe (@jopestpe)
 *
diff --git a/raylib/examples/models/models_skybox_rendering.c b/raylib/examples/models/models_skybox_rendering.c
--- a/raylib/examples/models/models_skybox_rendering.c
+++ b/raylib/examples/models/models_skybox_rendering.c
@@ -92,7 +92,7 @@
     }
     else
     {
-        // TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image 
+        // TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image
         // and generate the required cubemap image to be passed to rlLoadTextureCubemap()
         Image image = LoadImage("resources/skybox.png");
         skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(image, CUBEMAP_LAYOUT_AUTO_DETECT);
diff --git a/raylib/examples/models/models_tesseract_view.c b/raylib/examples/models/models_tesseract_view.c
--- a/raylib/examples/models/models_tesseract_view.c
+++ b/raylib/examples/models/models_tesseract_view.c
@@ -6,7 +6,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Timothy van der Valk (@arceryz) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/models/models_waving_cubes.c b/raylib/examples/models/models_waving_cubes.c
--- a/raylib/examples/models/models_waving_cubes.c
+++ b/raylib/examples/models/models_waving_cubes.c
@@ -85,9 +85,9 @@
 
                             // Calculate the cube position
                             Vector3 cubePos = {
-                                (float)(x - numBlocks/2)*(scale*3.0f) + scatter,
-                                (float)(y - numBlocks/2)*(scale*2.0f) + scatter,
-                                (float)(z - numBlocks/2)*(scale*3.0f) + scatter
+                                (float)(x - (float)numBlocks/2)*(scale*3.0f) + scatter,
+                                (float)(y - (float)numBlocks/2)*(scale*2.0f) + scatter,
+                                (float)(z - (float)numBlocks/2)*(scale*3.0f) + scatter
                             };
 
                             // Pick a color with a hue depending on cube position for the rainbow color effect
diff --git a/raylib/examples/models/models_yaw_pitch_roll.c b/raylib/examples/models/models_yaw_pitch_roll.c
--- a/raylib/examples/models/models_yaw_pitch_roll.c
+++ b/raylib/examples/models/models_yaw_pitch_roll.c
@@ -41,6 +41,9 @@
 
     Model model = LoadModel("resources/models/obj/plane.obj");                  // Load model
     Texture2D texture = LoadTexture("resources/models/obj/plane_diffuse.png");  // Load model texture
+
+    SetTextureWrap(texture, TEXTURE_WRAP_REPEAT);       // Force Repeat to avoid issue on Web version
+
     model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture;            // Set map diffuse texture
 
     float pitch = 0.0f;
diff --git a/raylib/examples/models/raygui.h b/raylib/examples/models/raygui.h
new file mode 100644
--- /dev/null
+++ b/raylib/examples/models/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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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/raylib/examples/others/easings_testbed.c b/raylib/examples/others/easings_testbed.c
deleted file mode 100644
--- a/raylib/examples/others/easings_testbed.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [others] example - easings testbed
-*
-*   Example originally created with raylib 2.5, last time updated with raylib 2.5
-*
-*   Example complexity rating: [★★★☆] 3/4
-*
-*   Example contributed by Juan Miguel López (@flashback-fx) and reviewed by Ramon Santamaria (@raysan5)
-*
-*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
-*   BSD-like license that allows static linking with closed source software
-*
-*   Copyright (c) 2019-2025 Juan Miguel López (@flashback-fx) and Ramon Santamaria (@raysan5)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-#include "reasings.h"       // Required for easing functions
-
-#define FONT_SIZE         20
-
-#define D_STEP         20.0f
-#define D_STEP_FINE     2.0f
-#define D_MIN           1.0f
-#define D_MAX       10000.0f
-
-// Easing types
-enum EasingTypes {
-    EASE_LINEAR_NONE = 0,
-    EASE_LINEAR_IN,
-    EASE_LINEAR_OUT,
-    EASE_LINEAR_IN_OUT,
-    EASE_SINE_IN,
-    EASE_SINE_OUT,
-    EASE_SINE_IN_OUT,
-    EASE_CIRC_IN,
-    EASE_CIRC_OUT,
-    EASE_CIRC_IN_OUT,
-    EASE_CUBIC_IN,
-    EASE_CUBIC_OUT,
-    EASE_CUBIC_IN_OUT,
-    EASE_QUAD_IN,
-    EASE_QUAD_OUT,
-    EASE_QUAD_IN_OUT,
-    EASE_EXPO_IN,
-    EASE_EXPO_OUT,
-    EASE_EXPO_IN_OUT,
-    EASE_BACK_IN,
-    EASE_BACK_OUT,
-    EASE_BACK_IN_OUT,
-    EASE_BOUNCE_OUT,
-    EASE_BOUNCE_IN,
-    EASE_BOUNCE_IN_OUT,
-    EASE_ELASTIC_IN,
-    EASE_ELASTIC_OUT,
-    EASE_ELASTIC_IN_OUT,
-    NUM_EASING_TYPES,
-    EASING_NONE = NUM_EASING_TYPES
-};
-
-static float NoEase(float t, float b, float c, float d);  // NoEase function declaration, function used when "no easing" is selected for any axis
-
-// Easing functions reference data
-static const struct {
-    const char *name;
-    float (*func)(float, float, float, float);
-} Easings[] = {
-    [EASE_LINEAR_NONE] = { .name = "EaseLinearNone", .func = EaseLinearNone },
-    [EASE_LINEAR_IN] = { .name = "EaseLinearIn", .func = EaseLinearIn },
-    [EASE_LINEAR_OUT] = { .name = "EaseLinearOut", .func = EaseLinearOut },
-    [EASE_LINEAR_IN_OUT] = { .name = "EaseLinearInOut", .func = EaseLinearInOut },
-    [EASE_SINE_IN] = { .name = "EaseSineIn", .func = EaseSineIn },
-    [EASE_SINE_OUT] = { .name = "EaseSineOut", .func = EaseSineOut },
-    [EASE_SINE_IN_OUT] = { .name = "EaseSineInOut", .func = EaseSineInOut },
-    [EASE_CIRC_IN] = { .name = "EaseCircIn", .func = EaseCircIn },
-    [EASE_CIRC_OUT] = { .name = "EaseCircOut", .func = EaseCircOut },
-    [EASE_CIRC_IN_OUT] = { .name = "EaseCircInOut", .func = EaseCircInOut },
-    [EASE_CUBIC_IN] = { .name = "EaseCubicIn", .func = EaseCubicIn },
-    [EASE_CUBIC_OUT] = { .name = "EaseCubicOut", .func = EaseCubicOut },
-    [EASE_CUBIC_IN_OUT] = { .name = "EaseCubicInOut", .func = EaseCubicInOut },
-    [EASE_QUAD_IN] = { .name = "EaseQuadIn", .func = EaseQuadIn },
-    [EASE_QUAD_OUT] = { .name = "EaseQuadOut", .func = EaseQuadOut },
-    [EASE_QUAD_IN_OUT] = { .name = "EaseQuadInOut", .func = EaseQuadInOut },
-    [EASE_EXPO_IN] = { .name = "EaseExpoIn", .func = EaseExpoIn },
-    [EASE_EXPO_OUT] = { .name = "EaseExpoOut", .func = EaseExpoOut },
-    [EASE_EXPO_IN_OUT] = { .name = "EaseExpoInOut", .func = EaseExpoInOut },
-    [EASE_BACK_IN] = { .name = "EaseBackIn", .func = EaseBackIn },
-    [EASE_BACK_OUT] = { .name = "EaseBackOut", .func = EaseBackOut },
-    [EASE_BACK_IN_OUT] = { .name = "EaseBackInOut", .func = EaseBackInOut },
-    [EASE_BOUNCE_OUT] = { .name = "EaseBounceOut", .func = EaseBounceOut },
-    [EASE_BOUNCE_IN] = { .name = "EaseBounceIn", .func = EaseBounceIn },
-    [EASE_BOUNCE_IN_OUT] = { .name = "EaseBounceInOut", .func = EaseBounceInOut },
-    [EASE_ELASTIC_IN] = { .name = "EaseElasticIn", .func = EaseElasticIn },
-    [EASE_ELASTIC_OUT] = { .name = "EaseElasticOut", .func = EaseElasticOut },
-    [EASE_ELASTIC_IN_OUT] = { .name = "EaseElasticInOut", .func = EaseElasticInOut },
-    [EASING_NONE] = { .name = "None", .func = NoEase },
-};
-
-//------------------------------------------------------------------------------------
-// Program main entry point
-//------------------------------------------------------------------------------------
-int main(void)
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    const int screenWidth = 800;
-    const int screenHeight = 450;
-
-    InitWindow(screenWidth, screenHeight, "raylib [others] example - easings testbed");
-
-    Vector2 ballPosition = { 100.0f, 100.0f };
-
-    float t = 0.0f;             // Current time (in any unit measure, but same unit as duration)
-    float d = 300.0f;           // Total time it should take to complete (duration)
-    bool paused = true;
-    bool boundedT = true;       // If true, t will stop when d >= td, otherwise t will keep adding td to its value every loop
-
-    int easingX = EASING_NONE;  // Easing selected for x axis
-    int easingY = EASING_NONE;  // Easing selected for y axis
-
-    SetTargetFPS(60);
-    //--------------------------------------------------------------------------------------
-
-    // Main game loop
-    while (!WindowShouldClose())    // Detect window close button or ESC key
-    {
-        // Update
-        //----------------------------------------------------------------------------------
-        if (IsKeyPressed(KEY_T)) boundedT = !boundedT;
-
-        // Choose easing for the X axis
-        if (IsKeyPressed(KEY_RIGHT))
-        {
-            easingX++;
-
-            if (easingX > EASING_NONE) easingX = 0;
-        }
-        else if (IsKeyPressed(KEY_LEFT))
-        {
-            if (easingX == 0) easingX = EASING_NONE;
-            else easingX--;
-        }
-
-        // Choose easing for the Y axis
-        if (IsKeyPressed(KEY_DOWN))
-        {
-            easingY++;
-
-            if (easingY > EASING_NONE) easingY = 0;
-        }
-        else if (IsKeyPressed(KEY_UP))
-        {
-            if (easingY == 0) easingY = EASING_NONE;
-            else easingY--;
-        }
-
-        // Change d (duration) value
-        if (IsKeyPressed(KEY_W) && d < D_MAX - D_STEP) d += D_STEP;
-        else if (IsKeyPressed(KEY_Q) && d > D_MIN + D_STEP) d -= D_STEP;
-
-        if (IsKeyDown(KEY_S) && d < D_MAX - D_STEP_FINE) d += D_STEP_FINE;
-        else if (IsKeyDown(KEY_A) && d > D_MIN + D_STEP_FINE) d -= D_STEP_FINE;
-
-        // Play, pause and restart controls
-        if (IsKeyPressed(KEY_SPACE) || IsKeyPressed(KEY_T) ||
-            IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_LEFT) ||
-            IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_UP) ||
-            IsKeyPressed(KEY_W) || IsKeyPressed(KEY_Q) ||
-            IsKeyDown(KEY_S)  || IsKeyDown(KEY_A) ||
-            (IsKeyPressed(KEY_ENTER) && (boundedT == true) && (t >= d)))
-        {
-            t = 0.0f;
-            ballPosition.x = 100.0f;
-            ballPosition.y = 100.0f;
-            paused = true;
-        }
-
-        if (IsKeyPressed(KEY_ENTER)) paused = !paused;
-
-        // Movement computation
-        if (!paused && ((boundedT && t < d) || !boundedT))
-        {
-            ballPosition.x = Easings[easingX].func(t, 100.0f, 700.0f - 170.0f, d);
-            ballPosition.y = Easings[easingY].func(t, 100.0f, 400.0f - 170.0f, d);
-            t += 1.0f;
-        }
-        //----------------------------------------------------------------------------------
-
-        // Draw
-        //----------------------------------------------------------------------------------
-        BeginDrawing();
-
-            ClearBackground(RAYWHITE);
-
-            // Draw information text
-            DrawText(TextFormat("Easing x: %s", Easings[easingX].name), 20, FONT_SIZE, FONT_SIZE, LIGHTGRAY);
-            DrawText(TextFormat("Easing y: %s", Easings[easingY].name), 20, FONT_SIZE*2, FONT_SIZE, LIGHTGRAY);
-            DrawText(TextFormat("t (%c) = %.2f d = %.2f", (boundedT == true)? 'b' : 'u', t, d), 20, FONT_SIZE*3, FONT_SIZE, LIGHTGRAY);
-
-            // Draw instructions text
-            DrawText("Use ENTER to play or pause movement, use SPACE to restart", 20, GetScreenHeight() - FONT_SIZE*2, FONT_SIZE, LIGHTGRAY);
-            DrawText("Use Q and W or A and S keys to change duration", 20, GetScreenHeight() - FONT_SIZE*3, FONT_SIZE, LIGHTGRAY);
-            DrawText("Use LEFT or RIGHT keys to choose easing for the x axis", 20, GetScreenHeight() - FONT_SIZE*4, FONT_SIZE, LIGHTGRAY);
-            DrawText("Use UP or DOWN keys to choose easing for the y axis", 20, GetScreenHeight() - FONT_SIZE*5, FONT_SIZE, LIGHTGRAY);
-
-            // Draw ball
-            DrawCircleV(ballPosition, 16.0f, MAROON);
-
-        EndDrawing();
-        //----------------------------------------------------------------------------------
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    CloseWindow();
-    //--------------------------------------------------------------------------------------
-
-    return 0;
-}
-
-
-// NoEase function, used when "no easing" is selected for any axis
-// It just ignores all parameters besides b
-static float NoEase(float t, float b, float c, float d)
-{
-    // Hack to avoid compiler warning (about unused variables)
-    float burn = t + b + c + d;
-    d += burn;
-
-    return b;
-}
diff --git a/raylib/examples/others/gl_scissor_shapes.c b/raylib/examples/others/gl_scissor_shapes.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/others/gl_scissor_shapes.c
@@ -0,0 +1,153 @@
+/*******************************************************************************************
+*
+*   raylib [others] example - scissor shapes
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 6.0
+*
+*   Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 David Buzatto (@davidbuzatto)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rlgl.h"
+
+#include <math.h>       // Required for: sinf()
+
+// BeginScissorMode() only clips to an axis-aligned rectangle, since it maps
+// directly to glScissor. Clipping to an arbitrary shape (the same idea as
+// Graphics2D.setClip(Shape) in Java2D) needs the stencil buffer instead:
+// the clip shape is rasterized into the stencil buffer first, then further
+// draws are only let through where the stencil was written.
+//
+// rlgl has no stencil wrapper (see raysan5/raylib discussion #2964), so this
+// example calls the handful of OpenGL 1.0 stencil functions directly - they
+// don't need glad/extension loading, same as glScissor doesn't.
+#if defined(__APPLE__)
+    #include <OpenGL/gl.h>
+#else
+    #if !defined(APIENTRY)
+        #if defined(_WIN32)
+            #define APIENTRY __stdcall
+        #else
+            #define APIENTRY
+        #endif
+    #endif
+    #if !defined(WINGDIAPI) && defined(_WIN32)
+        #define WINGDIAPI __declspec(dllimport)
+    #endif
+
+    #include <GL/gl.h>
+#endif
+
+// mask is a callback instead of a fixed shape, so the clip region can be any
+// combination of Draw* calls (circle, polygon, text, several shapes together)
+typedef void (*ScissorMaskDrawFunc)(void *userData);
+
+static void BeginScissorModeShape(ScissorMaskDrawFunc mask, void *userData)
+{
+    rlDrawRenderBatchActive();  // Flush before touching stencil state
+    glClear(GL_STENCIL_BUFFER_BIT);
+    glEnable(GL_STENCIL_TEST);
+    glStencilMask(0xFF);
+
+    // Pass 1: rasterize the mask into the stencil buffer only, no color write
+    rlColorMask(false, false, false, false);
+    glStencilFunc(GL_ALWAYS, 1, 0xFF);
+    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+    mask(userData);
+    rlDrawRenderBatchActive();  // Flush the mask draw
+
+    // Pass 2: subsequent draws only survive where the stencil was written
+    rlColorMask(true, true, true, true);
+    glStencilFunc(GL_EQUAL, 1, 0xFF);
+    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+}
+
+static void EndScissorModeShape(void)
+{
+    rlDrawRenderBatchActive();
+    glDisable(GL_STENCIL_TEST);
+}
+
+// Two example mask shapes, drawn in WHITE (the color is irrelevant here,
+// only the stencil write from pass 1 matters)
+typedef struct { Vector2 center; float radius; } CircleMask;
+static void DrawCircleMask(void *userData)
+{
+    CircleMask *m = (CircleMask *)userData;
+    DrawCircleV(m->center, m->radius, WHITE);
+}
+
+typedef struct { Vector2 center; float radius; int sides; } PolyMask;
+static void DrawPolyMask(void *userData)
+{
+    PolyMask *m = (PolyMask *)userData;
+    DrawPoly(m->center, m->sides, m->radius, 0.0f, WHITE);
+}
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [others] example - scissor shapes");
+
+    Vector2 circleCenter = { screenWidth/2.0f - 120, screenHeight/2.0f };
+    Vector2 hexCenter = { screenWidth/2.0f + 120, screenHeight/2.0f };
+    float maskRadius = 100.0f;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        circleCenter.y = screenHeight/2.0f + sinf((float)GetTime())*40.0f;
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            // Circle-shaped clip: the full-screen rectangle only shows inside the circle
+            CircleMask circleMask = { circleCenter, maskRadius };
+            BeginScissorModeShape(DrawCircleMask, &circleMask);
+                DrawRectangle(0, 0, screenWidth, screenHeight, BLUE);
+            EndScissorModeShape();
+
+            // Hexagon-shaped clip: same mechanism, a different mask shape
+            PolyMask hexMask = { hexCenter, maskRadius, 6 };
+            BeginScissorModeShape(DrawPolyMask, &hexMask);
+                DrawRectangle(0, 0, screenWidth, screenHeight, ORANGE);
+            EndScissorModeShape();
+
+            DrawText("BeginScissorMode() only clips to a rectangle (glScissor)", 10, 10, 10, DARKGRAY);
+            DrawText("This clips to arbitrary shapes instead, using the stencil buffer", 10, 25, 10, DARKGRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/others/raylib_opengl_interop.c b/raylib/examples/others/raylib_opengl_interop.c
--- a/raylib/examples/others/raylib_opengl_interop.c
+++ b/raylib/examples/others/raylib_opengl_interop.c
@@ -28,9 +28,8 @@
 
 #include "raylib.h"
 
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL)
+#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL) || defined(PLATFORM_DESKTOP_RGFW)
     #if defined(GRAPHICS_API_OPENGL_ES2)
-        #define GLAD_GLES2_IMPLEMENTATION
         #include "glad_gles2.h"       // Required for: OpenGL functionality
         #define glGenVertexArrays glGenVertexArraysOES
         #define glBindVertexArray glBindVertexArrayOES
diff --git a/raylib/examples/others/reasings.h b/raylib/examples/others/reasings.h
deleted file mode 100644
--- a/raylib/examples/others/reasings.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*******************************************************************************************
-*
-*   reasings - raylib easings library, based on Robert Penner library
-*
-*   Useful easing functions for values animation
-*
-*   This header uses:
-*       #define REASINGS_STATIC_INLINE      // Inlines all functions code, so it runs faster.
-*                                           // This requires lots of memory on system.
-*   How to use:
-*   The four inputs t,b,c,d are defined as follows:
-*   t = current time (in any unit measure, but same unit as duration)
-*   b = starting value to interpolate
-*   c = the total change in value of b that needs to occur
-*   d = total time it should take to complete (duration)
-*
-*   Example:
-*
-*   int currentTime = 0;
-*   int duration = 100;
-*   float startPositionX = 0.0f;
-*   float finalPositionX = 30.0f;
-*   float currentPositionX = startPositionX;
-*
-*   while (currentPositionX < finalPositionX)
-*   {
-*       currentPositionX = EaseSineIn(currentTime, startPositionX, finalPositionX - startPositionX, duration);
-*       currentTime++;
-*   }
-*
-*   A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
-*
-*   Robert Penner License
-*   ---------------------------------------------------------------------------------
-*   Open source under the BSD License.
-*
-*   Copyright (c) 2001 Robert Penner. All rights reserved.
-*
-*   Redistribution and use in source and binary forms, with or without modification,
-*   are permitted provided that the following conditions are met:
-*
-*       - Redistributions of source code must retain the above copyright notice,
-*         this list of conditions and the following disclaimer.
-*       - Redistributions in binary form must reproduce the above copyright notice,
-*         this list of conditions and the following disclaimer in the documentation
-*         and/or other materials provided with the distribution.
-*       - Neither the name of the author nor the names of contributors may be used
-*         to endorse or promote products derived from this software without specific
-*         prior written permission.
-*
-*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-*   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-*   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-*   IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-*   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-*   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-*   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-*   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-*   OF THE POSSIBILITY OF SUCH DAMAGE.
-*   ---------------------------------------------------------------------------------
-*
-*   Copyright (c) 2015-2024 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 REASINGS_H
-#define REASINGS_H
-
-#define REASINGS_STATIC_INLINE     // NOTE: By default, compile functions as static inline
-
-#if defined(REASINGS_STATIC_INLINE)
-    #define EASEDEF static inline
-#else
-    #define EASEDEF extern
-#endif
-
-#include <math.h>       // Required for: sinf(), cosf(), sqrtf(), powf()
-
-#ifndef PI
-    #define PI 3.14159265358979323846f //Required as PI is not always defined in math.h
-#endif
-
-#if defined(__cplusplus)
-extern "C" {            // Prevents name mangling of functions
-#endif
-
-// Linear Easing functions
-EASEDEF float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); }                            // Ease: Linear
-EASEDEF float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); }                              // Ease: Linear In
-EASEDEF float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); }                             // Ease: Linear Out
-EASEDEF float EaseLinearInOut(float t, float b, float c, float d) { return (c*t/d + b); }                           // Ease: Linear In Out
-
-// Sine Easing functions
-EASEDEF float EaseSineIn(float t, float b, float c, float d) { return (-c*cosf(t/d*(PI/2.0f)) + c + b); }            // Ease: Sine In
-EASEDEF float EaseSineOut(float t, float b, float c, float d) { return (c*sinf(t/d*(PI/2.0f)) + b); }                // Ease: Sine Out
-EASEDEF float EaseSineInOut(float t, float b, float c, float d) { return (-c/2.0f*(cosf(PI*t/d) - 1.0f) + b); }      // Ease: Sine In Out
-
-// Circular Easing functions
-EASEDEF float EaseCircIn(float t, float b, float c, float d) { t /= d; return (-c*(sqrtf(1.0f - t*t) - 1.0f) + b); } // Ease: Circular In
-EASEDEF float EaseCircOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*sqrtf(1.0f - t*t) + b); }  // Ease: Circular Out
-EASEDEF float EaseCircInOut(float t, float b, float c, float d)                                                      // Ease: Circular In Out
-{
-    if ((t/=d/2.0f) < 1.0f) return (-c/2.0f*(sqrtf(1.0f - t*t) - 1.0f) + b);
-    t -= 2.0f; return (c/2.0f*(sqrtf(1.0f - t*t) + 1.0f) + b);
-}
-
-// Cubic Easing functions
-EASEDEF float EaseCubicIn(float t, float b, float c, float d) { t /= d; return (c*t*t*t + b); }                      // Ease: Cubic In
-EASEDEF float EaseCubicOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*(t*t*t + 1.0f) + b); }    // Ease: Cubic Out
-EASEDEF float EaseCubicInOut(float t, float b, float c, float d)                                                     // Ease: Cubic In Out
-{
-    if ((t/=d/2.0f) < 1.0f) return (c/2.0f*t*t*t + b);
-    t -= 2.0f; return (c/2.0f*(t*t*t + 2.0f) + b);
-}
-
-// Quadratic Easing functions
-EASEDEF float EaseQuadIn(float t, float b, float c, float d) { t /= d; return (c*t*t + b); }                         // Ease: Quadratic In
-EASEDEF float EaseQuadOut(float t, float b, float c, float d) { t /= d; return (-c*t*(t - 2.0f) + b); }              // Ease: Quadratic Out
-EASEDEF float EaseQuadInOut(float t, float b, float c, float d)                                                      // Ease: Quadratic In Out
-{
-    if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
-    return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b);
-}
-
-// Exponential Easing functions
-EASEDEF float EaseExpoIn(float t, float b, float c, float d) { return (t == 0.0f) ? b : (c*powf(2.0f, 10.0f*(t/d - 1.0f)) + b); }       // Ease: Exponential In
-EASEDEF float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-powf(2.0f, -10.0f*t/d) + 1.0f) + b); } // Ease: Exponential Out
-EASEDEF float EaseExpoInOut(float t, float b, float c, float d)                                                                         // Ease: Exponential In Out
-{
-    if (t == 0.0f) return b;
-    if (t == d) return (b + c);
-    if ((t/=d/2.0f) < 1.0f) return (c/2.0f*powf(2.0f, 10.0f*(t - 1.0f)) + b);
-
-    return (c/2.0f*(-powf(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b);
-}
-
-// Back Easing functions
-EASEDEF float EaseBackIn(float t, float b, float c, float d) // Ease: Back In
-{
-    float s = 1.70158f;
-    float postFix = t/=d;
-    return (c*(postFix)*t*((s + 1.0f)*t - s) + b);
-}
-
-EASEDEF float EaseBackOut(float t, float b, float c, float d) // Ease: Back Out
-{
-    float s = 1.70158f;
-    t = t/d - 1.0f;
-    return (c*(t*t*((s + 1.0f)*t + s) + 1.0f) + b);
-}
-
-EASEDEF float EaseBackInOut(float t, float b, float c, float d) // Ease: Back In Out
-{
-    float s = 1.70158f;
-    if ((t/=d/2.0f) < 1.0f)
-    {
-        s *= 1.525f;
-        return (c/2.0f*(t*t*((s + 1.0f)*t - s)) + b);
-    }
-
-    float postFix = t-=2.0f;
-    s *= 1.525f;
-    return (c/2.0f*((postFix)*t*((s + 1.0f)*t + s) + 2.0f) + b);
-}
-
-// Bounce Easing functions
-EASEDEF float EaseBounceOut(float t, float b, float c, float d) // Ease: Bounce Out
-{
-    if ((t/=d) < (1.0f/2.75f))
-    {
-        return (c*(7.5625f*t*t) + b);
-    }
-    else if (t < (2.0f/2.75f))
-    {
-        float postFix = t-=(1.5f/2.75f);
-        return (c*(7.5625f*(postFix)*t + 0.75f) + b);
-    }
-    else if (t < (2.5/2.75))
-    {
-        float postFix = t-=(2.25f/2.75f);
-        return (c*(7.5625f*(postFix)*t + 0.9375f) + b);
-    }
-    else
-    {
-        float postFix = t-=(2.625f/2.75f);
-        return (c*(7.5625f*(postFix)*t + 0.984375f) + b);
-    }
-}
-
-EASEDEF float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d - t, 0.0f, c, d) + b); } // Ease: Bounce In
-EASEDEF float EaseBounceInOut(float t, float b, float c, float d) // Ease: Bounce In Out
-{
-    if (t < d/2.0f) return (EaseBounceIn(t*2.0f, 0.0f, c, d)*0.5f + b);
-    else return (EaseBounceOut(t*2.0f - d, 0.0f, c, d)*0.5f + c*0.5f + b);
-}
-
-// Elastic Easing functions
-EASEDEF float EaseElasticIn(float t, float b, float c, float d) // Ease: Elastic In
-{
-    if (t == 0.0f) return b;
-    if ((t/=d) == 1.0f) return (b + c);
-
-    float p = d*0.3f;
-    float a = c;
-    float s = p/4.0f;
-    float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
-
-    return (-(postFix*sinf((t*d-s)*(2.0f*PI)/p )) + b);
-}
-
-EASEDEF float EaseElasticOut(float t, float b, float c, float d) // Ease: Elastic Out
-{
-    if (t == 0.0f) return b;
-    if ((t/=d) == 1.0f) return (b + c);
-
-    float p = d*0.3f;
-    float a = c;
-    float s = p/4.0f;
-
-    return (a*powf(2.0f,-10.0f*t)*sinf((t*d-s)*(2.0f*PI)/p) + c + b);
-}
-
-EASEDEF float EaseElasticInOut(float t, float b, float c, float d) // Ease: Elastic In Out
-{
-    if (t == 0.0f) return b;
-    if ((t/=d/2.0f) == 2.0f) return (b + c);
-
-    float p = d*(0.3f*1.5f);
-    float a = c;
-    float s = p/4.0f;
-
-    if (t < 1.0f)
-    {
-        float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
-        return -0.5f*(postFix*sinf((t*d-s)*(2.0f*PI)/p)) + b;
-    }
-
-    float postFix = a*powf(2.0f, -10.0f*(t-=1.0f));
-
-    return (postFix*sinf((t*d-s)*(2.0f*PI)/p)*0.5f + c + b);
-}
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif // REASINGS_H
diff --git a/raylib/examples/others/rlgl_compute_shader.c b/raylib/examples/others/rlgl_compute_shader.c
deleted file mode 100644
--- a/raylib/examples/others/rlgl_compute_shader.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [others] example - compute shader
-*
-*   NOTE: This example requires raylib OpenGL 4.3 versions for compute shaders support,
-*         shaders used in this example are #version 430 (OpenGL 4.3)
-*
-*   Example complexity rating: [★★★★] 4/4
-*
-*   Example originally created with raylib 4.0, last time updated with raylib 4.0
-*
-*   Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
-*
-*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
-*   BSD-like license that allows static linking with closed source software
-*
-*   Copyright (c) 2021-2025 Teddy Astie (@tsnake41)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-#include "rlgl.h"
-
-#include <stdlib.h>
-
-// IMPORTANT: This must match gol*.glsl GOL_WIDTH constant
-// This must be a multiple of 16 (check golLogic compute dispatch)
-#define GOL_WIDTH 768
-
-// Maximum amount of queued draw commands (squares draw from mouse down events)
-#define MAX_BUFFERED_TRANSFERTS 48
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// Game Of Life Update Command
-typedef struct GolUpdateCmd {
-    unsigned int x;         // x coordinate of the gol command
-    unsigned int y;         // y coordinate of the gol command
-    unsigned int w;         // width of the filled zone
-    unsigned int enabled;   // whether to enable or disable zone
-} GolUpdateCmd;
-
-// Game Of Life Update Commands SSBO
-typedef struct GolUpdateSSBO {
-    unsigned int count;
-    GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
-} GolUpdateSSBO;
-
-//------------------------------------------------------------------------------------
-// Program main entry point
-//------------------------------------------------------------------------------------
-int main(void)
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    const int screenWidth = GOL_WIDTH;
-    const int screenHeight = GOL_WIDTH;
-
-    InitWindow(screenWidth, screenHeight, "raylib [others] example - compute shader");
-
-    const Vector2 resolution = { (float)screenWidth, (float)screenHeight };
-    unsigned int brushSize = 8;
-
-    // Game of Life logic compute shader
-    char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
-    unsigned int golLogicShader = rlCompileShader(golLogicCode, RL_COMPUTE_SHADER);
-    unsigned int golLogicProgram = rlLoadComputeShaderProgram(golLogicShader);
-    UnloadFileText(golLogicCode);
-
-    // Game of Life logic render shader
-    Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
-    int resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
-
-    // Game of Life transfert shader (CPU<->GPU download and upload)
-    char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
-    unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER);
-    unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader);
-    UnloadFileText(golTransfertCode);
-
-    // Load shader storage buffer object (SSBO), id returned
-    unsigned int ssboA = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
-    unsigned int ssboB = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
-    unsigned int ssboTransfert = rlLoadShaderBuffer(sizeof(GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
-
-    GolUpdateSSBO transfertBuffer = { 0 };
-
-    // Create a white texture of the size of the window to update
-    // each pixel of the window using the fragment shader: golRenderShader
-    Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
-    Texture whiteTex = LoadTextureFromImage(whiteImage);
-    UnloadImage(whiteImage);
-    //--------------------------------------------------------------------------------------
-
-    // Main game loop
-    while (!WindowShouldClose())
-    {
-        // Update
-        //----------------------------------------------------------------------------------
-        brushSize += (int)GetMouseWheelMove();
-
-        if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
-            && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
-        {
-            // Buffer a new command
-            transfertBuffer.commands[transfertBuffer.count].x = GetMouseX() - brushSize/2;
-            transfertBuffer.commands[transfertBuffer.count].y = GetMouseY() - brushSize/2;
-            transfertBuffer.commands[transfertBuffer.count].w = brushSize;
-            transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
-            transfertBuffer.count++;
-        }
-        else if (transfertBuffer.count > 0)  // Process transfert buffer
-        {
-            // Send SSBO buffer to GPU
-            rlUpdateShaderBuffer(ssboTransfert, &transfertBuffer, sizeof(GolUpdateSSBO), 0);
-
-            // Process SSBO commands on GPU
-            rlEnableShader(golTransfertProgram);
-            rlBindShaderBuffer(ssboA, 1);
-            rlBindShaderBuffer(ssboTransfert, 3);
-            rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // Each GPU unit will process a command!
-            rlDisableShader();
-
-            transfertBuffer.count = 0;
-        }
-        else
-        {
-            // Process game of life logic
-            rlEnableShader(golLogicProgram);
-            rlBindShaderBuffer(ssboA, 1);
-            rlBindShaderBuffer(ssboB, 2);
-            rlComputeShaderDispatch(GOL_WIDTH/16, GOL_WIDTH/16, 1);
-            rlDisableShader();
-
-            // ssboA <-> ssboB
-            int temp = ssboA;
-            ssboA = ssboB;
-            ssboB = temp;
-        }
-
-        rlBindShaderBuffer(ssboA, 1);
-        SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
-        //----------------------------------------------------------------------------------
-
-        // Draw
-        //----------------------------------------------------------------------------------
-        BeginDrawing();
-
-            ClearBackground(BLANK);
-
-            BeginShaderMode(golRenderShader);
-                DrawTexture(whiteTex, 0, 0, WHITE);
-            EndShaderMode();
-
-            DrawRectangleLines(GetMouseX() - brushSize/2, GetMouseY() - brushSize/2, brushSize, brushSize, RED);
-
-            DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, WHITE);
-            DrawFPS(GetScreenWidth() - 100, 10);
-
-        EndDrawing();
-        //----------------------------------------------------------------------------------
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    // Unload shader buffers objects
-    rlUnloadShaderBuffer(ssboA);
-    rlUnloadShaderBuffer(ssboB);
-    rlUnloadShaderBuffer(ssboTransfert);
-
-    // Unload compute shader programs
-    rlUnloadShaderProgram(golTransfertProgram);
-    rlUnloadShaderProgram(golLogicProgram);
-
-    UnloadTexture(whiteTex);            // Unload white texture
-    UnloadShader(golRenderShader);      // Unload rendering fragment shader
-
-    CloseWindow();                      // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-
-    return 0;
-}
diff --git a/raylib/examples/others/rlgl_standalone.c b/raylib/examples/others/rlgl_standalone.c
--- a/raylib/examples/others/rlgl_standalone.c
+++ b/raylib/examples/others/rlgl_standalone.c
@@ -24,7 +24,7 @@
 *
 *   APPLE COMPILATION:
 *       gcc -o rlgl_standalone rlgl_standalone.c -I../../src -Iexternal/include -Lexternal/lib \
-*           -lglfw3 -framework CoreVideo -framework OpenGL -framework IOKit -framework Cocoa
+*           -lglfw3 -framework CoreVideo -framework OpenGL -framework IOKit -framework Cocoa -framework QuartzCore
 *           -Wno-deprecated-declarations -std=c99 -DGRAPHICS_API_OPENGL_33
 *
 *
diff --git a/raylib/examples/others/web_basic_window.c b/raylib/examples/others/web_basic_window.c
deleted file mode 100644
--- a/raylib/examples/others/web_basic_window.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [others] example - basic window
-*
-*   This example has been adapted to compile for PLATFORM_WEB and PLATFORM_DESKTOP
-*   As you will notice, code structure is slightly different to the other examples
-*
-*   Example complexity rating: [★☆☆☆] 1/4
-*
-*   Example originally created with raylib 1.3, last time updated with raylib 5.5
-*
-*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
-*   BSD-like license that allows static linking with closed source software
-*
-*   Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-#if defined(PLATFORM_WEB)
-    #include <emscripten/emscripten.h>
-#endif
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-int screenWidth = 800;
-int screenHeight = 450;
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-void UpdateDrawFrame(void);     // Update and Draw one frame
-
-//----------------------------------------------------------------------------------
-// Program main entry point
-//----------------------------------------------------------------------------------
-int main(void)
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    InitWindow(screenWidth, screenHeight, "raylib [others] example - web basic window");
-
-#if defined(PLATFORM_WEB)
-    emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
-#else
-    SetTargetFPS(60);   // Set our game to run at 60 frames-per-second
-    //--------------------------------------------------------------------------------------
-
-    // Main game loop
-    while (!WindowShouldClose())    // Detect window close button or ESC key
-    {
-        UpdateDrawFrame();
-    }
-#endif
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    CloseWindow();        // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-
-    return 0;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-void UpdateDrawFrame(void)
-{
-    // Update
-    //----------------------------------------------------------------------------------
-    // TODO: Update your variables here
-    //----------------------------------------------------------------------------------
-
-    // Draw
-    //----------------------------------------------------------------------------------
-    BeginDrawing();
-
-        ClearBackground(RAYWHITE);
-
-        DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
-
-    EndDrawing();
-    //----------------------------------------------------------------------------------
-}
diff --git a/raylib/examples/shaders/raygui.h b/raylib/examples/shaders/raygui.h
--- a/raylib/examples/shaders/raygui.h
+++ b/raylib/examples/shaders/raygui.h
@@ -1,5949 +1,6422 @@
 /*******************************************************************************************
 *
-*   raygui v4.5-dev - 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        --> 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 set we have the EXTENDED properties (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_DEBUG_RECS_BOUNDS
-*           Draw control bounds rectangles for debug
-*
-*       #define RAYGUI_DEBUG_TEXT_BOUNDS
-*           Draw text bounds rectangles for debug
-*
-*   VERSIONS HISTORY:
-*       5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
-*                         ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
-*                         ADDED: GuiValueBoxFloat()
-*                         ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
-*                         ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
-*                         ADDED: GuiLoadIconsFromMemory()
-*                         ADDED: Multiple new icons
-*                         REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
-*                         REMOVED: GuiSliderPro(), functionality was redundant
-*                         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
-*                         REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
-*
-*       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 5.6-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-2025 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 4
-#define RAYGUI_VERSION_MINOR 5
-#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION  "5.0-dev"
-
-#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)     // We are building the library as a Win32 shared library (.dll)
-    #elif defined(USE_LIBTYPE_SHARED)
-        #define RAYGUIAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
-    #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
-
-//----------------------------------------------------------------------------------
-// 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;
-
-    // Rectangle type
-    typedef struct Rectangle {
-        float x;
-        float y;
-        float width;
-        float height;
-    } Rectangle;
-
-    // TODO: 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;
-
-    // TODO: 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 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
-typedef enum {
-    // Default -> populates to all controls when set
-    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
-} GuiControl;
-
-// Gui base properties for every control
-// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
-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
-} 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)
-//----------------------------------------------------------------------------------
-// DEFAULT extended properties
-// NOTE: Those properties are common to all controls or global
-// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
-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
-} GuiDefaultProperty;
-
-// Other possible text properties:
-// TEXT_WEIGHT                  // Normal, Italic, Bold -> Requires specific font change
-// TEXT_INDENT                  // Text indentation -> Now using TEXT_PADDING...
-
-// Label
-//typedef enum { } GuiLabelProperty;
-
-// Button/Spinner
-//typedef enum { } GuiButtonProperty;
-
-// Toggle/ToggleGroup
-typedef enum {
-    GROUP_PADDING = 16,         // ToggleGroup separation between toggles
-} 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
-} 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 (default rolls down)
-} GuiDropdownBoxProperty;
-
-// TextBox/TextBoxMulti/ValueBox/Spinner
-typedef enum {
-    TEXT_READONLY = 16,         // TextBox in read-only mode: 0-text editable, 1-text no-editable
-} GuiTextBoxProperty;
-
-// ValueBox/Spinner
-typedef enum {
-    SPINNER_BUTTON_WIDTH = 16,  // Spinner left/right buttons width
-    SPINNER_BUTTON_SPACING,     // Spinner buttons separation
-} GuiValueBoxProperty;
-
-// Control11
-//typedef enum { } GuiControl11Property;
-
-// ListView
-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)
-    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,
-    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
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// 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 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 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 GuiTabBar(Rectangle bounds, const 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
-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, const 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 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()
-//----------------------------------------------------------------------------------------------------------
-
-#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_250                      = 250,
-    ICON_251                      = 251,
-    ICON_252                      = 252,
-    ICON_253                      = 253,
-    ICON_254                      = 254,
-    ICON_255                      = 255
-} GuiIconName;
-#endif
-
-#endif
-
-#if defined(__cplusplus)
-}            // Prevents name mangling of functions
-#endif
-
-#endif // RAYGUI_H
-
-/***********************************************************************************
-*
-*   RAYGUI IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RAYGUI_IMPLEMENTATION)
-
-#include <ctype.h>              // required for: isspace() [GuiTextBox()]
-#include <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
-#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
-#include <math.h>               // Required for: roundf() [GuiColorPicker()]
-
-// 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 <stdlib.h>             // 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         256          // Maximum number of icons
-#define RAYGUI_ICON_MAX_NAME_LENGTH    32          // Maximum length of icon name id
-
-// 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: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 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
-    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
-};
-
-// 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 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 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()
-//-------------------------------------------------------------------------------
-
-// raylib functions already implemented in raygui
-//-------------------------------------------------------------------------------
-static Color GetColor(int hexValue);                // Returns a Color struct from hexadecimal value
-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 const 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
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize);    // Load style from memory (binary only)
-
-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 const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow);   // 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 Color GuiFade(Color color, float alpha);         // Fade color by an alpha factor
-
-//----------------------------------------------------------------------------------
-// Gui Setup Functions Definition
-//----------------------------------------------------------------------------------
-// Enable gui global state
-// NOTE: We check 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: We check 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 we try to setup a font but default style has not been
-        // lazily loaded before, it will be overwritten, so we need to force
-        // default style loading 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 = 0;
-    //GuiState state = guiState;
-
-    int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
-
-    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 - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
-    Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 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
-    //--------------------------------------------------------------------
-    GuiStatusBar(statusBar, title); // Draw window header as status bar
-    GuiPanel(windowPanel, NULL);    // Draw window base
-
-    // Draw window close button
-    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)
-    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;      // Window close button clicked: result = 1
-}
-
-// 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 = 0;
-    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 = 0;
-    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 = 0;
-    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) 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;
-}
-
-// Tab Bar control
-// NOTE: Using GuiToggle() for the TABS
-int GuiTabBar(Rectangle bounds, const 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(GetMousePosition(), 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)
-{
-    #define RAYGUI_MIN_SCROLLBAR_WIDTH     40
-    #define RAYGUI_MIN_SCROLLBAR_HEIGHT    40
-    #define RAYGUI_MIN_MOUSE_WHEEL_SPEED   20
-
-    int result = 0;
-    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 = hasVerticalScrollBar? 0.0f : -1.0f;
-    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 = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
-            if (hasHorizontalScrollBar)
-            {
-                if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-
-            if (hasVerticalScrollBar)
-            {
-                if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-#endif
-            float wheelMove = GetMouseWheelMove();
-
-            // Set scrolling speed with mouse wheel based on ratio between bounds and content
-            Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
-            if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-            if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-
-            // Horizontal and vertical scrolling with mouse wheel
-            if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
-            else scrollPos.y += wheelMove*mouseWheelSpeed.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) 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Button pressed: result = 1
-}
-
-// Label button control
-int GuiLabelButton(Rectangle bounds, const char *text)
-{
-    GuiState state = guiState;
-    bool pressed = false;
-
-    // NOTE: We 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 = GetMousePosition();
-
-        // Check checkbox state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
-    //--------------------------------------------------------------------
-
-    return pressed;
-}
-
-// Toggle Button control
-int GuiToggle(Rectangle bounds, const char *text, bool *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    bool temp = false;
-    if (active == NULL) active = &temp;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check toggle button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                state = STATE_NORMAL;
-                *active = !(*active);
-            }
-            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)
-{
-    #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
-        #define RAYGUI_TOGGLEGROUP_MAX_ITEMS    32
-    #endif
-
-    int result = 0;
-    float initBoundsX = bounds.x;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, rows);
-
-    int prevRow = rows[0];
-
-    for (int i = 0; i < itemCount; i++)
-    {
-        if (prevRow != rows[i])
-        {
-            bounds.x = initBoundsX;
-            bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
-            prevRow = rows[i];
-        }
-
-        if (i == (*active))
-        {
-            toggle = true;
-            GuiToggle(bounds, items[i], &toggle);
-        }
-        else
-        {
-            toggle = false;
-            GuiToggle(bounds, items[i], &toggle);
-            if (toggle) *active = i;
-        }
-
-        bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
-    }
-
-    return result;
-}
-
-// Toggle Slider control extended
-int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    if (active == NULL) active = &temp;
-
-    //bool toggle = false;    // Required for individual toggles
-
-    // Get substrings items from text (items pointers)
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = GetMousePosition();
-
-        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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                *checked = !(*checked);
-                result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds) ||
-            CheckCollisionPointRec(mousePoint, selector))
-        {
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                *active += 1;
-                if (*active >= itemCount) *active = 0;      // Cyclic combobox
-            }
-
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            // Check if mouse has been pressed or released outside limits
-            if (!CheckCollisionPointRec(mousePoint, boundsOpen))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-
-            // Check if already selected item has been pressed again
-            if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) 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 (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-                    {
-                        itemSelected = i;
-                        result = 1;         // Item selected
-                    }
-                    break;
-                }
-            }
-
-            itemBounds = bounds;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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? "#121#" : "#120#", 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;
-
-    // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
-    return result;   // Mouse click: result = 1
-}
-
-// 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 = 0;
-    GuiState state = guiState;
-
-    bool multiline = false;     // TODO: Consider multiline text input
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            // GLOBAL: Auto-cursor movement logic
-            // NOTE: Keystrokes are handled repeatedly when button is held down for some time
-            if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(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,
-            // we add 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 = GetCharPressed();       // Get Unicode codepoint
-            if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
-
-            // Encode codepoint as UTF-8
-            int codepointSize = 0;
-            const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
-
-            // Handle text paste action
-            if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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';
-                    }
-                }
-            }
-            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';
-            }
-
-            // Move cursor to start
-            if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
-
-            // Move cursor to end
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
-
-            // Delete related codepoints from text, after current cursor position
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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;
-            }
-
-            else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(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;
-            }
-
-            // Delete related codepoints from text, before current cursor position
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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;
-            }
-
-            else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(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;
-            }
-
-            // Move cursor position with keys
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                //int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
-            {
-                int prevCodepointSize = 0;
-                GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
-
-                textBoxCursorIndex -= prevCodepointSize;
-            }
-            else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
-            {
-                int nextCodepointSize = 0;
-                GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
-                textBoxCursorIndex += nextCodepointSize;
-            }
-
-            // Move cursor position with mouse
-            if (CheckCollisionPointRec(mousePosition, textBounds))     // Mouse hover text
-            {
-                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 (GetMousePosition().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) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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 && IsKeyPressed(KEY_ENTER)) ||
-                (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                textBoxCursorIndex = 0;     // GLOBAL: Reset the shared cursor index
-                autoCursorCounter = 0;      // GLOBAL: Reset counter for repeated keystrokes
-                result = 1;
-            }
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePosition, bounds))
-            {
-                state = STATE_FOCUSED;
-
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    textBoxCursorIndex = textLength;   // GLOBAL: Place cursor index to the end of current text
-                    autoCursorCounter = 0;             // GLOBAL: Reset counter for repeated keystrokes
-                    result = 1;
-                }
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Mouse button pressed: result = 1
-}
-
-/*
-// 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 = GetMousePosition();
-
-        // Check spinner state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) 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))));
-    //--------------------------------------------------------------------
-
-    *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;
-    GuiState state = guiState;
-
-    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 = GetMousePosition();
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                
-                // Only allow keys in range [48..57]
-                if ((key >= 48) && (key <= 57))
-                {
-                    textValue[keyCount] = (char)key;
-                    keyCount++;
-                    valueHasChanged = true;
-                }
-            }
-
-            // Delete text
-            if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
-            {
-                keyCount--;
-                textValue[keyCount] = '\0';
-                valueHasChanged = true;
-            }
-
-            if (valueHasChanged) *value = TextToInteger(textValue);
-
-            // NOTE: We are not clamp values until user input finishes
-            //if (*value > maxValue) *value = maxValue;
-            //else if (*value < minValue) *value = minValue;
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                if (*value > maxValue) *value = maxValue;
-                else if (*value < minValue) *value = minValue;
-
-                result = 1;
-            }
-        }
-        else
-        {
-            if (*value > maxValue) *value = maxValue;
-            else if (*value < minValue) *value = minValue;
-
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-// 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;
-    GuiState state = guiState;
-
-    //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
-    //snprintf(textValue, sizeof(textValue), "%2.2f", *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 = GetMousePosition();
-
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                    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 (IsKeyPressed(KEY_BACKSPACE))
-            {
-                if (keyCount > 0)
-                {
-                    keyCount--;
-                    textValue[keyCount] = '\0';
-                    valueHasChanged = true;
-                }
-            }
-
-            if (valueHasChanged) *value = TextToFloat(textValue);
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-    float oldValue = *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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    }
-
-    // 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
-    {
-        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);
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-
-    // 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));
-    //--------------------------------------------------------------------
-
-    // 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)
-        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 = 0;
-    GuiState state = guiState;
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
-
-    return result;
-}
-
-// List View control with extended parameters
-int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int itemFocused = (focus == NULL)? -1 : *focus;
-    int itemSelected = (active == NULL)? -1 : *active;
-
-    // Check if we need a scroll bar
-    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 = GetMousePosition();
-
-        // 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 (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                    {
-                        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)
-            {
-                int wheelMove = (int)GetMouseWheelMove();
-                startIndex -= wheelMove;
-
-                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(DEFAULT, 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
-            }
-            else if (((startIndex + i) == itemFocused)) // && (focus != NULL))  // NOTE: We want 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
-            }
-            else
-            {
-                // Draw item normal (no rectangle)
-                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, 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;
-
-    return result;
-}
-
-// Color Panel control - Color (RGBA) variant
-int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
-{
-    int result = 0;
-
-    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
-
-    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)
-    {
-        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 };
-    }
-    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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_UP))
-            {
-                hue -= 2.0f;
-                if (hue <= 0.0f) hue = 0.0f;
-            }
-            else if (IsKeyDown(KEY_DOWN))
-            {
-                hue += 2.0f;
-                if (hue >= 360.0f) hue = 360.0f;
-            }*/
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    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));
-    }
-    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);
-
-    // 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 = 0;
-
-    Color temp = { 200, 0, 0, 255 };
-    if (color == NULL) color = &temp;
-
-    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 });
-
-    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 = 0;
-
-    Vector3 tempHsv = { 0 };
-
-    if (colorHsv == NULL)
-    {
-        const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
-        tempHsv = ConvertRGBtoHSV(tempColor);
-        colorHsv = &tempHsv;
-    }
-
-    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 };
-
-    GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
-
-    return result;
-}
-
-// Color Panel control - HSV variant
-int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
-{
-    int result = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
-{
-    #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 = -1;    // Returns clicked button from buttons list, 0 refers to closed window button
-
-    int buttonCount = 0;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    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, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
-    //--------------------------------------------------------------------
-
-    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)
-{
-    #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
-
-    // 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;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    // 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);
-    }
-
-    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, textMaxSize, textEditMode)) 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);
-    }
-    else
-    {
-        if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
-    }
-
-    int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
-
-    for (int i = 0; i < buttonCount; i++)
-    {
-        if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    if (result >= 0) textEditMode = false;
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
-    //--------------------------------------------------------------------
-
-    return result;      // Result is the pressed button index
-}
-
-// Grid control
-// NOTE: Returns grid mouse-hover selected cell
-// About drawing lines at subpixel spacing, simple put, not easy solution:
-// 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 = 0;
-    GuiState state = guiState;
-
-    Vector2 mousePoint = GetMousePosition();
-    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);
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;
-
-            while (!feof(rgsFile))
-            {
-                switch (buffer[0])
-                {
-                    case 'p':
-                    {
-                        // Style property: p <control_id> <property_id> <property_value> <property_name>
-
-                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
-                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
-
-                    } break;
-                    case 'f':
-                    {
-                        // Style font: f <gen_font_size> <charmap_file> <font_file>
-
-                        int fontSize = 0;
-                        char charmapFileName[256] = { 0 };
-                        char fontFileName[256] = { 0 };
-                        sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, 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));
-                fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
-
-                GuiLoadStyleFromMemory(fileData, fileDataSize);
-
-                RAYGUI_FREE(fileData);
-            }
-
-            fclose(rgsFile);
-        }
-    }
-}
-
-// Load style default over global style
-void GuiLoadStyleDefault(void)
-{
-    // We set this variable 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, 15);        // DEFAULT, 15 pixels between lines
-    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);
-
-    // 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: We set 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 });
-    }
-}
-
-// 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)
-// 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;
-
-        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);
-
-        if ((signature[0] == 'r') &&
-            (signature[1] == 'G') &&
-            (signature[2] == 'I') &&
-            (signature[3] == ' '))
-        {
-            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);
-
-            // Read icons data directly over internal icons array
-            fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
-        }
-
-        fclose(rgiFile);
-    }
-
-    return guiIconsName;
-}
-
-// Load icons from memory
-// WARNING: Binary files only
-char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
-{
-    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)
-        {
-            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));
-                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)
-{
-    #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))
-            {
-            #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
-            }
-
-            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)
-int GuiGetTextWidth(const char *text)
-{
-    #if !defined(ICON_TEXT_PADDING)
-        #define ICON_TEXT_PADDING   4
-    #endif
-
-    Vector2 textSize = { 0 };
-    int textIconOffset = 0;
-
-    if ((text != NULL) && (text[0] != '\0'))
-    {
-        if (text[0] == '#')
-        {
-            for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
-            {
-                if (text[i] == '#')
-                {
-                    textIconOffset = i;
-                    break;
-                }
-            }
-        }
-
-        text += textIconOffset;
-
-        // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
-        float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
-        // Custom MeasureText() implementation
-        if ((guiFont.texture.id > 0) && (text != NULL))
-        {
-            // Get size in bytes of text, 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 + 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)
-{
-    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 CONTROL11:
-            // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
-        default:
-        {
-            // TODO: 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: We support up to 999 values for iconId
-static const char *GetTextIcon(const char *text, int *iconId)
-{
-#if !defined(RAYGUI_NO_ICONS)
-    *iconId = -1;
-    if (text[0] == '#')     // Maybe we have an icon!
-    {
-        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] == '#')
-        {
-            *iconId = TextToInteger(iconValue);
-
-            // 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 textSize = (int)strlen(text);
-
-    lines[0] = text;
-    *count = 1;
-
-    for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
-    {
-        if (text[i] == '\n')
-        {
-            k++;
-            lines[k] = &text[i + 1]; // WARNING: next value is valid?
-            *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(ICON_TEXT_PADDING)
-        #define 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: We can't use GuiTextSplit() function because it can be already 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_SIZE)/2);
-    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: We get text size after icon has been processed
-        // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
-        int textSizeX = GuiGetTextWidth(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 += 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 we get pixel-perfect coordinates,
-        // In case of decimals we got weird text positioning
-        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: We consider 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);
-        }
-#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 we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
-            // but we need to draw all of the bad bytes using the '?' symbol moving one byte
-            if (codepoint == 0x3f) codepointSize = 1; // TODO: Review 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_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_LINE_SPACING);
-                }
-            }
-
-            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,
-                // 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_LINE_SPACING);
-        else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
-        //---------------------------------------------------------------------------------
-    }
-
-#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(GuiGetFont(), 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);
-
-        GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, 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, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
-        GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
-        GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
-    }
-}
-
-// Split controls text into multiple strings
-// Also check for multiple columns (required by GuiToggleGroup())
-static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
-{
-    // 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
-
-    // 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
-    #endif
-
-    static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };   // 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;
-
-    // Count how many substrings we have on text and point to every one
-    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'))
-        {
-            result[counter] = buffer + i + 1;
-
-            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;
-        }
-    }
-
-    *count = counter;
-
-    return result;
-}
-
-// 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;
-}
-
-// 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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
-                !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
-            int wheel = (int)GetMouseWheelMove();
-            if (wheel != 0) value += wheel;
-
-            // Handle mouse button down
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_DOWN)) value += 5;
-                else if (IsKeyDown(KEY_UP)) value -= 5;
-            }
-            else
-            {
-                if (IsKeyDown(KEY_RIGHT)) value += 5;
-                else if (IsKeyDown(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
-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;
-}
-
-// 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];
-
-    va_list args;
-    va_start(args, text);
-    vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
-    va_end(args);
-
-    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
-const 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 we have on text and point to every one
-        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)
-{
-    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 we exit as soon as possible and a '?'(0x3f) codepoint is returned
-// Total number of bytes processed are returned as a parameter
-// NOTE: the standard says U+FFFD should be returned in case of errors
+*   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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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)
 {
diff --git a/raylib/examples/shaders/shaders_ascii_rendering.c b/raylib/examples/shaders/shaders_ascii_rendering.c
--- a/raylib/examples/shaders/shaders_ascii_rendering.c
+++ b/raylib/examples/shaders/shaders_ascii_rendering.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.6
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *
 *   Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shaders/shaders_cel_shading.c b/raylib/examples/shaders/shaders_cel_shading.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shaders/shaders_cel_shading.c
@@ -0,0 +1,175 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - cel shading
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+*         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+*   NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
+*
+*   Example contributed by Gleb A (@ggrizzly) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Gleb A (@ggrizzly)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+#include "rlgl.h"
+
+#include <math.h>       // Required for: sinf(), cosf()
+
+#define RLIGHTS_IMPLEMENTATION
+#include "rlights.h"
+
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    SetConfigFlags(FLAG_MSAA_4X_HINT);
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - cel shading");
+
+    Camera camera = { 0 };
+    camera.position = (Vector3){ 9.0f, 6.0f, 9.0f };
+    camera.target = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    // Load model
+    Model model = LoadModel("resources/models/old_car_new.glb");
+
+    // Load cel shader
+    Shader celShader = LoadShader(
+        TextFormat("resources/shaders/glsl%i/cel.vs", GLSL_VERSION),
+        TextFormat("resources/shaders/glsl%i/cel.fs", GLSL_VERSION));
+    celShader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(celShader, "viewPos");
+
+    // Apply cel shader to model, keep copy of default shader
+    Shader defaultShader = model.materials[0].shader;
+    model.materials[0].shader = celShader;
+
+    // numBands: controls toon quantization steps (2 = hard binary, 20 = near-smooth)
+    float numBands = 10.0f;
+    int numBandsLoc = GetShaderLocation(celShader, "numBands");
+    SetShaderValue(celShader, numBandsLoc, &numBands, SHADER_UNIFORM_FLOAT);
+
+    // Inverted-hull outline shader: draws back faces extruded along normals
+    Shader outlineShader = LoadShader(
+        TextFormat("resources/shaders/glsl%i/outline_hull.vs", GLSL_VERSION),
+        TextFormat("resources/shaders/glsl%i/outline_hull.fs", GLSL_VERSION));
+    int outlineThicknessLoc = GetShaderLocation(outlineShader, "outlineThickness");
+
+    // Single directional white light, angled so toon bands are visible on the model sides.
+    // Spins opposite to CAMERA_ORBITAL (0.5 rad/s) so lighting changes as you watch.
+    Light lights[MAX_LIGHTS] = { 0 };
+    lights[0] = CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 50.0f, 50.0f, 50.0f }, Vector3Zero(), WHITE, celShader);
+
+    bool celEnabled = true;
+    bool outlineEnabled = true;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
+        SetShaderValue(celShader, celShader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
+
+        // [Z] Toggle cel shading on/off
+        if (IsKeyPressed(KEY_Z))
+        {
+            celEnabled = !celEnabled;
+            if (celEnabled) model.materials[0].shader = celShader; // Apply cel shader to model
+            else model.materials[0].shader = defaultShader; // Apply default shader to model
+        }
+
+        // [C] Toggle outline on/off
+        if (IsKeyPressed(KEY_C)) outlineEnabled = !outlineEnabled;
+
+        // [Q/E] Decrease/increase toon band count (press or hold to repeat)
+        if (IsKeyPressed(KEY_E) || IsKeyPressedRepeat(KEY_E)) numBands = Clamp(numBands + 1.0f, 2.0f, 20.0f);
+        if (IsKeyPressed(KEY_Q) || IsKeyPressedRepeat(KEY_Q)) numBands = Clamp(numBands - 1.0f, 2.0f, 20.0f);
+        SetShaderValue(celShader, numBandsLoc, &numBands, SHADER_UNIFORM_FLOAT);
+
+        // Spin light opposite to CAMERA_ORBITAL (0.5 rad/s), angled 45 degrees off vertical
+        float t = (float)GetTime();
+        lights[0].position = (Vector3){ sinf(-t*0.3f)*5.0f, 5.0f, cosf(-t*0.3f)*5.0f };
+
+        for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(celShader, lights[i]);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                if (outlineEnabled)
+                {
+                    // Outline pass: cull front faces, draw extruded back faces as silhouette
+                    float thickness = 0.005f;
+                    SetShaderValue(outlineShader, outlineThicknessLoc, &thickness, SHADER_UNIFORM_FLOAT);
+
+                    rlSetCullFace(RL_CULL_FACE_FRONT);
+
+                    model.materials[0].shader = outlineShader;
+
+                    DrawModel(model, Vector3Zero(), 0.75f, WHITE);
+
+                    if (celEnabled) model.materials[0].shader = celShader; // Apply cel shader to model
+                    else model.materials[0].shader = defaultShader; // Apply default shader to model
+
+                    rlSetCullFace(RL_CULL_FACE_BACK);
+                }
+
+                DrawModel(model, Vector3Zero(), 0.75f, WHITE);
+                DrawSphereEx(lights[0].position, 0.2f, 50, 50, YELLOW);  // Light position indicator
+                DrawGrid(10, 10.0f);
+
+            EndMode3D();
+
+            DrawFPS(10, 10);
+            DrawText(TextFormat("Cel: %s  [Z]", celEnabled? "ON" : "OFF"), 10, 65, 20, celEnabled? DARKGREEN : DARKGRAY);
+            DrawText(TextFormat("Outline: %s  [C]", outlineEnabled? "ON" : "OFF"), 10, 90, 20, outlineEnabled? DARKGREEN : DARKGRAY);
+            DrawText(TextFormat("Bands: %.0f  [Q/E]", numBands), 10, 115, 20, DARKGRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModel(model);
+    UnloadShader(celShader);
+    UnloadShader(outlineShader);
+
+    CloseWindow();
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shaders/shaders_color_correction.c b/raylib/examples/shaders/shaders_color_correction.c
--- a/raylib/examples/shaders/shaders_color_correction.c
+++ b/raylib/examples/shaders/shaders_color_correction.c
@@ -7,7 +7,7 @@
 *   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
 *         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
 *
-*   Example originally created with raylib 5.6, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shaders/shaders_deferred_rendering.c b/raylib/examples/shaders/shaders_deferred_rendering.c
--- a/raylib/examples/shaders/shaders_deferred_rendering.c
+++ b/raylib/examples/shaders/shaders_deferred_rendering.c
@@ -210,7 +210,7 @@
             rlClearColor(0, 0, 0, 0);
             rlClearScreenBuffers();  // Clear color and depth buffer
             rlDisableColorBlend();
-            
+
             BeginMode3D(camera);
                 // NOTE: We have to use rlEnableShader here. `BeginShaderMode` or thus `rlSetShader`
                 // will not work, as they won't immediately load the shader program
@@ -226,7 +226,7 @@
                     }
                 rlDisableShader();
             EndMode3D();
-            
+
             rlEnableColorBlend();
 
             // Go back to the default framebufferId (0) and draw our deferred shading
diff --git a/raylib/examples/shaders/shaders_depth_rendering.c b/raylib/examples/shaders/shaders_depth_rendering.c
--- a/raylib/examples/shaders/shaders_depth_rendering.c
+++ b/raylib/examples/shaders/shaders_depth_rendering.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Luís Almeida (@luis605) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shaders/shaders_fog_rendering.c b/raylib/examples/shaders/shaders_fog_rendering.c
--- a/raylib/examples/shaders/shaders_fog_rendering.c
+++ b/raylib/examples/shaders/shaders_fog_rendering.c
@@ -72,8 +72,13 @@
     shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
 
     // Ambient light level
+    Vector4 ambient = (Vector4){ 0.2f, 0.2f, 0.2f, 1.0f };
     int ambientLoc = GetShaderLocation(shader, "ambient");
-    SetShaderValue(shader, ambientLoc, (float[4]){ 0.2f, 0.2f, 0.2f, 1.0f }, SHADER_UNIFORM_VEC4);
+    SetShaderValue(shader, ambientLoc, &ambient, SHADER_UNIFORM_VEC4);
+
+    Vector4 fogColor = ColorNormalize(GRAY);
+    int fogColorLoc = GetShaderLocation(shader, "fogColor");
+    SetShaderValue(shader, fogColorLoc, &fogColor, SHADER_UNIFORM_VEC4);
 
     float fogDensity = 0.15f;
     int fogDensityLoc = GetShaderLocation(shader, "fogDensity");
diff --git a/raylib/examples/shaders/shaders_game_of_life.c b/raylib/examples/shaders/shaders_game_of_life.c
--- a/raylib/examples/shaders/shaders_game_of_life.c
+++ b/raylib/examples/shaders/shaders_game_of_life.c
@@ -7,7 +7,7 @@
 *   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
 *         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
 *
-*   Example originally created with raylib 5.6, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -59,7 +59,7 @@
     //--------------------------------------------------------------------------------------
     const int screenWidth = 800;
     const int screenHeight = 450;
-    
+
     InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life");
 
     const int menuWidth = 100;
@@ -81,7 +81,7 @@
         { "Puffer train", { 0.1f, 0.5f } }, { "Glider Gun", { 0.2f, 0.2f } }, { "Breeder", { 0.1f, 0.5f } },
         { "Random", { 0.5f, 0.5f } }
     };
-    
+
     const int numberOfPresets = sizeof(presetPatterns)/sizeof(presetPatterns[0]);
 
     int zoom = 1;
@@ -90,7 +90,7 @@
     int framesPerStep = 1;
     int frame = 0;
 
-    int preset = -1;            // No button pressed for preset 
+    int preset = -1;            // No button pressed for preset
     int mode = MODE_RUN;        // Starting mode: running
     bool buttonZoomIn = false;  // Button states: false not pressed
     bool buttonZomOut = false;
@@ -185,7 +185,7 @@
                 EndTextureMode();
                 imageToDraw = (Image*)RL_MALLOC(sizeof(Image));
                 *imageToDraw = LoadImageFromTexture(worldOnScreen.texture);
-                
+
                 UnloadRenderTexture(worldOnScreen);
             }
 
@@ -199,9 +199,9 @@
                 if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1;
                 if (firstColor == -1) firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
                 const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
-                
+
                 ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE);
-                
+
                 if (prevColor != firstColor) UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data);
             }
             else firstColor = -1;
@@ -228,7 +228,7 @@
                 BeginTextureMode(*currentWorld);
                     ClearBackground(RAYWHITE);
                 EndTextureMode();
-                
+
                 UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f,
                                                                      worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f,
                                                                      (float)(pattern.width), (float)(pattern.height) }, pattern.data);
@@ -256,10 +256,10 @@
             }
 
             UnloadImage(pattern);
-            
+
             mode = MODE_PAUSE;
-            offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f;
-            offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f;
+            offsetX = worldWidth*presetPatterns[preset].position.x - (float)windowWidth/zoom/2.0f;
+            offsetY = worldHeight*presetPatterns[preset].position.y - (float)windowHeight/zoom/2.0f;
         }
 
         // Check window draw inside world limits
@@ -293,7 +293,7 @@
         // Draw to screen
         //----------------------------------------------------------------------------------
         BeginDrawing();
-        
+
             DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE);
 
             DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 });
diff --git a/raylib/examples/shaders/shaders_hybrid_rendering.c b/raylib/examples/shaders/shaders_hybrid_rendering.c
--- a/raylib/examples/shaders/shaders_hybrid_rendering.c
+++ b/raylib/examples/shaders/shaders_hybrid_rendering.c
@@ -65,7 +65,7 @@
     Shader shdrRaster = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION));
 
     // Declare Struct used to store camera locs
-    RayLocs marchLocs = {0};
+    RayLocs marchLocs = { 0 };
 
     // Fill the struct with shader locs
     marchLocs.camPos = GetShaderLocation(shdrRaymarch, "camPos");
diff --git a/raylib/examples/shaders/shaders_lights_bloom.c b/raylib/examples/shaders/shaders_lights_bloom.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shaders/shaders_lights_bloom.c
@@ -0,0 +1,185 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - forward multi-lighting with bloom
+*
+*   Example demonstrates forward multi-point lighting (8 point lights, attenuation and
+*   Blinn-Phong specular) combined with a threshold-based bloom pass and Reinhard tone
+*   mapping, applied as a full-screen post-process pass
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example uses resources/shaders/glsl100 and resources/shaders/glsl330, shared with the
+*   rest of the shaders examples
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2025 PanicTitan (@PanicTitan)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+#include "rlgl.h"
+
+#include <math.h>       // Required for: sinf(), cosf()
+
+#if defined(PLATFORM_DESKTOP)
+    #define GLSL_VERSION            330
+#else   // PLATFORM_ANDROID, PLATFORM_WEB
+    #define GLSL_VERSION            100
+#endif
+
+//--------------------------------------------------------------------------------------
+// Global Definitions
+//--------------------------------------------------------------------------------------
+#define MAX_LIGHTS      8
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - forward multi-lighting bloom");
+
+    Camera3D camera = { 0 };
+    camera.position = (Vector3){ 0.0f, 5.0f, 9.0f };
+    camera.target = (Vector3){ 0.0f, 0.5f, 0.0f };
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
+
+    // Forward multi-light shader and bloom post-process shader, both loaded from the
+    // resources folder shared with the rest of the shaders examples. If the GLSL version
+    // guessed from the PLATFORM_DESKTOP build flag turns out to be wrong for whatever
+    // raylib was built against, linking fails and silently falls back to the default
+    // shader - so this retries once with the other version, and either way the result
+    // is checked explicitly and reported on screen rather than staying silently wrong
+    Shader lightShader = LoadShader(TextFormat("resources/shaders/glsl%i/lights_bloom.vs", GLSL_VERSION),
+                                     TextFormat("resources/shaders/glsl%i/lights_bloom.fs", GLSL_VERSION));
+    Shader bloomShader = LoadShader(0, TextFormat("resources/shaders/glsl%i/lights_bloom_post.fs", GLSL_VERSION));
+
+    // Load models from generated cube mesh and plane
+    // NOTE: Meshes are automatically unloaded on UnloadModel()
+    Model cube = LoadModelFromMesh(GenMeshCube(2.0f, 2.0f, 2.0f));
+    Model floor = LoadModelFromMesh(GenMeshPlane(14.0f, 14.0f, 1, 1));
+    cube.materials[0].shader = lightShader;
+    floor.materials[0].shader = lightShader;
+
+    int lightPosLoc = GetShaderLocation(lightShader, "lightPositions");
+    int lightColLoc = GetShaderLocation(lightShader, "lightColors");
+    int viewPosLoc = GetShaderLocation(lightShader, "viewPos");
+
+    Vector3 lightPositions[MAX_LIGHTS] = { 0 };
+    Vector3 lightColors[MAX_LIGHTS] = {
+        { 1.0f, 0.2f, 0.2f },   // Red
+        { 0.2f, 1.0f, 0.3f },   // Green
+        { 0.2f, 0.5f, 1.0f },   // Blue
+        { 1.0f, 0.8f, 0.1f },   // Yellow
+        { 1.0f, 0.1f, 0.8f },   // Magenta
+        { 0.1f, 1.0f, 1.0f },   // Cyan
+        { 1.0f, 0.4f, 0.1f },   // Orange
+        { 0.7f, 0.2f, 1.0f },   // Purple
+    };
+
+    SetShaderValueV(lightShader, lightColLoc, lightColors, SHADER_UNIFORM_VEC3, MAX_LIGHTS);
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        float time = (float)GetTime();
+
+        // Orbital path for each point light, its own radius/height offset by index
+        for (int i = 0; i < MAX_LIGHTS; i++)
+        {
+            float angle = (i/(float)MAX_LIGHTS)*2.0f*PI + time*0.6f;
+            float radius = 4.2f + sinf(time*1.2f + i)*0.4f;
+            float height = 1.0f + sinf(time*1.8f + i)*0.6f;
+
+            lightPositions[i] = (Vector3){ sinf(angle)*radius, height, cosf(angle)*radius };
+        }
+
+        SetShaderValueV(lightShader, lightPosLoc, lightPositions, SHADER_UNIFORM_VEC3, MAX_LIGHTS);
+        SetShaderValue(lightShader, viewPosLoc, &camera.position, SHADER_UNIFORM_VEC3);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        // Render the lit scene to an offscreen texture
+        BeginTextureMode(target);
+
+            ClearBackground((Color){ 12, 12, 18, 255 });
+
+            BeginMode3D(camera);
+
+                DrawModel(cube, (Vector3){ 0.0f, 1.0f, 0.0f }, 1.0f, GRAY);
+                DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 1.0f, DARKGRAY);
+                DrawGrid(10, 1.0f);
+
+                // Glowing bulbs mark each light's position
+                for (int i = 0; i < MAX_LIGHTS; i++)
+                {
+                    Color bulbColor = (Color){
+                        (unsigned char)(lightColors[i].x*255),
+                        (unsigned char)(lightColors[i].y*255),
+                        (unsigned char)(lightColors[i].z*255),
+                        255 };
+
+                    DrawSphere(lightPositions[i], 0.15f, bulbColor);
+                }
+
+            EndMode3D();
+
+        EndTextureMode();
+
+        // Present the offscreen texture through the bloom + tone mapping shader
+        BeginDrawing();
+
+            ClearBackground(BLACK);
+
+            Rectangle srcRec = { 0, 0, (float)target.texture.width, (float)-target.texture.height };
+
+            BeginShaderMode(bloomShader);
+                // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
+                DrawTextureRec(target.texture, srcRec, (Vector2){ 0, 0 }, WHITE);
+            EndShaderMode();
+
+            DrawText("BALANCED MULTI-LIGHT + REINHARD TONE MAPPED BLOOM", 20, 20, 20, GREEN);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadModel(cube);
+    UnloadModel(floor);
+    UnloadShader(lightShader);
+    UnloadShader(bloomShader);
+    UnloadRenderTexture(target);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shaders/shaders_mandelbrot_set.c b/raylib/examples/shaders/shaders_mandelbrot_set.c
--- a/raylib/examples/shaders/shaders_mandelbrot_set.c
+++ b/raylib/examples/shaders/shaders_mandelbrot_set.c
@@ -9,7 +9,7 @@
 *
 *   NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
 *
-*   Example originally created with raylib 5.6, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jordi Santonja (@JordSant)
 *   Based on previous work by Josh Colclough (@joshcol9232)
diff --git a/raylib/examples/shaders/shaders_normalmap_rendering.c b/raylib/examples/shaders/shaders_normalmap_rendering.c
--- a/raylib/examples/shaders/shaders_normalmap_rendering.c
+++ b/raylib/examples/shaders/shaders_normalmap_rendering.c
@@ -7,7 +7,7 @@
 *   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
 *        OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
 *
-*   Example originally created with raylib 5.6, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shaders/shaders_rlgl_compute.c b/raylib/examples/shaders/shaders_rlgl_compute.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shaders/shaders_rlgl_compute.c
@@ -0,0 +1,185 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - rlgl compute
+*
+*   WARNING: This example requires raylib compiled with OpenGL 4.3 version for
+*         compute shaders support, shaders used in this example are #version 430
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 4.0, last time updated with raylib 4.0
+*
+*   Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2021-2025 Teddy Astie (@tsnake41)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "rlgl.h"
+
+#include <stdlib.h>     // Required for: NULL
+
+// IMPORTANT: This must match gol*.glsl GOL_WIDTH constant
+// This must be a multiple of 16 (check golLogic compute dispatch)
+#define GOL_WIDTH 768
+
+// Maximum amount of queued draw commands (squares draw from mouse down events)
+#define MAX_BUFFERED_TRANSFERTS 48
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Game Of Life Update Command
+typedef struct GolUpdateCmd {
+    unsigned int x;         // x coordinate of the gol command
+    unsigned int y;         // y coordinate of the gol command
+    unsigned int w;         // width of the filled zone
+    unsigned int enabled;   // whether to enable or disable zone
+} GolUpdateCmd;
+
+// Game Of Life Update Commands SSBO
+typedef struct GolUpdateSSBO {
+    unsigned int count;
+    GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
+} GolUpdateSSBO;
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = GOL_WIDTH;
+    const int screenHeight = GOL_WIDTH;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - rlgl compute");
+
+    const Vector2 resolution = { (float)screenWidth, (float)screenHeight };
+    unsigned int brushSize = 8;
+
+    // Game of Life logic compute shader
+    char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
+    unsigned int golLogicShader = rlLoadShader(golLogicCode, RL_COMPUTE_SHADER);
+    unsigned int golLogicProgram = rlLoadShaderProgramCompute(golLogicShader);
+    UnloadFileText(golLogicCode);
+
+    // Game of Life logic render shader
+    Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
+    int resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
+
+    // Game of Life transfert shader (CPU<->GPU download and upload)
+    char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
+    unsigned int golTransfertShader = rlLoadShader(golTransfertCode, RL_COMPUTE_SHADER);
+    unsigned int golTransfertProgram = rlLoadShaderProgramCompute(golTransfertShader);
+    UnloadFileText(golTransfertCode);
+
+    // Load shader storage buffer object (SSBO), id returned
+    unsigned int ssboA = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
+    unsigned int ssboB = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
+    unsigned int ssboTransfert = rlLoadShaderBuffer(sizeof(GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
+
+    GolUpdateSSBO transfertBuffer = { 0 };
+
+    // Create a white texture of the size of the window to update
+    // each pixel of the window using the fragment shader: golRenderShader
+    Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
+    Texture whiteTex = LoadTextureFromImage(whiteImage);
+    UnloadImage(whiteImage);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        brushSize += (int)GetMouseWheelMove();
+
+        if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
+            && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
+        {
+            // Buffer a new command
+            transfertBuffer.commands[transfertBuffer.count].x = GetMouseX() - brushSize/2;
+            transfertBuffer.commands[transfertBuffer.count].y = GetMouseY() - brushSize/2;
+            transfertBuffer.commands[transfertBuffer.count].w = brushSize;
+            transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
+            transfertBuffer.count++;
+        }
+        else if (transfertBuffer.count > 0)  // Process transfert buffer
+        {
+            // Send SSBO buffer to GPU
+            rlUpdateShaderBuffer(ssboTransfert, &transfertBuffer, sizeof(GolUpdateSSBO), 0);
+
+            // Process SSBO commands on GPU
+            rlEnableShader(golTransfertProgram);
+            rlBindShaderBuffer(ssboA, 1);
+            rlBindShaderBuffer(ssboTransfert, 3);
+            rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // Each GPU unit will process a command!
+            rlDisableShader();
+
+            transfertBuffer.count = 0;
+        }
+        else
+        {
+            // Process game of life logic
+            rlEnableShader(golLogicProgram);
+            rlBindShaderBuffer(ssboA, 1);
+            rlBindShaderBuffer(ssboB, 2);
+            rlComputeShaderDispatch(GOL_WIDTH/16, GOL_WIDTH/16, 1);
+            rlDisableShader();
+
+            // ssboA <-> ssboB
+            int temp = ssboA;
+            ssboA = ssboB;
+            ssboB = temp;
+        }
+
+        rlBindShaderBuffer(ssboA, 1);
+        SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(BLANK);
+
+            BeginShaderMode(golRenderShader);
+                DrawTexture(whiteTex, 0, 0, WHITE);
+            EndShaderMode();
+
+            DrawRectangleLines(GetMouseX() - brushSize/2, GetMouseY() - brushSize/2, brushSize, brushSize, RED);
+
+            DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, WHITE);
+            DrawFPS(GetScreenWidth() - 100, 10);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    // Unload shader buffers objects
+    rlUnloadShaderBuffer(ssboA);
+    rlUnloadShaderBuffer(ssboB);
+    rlUnloadShaderBuffer(ssboTransfert);
+
+    // Unload compute shader
+    rlUnloadShader(golLogicShader);
+    rlUnloadShader(golTransfertShader);
+    rlUnloadShaderProgram(golTransfertProgram);
+    rlUnloadShaderProgram(golLogicProgram);
+
+    UnloadTexture(whiteTex);            // Unload white texture
+    UnloadShader(golRenderShader);      // Unload rendering fragment shader
+
+    CloseWindow();                      // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shaders/shaders_shadowmap_rendering.c b/raylib/examples/shaders/shaders_shadowmap_rendering.c
--- a/raylib/examples/shaders/shaders_shadowmap_rendering.c
+++ b/raylib/examples/shaders/shaders_shadowmap_rendering.c
@@ -68,7 +68,7 @@
     SetShaderValue(shadowShader, lightDirLoc, &lightDir, SHADER_UNIFORM_VEC3);
     SetShaderValue(shadowShader, lightColLoc, &lightColorNormalized, SHADER_UNIFORM_VEC4);
     int ambientLoc = GetShaderLocation(shadowShader, "ambient");
-    float ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
+    float ambient[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
     SetShaderValue(shadowShader, ambientLoc, ambient, SHADER_UNIFORM_VEC4);
     int lightVPLoc = GetShaderLocation(shadowShader, "lightVP");
     int shadowMapLoc = GetShaderLocation(shadowShader, "shadowMap");
@@ -79,8 +79,9 @@
     cube.materials[0].shader = shadowShader;
     Model robot = LoadModel("resources/models/robot.glb");
     for (int i = 0; i < robot.materialCount; i++) robot.materials[i].shader = shadowShader;
+
     int animCount = 0;
-    ModelAnimation *robotAnimations = LoadModelAnimations("resources/models/robot.glb", &animCount);
+    ModelAnimation* anims = LoadModelAnimations("resources/models/robot.glb", &animCount);
 
     RenderTexture2D shadowMap = LoadShadowmapRenderTexture(SHADOWMAP_RESOLUTION, SHADOWMAP_RESOLUTION);
 
@@ -110,13 +111,15 @@
         //----------------------------------------------------------------------------------
         float deltaTime = GetFrameTime();
 
+        UpdateCamera(&camera, CAMERA_ORBITAL);
+
+        // send the updated camera position to the shader so that it can calculate the correct lighting for the scene
         Vector3 cameraPos = camera.position;
         SetShaderValue(shadowShader, shadowShader.locs[SHADER_LOC_VECTOR_VIEW], &cameraPos, SHADER_UNIFORM_VEC3);
-        UpdateCamera(&camera, CAMERA_ORBITAL);
 
         frameCounter++;
-        frameCounter %= (robotAnimations[0].frameCount);
-        UpdateModelAnimation(robot, robotAnimations[0], frameCounter);
+        frameCounter %= (anims[0].keyframeCount);
+        UpdateModelAnimation(robot, anims[0], (float)frameCounter);
 
         // Move light with arrow keys
         const float cameraSpeed = 0.05f;
@@ -159,6 +162,7 @@
             EndMode3D();
 
         EndTextureMode();
+
         lightViewProj = MatrixMultiply(lightView, lightProj);
 
         // PASS 02: Draw the scene into main framebuffer, using the generated shadowmap
@@ -190,7 +194,7 @@
     UnloadShader(shadowShader);
     UnloadModel(cube);
     UnloadModel(robot);
-    UnloadModelAnimations(robotAnimations, animCount);
+    UnloadModelAnimations(anims, animCount);
     UnloadShadowmapRenderTexture(shadowMap);
 
     CloseWindow();        // Close window and OpenGL context
diff --git a/raylib/examples/shaders/shaders_shapes_textures.c b/raylib/examples/shaders/shaders_shapes_textures.c
--- a/raylib/examples/shaders/shaders_shapes_textures.c
+++ b/raylib/examples/shaders/shaders_shapes_textures.c
@@ -69,7 +69,7 @@
             DrawText("USING DEFAULT SHADER", 20, 40, 10, RED);
 
             DrawCircle(80, 120, 35, DARKBLUE);
-            DrawCircleGradient(80, 220, 60, GREEN, SKYBLUE);
+            DrawCircleGradient((Vector2){ 80.0f, 220.0f }, 60, GREEN, SKYBLUE);
             DrawCircleLines(80, 340, 80, DARKBLUE);
 
 
diff --git a/raylib/examples/shaders/shaders_texture_tiling.c b/raylib/examples/shaders/shaders_texture_tiling.c
--- a/raylib/examples/shaders/shaders_texture_tiling.c
+++ b/raylib/examples/shaders/shaders_texture_tiling.c
@@ -56,6 +56,7 @@
     // Set the texture tiling using a shader
     float tiling[2] = { 3.0f, 3.0f };
     Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/tiling.fs", GLSL_VERSION));
+    SetTextureWrap(texture, TEXTURE_WRAP_REPEAT);
     SetShaderValue(shader, GetShaderLocation(shader, "tiling"), tiling, SHADER_UNIFORM_VEC2);
     model.materials[0].shader = shader;
 
diff --git a/raylib/examples/shaders/shaders_vertex_displacement.c b/raylib/examples/shaders/shaders_vertex_displacement.c
--- a/raylib/examples/shaders/shaders_vertex_displacement.c
+++ b/raylib/examples/shaders/shaders_vertex_displacement.c
@@ -41,7 +41,7 @@
     InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement");
 
     // set up camera
-    Camera camera = {0};
+    Camera camera = { 0 };
     camera.position = (Vector3) {20.0f, 5.0f, -20.0f};
     camera.target = (Vector3) {0.0f, 0.0f, 0.0f};
     camera.up = (Vector3) {0.0f, 1.0f, 0.0f};
diff --git a/raylib/examples/shapes/raygui.h b/raylib/examples/shapes/raygui.h
--- a/raylib/examples/shapes/raygui.h
+++ b/raylib/examples/shapes/raygui.h
@@ -1,5949 +1,6422 @@
 /*******************************************************************************************
 *
-*   raygui v4.5-dev - 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        --> 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 set we have the EXTENDED properties (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_DEBUG_RECS_BOUNDS
-*           Draw control bounds rectangles for debug
-*
-*       #define RAYGUI_DEBUG_TEXT_BOUNDS
-*           Draw text bounds rectangles for debug
-*
-*   VERSIONS HISTORY:
-*       5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
-*                         ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
-*                         ADDED: GuiValueBoxFloat()
-*                         ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
-*                         ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
-*                         ADDED: GuiLoadIconsFromMemory()
-*                         ADDED: Multiple new icons
-*                         REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
-*                         REMOVED: GuiSliderPro(), functionality was redundant
-*                         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
-*                         REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
-*
-*       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 5.6-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-2025 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 4
-#define RAYGUI_VERSION_MINOR 5
-#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION  "5.0-dev"
-
-#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)     // We are building the library as a Win32 shared library (.dll)
-    #elif defined(USE_LIBTYPE_SHARED)
-        #define RAYGUIAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
-    #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
-
-//----------------------------------------------------------------------------------
-// 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;
-
-    // Rectangle type
-    typedef struct Rectangle {
-        float x;
-        float y;
-        float width;
-        float height;
-    } Rectangle;
-
-    // TODO: 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;
-
-    // TODO: 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 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
-typedef enum {
-    // Default -> populates to all controls when set
-    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
-} GuiControl;
-
-// Gui base properties for every control
-// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
-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
-} 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)
-//----------------------------------------------------------------------------------
-// DEFAULT extended properties
-// NOTE: Those properties are common to all controls or global
-// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
-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
-} GuiDefaultProperty;
-
-// Other possible text properties:
-// TEXT_WEIGHT                  // Normal, Italic, Bold -> Requires specific font change
-// TEXT_INDENT                  // Text indentation -> Now using TEXT_PADDING...
-
-// Label
-//typedef enum { } GuiLabelProperty;
-
-// Button/Spinner
-//typedef enum { } GuiButtonProperty;
-
-// Toggle/ToggleGroup
-typedef enum {
-    GROUP_PADDING = 16,         // ToggleGroup separation between toggles
-} 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
-} 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 (default rolls down)
-} GuiDropdownBoxProperty;
-
-// TextBox/TextBoxMulti/ValueBox/Spinner
-typedef enum {
-    TEXT_READONLY = 16,         // TextBox in read-only mode: 0-text editable, 1-text no-editable
-} GuiTextBoxProperty;
-
-// ValueBox/Spinner
-typedef enum {
-    SPINNER_BUTTON_WIDTH = 16,  // Spinner left/right buttons width
-    SPINNER_BUTTON_SPACING,     // Spinner buttons separation
-} GuiValueBoxProperty;
-
-// Control11
-//typedef enum { } GuiControl11Property;
-
-// ListView
-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)
-    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,
-    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
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// 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 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 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 GuiTabBar(Rectangle bounds, const 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
-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, const 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 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()
-//----------------------------------------------------------------------------------------------------------
-
-#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_250                      = 250,
-    ICON_251                      = 251,
-    ICON_252                      = 252,
-    ICON_253                      = 253,
-    ICON_254                      = 254,
-    ICON_255                      = 255
-} GuiIconName;
-#endif
-
-#endif
-
-#if defined(__cplusplus)
-}            // Prevents name mangling of functions
-#endif
-
-#endif // RAYGUI_H
-
-/***********************************************************************************
-*
-*   RAYGUI IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RAYGUI_IMPLEMENTATION)
-
-#include <ctype.h>              // required for: isspace() [GuiTextBox()]
-#include <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
-#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
-#include <math.h>               // Required for: roundf() [GuiColorPicker()]
-
-// 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 <stdlib.h>             // 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         256          // Maximum number of icons
-#define RAYGUI_ICON_MAX_NAME_LENGTH    32          // Maximum length of icon name id
-
-// 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: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 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
-    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
-};
-
-// 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 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 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()
-//-------------------------------------------------------------------------------
-
-// raylib functions already implemented in raygui
-//-------------------------------------------------------------------------------
-static Color GetColor(int hexValue);                // Returns a Color struct from hexadecimal value
-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 const 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
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize);    // Load style from memory (binary only)
-
-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 const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow);   // 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 Color GuiFade(Color color, float alpha);         // Fade color by an alpha factor
-
-//----------------------------------------------------------------------------------
-// Gui Setup Functions Definition
-//----------------------------------------------------------------------------------
-// Enable gui global state
-// NOTE: We check 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: We check 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 we try to setup a font but default style has not been
-        // lazily loaded before, it will be overwritten, so we need to force
-        // default style loading 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 = 0;
-    //GuiState state = guiState;
-
-    int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
-
-    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 - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
-    Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 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
-    //--------------------------------------------------------------------
-    GuiStatusBar(statusBar, title); // Draw window header as status bar
-    GuiPanel(windowPanel, NULL);    // Draw window base
-
-    // Draw window close button
-    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)
-    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;      // Window close button clicked: result = 1
-}
-
-// 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 = 0;
-    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 = 0;
-    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 = 0;
-    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) 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;
-}
-
-// Tab Bar control
-// NOTE: Using GuiToggle() for the TABS
-int GuiTabBar(Rectangle bounds, const 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(GetMousePosition(), 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)
-{
-    #define RAYGUI_MIN_SCROLLBAR_WIDTH     40
-    #define RAYGUI_MIN_SCROLLBAR_HEIGHT    40
-    #define RAYGUI_MIN_MOUSE_WHEEL_SPEED   20
-
-    int result = 0;
-    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 = hasVerticalScrollBar? 0.0f : -1.0f;
-    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 = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
-            if (hasHorizontalScrollBar)
-            {
-                if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-
-            if (hasVerticalScrollBar)
-            {
-                if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-                if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
-            }
-#endif
-            float wheelMove = GetMouseWheelMove();
-
-            // Set scrolling speed with mouse wheel based on ratio between bounds and content
-            Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
-            if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-            if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
-
-            // Horizontal and vertical scrolling with mouse wheel
-            if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
-            else scrollPos.y += wheelMove*mouseWheelSpeed.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) 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Button pressed: result = 1
-}
-
-// Label button control
-int GuiLabelButton(Rectangle bounds, const char *text)
-{
-    GuiState state = guiState;
-    bool pressed = false;
-
-    // NOTE: We 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 = GetMousePosition();
-
-        // Check checkbox state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
-    //--------------------------------------------------------------------
-
-    return pressed;
-}
-
-// Toggle Button control
-int GuiToggle(Rectangle bounds, const char *text, bool *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    bool temp = false;
-    if (active == NULL) active = &temp;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check toggle button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                state = STATE_NORMAL;
-                *active = !(*active);
-            }
-            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)
-{
-    #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
-        #define RAYGUI_TOGGLEGROUP_MAX_ITEMS    32
-    #endif
-
-    int result = 0;
-    float initBoundsX = bounds.x;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, rows);
-
-    int prevRow = rows[0];
-
-    for (int i = 0; i < itemCount; i++)
-    {
-        if (prevRow != rows[i])
-        {
-            bounds.x = initBoundsX;
-            bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
-            prevRow = rows[i];
-        }
-
-        if (i == (*active))
-        {
-            toggle = true;
-            GuiToggle(bounds, items[i], &toggle);
-        }
-        else
-        {
-            toggle = false;
-            GuiToggle(bounds, items[i], &toggle);
-            if (toggle) *active = i;
-        }
-
-        bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
-    }
-
-    return result;
-}
-
-// Toggle Slider control extended
-int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    if (active == NULL) active = &temp;
-
-    //bool toggle = false;    // Required for individual toggles
-
-    // Get substrings items from text (items pointers)
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = GetMousePosition();
-
-        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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-
-            if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-            {
-                *checked = !(*checked);
-                result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (CheckCollisionPointRec(mousePoint, bounds) ||
-            CheckCollisionPointRec(mousePoint, selector))
-        {
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                *active += 1;
-                if (*active >= itemCount) *active = 0;      // Cyclic combobox
-            }
-
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    int temp = 0;
-    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;
-    const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            // Check if mouse has been pressed or released outside limits
-            if (!CheckCollisionPointRec(mousePoint, boundsOpen))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-
-            // Check if already selected item has been pressed again
-            if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) 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 (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
-                    {
-                        itemSelected = i;
-                        result = 1;         // Item selected
-                    }
-                    break;
-                }
-            }
-
-            itemBounds = bounds;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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? "#121#" : "#120#", 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;
-
-    // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
-    return result;   // Mouse click: result = 1
-}
-
-// 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 = 0;
-    GuiState state = guiState;
-
-    bool multiline = false;     // TODO: Consider multiline text input
-    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 = GetMousePosition();
-
-        if (editMode)
-        {
-            // GLOBAL: Auto-cursor movement logic
-            // NOTE: Keystrokes are handled repeatedly when button is held down for some time
-            if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(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,
-            // we add 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 = GetCharPressed();       // Get Unicode codepoint
-            if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
-
-            // Encode codepoint as UTF-8
-            int codepointSize = 0;
-            const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
-
-            // Handle text paste action
-            if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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';
-                    }
-                }
-            }
-            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';
-            }
-
-            // Move cursor to start
-            if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
-
-            // Move cursor to end
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
-
-            // Delete related codepoints from text, after current cursor position
-            if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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;
-            }
-
-            else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(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;
-            }
-
-            // Delete related codepoints from text, before current cursor position
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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;
-            }
-
-            else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(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;
-            }
-
-            // Move cursor position with keys
-            if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
-            {
-                int offset = textBoxCursorIndex;
-                //int accCodepointSize = 0;
-                int prevCodepointSize;
-                int prevCodepoint;
-
-                // 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) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
-            {
-                int prevCodepointSize = 0;
-                GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
-
-                textBoxCursorIndex -= prevCodepointSize;
-            }
-            else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(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) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
-            {
-                int nextCodepointSize = 0;
-                GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
-                textBoxCursorIndex += nextCodepointSize;
-            }
-
-            // Move cursor position with mouse
-            if (CheckCollisionPointRec(mousePosition, textBounds))     // Mouse hover text
-            {
-                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 (GetMousePosition().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) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    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 && IsKeyPressed(KEY_ENTER)) ||
-                (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                textBoxCursorIndex = 0;     // GLOBAL: Reset the shared cursor index
-                autoCursorCounter = 0;      // GLOBAL: Reset counter for repeated keystrokes
-                result = 1;
-            }
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePosition, bounds))
-            {
-                state = STATE_FOCUSED;
-
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                {
-                    textBoxCursorIndex = textLength;   // GLOBAL: Place cursor index to the end of current text
-                    autoCursorCounter = 0;             // GLOBAL: Reset counter for repeated keystrokes
-                    result = 1;
-                }
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;      // Mouse button pressed: result = 1
-}
-
-/*
-// 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 = GetMousePosition();
-
-        // Check spinner state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) 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))));
-    //--------------------------------------------------------------------
-
-    *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;
-    GuiState state = guiState;
-
-    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 = GetMousePosition();
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                
-                // Only allow keys in range [48..57]
-                if ((key >= 48) && (key <= 57))
-                {
-                    textValue[keyCount] = (char)key;
-                    keyCount++;
-                    valueHasChanged = true;
-                }
-            }
-
-            // Delete text
-            if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
-            {
-                keyCount--;
-                textValue[keyCount] = '\0';
-                valueHasChanged = true;
-            }
-
-            if (valueHasChanged) *value = TextToInteger(textValue);
-
-            // NOTE: We are not clamp values until user input finishes
-            //if (*value > maxValue) *value = maxValue;
-            //else if (*value < minValue) *value = minValue;
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
-            {
-                if (*value > maxValue) *value = maxValue;
-                else if (*value < minValue) *value = minValue;
-
-                result = 1;
-            }
-        }
-        else
-        {
-            if (*value > maxValue) *value = maxValue;
-            else if (*value < minValue) *value = minValue;
-
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-// 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;
-    GuiState state = guiState;
-
-    //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
-    //snprintf(textValue, sizeof(textValue), "%2.2f", *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 = GetMousePosition();
-
-        bool valueHasChanged = false;
-
-        if (editMode)
-        {
-            state = STATE_PRESSED;
-
-            int keyCount = (int)strlen(textValue);
-
-            // Add or remove minus symbol
-            if (IsKeyPressed(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 = GetCharPressed();
-                    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 (IsKeyPressed(KEY_BACKSPACE))
-            {
-                if (keyCount > 0)
-                {
-                    keyCount--;
-                    textValue[keyCount] = '\0';
-                    valueHasChanged = true;
-                }
-            }
-
-            if (valueHasChanged) *value = TextToFloat(textValue);
-
-            if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
-        }
-        else
-        {
-            if (CheckCollisionPointRec(mousePoint, bounds))
-            {
-                state = STATE_FOCUSED;
-                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
-            }
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-    float oldValue = *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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-    }
-
-    // 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
-    {
-        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);
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    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 = 0;
-    GuiState state = guiState;
-
-    float temp = (maxValue - minValue)/2.0f;
-    if (value == NULL) value = &temp;
-
-    // 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));
-    //--------------------------------------------------------------------
-
-    // 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)
-        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 = 0;
-    GuiState state = guiState;
-
-    // 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 = 0;
-    GuiState state = guiState;
-
-    // Update control
-    //--------------------------------------------------------------------
-    if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
-    {
-        Vector2 mousePoint = GetMousePosition();
-
-        // Check button state
-        if (CheckCollisionPointRec(mousePoint, bounds))
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
-            else state = STATE_FOCUSED;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    int itemCount = 0;
-    const char **items = NULL;
-
-    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
-
-    result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
-
-    return result;
-}
-
-// List View control with extended parameters
-int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
-{
-    int result = 0;
-    GuiState state = guiState;
-
-    int itemFocused = (focus == NULL)? -1 : *focus;
-    int itemSelected = (active == NULL)? -1 : *active;
-
-    // Check if we need a scroll bar
-    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 = GetMousePosition();
-
-        // 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 (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-                    {
-                        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)
-            {
-                int wheelMove = (int)GetMouseWheelMove();
-                startIndex -= wheelMove;
-
-                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(DEFAULT, 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
-            }
-            else if (((startIndex + i) == itemFocused)) // && (focus != NULL))  // NOTE: We want 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
-            }
-            else
-            {
-                // Draw item normal (no rectangle)
-                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, 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;
-
-    return result;
-}
-
-// Color Panel control - Color (RGBA) variant
-int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
-{
-    int result = 0;
-
-    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
-
-    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)
-    {
-        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 };
-    }
-    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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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 = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_UP))
-            {
-                hue -= 2.0f;
-                if (hue <= 0.0f) hue = 0.0f;
-            }
-            else if (IsKeyDown(KEY_DOWN))
-            {
-                hue += 2.0f;
-                if (hue >= 360.0f) hue = 360.0f;
-            }*/
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // Draw control
-    //--------------------------------------------------------------------
-    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));
-    }
-    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);
-
-    // 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 = 0;
-
-    Color temp = { 200, 0, 0, 255 };
-    if (color == NULL) color = &temp;
-
-    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 });
-
-    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 = 0;
-
-    Vector3 tempHsv = { 0 };
-
-    if (colorHsv == NULL)
-    {
-        const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
-        tempHsv = ConvertRGBtoHSV(tempColor);
-        colorHsv = &tempHsv;
-    }
-
-    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 };
-
-    GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
-
-    return result;
-}
-
-// Color Panel control - HSV variant
-int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
-{
-    int result = 0;
-    GuiState state = guiState;
-    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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
-            {
-                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;
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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
-int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
-{
-    #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 = -1;    // Returns clicked button from buttons list, 0 refers to closed window button
-
-    int buttonCount = 0;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    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, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
-    //--------------------------------------------------------------------
-
-    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)
-{
-    #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
-
-    // 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;
-    const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
-    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 = 0;
-
-    // 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);
-    }
-
-    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, textMaxSize, textEditMode)) 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);
-    }
-    else
-    {
-        if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
-    }
-
-    int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
-
-    for (int i = 0; i < buttonCount; i++)
-    {
-        if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
-        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
-    }
-
-    if (result >= 0) textEditMode = false;
-
-    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
-    //--------------------------------------------------------------------
-
-    return result;      // Result is the pressed button index
-}
-
-// Grid control
-// NOTE: Returns grid mouse-hover selected cell
-// About drawing lines at subpixel spacing, simple put, not easy solution:
-// 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 = 0;
-    GuiState state = guiState;
-
-    Vector2 mousePoint = GetMousePosition();
-    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);
-        }
-    }
-    //--------------------------------------------------------------------
-
-    // 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;
-
-            while (!feof(rgsFile))
-            {
-                switch (buffer[0])
-                {
-                    case 'p':
-                    {
-                        // Style property: p <control_id> <property_id> <property_value> <property_name>
-
-                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
-                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
-
-                    } break;
-                    case 'f':
-                    {
-                        // Style font: f <gen_font_size> <charmap_file> <font_file>
-
-                        int fontSize = 0;
-                        char charmapFileName[256] = { 0 };
-                        char fontFileName[256] = { 0 };
-                        sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, 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));
-                fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
-
-                GuiLoadStyleFromMemory(fileData, fileDataSize);
-
-                RAYGUI_FREE(fileData);
-            }
-
-            fclose(rgsFile);
-        }
-    }
-}
-
-// Load style default over global style
-void GuiLoadStyleDefault(void)
-{
-    // We set this variable 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, 15);        // DEFAULT, 15 pixels between lines
-    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);
-
-    // 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: We set 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 });
-    }
-}
-
-// 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)
-// 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;
-
-        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);
-
-        if ((signature[0] == 'r') &&
-            (signature[1] == 'G') &&
-            (signature[2] == 'I') &&
-            (signature[3] == ' '))
-        {
-            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);
-
-            // Read icons data directly over internal icons array
-            fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
-        }
-
-        fclose(rgiFile);
-    }
-
-    return guiIconsName;
-}
-
-// Load icons from memory
-// WARNING: Binary files only
-char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
-{
-    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)
-        {
-            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));
-                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)
-{
-    #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))
-            {
-            #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
-            }
-
-            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)
-int GuiGetTextWidth(const char *text)
-{
-    #if !defined(ICON_TEXT_PADDING)
-        #define ICON_TEXT_PADDING   4
-    #endif
-
-    Vector2 textSize = { 0 };
-    int textIconOffset = 0;
-
-    if ((text != NULL) && (text[0] != '\0'))
-    {
-        if (text[0] == '#')
-        {
-            for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
-            {
-                if (text[i] == '#')
-                {
-                    textIconOffset = i;
-                    break;
-                }
-            }
-        }
-
-        text += textIconOffset;
-
-        // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
-        float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
-        // Custom MeasureText() implementation
-        if ((guiFont.texture.id > 0) && (text != NULL))
-        {
-            // Get size in bytes of text, 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 + 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)
-{
-    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 CONTROL11:
-            // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
-        default:
-        {
-            // TODO: 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: We support up to 999 values for iconId
-static const char *GetTextIcon(const char *text, int *iconId)
-{
-#if !defined(RAYGUI_NO_ICONS)
-    *iconId = -1;
-    if (text[0] == '#')     // Maybe we have an icon!
-    {
-        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] == '#')
-        {
-            *iconId = TextToInteger(iconValue);
-
-            // 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 textSize = (int)strlen(text);
-
-    lines[0] = text;
-    *count = 1;
-
-    for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
-    {
-        if (text[i] == '\n')
-        {
-            k++;
-            lines[k] = &text[i + 1]; // WARNING: next value is valid?
-            *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(ICON_TEXT_PADDING)
-        #define 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: We can't use GuiTextSplit() function because it can be already 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_SIZE)/2);
-    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: We get text size after icon has been processed
-        // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
-        int textSizeX = GuiGetTextWidth(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 += 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 we get pixel-perfect coordinates,
-        // In case of decimals we got weird text positioning
-        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: We consider 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);
-        }
-#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 we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
-            // but we need to draw all of the bad bytes using the '?' symbol moving one byte
-            if (codepoint == 0x3f) codepointSize = 1; // TODO: Review 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_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_LINE_SPACING);
-                }
-            }
-
-            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,
-                // 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_LINE_SPACING);
-        else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
-        //---------------------------------------------------------------------------------
-    }
-
-#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(GuiGetFont(), 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);
-
-        GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, 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, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
-        GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
-        GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
-    }
-}
-
-// Split controls text into multiple strings
-// Also check for multiple columns (required by GuiToggleGroup())
-static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
-{
-    // 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
-
-    // 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
-    #endif
-
-    static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };   // 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;
-
-    // Count how many substrings we have on text and point to every one
-    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'))
-        {
-            result[counter] = buffer + i + 1;
-
-            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;
-        }
-    }
-
-    *count = counter;
-
-    return result;
-}
-
-// 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;
-}
-
-// 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 = GetMousePosition();
-
-        if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
-        {
-            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
-                !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
-            int wheel = (int)GetMouseWheelMove();
-            if (wheel != 0) value += wheel;
-
-            // Handle mouse button down
-            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
-            {
-                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 (IsKeyDown(KEY_DOWN)) value += 5;
-                else if (IsKeyDown(KEY_UP)) value -= 5;
-            }
-            else
-            {
-                if (IsKeyDown(KEY_RIGHT)) value += 5;
-                else if (IsKeyDown(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
-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;
-}
-
-// 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];
-
-    va_list args;
-    va_start(args, text);
-    vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
-    va_end(args);
-
-    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
-const 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 we have on text and point to every one
-        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)
-{
-    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 we exit as soon as possible and a '?'(0x3f) codepoint is returned
-// Total number of bytes processed are returned as a parameter
-// NOTE: the standard says U+FFFD should be returned in case of errors
+*   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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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)
 {
diff --git a/raylib/examples/shapes/shapes_ball_physics.c b/raylib/examples/shapes/shapes_ball_physics.c
--- a/raylib/examples/shapes/shapes_ball_physics.c
+++ b/raylib/examples/shapes/shapes_ball_physics.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -17,17 +17,23 @@
 
 #include "raylib.h"
 
-#include <stdlib.h>
-#include <math.h>
+#include "raymath.h"
 
-#define MAX_BALLS 5000 // Maximum quantity of balls
+#include <stdlib.h>         // Required for: malloc(), free()
+#include <math.h>           // Required for: hypot()
 
+#define MAX_BALLS     5000  // Maximum quantity of balls
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Ball data type
 typedef struct Ball {
-    Vector2 pos;       // Position
-    Vector2 vel;       // Velocity
-    Vector2 ppos;      // Previous position
+    Vector2 position;
+    Vector2 speed;
+    Vector2 prevPosition;
     float radius;
-    float friction;   
+    float friction;
     float elasticity;
     Color color;
     bool grabbed;
@@ -45,24 +51,29 @@
 
     InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ball physics");
 
-    Ball balls[MAX_BALLS] = {{
-        .pos = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f },
-        .vel = { 200, 200 },
-        .ppos = { 0 },
+    Ball *balls = (Ball*)RL_MALLOC(sizeof(Ball)*MAX_BALLS);
+
+    // Init first ball in the array
+    balls[0] = (Ball){
+        .position = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f },
+        .speed = { 200, 200 },
+        .prevPosition = { 0 },
         .radius = 40,
         .friction = 0.99f,
         .elasticity = 0.9f,
         .color = BLUE,
         .grabbed = false
-    }};
-    
+    };
+
     int ballCount = 1;
-    Ball *grabbedBall = NULL;   // A pointer to the current ball that is grabbed
-    Vector2 pressOffset = {0};  // Mouse press offset relative to the ball that grabbedd
+    Ball *grabbedBall = NULL;       // A pointer to the current ball that is grabbed
+    Vector2 pressOffset = { 0 };    // Mouse press offset relative to the ball that grabbedd
 
-    float gravity = 100;        // World gravity
+    float gravity = 100;            // World gravity
+    
+    Vector2 windowPosition = GetWindowPosition();
 
-    SetTargetFPS(60);           // Set our game to run at 60 frames-per-second
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //---------------------------------------------------------------------------------------
 
     // Main game loop
@@ -79,8 +90,8 @@
             for (int i = ballCount - 1; i >= 0; i--)
             {
                 Ball *ball = &balls[i];
-                pressOffset.x = mousePos.x - ball->pos.x;
-                pressOffset.y = mousePos.y - ball->pos.y;
+                pressOffset.x = mousePos.x - ball->position.x;
+                pressOffset.y = mousePos.y - ball->position.y;
 
                 // If the distance between the ball position and the mouse press position
                 // is less than or equal to the ball radius, the event occurred inside the ball
@@ -109,9 +120,9 @@
             if (ballCount < MAX_BALLS)
             {
                 balls[ballCount++] = (Ball){
-                    .pos = mousePos,
-                    .vel = { (float)GetRandomValue(-300, 300), (float)GetRandomValue(-300, 300) },
-                    .ppos = { 0 },
+                    .position = mousePos,
+                    .speed = { (float)GetRandomValue(-300, 300), (float)GetRandomValue(-300, 300) },
+                    .prevPosition = { 0 },
                     .radius = 20.0f + (float)GetRandomValue(0, 30),
                     .friction = 0.99f,
                     .elasticity = 0.9f,
@@ -121,12 +132,23 @@
             }
         }
 
+        // Get window position change for shaking
+        Vector2 windowPositionDelta = Vector2Subtract(windowPosition, GetWindowPosition());
+        
+        if (Vector2Length(windowPositionDelta) > 5.0f)
+        {
+            for (int i = 0; i < ballCount; i++)
+            {
+                if (!balls[i].grabbed) balls[i].speed = Vector2Add(balls[i].speed, Vector2Scale(windowPositionDelta, 10.0f));
+            }
+        }
+
         // Shake balls
         if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
         {
             for (int i = 0; i < ballCount; i++)
             {
-                if (!balls[i].grabbed) balls[i].vel = (Vector2){ (float)GetRandomValue(-2000, 2000), (float)GetRandomValue(-2000, 2000) };
+                if (!balls[i].grabbed) balls[i].speed = (Vector2){ (float)GetRandomValue(-2000, 2000), (float)GetRandomValue(-2000, 2000) };
             }
         }
 
@@ -139,54 +161,56 @@
             Ball *ball = &balls[i];
 
             // The ball is not grabbed
-            if (!ball->grabbed) 
+            if (!ball->grabbed)
             {
                 // Ball repositioning using the velocity
-                ball->pos.x += ball->vel.x * delta;
-                ball->pos.y += ball->vel.y * delta;
+                ball->position.x += ball->speed.x * delta;
+                ball->position.y += ball->speed.y * delta;
 
                 // Does the ball hit the screen right boundary?
-                if ((ball->pos.x + ball->radius) >= screenWidth) 
+                if ((ball->position.x + ball->radius) >= screenWidth)
                 {
-                    ball->pos.x = screenWidth - ball->radius; // Ball repositioning
-                    ball->vel.x = -ball->vel.x*ball->elasticity;  // Elasticity makes the ball lose 10% of its velocity on hit
-                } 
+                    ball->position.x = screenWidth - ball->radius; // Ball repositioning
+                    ball->speed.x = -ball->speed.x*ball->elasticity;  // Elasticity makes the ball lose 10% of its velocity on hit
+                }
                 // Does the ball hit the screen left boundary?
-                else if ((ball->pos.x - ball->radius) <= 0)
-                { 
-                    ball->pos.x = ball->radius;
-                    ball->vel.x = -ball->vel.x*ball->elasticity;
+                else if ((ball->position.x - ball->radius) <= 0)
+                {
+                    ball->position.x = ball->radius;
+                    ball->speed.x = -ball->speed.x*ball->elasticity;
                 }
 
                 // The same for y axis
-                if ((ball->pos.y + ball->radius) >= screenHeight) 
+                if ((ball->position.y + ball->radius) >= screenHeight)
                 {
-                    ball->pos.y = screenHeight - ball->radius;
-                    ball->vel.y = -ball->vel.y*ball->elasticity;
-                } 
-                else if ((ball->pos.y - ball->radius) <= 0) 
-                { 
-                    ball->pos.y = ball->radius;
-                    ball->vel.y = -ball->vel.y*ball->elasticity;
+                    ball->position.y = screenHeight - ball->radius;
+                    ball->speed.y = -ball->speed.y*ball->elasticity;
                 }
+                else if ((ball->position.y - ball->radius) <= 0)
+                {
+                    ball->position.y = ball->radius;
+                    ball->speed.y = -ball->speed.y*ball->elasticity;
+                }
 
                 // Friction makes the ball lose 1% of its velocity each frame
-                ball->vel.x = ball->vel.x*ball->friction;
+                ball->speed.x = ball->speed.x*ball->friction;
                 // Gravity affects only the y axis
-                ball->vel.y = ball->vel.y*ball->friction + gravity;
+                ball->speed.y = ball->speed.y*ball->friction + gravity;
             }
             else
             {
                 // Ball repositioning using the mouse position
-                ball->pos.x = mousePos.x - pressOffset.x;
-                ball->pos.y = mousePos.y - pressOffset.y;
+                ball->position.x = mousePos.x - pressOffset.x;
+                ball->position.y = mousePos.y - pressOffset.y;
 
                 // While the ball is grabbed, recalculates its velocity
-                ball->vel.x = (ball->pos.x - ball->ppos.x)/delta;
-                ball->vel.y = (ball->pos.y - ball->ppos.y)/delta;
-                ball->ppos = ball->pos;
+                ball->speed.x = (ball->position.x - ball->prevPosition.x)/delta;
+                ball->speed.y = (ball->position.y - ball->prevPosition.y)/delta;
+                ball->prevPosition = ball->position;
             }
         }
+
+        windowPosition = GetWindowPosition();
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -197,8 +221,8 @@
 
             for (int i = 0; i < ballCount; i++)
             {
-                DrawCircleV(balls[i].pos, balls[i].radius, balls[i].color);
-                DrawCircleLinesV(balls[i].pos, balls[i].radius, BLACK);
+                DrawCircleV(balls[i].position, balls[i].radius, balls[i].color);
+                DrawCircleLinesV(balls[i].position, balls[i].radius, BLACK);
             }
 
             DrawText("grab a ball by pressing with the mouse and throw it by releasing", 10, 10, 10, DARKGRAY);
@@ -214,6 +238,8 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
+    RL_FREE(balls);
+
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/examples/shapes/shapes_basic_shapes.c b/raylib/examples/shapes/shapes_basic_shapes.c
--- a/raylib/examples/shapes/shapes_basic_shapes.c
+++ b/raylib/examples/shapes/shapes_basic_shapes.c
@@ -50,7 +50,7 @@
 
             // Circle shapes and lines
             DrawCircle(screenWidth/5, 120, 35, DARKBLUE);
-            DrawCircleGradient(screenWidth/5, 220, 60, GREEN, SKYBLUE);
+            DrawCircleGradient((Vector2){ screenWidth/5.0f, 220.0f }, 60, GREEN, SKYBLUE);
             DrawCircleLines(screenWidth/5, 340, 80, DARKBLUE);
             DrawEllipse(screenWidth/5, 120, 25, 20, YELLOW);
             DrawEllipseLines(screenWidth/5, 120, 30, 25, YELLOW);
diff --git a/raylib/examples/shapes/shapes_clock_of_clocks.c b/raylib/examples/shapes/shapes_clock_of_clocks.c
--- a/raylib/examples/shapes/shapes_clock_of_clocks.c
+++ b/raylib/examples/shapes/shapes_clock_of_clocks.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *
 *   Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shapes/shapes_colors_palette.c b/raylib/examples/shapes/shapes_colors_palette.c
--- a/raylib/examples/shapes/shapes_colors_palette.c
+++ b/raylib/examples/shapes/shapes_colors_palette.c
@@ -45,7 +45,7 @@
     for (int i = 0; i < MAX_COLORS_COUNT; i++)
     {
         colorsRecs[i].x = 20.0f + 100.0f *(i%7) + 10.0f *(i%7);
-        colorsRecs[i].y = 80.0f + 100.0f *(i/7) + 10.0f *(i/7);
+        colorsRecs[i].y = 80.0f + 100.0f *((int)i/7) + 10.0f *((float)i/7);
         colorsRecs[i].width = 100.0f;
         colorsRecs[i].height = 100.0f;
     }
diff --git a/raylib/examples/shapes/shapes_digital_clock.c b/raylib/examples/shapes/shapes_digital_clock.c
--- a/raylib/examples/shapes/shapes_digital_clock.c
+++ b/raylib/examples/shapes/shapes_digital_clock.c
@@ -311,7 +311,7 @@
             (Vector2){ center.x + thick/2.0f, center.y - length/2.0f },   // Point 3
             (Vector2){ center.x - thick/2.0f,  center.y + length/2.0f },  // Point 4
             (Vector2){ center.x + thick/2.0f,  center.y + length/2.0f },  // Point 5
-            (Vector2){ center.x,  center.y + length/2 + thick/2.0f },     // Point 6
+            (Vector2){ center.x,  center.y + (float)length/2 + thick/2.0f },     // Point 6
         };
 
         DrawTriangleStrip(segmentPointsV, 6, color);
diff --git a/raylib/examples/shapes/shapes_double_pendulum.c b/raylib/examples/shapes/shapes_double_pendulum.c
--- a/raylib/examples/shapes/shapes_double_pendulum.c
+++ b/raylib/examples/shapes/shapes_double_pendulum.c
@@ -49,8 +49,8 @@
     float totalM = m1 + m2;
 
     Vector2 previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
-    previousPosition.x += (screenWidth/2);
-    previousPosition.y += (screenHeight/2 - 100);
+    previousPosition.x += ((float)screenWidth/2);
+    previousPosition.y += ((float)screenHeight/2 - 100);
 
     // Scale length
     float L1 = l1*lengthScaler;
@@ -105,8 +105,8 @@
 
         // Calculate position
         Vector2 currentPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
-        currentPosition.x += screenWidth/2;
-        currentPosition.y += screenHeight/2 - 100;
+        currentPosition.x += (float)screenWidth/2;
+        currentPosition.y += (float)screenHeight/2 - 100;
 
         // Draw to render texture
         BeginTextureMode(target);
diff --git a/raylib/examples/shapes/shapes_easings_testbed.c b/raylib/examples/shapes/shapes_easings_testbed.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shapes/shapes_easings_testbed.c
@@ -0,0 +1,247 @@
+/*******************************************************************************************
+*
+*   raylib [shapes] example - easings testbed
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 2.5, last time updated with raylib 2.5
+*
+*   Example contributed by Juan Miguel López (@flashback-fx) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2019-2025 Juan Miguel López (@flashback-fx) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "reasings.h"       // Required for: easing functions
+
+#define FONT_SIZE         20
+
+#define D_STEP         20.0f
+#define D_STEP_FINE     2.0f
+#define D_MIN           1.0f
+#define D_MAX       10000.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Easing types
+enum EasingTypes {
+    EASE_LINEAR_NONE = 0,
+    EASE_LINEAR_IN,
+    EASE_LINEAR_OUT,
+    EASE_LINEAR_IN_OUT,
+    EASE_SINE_IN,
+    EASE_SINE_OUT,
+    EASE_SINE_IN_OUT,
+    EASE_CIRC_IN,
+    EASE_CIRC_OUT,
+    EASE_CIRC_IN_OUT,
+    EASE_CUBIC_IN,
+    EASE_CUBIC_OUT,
+    EASE_CUBIC_IN_OUT,
+    EASE_QUAD_IN,
+    EASE_QUAD_OUT,
+    EASE_QUAD_IN_OUT,
+    EASE_EXPO_IN,
+    EASE_EXPO_OUT,
+    EASE_EXPO_IN_OUT,
+    EASE_BACK_IN,
+    EASE_BACK_OUT,
+    EASE_BACK_IN_OUT,
+    EASE_BOUNCE_OUT,
+    EASE_BOUNCE_IN,
+    EASE_BOUNCE_IN_OUT,
+    EASE_ELASTIC_IN,
+    EASE_ELASTIC_OUT,
+    EASE_ELASTIC_IN_OUT,
+    NUM_EASING_TYPES,
+    EASING_NONE = NUM_EASING_TYPES
+};
+
+typedef struct EasingFuncs {
+    const char *name;
+    float (*func)(float, float, float, float);
+} EasingFuncs;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+// Function used when "no easing" is selected for any axis
+static float NoEase(float t, float b, float c, float d);
+
+//------------------------------------------------------------------------------------
+// Global Variables Definition
+//------------------------------------------------------------------------------------
+// Easing functions reference data
+static const EasingFuncs easings[] = {
+    [EASE_LINEAR_NONE] = { .name = "EaseLinearNone", .func = EaseLinearNone },
+    [EASE_LINEAR_IN] = { .name = "EaseLinearIn", .func = EaseLinearIn },
+    [EASE_LINEAR_OUT] = { .name = "EaseLinearOut", .func = EaseLinearOut },
+    [EASE_LINEAR_IN_OUT] = { .name = "EaseLinearInOut", .func = EaseLinearInOut },
+    [EASE_SINE_IN] = { .name = "EaseSineIn", .func = EaseSineIn },
+    [EASE_SINE_OUT] = { .name = "EaseSineOut", .func = EaseSineOut },
+    [EASE_SINE_IN_OUT] = { .name = "EaseSineInOut", .func = EaseSineInOut },
+    [EASE_CIRC_IN] = { .name = "EaseCircIn", .func = EaseCircIn },
+    [EASE_CIRC_OUT] = { .name = "EaseCircOut", .func = EaseCircOut },
+    [EASE_CIRC_IN_OUT] = { .name = "EaseCircInOut", .func = EaseCircInOut },
+    [EASE_CUBIC_IN] = { .name = "EaseCubicIn", .func = EaseCubicIn },
+    [EASE_CUBIC_OUT] = { .name = "EaseCubicOut", .func = EaseCubicOut },
+    [EASE_CUBIC_IN_OUT] = { .name = "EaseCubicInOut", .func = EaseCubicInOut },
+    [EASE_QUAD_IN] = { .name = "EaseQuadIn", .func = EaseQuadIn },
+    [EASE_QUAD_OUT] = { .name = "EaseQuadOut", .func = EaseQuadOut },
+    [EASE_QUAD_IN_OUT] = { .name = "EaseQuadInOut", .func = EaseQuadInOut },
+    [EASE_EXPO_IN] = { .name = "EaseExpoIn", .func = EaseExpoIn },
+    [EASE_EXPO_OUT] = { .name = "EaseExpoOut", .func = EaseExpoOut },
+    [EASE_EXPO_IN_OUT] = { .name = "EaseExpoInOut", .func = EaseExpoInOut },
+    [EASE_BACK_IN] = { .name = "EaseBackIn", .func = EaseBackIn },
+    [EASE_BACK_OUT] = { .name = "EaseBackOut", .func = EaseBackOut },
+    [EASE_BACK_IN_OUT] = { .name = "EaseBackInOut", .func = EaseBackInOut },
+    [EASE_BOUNCE_OUT] = { .name = "EaseBounceOut", .func = EaseBounceOut },
+    [EASE_BOUNCE_IN] = { .name = "EaseBounceIn", .func = EaseBounceIn },
+    [EASE_BOUNCE_IN_OUT] = { .name = "EaseBounceInOut", .func = EaseBounceInOut },
+    [EASE_ELASTIC_IN] = { .name = "EaseElasticIn", .func = EaseElasticIn },
+    [EASE_ELASTIC_OUT] = { .name = "EaseElasticOut", .func = EaseElasticOut },
+    [EASE_ELASTIC_IN_OUT] = { .name = "EaseElasticInOut", .func = EaseElasticInOut },
+    [EASING_NONE] = { .name = "None", .func = NoEase },
+};
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings testbed");
+
+    Vector2 ballPosition = { 100.0f, 100.0f };
+
+    float t = 0.0f;             // Current time (in any unit measure, but same unit as duration)
+    float d = 300.0f;           // Total time it should take to complete (duration)
+    bool paused = true;
+    bool boundedT = true;       // If true, t will stop when d >= td, otherwise t will keep adding td to its value every loop
+
+    int easingX = EASING_NONE;  // Easing selected for x axis
+    int easingY = EASING_NONE;  // Easing selected for y axis
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_T)) boundedT = !boundedT;
+
+        // Choose easing for the X axis
+        if (IsKeyPressed(KEY_RIGHT))
+        {
+            easingX++;
+
+            if (easingX > EASING_NONE) easingX = 0;
+        }
+        else if (IsKeyPressed(KEY_LEFT))
+        {
+            if (easingX == 0) easingX = EASING_NONE;
+            else easingX--;
+        }
+
+        // Choose easing for the Y axis
+        if (IsKeyPressed(KEY_DOWN))
+        {
+            easingY++;
+
+            if (easingY > EASING_NONE) easingY = 0;
+        }
+        else if (IsKeyPressed(KEY_UP))
+        {
+            if (easingY == 0) easingY = EASING_NONE;
+            else easingY--;
+        }
+
+        // Change d (duration) value
+        if (IsKeyPressed(KEY_W) && (d < D_MAX - D_STEP)) d += D_STEP;
+        else if (IsKeyPressed(KEY_Q) && (d > D_MIN + D_STEP)) d -= D_STEP;
+
+        if (IsKeyDown(KEY_S) && (d < D_MAX - D_STEP_FINE)) d += D_STEP_FINE;
+        else if (IsKeyDown(KEY_A) && (d > D_MIN + D_STEP_FINE)) d -= D_STEP_FINE;
+
+        // Play, pause and restart controls
+        if (IsKeyPressed(KEY_SPACE) || IsKeyPressed(KEY_T) ||
+            IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_LEFT) ||
+            IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_UP) ||
+            IsKeyPressed(KEY_W) || IsKeyPressed(KEY_Q) ||
+            IsKeyDown(KEY_S)  || IsKeyDown(KEY_A) ||
+            (IsKeyPressed(KEY_ENTER) && (boundedT == true) && (t >= d)))
+        {
+            t = 0.0f;
+            ballPosition.x = 100.0f;
+            ballPosition.y = 100.0f;
+            paused = true;
+        }
+
+        if (IsKeyPressed(KEY_ENTER)) paused = !paused;
+
+        // Movement computation
+        if (!paused && ((boundedT && t < d) || !boundedT))
+        {
+            ballPosition.x = easings[easingX].func(t, 100.0f, 700.0f - 170.0f, d);
+            ballPosition.y = easings[easingY].func(t, 100.0f, 400.0f - 170.0f, d);
+            t += 1.0f;
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            // Draw information text
+            DrawText(TextFormat("Easing x: %s", easings[easingX].name), 20, FONT_SIZE, FONT_SIZE, LIGHTGRAY);
+            DrawText(TextFormat("Easing y: %s", easings[easingY].name), 20, FONT_SIZE*2, FONT_SIZE, LIGHTGRAY);
+            DrawText(TextFormat("t (%c) = %.2f d = %.2f", (boundedT == true)? 'b' : 'u', t, d), 20, FONT_SIZE*3, FONT_SIZE, LIGHTGRAY);
+
+            // Draw instructions text
+            DrawText("Use ENTER to play or pause movement, use SPACE to restart", 20, GetScreenHeight() - FONT_SIZE*2, FONT_SIZE, LIGHTGRAY);
+            DrawText("Use Q and W or A and S keys to change duration", 20, GetScreenHeight() - FONT_SIZE*3, FONT_SIZE, LIGHTGRAY);
+            DrawText("Use LEFT or RIGHT keys to choose easing for the x axis", 20, GetScreenHeight() - FONT_SIZE*4, FONT_SIZE, LIGHTGRAY);
+            DrawText("Use UP or DOWN keys to choose easing for the y axis", 20, GetScreenHeight() - FONT_SIZE*5, FONT_SIZE, LIGHTGRAY);
+
+            // Draw ball
+            DrawCircleV(ballPosition, 16.0f, MAROON);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+// NoEase function, used when "no easing" is selected for any axis
+// It just ignores all parameters besides b
+static float NoEase(float t, float b, float c, float d)
+{
+    // Hack to avoid compiler warning (about unused variables)
+    float burn = t + b + c + d;
+    d += burn;
+
+    return b;
+}
diff --git a/raylib/examples/shapes/shapes_ellipse_collision.c b/raylib/examples/shapes/shapes_ellipse_collision.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shapes/shapes_ellipse_collision.c
@@ -0,0 +1,133 @@
+/*******************************************************************************************
+*
+*   raylib [shapes] example - ellipse collision
+*
+*   Example complexity rating: [★★☆☆] 2/4
+*
+*   Example originally created with raylib 5.5, last time updated with raylib 5.5
+*
+*   Example contributed by Ziya (@Monjaris)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2025 Ziya (@Monjaris)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include <math.h>
+
+// Check if point is inside ellipse
+static bool CheckCollisionPointEllipse(Vector2 point, Vector2 center, float rx, float ry)
+{
+    float dx = (point.x - center.x)/rx;
+    float dy = (point.y - center.y)/ry;
+    return (dx*dx + dy*dy) <= 1.0f;
+}
+
+// Check if two ellipses collide
+// Uses radial boundary distance in the direction between centers — scales correctly with radii
+static bool CheckCollisionEllipses(Vector2 c1, float rx1, float ry1, Vector2 c2, float rx2, float ry2)
+{
+    float dx = c2.x - c1.x;
+    float dy = c2.y - c1.y;
+    float dist = sqrtf(dx*dx + dy*dy);
+
+    // Ellipses are on top of each other
+    if (dist == 0.0f) return true;
+
+    float theta = atan2f(dy, dx);
+    float cosT = cosf(theta);
+    float sinT = sinf(theta);
+
+    // Radial distance from center to ellipse boundary in direction theta
+    // r(theta) = (rx * ry) / sqrt((ry*cos)^2 + (rx*sin)^2)
+    float r1 = (rx1*ry1)/sqrtf((ry1*cosT)*(ry1*cosT) + (rx1*sinT)*(rx1*sinT));
+    float r2 = (rx2*ry2)/sqrtf((ry2*cosT)*(ry2*cosT) + (rx2*sinT)*(rx2*sinT));
+
+    return dist <= (r1 + r2);
+}
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision ellipses");
+    SetTargetFPS(60);
+
+    Vector2 ellipseACenter = { (float)screenWidth/4, (float)screenHeight/2 };
+    float ellipseARx = 120.0f;
+    float ellipseARy = 70.0f;
+
+    Vector2 ellipseBCenter = { (float)screenWidth*3/4, (float)screenHeight/2 };
+    float ellipseBRx = 90.0f;
+    float ellipseBRy = 140.0f;
+
+    // 0 = controlling A, 1 = controlling B
+    int controlled = 0;
+
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_A)) controlled = 0;
+        if (IsKeyPressed(KEY_B)) controlled = 1;
+
+        if (controlled == 0) ellipseACenter = GetMousePosition();
+        else ellipseBCenter = GetMousePosition();
+
+        bool ellipsesCollide = CheckCollisionEllipses(
+            ellipseACenter, ellipseARx, ellipseARy,
+            ellipseBCenter, ellipseBRx, ellipseBRy
+        );
+
+        bool mouseInA = CheckCollisionPointEllipse(GetMousePosition(), ellipseACenter, ellipseARx, ellipseARy);
+        bool mouseInB = CheckCollisionPointEllipse(GetMousePosition(), ellipseBCenter, ellipseBRx, ellipseBRy);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            DrawEllipse((int)ellipseACenter.x, (int)ellipseACenter.y, ellipseARx, ellipseARy, ellipsesCollide ? RED : BLUE);
+
+            DrawEllipse((int)ellipseBCenter.x, (int)ellipseBCenter.y, ellipseBRx, ellipseBRy, ellipsesCollide ? RED : GREEN);
+
+            DrawEllipseLines((int)ellipseACenter.x, (int)ellipseACenter.y, ellipseARx, ellipseARy, WHITE);
+
+            DrawEllipseLines((int)ellipseBCenter.x, (int)ellipseBCenter.y, ellipseBRx, ellipseBRy, WHITE);
+
+            DrawCircleV(ellipseACenter, 4, WHITE);
+            DrawCircleV(ellipseBCenter, 4, WHITE);
+
+            if (ellipsesCollide) DrawText("ELLIPSES COLLIDE", screenWidth/2 - 120, 40, 28, RED);
+            else DrawText("NO COLLISION", screenWidth/2 - 80, 40, 28, DARKGRAY);
+
+            DrawText(controlled == 0 ? "Controlling: A" : "Controlling: B", 20, screenHeight - 40, 20, YELLOW);
+
+            if (mouseInA && controlled != 0) DrawText("Mouse inside ellipse A", 20, screenHeight - 70, 20, BLUE);
+            if (mouseInB && controlled != 1) DrawText("Mouse inside ellipse B", 20, screenHeight - 70, 20, GREEN);
+
+            DrawText("Press [A] or [B] to switch control", 20, 20, 20, GRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    CloseWindow();
+
+    return 0;
+}
diff --git a/raylib/examples/shapes/shapes_hilbert_curve.c b/raylib/examples/shapes/shapes_hilbert_curve.c
--- a/raylib/examples/shapes/shapes_hilbert_curve.c
+++ b/raylib/examples/shapes/shapes_hilbert_curve.c
@@ -43,16 +43,16 @@
     InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve");
 
     int order = 2;
-    float size = GetScreenHeight();
+    float size = (float)GetScreenHeight();
     int strokeCount = 0;
     Vector2 *hilbertPath = LoadHilbertPath(order, size, &strokeCount);
-    
+
     int prevOrder = order;
     int prevSize = (int)size;       // NOTE: Size from slider is float but for comparison we use int
     int counter = 0;
     float thick = 2.0f;
     bool animate = true;
-    
+
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
@@ -68,19 +68,19 @@
         {
             UnloadHilbertPath(hilbertPath);
             hilbertPath = LoadHilbertPath(order, size, &strokeCount);
-            
+
             if (animate) counter = 0;
             else counter = strokeCount;
-            
+
             prevOrder = order;
-            prevSize = size;
+            prevSize = (int)size;
         }
         //----------------------------------------------------------------------------------
-        
+
         // Draw
         //--------------------------------------------------------------------------
         BeginDrawing();
-        
+
             ClearBackground(RAYWHITE);
 
             if (counter < strokeCount)
@@ -90,7 +90,7 @@
                 {
                     DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
                 }
-                
+
                 counter += 1;
             }
             else
@@ -101,13 +101,13 @@
                     DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
                 }
             }
-        
+
             // Draw UI using raygui
             GuiCheckBox((Rectangle){ 450, 50, 20, 20 }, "ANIMATE GENERATION ON CHANGE", &animate);
             GuiSpinner((Rectangle){ 585, 100, 180, 30 }, "HILBERT CURVE ORDER:  ", &order, 2, 8, false);
             GuiSlider((Rectangle){ 524, 150, 240, 24 }, "THICKNESS:  ", NULL, &thick, 1.0f, 10.0f);
             GuiSlider((Rectangle){ 524, 190, 240, 24 }, "TOTAL SIZE: ", NULL, &size, 10.0f, GetScreenHeight()*1.5f);
-        
+
         EndDrawing();
         //--------------------------------------------------------------------------
     }
@@ -116,7 +116,7 @@
     // De-Initialization
     //--------------------------------------------------------------------------------------
     UnloadHilbertPath(hilbertPath);
-    
+
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
     return 0;
@@ -133,14 +133,14 @@
     *strokeCount = N*N;
 
     Vector2 *hilbertPath = (Vector2 *)RL_CALLOC(*strokeCount, sizeof(Vector2));
-    
+
     for (int i = 0; i < *strokeCount; i++)
     {
         hilbertPath[i] = ComputeHilbertStep(order, i);
         hilbertPath[i].x = hilbertPath[i].x*len + len/2.0f;
         hilbertPath[i].y = hilbertPath[i].y*len + len/2.0f;
     }
-    
+
     return hilbertPath;
 }
 
@@ -160,7 +160,7 @@
         [2] = { .x = 1, .y = 1 },
         [3] = { .x = 1, .y = 0 },
     };
-       
+
     int hilbertIndex = index&3;
     Vector2 vect = hilbertPoints[hilbertIndex];
     float temp = 0.0f;
@@ -171,7 +171,7 @@
         index = index >> 2;
         hilbertIndex = index&3;
         len = 1 << j;
-        
+
         switch (hilbertIndex)
         {
             case 0:
@@ -191,6 +191,6 @@
             default: break;
         }
     }
-    
+
     return vect;
 }
diff --git a/raylib/examples/shapes/shapes_lines_drawing.c b/raylib/examples/shapes/shapes_lines_drawing.c
--- a/raylib/examples/shapes/shapes_lines_drawing.c
+++ b/raylib/examples/shapes/shapes_lines_drawing.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 5.6
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shapes/shapes_math_angle_rotation.c b/raylib/examples/shapes/shapes_math_angle_rotation.c
--- a/raylib/examples/shapes/shapes_math_angle_rotation.c
+++ b/raylib/examples/shapes/shapes_math_angle_rotation.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*   Example originally created with raylib 6.0, last time updated with raylib 5.6
 *
 *   Example contributed by Kris (@krispy-snacc) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shapes/shapes_math_sine_cosine.c b/raylib/examples/shapes/shapes_math_sine_cosine.c
--- a/raylib/examples/shapes/shapes_math_sine_cosine.c
+++ b/raylib/examples/shapes/shapes_math_sine_cosine.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jopestpe (@jopestpe) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -89,7 +89,7 @@
 
             // Cotangent (orange)
             DrawLineEx((Vector2){ center.x , limitMin.y }, (Vector2){ cotangentPoint.x, limitMin.y }, 2.0f, ORANGE);
-            DrawLineDashed(center, cotangentPoint, 10.0f, 4.0f, ORANGE);
+            DrawLineDashed(center, cotangentPoint, 10, 4, ORANGE);
 
             // Side background
             DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
@@ -106,48 +106,48 @@
             DrawLineEx((Vector2){ start.x, start.y + start.height/2 }, (Vector2){ start.x + start.width, start.y + start.height/2 }, 2.0f, GRAY);
 
             // Wave graph axis labels
-            DrawText("1", start.x - 8,  start.y, 6, GRAY);
-            DrawText("0", start.x - 8,  start.y + start.height/2 - 6, 6, GRAY);
-            DrawText("-1", start.x - 12, start.y + start.height - 8, 6, GRAY);
-            DrawText("0", start.x - 2,  start.y + start.height + 4, 6, GRAY);
-            DrawText("360", start.x + start.width - 8,  start.y + start.height + 4, 6, GRAY);
+            DrawText("1", (int)start.x - 8, (int)start.y, 6, GRAY);
+            DrawText("0", (int)start.x - 8, (int)start.y + (int)start.height/2 - 6, 6, GRAY);
+            DrawText("-1", (int)start.x - 12, (int)start.y + (int)start.height - 8, 6, GRAY);
+            DrawText("0", (int)start.x - 2, (int)start.y + (int)start.height + 4, 6, GRAY);
+            DrawText("360", (int)start.x + (int)start.width - 8, (int)start.y + (int)start.height + 4, 6, GRAY);
 
             // Sine (red - vertical)
             DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ center.x, point.y }, 2.0f, RED);
-            DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, RED);
+            DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10, 4, RED);
             DrawText(TextFormat("Sine %.2f", sinRad), 640, 190, 6, RED);
             DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-sinRad + 1)*start.height/2.0f) }, 4.0f, RED);
             DrawSplineLinear(sinePoints, WAVE_POINTS, 1.0f, RED);
 
             // Cosine (blue - horizontal)
             DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ point.x, center.y }, 2.0f, BLUE);
-            DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, BLUE);
+            DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10, 4, BLUE);
             DrawText(TextFormat("Cosine %.2f", cosRad), 640, 210, 6, BLUE);
             DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-cosRad + 1)*start.height/2.0f) }, 4.0f, BLUE);
             DrawSplineLinear(cosPoints, WAVE_POINTS, 1.0f, BLUE);
 
             // Tangent (purple)
             DrawLineEx((Vector2){ limitMax.x , center.y }, (Vector2){ limitMax.x, tangentPoint.y }, 2.0f, PURPLE);
-            DrawLineDashed(center, tangentPoint, 10.0f, 4.0f, PURPLE);
+            DrawLineDashed(center, tangentPoint, 10, 4, PURPLE);
             DrawText(TextFormat("Tangent %.2f", tangent), 640, 230, 6, PURPLE);
 
             // Cotangent (orange)
             DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE);
 
             // Complementary angle (beige)
-            DrawCircleSectorLines(center, radius*0.6f , -angle, -90.0f , 36.0f, BEIGE);
+            DrawCircleSectorLines(center, radius*0.6f , -angle, -90.0f , 36, BEIGE);
             DrawText(TextFormat("Complementary  %0.f°",complementary), 640, 150, 6, BEIGE);
 
             // Supplementary angle (darkblue)
-            DrawCircleSectorLines(center, radius*0.5f , -angle, -180.0f , 36.0f, DARKBLUE);
+            DrawCircleSectorLines(center, radius*0.5f , -angle, -180.0f , 36, DARKBLUE);
             DrawText(TextFormat("Supplementary  %0.f°",supplementary), 640, 130, 6, DARKBLUE);
 
             // Explementary angle (pink)
-            DrawCircleSectorLines(center, radius*0.4f , -angle, -360.0f , 36.0f, PINK);
+            DrawCircleSectorLines(center, radius*0.4f , -angle, -360.0f , 36, PINK);
             DrawText(TextFormat("Explementary  %0.f°",explementary), 640, 170, 6, PINK);
 
             // Current angle - arc (lime), radius (black), endpoint (black)
-            DrawCircleSectorLines(center, radius*0.7f , -angle, 0.0f, 36.0f, LIME);
+            DrawCircleSectorLines(center, radius*0.7f , -angle, 0.0f, 36, LIME);
             DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK);
             DrawCircleV(point, 4.0f, BLACK);
 
diff --git a/raylib/examples/shapes/shapes_outlines_testbed.c b/raylib/examples/shapes/shapes_outlines_testbed.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shapes/shapes_outlines_testbed.c
@@ -0,0 +1,407 @@
+/*******************************************************************************************
+*
+*   raylib [shapes] example - outlines testbed
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 6.1, last time updated with raylib 6.1
+*
+*   Example contributed by Matthew Roush (@MatthewRoush) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Matthew Roush (@MatthewRoush)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"                 // Required for GUI controls
+
+#include <stdbool.h>
+
+#define COLOR_FILLED  DARKBLUE
+#define COLOR_OUTLINE YELLOW
+
+#define SHAPE_SPACING 14.0f
+#define SHAPE_SIZE 46.0f
+#define BOX_SPACING 10.0f
+
+#define MOUSE_CAMERA_ZOOM_SPEED 0.3f
+#define KEYBOARD_CAMERA_MOVE_SPEED 10.0f
+#define KEYBOARD_CAMERA_ZOOM_SPEED 0.1f
+
+#define CAMERA_ZOOM_MIN 0.1f
+#define CAMERA_ZOOM_MAX 1000.0f
+
+// The shapes are ordered according to their order in this enum, left to right
+enum {
+    ORDER_RECTANGLE = 0,
+    ORDER_RECTANGLE_ROUNDED,
+    ORDER_CIRCLE,
+    ORDER_ELLIPSE,
+    ORDER_CIRCLE_SECTOR,
+    ORDER_RING,
+    ORDER_TRIANGLE,
+    ORDER_POLYGON,
+    COUNT_SHAPES
+};
+
+// The line style groups are ordered according to their order in this enum, top to bottom
+enum {
+    ORDER_LINES = 0,
+    ORDER_LINES_EX_WORLD,
+    ORDER_LINES_EX_SCREEN,
+};
+
+#define BOX_WIDTH (SHAPE_SIZE*COUNT_SHAPES + SHAPE_SPACING*(COUNT_SHAPES - 1) + BOX_SPACING*2.0f)
+#define BOX_HEIGHT (SHAPE_SIZE + BOX_SPACING*2.0f)
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - outlines testbed");
+
+    Camera2D camera = { .zoom = 1 };
+
+    // User configurable options while running the program.
+    float lineOpacity          = 130;
+    float lineThickness        = 4.0f;
+    float rectangleRoundness   = 0.4f;
+    float rectangleSegments    = 9;
+    float ellipseRadiusY       = 0.5f;
+    float circleStartAngle     = 20.0f;
+    float circleEndAngle       = 270.0f;
+    float circleSegments       = 36;
+    float ringInnerRadiusScale = 0.3f;
+    float polygonSides         = 6;
+
+    bool disableMouseControl = false;
+
+    const Rectangle optionsBackground = { 510, 0, 290, 450 };
+
+    const Vector2 zoomPoint = {((float)screenWidth - optionsBackground.width)/2.0f, (float)screenHeight/2.0f};
+
+    GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(WHITE));
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        const Vector2 mousePosScreen = GetMousePosition();
+        const Vector2 mouseWheelVec = GetMouseWheelMoveV();
+
+        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mousePosScreen, optionsBackground)) disableMouseControl = true;
+
+        if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) disableMouseControl = false;
+
+        if (!disableMouseControl) {
+            if (mouseWheelVec.y != 0.0f) {
+                const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+
+                camera.zoom *= exp2f(MOUSE_CAMERA_ZOOM_SPEED*mouseWheelVec.y); // Constant zoom rate
+                camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);
+
+                const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+                camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
+            }
+
+            if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
+                const Vector2 mouseDelta = GetMouseDelta();
+                camera.target.x -= mouseDelta.x/camera.zoom;
+                camera.target.y -= mouseDelta.y/camera.zoom;
+
+                const int mouseMaxX = (int)optionsBackground.x;
+                const int mouseMaxY = screenHeight;
+
+                int newX = (int)mousePosScreen.x;
+                int newY = (int)mousePosScreen.y;
+
+                // In C, the '%' operator computes the remainder, we want the modulus
+                newX = (newX%mouseMaxX + mouseMaxX)%mouseMaxX;
+                newY = (newY%mouseMaxY + mouseMaxY)%mouseMaxY;
+
+                if ((newX != (int)mousePosScreen.x) || (newY != (int)mousePosScreen.y)) SetMousePosition(newX, newY);
+            }
+        }
+
+        if (IsKeyDown(KEY_A)) camera.target.x -= KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
+        if (IsKeyDown(KEY_D)) camera.target.x += KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
+        if (IsKeyDown(KEY_W)) camera.target.y -= KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
+        if (IsKeyDown(KEY_S)) camera.target.y += KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
+
+        if (IsKeyDown(KEY_UP))
+        {
+            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+
+            camera.zoom *= exp2f(KEYBOARD_CAMERA_ZOOM_SPEED);
+            camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);
+
+            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
+        }
+        if (IsKeyDown(KEY_DOWN))
+        {
+            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+
+            camera.zoom *= exp2f(-KEYBOARD_CAMERA_ZOOM_SPEED);
+            camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);
+
+            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
+        }
+
+        if (IsKeyPressed(KEY_Z))
+        {
+            const Vector2 zoomPoint = {((float)screenWidth - optionsBackground.width)/2.0f, (float)screenHeight/2.0f};
+            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+
+            camera.zoom = 1.0f;
+
+            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
+            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
+        }
+
+        if (IsKeyPressed(KEY_C)) camera.target = (Vector2){ 0 };
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground((Color){ 50, 50, 55, 255 });
+
+            Color colorOutline = COLOR_OUTLINE;
+            colorOutline.a = (unsigned char)lineOpacity;
+
+            BeginMode2D(camera);
+
+            const float shapeOffset = BOX_SPACING*2.0f;
+            const float shapePaddingX = SHAPE_SIZE + SHAPE_SPACING;
+            const float shapePaddingY = SHAPE_SIZE + SHAPE_SPACING + BOX_SPACING*2.0f;
+
+            const float radiusX = SHAPE_SIZE/2.0f;
+            const float radiusY = radiusX*ellipseRadiusY;
+
+            const float ringOuterRadius = SHAPE_SIZE/2.0f;
+            const float ringInnerRadius = ringOuterRadius*ringInnerRadiusScale;
+
+            const Vector2 triangleVertex0Offset = { 0.0f, SHAPE_SIZE*0.8f };
+            const Vector2 triangleVertex1Offset = { SHAPE_SIZE*0.6f, SHAPE_SIZE };
+            const Vector2 triangleVertex2Offset = { SHAPE_SIZE, 0.0f };
+
+            // ----------------------------------------
+            // Draw*Lines()
+            float posY = shapeOffset + shapePaddingY*ORDER_LINES;
+
+            // Rectangle
+            float posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
+            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
+            DrawRectangleLines(posX, posY, SHAPE_SIZE, SHAPE_SIZE, colorOutline);
+
+            // Rectangle Rounded
+            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
+            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
+            DrawRectangleRoundedLines((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, colorOutline);
+
+            // Circle
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
+            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
+            DrawCircleLinesV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, colorOutline);
+
+            // Ellipse
+            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
+            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
+            DrawEllipseLinesV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, colorOutline);
+
+            // Circle Sector
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
+            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawCircleSectorLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, colorOutline);
+
+            // Ring
+            posX = shapeOffset + shapePaddingX*ORDER_RING;
+            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawRingLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, colorOutline);
+
+            // Triangle
+            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
+            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                         COLOR_FILLED);
+            DrawTriangleLines((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                              (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                              (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                              colorOutline);
+
+            // Polygon
+            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
+            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
+            DrawPolyLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, colorOutline);
+
+            // Group the shapes
+            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*Lines()");
+            // ----------------------------------------
+
+            // ----------------------------------------
+            // Draw*LinesEx() with world space pixel thickness
+            posY = shapeOffset + shapePaddingY*ORDER_LINES_EX_WORLD;
+
+            // Rectangle
+            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
+            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
+            DrawRectangleLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, lineThickness, colorOutline);
+
+            // Rectangle Rounded
+            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
+            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
+            DrawRectangleRoundedLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, lineThickness, colorOutline);
+
+            // Circle
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
+            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
+            DrawCircleLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, lineThickness, colorOutline);
+
+            // Ellipse
+            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
+            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
+            DrawEllipseLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, lineThickness, colorOutline);
+
+            // Circle Sector
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
+            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawCircleSectorLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, lineThickness, colorOutline);
+
+            // Ring
+            posX = shapeOffset + shapePaddingX*ORDER_RING;
+            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawRingLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, lineThickness, colorOutline);
+
+            // Triangle
+            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
+            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                         COLOR_FILLED);
+            DrawTriangleLinesEx((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                                (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                                (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                                lineThickness, colorOutline);
+
+            // Polygon
+            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
+            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
+            DrawPolyLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, lineThickness, colorOutline);
+
+            // Group the shapes
+            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*LinesEx() with *world space* pixel thickness");
+            // ----------------------------------------
+
+            // ----------------------------------------
+            // Draw*LinesEx() with screen space pixel thickness
+            posY = shapeOffset + shapePaddingY*ORDER_LINES_EX_SCREEN;
+
+            float constantThickness = lineThickness/camera.zoom;
+
+            // Rectangle
+            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
+            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
+            DrawRectangleLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, constantThickness, colorOutline);
+
+            // Rectangle Rounded
+            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
+            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
+            DrawRectangleRoundedLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, constantThickness, colorOutline);
+
+            // Circle
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
+            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
+            DrawCircleLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, constantThickness, colorOutline);
+
+            // Ellipse
+            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
+            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
+            DrawEllipseLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, constantThickness, colorOutline);
+
+            // Circle Sector
+            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
+            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawCircleSectorLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, constantThickness, colorOutline);
+
+            // Ring
+            posX = shapeOffset + shapePaddingX*ORDER_RING;
+            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
+            DrawRingLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, constantThickness, colorOutline);
+
+            // Triangle
+            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
+            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                         COLOR_FILLED);
+            DrawTriangleLinesEx((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
+                                (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
+                                (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
+                                constantThickness, colorOutline);
+
+            // Polygon
+            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
+            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
+            DrawPolyLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, constantThickness, colorOutline);
+
+            // Group the shapes
+            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*LinesEx() with *screen space* pixel thickness");
+            // ----------------------------------------
+
+            EndMode2D();
+
+            DrawRectangleRec(optionsBackground, Fade(DARKGRAY, 0.75f));
+
+            DrawRectangleRec((Rectangle){ optionsBackground.x, 360, optionsBackground.width, 90 }, Fade(BLACK, 0.4f));
+            DrawLineEx((Vector2){ optionsBackground.x, 360 }, (Vector2){ optionsBackground.x + optionsBackground.width, 360 }, 1.0f, BLACK);
+
+            DrawText("Move with the mouse or WASD keys", (int)optionsBackground.x + 10, 370, 10, ORANGE);
+            DrawText("Zoom with the mouse or UP and DOWN keys", (int)optionsBackground.x + 10, 390, 10, ORANGE);
+            DrawText("Press C to reset position", (int)optionsBackground.x + 10, 410, 10, ORANGE);
+            DrawText("Press Z to reset zoom", (int)optionsBackground.x + 10, 430, 10, ORANGE);
+
+            DrawLineEx((Vector2){ optionsBackground.x, optionsBackground.y }, (Vector2){ optionsBackground.x, optionsBackground.y + optionsBackground.height }, 1.0f, BLACK);
+
+            GuiSliderBar((Rectangle){ 605,  10, 150, 25 }, "Line Opacity"    , TextFormat("%d"  , (int)lineOpacity)      , &lineOpacity         ,  0     , 255);
+            GuiSliderBar((Rectangle){ 605,  45, 150, 25 }, "Thickness"       , TextFormat("%.2f", lineThickness)         , &lineThickness       , -20.0f , 40.0f);
+            GuiSliderBar((Rectangle){ 605,  80, 150, 25 }, "Rect Roundness"  , TextFormat("%.2f", rectangleRoundness)    , &rectangleRoundness  , -1.0f  , 2.0f);
+            GuiSliderBar((Rectangle){ 605, 115, 150, 25 }, "Rect Segments"   , TextFormat("%d"  , (int)rectangleSegments), &rectangleSegments   , -1     , 100);
+            GuiSliderBar((Rectangle){ 605, 150, 150, 25 }, "Ellipse Radius Y", TextFormat("%.2f", ellipseRadiusY)        , &ellipseRadiusY      , 0.0f   , 1.25f);
+            GuiSliderBar((Rectangle){ 605, 185, 150, 25 }, "Start Angle"     , TextFormat("%.2f", circleStartAngle)      , &circleStartAngle    , -360.0f, 360.0f);
+            GuiSliderBar((Rectangle){ 605, 220, 150, 25 }, "End Angle"       , TextFormat("%.2f", circleEndAngle)        , &circleEndAngle      , -360.0f, 360.0f);
+            GuiSliderBar((Rectangle){ 605, 255, 150, 25 }, "Circle Segments" , TextFormat("%d"  , (int)circleSegments)   , &circleSegments      , -1     , 100);
+            GuiSliderBar((Rectangle){ 605, 290, 150, 25 }, "Ring Radius"     , TextFormat("%.2f", ringInnerRadiusScale)  , &ringInnerRadiusScale, -1.0f  , 2.0f);
+            GuiSliderBar((Rectangle){ 605, 325, 150, 25 }, "Poly Sides"      , TextFormat("%d"  , (int)polygonSides)     , &polygonSides        , -1     , 100);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shapes/shapes_outlines_thickness.c b/raylib/examples/shapes/shapes_outlines_thickness.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shapes/shapes_outlines_thickness.c
@@ -0,0 +1,78 @@
+/*******************************************************************************************
+*
+*   raylib [shapes] example - outlines thickness
+*
+*   Example complexity rating: [★☆☆☆] 1/4
+*
+*   Example originally created with raylib 6.1, last time updated with raylib 6.1
+*
+*   Example contributed by Matthew Roush (@MatthewRoush) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Matthew Roush (@MatthewRoush)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"         // Required for GUI controls
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - outlines thickness");
+
+    float thick = 5.0f;
+
+    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);
+
+            GuiSliderBar((Rectangle){ 290, 50, 220, 24 }, "Thickness", TextFormat("%.2f", thick), &thick, -30.0f, 30.0f);
+
+            DrawRectangle(35, 180, 220, 220, LIGHTGRAY);
+            DrawRectangleLinesEx((Rectangle){ 35, 180, 220, 220 }, thick, BLUE);
+            DrawText("DrawRectangleLinesEx()", 35, 160, 10, BLACK);
+
+            DrawRectangleRounded((Rectangle){ 290, 180, 220, 220 }, 0.2f, 9, LIGHTGRAY);
+            DrawRectangleRoundedLinesEx((Rectangle){ 290, 180, 220, 220 }, 0.2f, 9, thick, BLUE);
+            DrawText("DrawRectangleRoundedLinesEx()", 290, 160, 10, BLACK);
+
+            DrawCircle(655, 290, 110, LIGHTGRAY);
+            DrawCircleLinesEx((Vector2){ 655, 290 }, 110, thick, BLUE);
+            DrawText("DrawCircleLinesEx()", 545, 160, 10, BLACK);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shapes/shapes_penrose_tile.c b/raylib/examples/shapes/shapes_penrose_tile.c
--- a/raylib/examples/shapes/shapes_penrose_tile.c
+++ b/raylib/examples/shapes/shapes_penrose_tile.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★★] 4/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *   Based on: https://processing.org/examples/penrosetile.html
 *
 *   Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
@@ -30,7 +30,7 @@
 //----------------------------------------------------------------------------------
 typedef struct TurtleState {
     Vector2 origin;
-    double angle;
+    float angle;
 } TurtleState;
 
 typedef struct PenroseLSystem {
@@ -106,7 +106,7 @@
                 if (generations > 0) rebuild = true;
             }
         }
-        
+
         if (rebuild)
         {
             RL_FREE(ls.production); // Free previous production for re-creation
@@ -118,15 +118,15 @@
         // Draw
         //----------------------------------------------------------------------------------
         BeginDrawing();
-        
+
             ClearBackground( RAYWHITE );
-            
+
             if (generations > 0) DrawPenroseLSystem(&ls);
-            
+
             DrawText("penrose l-system", 10, 10, 20, DARKGRAY);
             DrawText("press up or down to change generations", 10, 30, 20, DARKGRAY);
             DrawText(TextFormat("generations: %d", generations), 10, 50, 20, DARKGRAY);
-            
+
         EndDrawing();
         //----------------------------------------------------------------------------------
     }
@@ -171,11 +171,11 @@
         .drawLength = drawLength,
         .theta = 36.0f // Degrees
     };
-    
+
     ls.production = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
     ls.production[0] = '\0';
     strncpy(ls.production, "[X]++[X]++[X]++[X]++[X]", STR_MAX_SIZE);
-    
+
     return ls;
 }
 
@@ -211,7 +211,7 @@
 
     ls->drawLength *= 0.5f;
     strncpy(ls->production, newProduction, STR_MAX_SIZE);
-    
+
     RL_FREE(newProduction);
 }
 
@@ -228,9 +228,9 @@
     int repeats = 1;
     int productionLength = (int)strnlen(ls->production, STR_MAX_SIZE);
     ls->steps += 12;
-    
+
     if (ls->steps > productionLength) ls->steps = productionLength;
-    
+
     for (int i = 0; i < ls->steps; i++)
     {
         char step = ls->production[i];
@@ -244,24 +244,24 @@
                 turtle.origin.y += ls->drawLength*sinf(radAngle);
                 Vector2 startPosScreen = { startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y };
                 Vector2 endPosScreen = { turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y };
-                
+
                 DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2f));
             }
-            
+
             repeats = 1;
-        } 
+        }
         else if (step == '+')
         {
             for (int j = 0; j < repeats; j++) turtle.angle += ls->theta;
 
             repeats = 1;
-        } 
+        }
         else if (step == '-')
         {
             for (int j = 0; j < repeats; j++) turtle.angle += -ls->theta;
 
             repeats = 1;
-        } 
+        }
         else if (step == '[') PushTurtleState(turtle);
         else if (step == ']') turtle = PopTurtleState();
         else if ((step >= 48) && (step <= 57)) repeats = (int) step - 48;
diff --git a/raylib/examples/shapes/shapes_pie_chart.c b/raylib/examples/shapes/shapes_pie_chart.c
--- a/raylib/examples/shapes/shapes_pie_chart.c
+++ b/raylib/examples/shapes/shapes_pie_chart.c
@@ -49,8 +49,8 @@
     bool showPercentages = false;
     bool showDonut = false;
     int hoveredSlice = -1;
-    Rectangle scrollPanelBounds = {0};
-    Vector2 scrollContentOffset = {0};
+    Rectangle scrollPanelBounds = { 0 };
+    Vector2 scrollContentOffset = { 0 };
     Rectangle view = { 0 };
 
     // UI layout parameters
@@ -160,7 +160,7 @@
 
                 // Draw inner circle to create donut effect
                 // TODO: This is a hacky solution, better use DrawRing()
-                if (showDonut) DrawCircle(center.x, center.y, donutInnerRadius, RAYWHITE);
+                if (showDonut) DrawCircleV(center, donutInnerRadius, RAYWHITE);
 
                 startAngle += sweepAngle;
             }
diff --git a/raylib/examples/shapes/shapes_polygon_lines.c b/raylib/examples/shapes/shapes_polygon_lines.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/shapes/shapes_polygon_lines.c
@@ -0,0 +1,118 @@
+/*******************************************************************************************
+*
+*   raylib [shapes] example - polygon lines
+*
+*   Example complexity rating: [★★☆☆] 2/4
+*
+*   Example originally created with raylib 6.1, last time updated with raylib 6.1
+*
+*   Example contributed by Matthew Roush (@MatthewRoush) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Matthew Roush (@MatthewRoush)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - polygon lines");
+
+    int thick = 2;
+    float rotation = 0.0f;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_UP))   thick = thick + 1;
+        if (IsKeyPressed(KEY_DOWN)) thick = thick - 1;
+
+        thick = (thick < 1) ? 1 : (thick > 60) ? 60 : thick;
+
+        rotation += (360.0f/10.0f)*GetFrameTime();
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            DrawText(TextFormat("thick = %d", thick), 10, 280, 20, LIME);
+
+            // The square and circle outlines in the top left should match
+            // The fist pair of outlines are drawn using `DrawRectangleLinesEx()` and `DrawCircleLinesEx()`
+            // The second pair are drawn using `DrawPolyLinesEx()` with parameters that should visually match the first pair
+
+            DrawText("These should look identical!", 10, 10, 20, MAROON);
+
+            // Outline pair 1
+            DrawRectangle(10, 40, 50, 50, LIGHTGRAY);
+            DrawRectangleLinesEx((Rectangle){ 10, 40, 50, 50 }, (float)thick, RED);
+
+            DrawCircle(95, 65, 25, LIGHTGRAY);
+            DrawCircleLinesEx((Vector2){ 95, 65 }, 25, (float)thick, RED);
+
+            DrawText("DrawRectangleLinesEx() and DrawCircleLinesEx()", 130, 60, 10, BLACK);
+
+            // Outline pair 2
+            DrawPoly((Vector2){ 35, 125 }, 4, 35.355f, 45, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 35, 125 }, 4, 35.355f, 45, (float)thick, RED);
+
+            DrawPoly((Vector2){ 95, 125 }, 36, 25, 0, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 95, 125 }, 36, 25, 0, (float)thick, RED);
+
+            DrawText("DrawPolyLinesEx()", 130, 120, 10, BLACK);
+
+            // Some other shapes, all of these outlines should have the same looking thickness
+            DrawPoly((Vector2){ 290, 220 }, 3, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 290, 220 }, 3, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 430, 220 }, 4, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 430, 220 }, 4, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 570, 220 }, 5, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 570, 220 }, 5, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 710, 220 }, 6, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 710, 220 }, 6, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 290, 360 }, 7, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 290, 360 }, 7, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 430, 360 }, 8, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 430, 360 }, 8, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 570, 360 }, 9, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 570, 360 }, 9, 60, rotation, (float)thick, BLUE);
+
+            DrawPoly((Vector2){ 710, 360 }, 10, 60, rotation, LIGHTGRAY);
+            DrawPolyLinesEx((Vector2){ 710, 360 }, 10, 60, rotation, (float)thick, BLUE);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/shapes/shapes_recursive_tree.c b/raylib/examples/shapes/shapes_recursive_tree.c
--- a/raylib/examples/shapes/shapes_recursive_tree.c
+++ b/raylib/examples/shapes/shapes_recursive_tree.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jopestpe (@jopestpe)
 *
diff --git a/raylib/examples/shapes/shapes_rlgl_color_wheel.c b/raylib/examples/shapes/shapes_rlgl_color_wheel.c
--- a/raylib/examples/shapes/shapes_rlgl_color_wheel.c
+++ b/raylib/examples/shapes/shapes_rlgl_color_wheel.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shapes/shapes_rlgl_triangle.c b/raylib/examples/shapes/shapes_rlgl_triangle.c
--- a/raylib/examples/shapes/shapes_rlgl_triangle.c
+++ b/raylib/examples/shapes/shapes_rlgl_triangle.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/examples/shapes/shapes_starfield_effect.c b/raylib/examples/shapes/shapes_starfield_effect.c
--- a/raylib/examples/shapes/shapes_starfield_effect.c
+++ b/raylib/examples/shapes/shapes_starfield_effect.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 5.5, last time updated with raylib 6.0
 *
 *   Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -47,8 +47,8 @@
     // Setup the stars with a random position
     for (int i = 0; i < STAR_COUNT; i++)
     {
-        stars[i].x = GetRandomValue(-screenWidth*0.5f, screenWidth*0.5f);
-        stars[i].y = GetRandomValue(-screenHeight*0.5f, screenHeight*0.5f);
+        stars[i].x = (float)GetRandomValue(-screenWidth / 2, (int)screenWidth / 2);
+        stars[i].y = (float)GetRandomValue(-screenHeight / 2, (int)screenHeight / 2);
         stars[i].z = 1.0f;
     }
 
@@ -85,8 +85,8 @@
             if ((stars[i].z < 0.0f) || (starsScreenPos[i].x < 0) || (starsScreenPos[i].y < 0.0f) ||
                 (starsScreenPos[i].x > screenWidth) || (starsScreenPos[i].y > screenHeight))
             {
-                stars[i].x = GetRandomValue(-screenWidth*0.5f, screenWidth*0.5f);
-                stars[i].y = GetRandomValue(-screenHeight*0.5f, screenHeight*0.5f);
+                stars[i].x = (float)GetRandomValue(-screenWidth / 2, screenWidth / 2);
+                stars[i].y = (float)GetRandomValue(-screenHeight / 2, screenHeight / 2);
                 stars[i].z = 1.0f;
             }
         }
diff --git a/raylib/examples/shapes/shapes_top_down_lights.c b/raylib/examples/shapes/shapes_top_down_lights.c
--- a/raylib/examples/shapes/shapes_top_down_lights.c
+++ b/raylib/examples/shapes/shapes_top_down_lights.c
@@ -341,7 +341,7 @@
         rlSetBlendMode(BLEND_CUSTOM);
 
         // If we are valid, then draw the light radius to the alpha mask
-        if (lights[slot].valid) DrawCircleGradient((int)lights[slot].position.x, (int)lights[slot].position.y, lights[slot].outerRadius, ColorAlpha(WHITE, 0), WHITE);
+        if (lights[slot].valid) DrawCircleGradient(lights[slot].position, lights[slot].outerRadius, ColorAlpha(WHITE, 0), WHITE);
 
         rlDrawRenderBatchActive();
 
diff --git a/raylib/examples/shapes/shapes_triangle_strip.c b/raylib/examples/shapes/shapes_triangle_strip.c
--- a/raylib/examples/shapes/shapes_triangle_strip.c
+++ b/raylib/examples/shapes/shapes_triangle_strip.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Jopestpe (@jopestpe)
 *
diff --git a/raylib/examples/text/raygui.h b/raylib/examples/text/raygui.h
new file mode 100644
--- /dev/null
+++ b/raylib/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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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/raylib/examples/text/text_3d_drawing.c b/raylib/examples/text/text_3d_drawing.c
--- a/raylib/examples/text/text_3d_drawing.c
+++ b/raylib/examples/text/text_3d_drawing.c
@@ -113,7 +113,7 @@
 
     // Set the text (using markdown!)
     char text[64] = "Hello ~~World~~ in 3D!";
-    Vector3 tbox = {0};
+    Vector3 tbox = { 0 };
     int layers = 1;
     int quads = 0;
     float layerDistance = 0.01f;
@@ -133,7 +133,7 @@
     Shader alphaDiscard = LoadShader(NULL, TextFormat("resources/shaders/glsl%i/alpha_discard.fs", GLSL_VERSION));
 
     // Array filled with multiple random colors (when multicolor mode is set)
-    Color multi[TEXT_MAX_LAYERS] = {0};
+    Color multi[TEXT_MAX_LAYERS] = { 0 };
 
     DisableCursor();                    // Limit cursor to relative movement inside the window
 
diff --git a/raylib/examples/text/text_codepoints_loading.c b/raylib/examples/text/text_codepoints_loading.c
--- a/raylib/examples/text/text_codepoints_loading.c
+++ b/raylib/examples/text/text_codepoints_loading.c
@@ -61,7 +61,7 @@
     SetTextLineSpacing(20);         // Set line spacing for multiline text (when line breaks are included '\n')
 
     // Free codepoints, atlas has already been generated
-    free(codepointsNoDups);
+    RL_FREE(codepointsNoDups);
 
     bool showFontAtlas = false;
 
@@ -139,7 +139,7 @@
 static int *CodepointRemoveDuplicates(int *codepoints, int codepointCount, int *codepointsResultCount)
 {
     int codepointsNoDupsCount = codepointCount;
-    int *codepointsNoDups = (int *)calloc(codepointCount, sizeof(int));
+    int *codepointsNoDups = (int *)RL_CALLOC(codepointCount, sizeof(int));
     memcpy(codepointsNoDups, codepoints, codepointCount*sizeof(int));
 
     // Remove duplicates
diff --git a/raylib/examples/text/text_font_loading.c b/raylib/examples/text/text_font_loading.c
--- a/raylib/examples/text/text_font_loading.c
+++ b/raylib/examples/text/text_font_loading.c
@@ -38,12 +38,12 @@
 
     // Define characters to draw
     // NOTE: raylib supports UTF-8 encoding, following list is actually codified as UTF8 internally
-    const char msg[256] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI\nJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmn\nopqrstuvwxyz{|}~¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓ\nÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷\nøùúûüýþÿ";
+    const char msg[256] = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI\nJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmn\nopqrstuvwxyz{|}~¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓ\nÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷\nøùúûüýþÿ";
 
     // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
 
     // BMFont (AngelCode) : Font data and image atlas have been generated using external program
-    Font fontBm = LoadFont("resources/pixantiqua.fnt");
+    Font fontBm = LoadFont("resources/pixantiqua.fnt"); // Requires "resources/pixantiqua.png"
 
     // TTF font : Font data and atlas are generated directly from TTF
     // NOTE: We define a font base size of 32 pixels tall and up-to 250 characters
diff --git a/raylib/examples/text/text_font_sdf.c b/raylib/examples/text/text_font_sdf.c
--- a/raylib/examples/text/text_font_sdf.c
+++ b/raylib/examples/text/text_font_sdf.c
@@ -97,8 +97,8 @@
         if (currentFont == 0) textSize = MeasureTextEx(fontDefault, msg, fontSize, 0);
         else textSize = MeasureTextEx(fontSDF, msg, fontSize, 0);
 
-        fontPosition.x = GetScreenWidth()/2 - textSize.x/2;
-        fontPosition.y = GetScreenHeight()/2 - textSize.y/2 + 80;
+        fontPosition.x = (float)GetScreenWidth()/2 - textSize.x/2;
+        fontPosition.y = (float)GetScreenHeight()/2 - textSize.y/2 + 80;
         //----------------------------------------------------------------------------------
 
         // Draw
diff --git a/raylib/examples/text/text_inline_styling.c b/raylib/examples/text/text_inline_styling.c
--- a/raylib/examples/text/text_inline_styling.c
+++ b/raylib/examples/text/text_inline_styling.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Wagner Barongello (@SultansOfCode) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -180,12 +180,12 @@
                     if (text[i - 1] == 'c')
                     {
 						colFront = GetColor(colHexValue);
-						colFront.a = (unsigned char)(colFront.a * (float)color.a/255.0f);
+						//colFront.a *= (unsigned char)(colFront.a*(float)color.a/255.0f); // TODO: Review
 					}
                     else if (text[i - 1] == 'b')
 					{
 						colBack = GetColor(colHexValue);
-						colBack.a *= (unsigned char)(colFront.a * (float)color.a / 255.0f);
+						//colBack.a *= (unsigned char)(colFront.a*(float)color.a/255.0f);
 					}
 
                     i += (colHexCount + 1); // Skip color value retrieved and ']'
diff --git a/raylib/examples/text/text_rectangle_bounds.c b/raylib/examples/text/text_rectangle_bounds.c
--- a/raylib/examples/text/text_rectangle_bounds.c
+++ b/raylib/examples/text/text_rectangle_bounds.c
@@ -226,7 +226,7 @@
             {
                 if (!wordWrap)
                 {
-                    textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                    textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                     textOffsetX = 0;
                 }
             }
@@ -234,7 +234,7 @@
             {
                 if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
                 {
-                    textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                    textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                     textOffsetX = 0;
                 }
 
@@ -258,7 +258,7 @@
 
             if (wordWrap && (i == endLine))
             {
-                textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                 textOffsetX = 0;
                 startLine = endLine;
                 endLine = -1;
diff --git a/raylib/examples/text/text_strings_management.c b/raylib/examples/text/text_strings_management.c
--- a/raylib/examples/text/text_strings_management.c
+++ b/raylib/examples/text/text_strings_management.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★★☆] 3/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -33,7 +33,7 @@
     Vector2 ppos;      // Previous position
     float padding;
     float borderWidth;
-    float friction;   
+    float friction;
     float elasticity;
     Color color;
     bool grabbed;
@@ -65,7 +65,7 @@
     TextParticle textParticles[MAX_TEXT_PARTICLES] = { 0 };
     int particleCount = 0;
     TextParticle *grabbedTextParticle = NULL;
-    Vector2 pressOffset = {0};
+    Vector2 pressOffset = { 0 };
 
     PrepareFirstTextParticle("raylib => fun videogames programming!", textParticles, &particleCount);
 
@@ -118,7 +118,7 @@
                     if (IsKeyDown(KEY_LEFT_SHIFT))
                     {
                         ShatterTextParticle(tp, i, textParticles, &particleCount);
-                    } 
+                    }
                     else
                     {
                         SliceTextParticle(tp, i, TextLength(tp->text)/2, textParticles, &particleCount);
@@ -158,33 +158,33 @@
             TextParticle *tp = &textParticles[i];
 
             // The text particle is not grabbed
-            if (!tp->grabbed) 
+            if (!tp->grabbed)
             {
                 // text particle repositioning using the velocity
                 tp->rect.x += tp->vel.x * delta;
                 tp->rect.y += tp->vel.y * delta;
 
                 // Does the text particle hit the screen right boundary?
-                if ((tp->rect.x + tp->rect.width) >= screenWidth) 
+                if ((tp->rect.x + tp->rect.width) >= screenWidth)
                 {
                     tp->rect.x = screenWidth - tp->rect.width; // Text particle repositioning
                     tp->vel.x = -tp->vel.x*tp->elasticity;  // Elasticity makes the text particle lose 10% of its velocity on hit
-                } 
+                }
                 // Does the text particle hit the screen left boundary?
                 else if (tp->rect.x <= 0)
-                { 
+                {
                     tp->rect.x = 0.0f;
                     tp->vel.x = -tp->vel.x*tp->elasticity;
                 }
 
                 // The same for y axis
-                if ((tp->rect.y + tp->rect.height) >= screenHeight) 
+                if ((tp->rect.y + tp->rect.height) >= screenHeight)
                 {
                     tp->rect.y = screenHeight - tp->rect.height;
                     tp->vel.y = -tp->vel.y*tp->elasticity;
-                } 
-                else if (tp->rect.y <= 0) 
-                { 
+                }
+                else if (tp->rect.y <= 0)
+                {
                     tp->rect.y = 0.0f;
                     tp->vel.y = -tp->vel.y*tp->elasticity;
                 }
@@ -264,9 +264,9 @@
 void PrepareFirstTextParticle(const char* text, TextParticle *tps, int *particleCount)
 {
     tps[0] = CreateTextParticle(
-        text, 
-        GetScreenWidth()/2.0f, 
-        GetScreenHeight()/2.0f, 
+        text,
+        GetScreenWidth()/2.0f,
+        GetScreenHeight()/2.0f,
         RAYWHITE
     );
     *particleCount = 1;
@@ -317,7 +317,7 @@
 {
     int tokenCount = 0;
     char **tokens = TextSplit(tp->text, charToSlice, &tokenCount);
-    
+
     if (tokenCount > 1)
     {
         int textLength = TextLength(tp->text);
diff --git a/raylib/examples/text/text_unicode_emojis.c b/raylib/examples/text/text_unicode_emojis.c
--- a/raylib/examples/text/text_unicode_emojis.c
+++ b/raylib/examples/text/text_unicode_emojis.c
@@ -277,7 +277,7 @@
                 DrawTriangle(a, b, c, emoji[selected].color);
 
                 // Draw the main text message
-                Rectangle textRect = { msgRect.x + horizontalPadding/2, msgRect.y + verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height };
+                Rectangle textRect = { msgRect.x + (float)horizontalPadding/2, msgRect.y + (float)verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height };
                 DrawTextBoxed(*font, messages[message].text, textRect, (float)font->baseSize, 1.0f, true, WHITE);
 
                 // Draw the info text below the main message
@@ -421,7 +421,7 @@
             {
                 if (!wordWrap)
                 {
-                    textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                    textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                     textOffsetX = 0;
                 }
             }
@@ -429,7 +429,7 @@
             {
                 if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
                 {
-                    textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                    textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                     textOffsetX = 0;
                 }
 
@@ -453,7 +453,7 @@
 
             if (wordWrap && (i == endLine))
             {
-                textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
+                textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
                 textOffsetX = 0;
                 startLine = endLine;
                 endLine = -1;
diff --git a/raylib/examples/text/text_words_alignment.c b/raylib/examples/text/text_words_alignment.c
--- a/raylib/examples/text/text_words_alignment.c
+++ b/raylib/examples/text/text_words_alignment.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★☆☆☆] 1/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
 *
@@ -41,7 +41,7 @@
     InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment");
 
     // Define the rectangle we will draw the text in
-    Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 };
+    Rectangle textContainerRect = (Rectangle){ (float)screenWidth/2-(float)screenWidth/4, (float)screenHeight/2-(float)screenHeight/3, (float)screenWidth/2, (float)screenHeight*2/3 };
 
     // Some text to display the current alignment
     const char *textAlignNameH[] = { "Left", "Centre", "Right" };
@@ -109,7 +109,7 @@
             DrawRectangleRec(textContainerRect, BLUE);
 
             // Get the size of the text to draw
-            Vector2 textSize = MeasureTextEx(font, words[wordIndex], fontSize, fontSize*.1f);
+            Vector2 textSize = MeasureTextEx(font, words[wordIndex], (float)fontSize, fontSize*.1f);
 
             // Calculate the top-left text position based on the rectangle and alignment
             Vector2 textPos = (Vector2){
@@ -118,7 +118,7 @@
             };
 
             // Draw the text
-            DrawTextEx(font, words[wordIndex], textPos, fontSize, fontSize*.1f, RAYWHITE);
+            DrawTextEx(font, words[wordIndex], textPos, (float)fontSize, fontSize*.1f, RAYWHITE);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
diff --git a/raylib/examples/textures/raygui.h b/raylib/examples/textures/raygui.h
new file mode 100644
--- /dev/null
+++ b/raylib/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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+#include <ctype.h>              // 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 <stdlib.h>             // 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 });
+
+    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 messageTextSize = GuiGetTextWidth(message) + 2;
+
+        textBounds.x = bounds.x + bounds.width/2 - messageTextSize/2;
+        textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        textBounds.width = (float)messageTextSize;
+        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 %u", &version);
+                    } break;
+                    case 'p':
+                    {
+                        // Style property: p <control_id> <property_id> <property_value> <property_name>
+
+                        sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+                        GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+                    } break;
+                    case 'f':
+                    {
+                        // Style font: f <gen_font_size> <font_file> <charmap_file>
+
+                        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/raylib/examples/textures/textures_bunnymark.c b/raylib/examples/textures/textures_bunnymark.c
--- a/raylib/examples/textures/textures_bunnymark.c
+++ b/raylib/examples/textures/textures_bunnymark.c
@@ -17,7 +17,7 @@
 
 #include <stdlib.h>                 // Required for: malloc(), free()
 
-#define MAX_BUNNIES        50000    // 50K bunnies limit
+#define MAX_BUNNIES        80000    // 80K bunnies limit
 
 // This is the maximum amount of elements (quads) per batch
 // NOTE: This value is defined in [rlgl] module and can be changed there
@@ -47,11 +47,13 @@
     // Load bunny texture
     Texture2D texBunny = LoadTexture("resources/raybunny.png");
 
-    Bunny *bunnies = (Bunny *)malloc(MAX_BUNNIES*sizeof(Bunny));    // Bunnies array
+    Bunny *bunnies = (Bunny *)RL_MALLOC(MAX_BUNNIES*sizeof(Bunny));    // Bunnies array
 
     int bunniesCount = 0;           // Bunnies counter
 
-    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    bool paused = false;
+
+    //SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
 
     // Main game loop
@@ -67,8 +69,8 @@
                 if (bunniesCount < MAX_BUNNIES)
                 {
                     bunnies[bunniesCount].position = GetMousePosition();
-                    bunnies[bunniesCount].speed.x = (float)GetRandomValue(-250, 250)/60.0f;
-                    bunnies[bunniesCount].speed.y = (float)GetRandomValue(-250, 250)/60.0f;
+                    bunnies[bunniesCount].speed.x = (float)GetRandomValue(-250, 250);
+                    bunnies[bunniesCount].speed.y = (float)GetRandomValue(-250, 250);
                     bunnies[bunniesCount].color = (Color){ GetRandomValue(50, 240),
                                                        GetRandomValue(80, 240),
                                                        GetRandomValue(100, 240), 255 };
@@ -77,16 +79,21 @@
             }
         }
 
-        // Update bunnies
-        for (int i = 0; i < bunniesCount; i++)
+        if (IsKeyPressed(KEY_P)) paused = !paused;
+
+        if (!paused)
         {
-            bunnies[i].position.x += bunnies[i].speed.x;
-            bunnies[i].position.y += bunnies[i].speed.y;
+            // Update bunnies
+            for (int i = 0; i < bunniesCount; i++)
+            {
+                bunnies[i].position.x += bunnies[i].speed.x*GetFrameTime();
+                bunnies[i].position.y += bunnies[i].speed.y*GetFrameTime();
 
-            if (((bunnies[i].position.x + texBunny.width/2) > GetScreenWidth()) ||
-                ((bunnies[i].position.x + texBunny.width/2) < 0)) bunnies[i].speed.x *= -1;
-            if (((bunnies[i].position.y + texBunny.height/2) > GetScreenHeight()) ||
-                ((bunnies[i].position.y + texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1;
+                if (((bunnies[i].position.x + (float)texBunny.width/2) > GetScreenWidth()) ||
+                    ((bunnies[i].position.x + (float)texBunny.width/2) < 0)) bunnies[i].speed.x *= -1;
+                if (((bunnies[i].position.y + (float)texBunny.height/2) > GetScreenHeight()) ||
+                    ((bunnies[i].position.y + (float)texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1;
+            }
         }
         //----------------------------------------------------------------------------------
 
@@ -119,7 +126,7 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    free(bunnies);              // Unload bunnies data array
+    RL_FREE(bunnies);           // Unload bunnies data array
 
     UnloadTexture(texBunny);    // Unload bunny texture
 
diff --git a/raylib/examples/textures/textures_clipboard_image.c b/raylib/examples/textures/textures_clipboard_image.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/textures/textures_clipboard_image.c
@@ -0,0 +1,110 @@
+/*******************************************************************************************
+*
+*   raylib [textures] example - clipboard image
+*
+*   Example complexity rating: [★☆☆☆] 1/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Maicon Santana (@maiconpintoabreu)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define MAX_TEXTURE_COLLECTION  20
+
+typedef struct TextureCollection {
+    Texture2D texture;
+    Vector2 position;
+} TextureCollection;
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [textures] example - clipboard image");
+
+    TextureCollection collection[MAX_TEXTURE_COLLECTION] = { 0 };
+    int currentCollectionIndex = 0;
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyPressed(KEY_R))    // Reset image collection
+        {
+            // Unload textures to avoid memory leaks
+            for (int i = 0; i < MAX_TEXTURE_COLLECTION; i++) UnloadTexture(collection[i].texture);
+
+            currentCollectionIndex = 0;
+        }
+
+        if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V) &&
+            (currentCollectionIndex < MAX_TEXTURE_COLLECTION))
+        {
+            Image image = GetClipboardImage();
+
+            if (IsImageValid(image))
+            {
+                collection[currentCollectionIndex].texture = LoadTextureFromImage(image);
+                collection[currentCollectionIndex].position = GetMousePosition();
+                currentCollectionIndex++;
+                UnloadImage(image);
+            }
+            else TraceLog(LOG_INFO, "IMAGE: Could not retrieve image from clipboard");
+        }
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            for (int i = 0; i < currentCollectionIndex; i++)
+            {
+                if (IsTextureValid(collection[i].texture))
+                {
+                    DrawTexturePro(collection[i].texture,
+                        (Rectangle){0,0,(float)collection[i].texture.width, (float)collection[i].texture.height},
+                        (Rectangle){collection[i].position.x,collection[i].position.y, (float)collection[i].texture.width, (float)collection[i].texture.height},
+                        (Vector2){collection[i].texture.width*0.5f, collection[i].texture.height*0.5f},
+                        0.0f, WHITE);
+                }
+            }
+
+            DrawRectangle(0, 0, screenWidth, 40, BLACK);
+            DrawText("Clipboard Image - Ctrl+V to Paste and R to Reset ", 120, 10, 20, LIGHTGRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    for (int i = 0; i < MAX_TEXTURE_COLLECTION;i ++)
+    {
+        UnloadTexture(collection[i].texture);
+    }
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/textures/textures_fog_of_war.c b/raylib/examples/textures/textures_fog_of_war.c
--- a/raylib/examples/textures/textures_fog_of_war.c
+++ b/raylib/examples/textures/textures_fog_of_war.c
@@ -51,8 +51,8 @@
     // NOTE: We can have up to 256 values for tile ids and for tile fog state,
     // probably we don't need that many values for fog state, it can be optimized
     // to use only 2 bits per fog state (reducing size by 4) but logic will be a bit more complex
-    map.tileIds = (unsigned char *)calloc(map.tilesX*map.tilesY, sizeof(unsigned char));
-    map.tileFog = (unsigned char *)calloc(map.tilesX*map.tilesY, sizeof(unsigned char));
+    map.tileIds = (unsigned char *)RL_CALLOC(map.tilesX*map.tilesY, sizeof(unsigned char));
+    map.tileFog = (unsigned char *)RL_CALLOC(map.tilesX*map.tilesY, sizeof(unsigned char));
 
     // Load map tiles (generating 2 random tile ids for testing)
     // NOTE: Map tile ids should be probably loaded from an external map file
@@ -68,6 +68,7 @@
     // at a smaller size (one pixel per tile) and scale it on drawing with bilinear filtering
     RenderTexture2D fogOfWar = LoadRenderTexture(map.tilesX, map.tilesY);
     SetTextureFilter(fogOfWar.texture, TEXTURE_FILTER_BILINEAR);
+    SetTextureWrap(fogOfWar.texture, TEXTURE_WRAP_CLAMP);
 
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -93,8 +94,8 @@
         for (unsigned int i = 0; i < map.tilesX*map.tilesY; i++) if (map.tileFog[i] == 1) map.tileFog[i] = 2;
 
         // Get current tile position from player pixel position
-        playerTileX = (int)((playerPosition.x + MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
-        playerTileY = (int)((playerPosition.y + MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
+        playerTileX = (int)((playerPosition.x + (float)MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
+        playerTileY = (int)((playerPosition.y + (float)MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
 
         // Check visibility and update fog
         // NOTE: We check tilemap limits to avoid processing tiles out-of-array-bounds (it could crash program)
@@ -148,8 +149,8 @@
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    free(map.tileIds);      // Free allocated map tile ids
-    free(map.tileFog);      // Free allocated map tile fog state
+    RL_FREE(map.tileIds);   // Free allocated map tile ids
+    RL_FREE(map.tileFog);   // Free allocated map tile fog state
 
     UnloadRenderTexture(fogOfWar);  // Unload render texture
 
diff --git a/raylib/examples/textures/textures_framebuffer_rendering.c b/raylib/examples/textures/textures_framebuffer_rendering.c
--- a/raylib/examples/textures/textures_framebuffer_rendering.c
+++ b/raylib/examples/textures/textures_framebuffer_rendering.c
@@ -65,7 +65,7 @@
     // Rectangles for cropping render texture
     const float captureSize = 128.0f;
     Rectangle cropSource = { (subjectTarget.texture.width - captureSize)/2.0f, (subjectTarget.texture.height - captureSize)/2.0f, captureSize, -captureSize };
-    Rectangle cropDest = { splitWidth + 20, 20, captureSize, captureSize};
+    Rectangle cropDest = { splitWidth + 20.0f, 20.0f, captureSize, captureSize};
 
     SetTargetFPS(60);
     DisableCursor();
@@ -115,7 +115,7 @@
 
             EndMode3D();
 
-            DrawRectangleLines((subjectTarget.texture.width - captureSize)/2, (subjectTarget.texture.height - captureSize)/2, captureSize, captureSize, GREEN);
+            DrawRectangleLines((int)((subjectTarget.texture.width - captureSize)/2.0f), (int)((subjectTarget.texture.height - captureSize)/2.0f), (int)captureSize, (int)captureSize, GREEN);
             DrawText("Subject View", 10, subjectTarget.texture.height - 30, 20, BLACK);
 
         EndTextureMode();
@@ -148,6 +148,7 @@
     //--------------------------------------------------------------------------------------
     UnloadRenderTexture(observerTarget);
     UnloadRenderTexture(subjectTarget);
+
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/examples/textures/textures_image_drawing.c b/raylib/examples/textures/textures_image_drawing.c
--- a/raylib/examples/textures/textures_image_drawing.c
+++ b/raylib/examples/textures/textures_image_drawing.c
@@ -39,7 +39,8 @@
     Image parrots = LoadImage("resources/parrots.png");     // Load image in CPU memory (RAM)
 
     // Draw one image over the other with a scaling of 1.5f
-    ImageDraw(&parrots, cat, (Rectangle){ 0, 0, (float)cat.width, (float)cat.height }, (Rectangle){ 30, 40, cat.width*1.5f, cat.height*1.5f }, WHITE);
+    ImageDrawImagePro(&parrots, cat, (Rectangle){ 0, 0, (float)cat.width, (float)cat.height }, 
+        (Rectangle){ 30, 40, cat.width*1.5f, cat.height*1.5f }, (Vector2){ 0 }, 0.0f, WHITE);
     ImageCrop(&parrots, (Rectangle){ 0, 50, (float)parrots.width, (float)parrots.height - 100 }); // Crop resulting image
 
     // Draw on the image with a few image draw methods
diff --git a/raylib/examples/textures/textures_image_processing.c b/raylib/examples/textures/textures_image_processing.c
--- a/raylib/examples/textures/textures_image_processing.c
+++ b/raylib/examples/textures/textures_image_processing.c
@@ -156,7 +156,7 @@
             {
                 DrawRectangleRec(toggleRecs[i], ((i == currentProcess) || (i == mouseHoverRec)) ? SKYBLUE : LIGHTGRAY);
                 DrawRectangleLines((int)toggleRecs[i].x, (int) toggleRecs[i].y, (int) toggleRecs[i].width, (int) toggleRecs[i].height, ((i == currentProcess) || (i == mouseHoverRec)) ? BLUE : GRAY);
-                DrawText( processText[i], (int)( toggleRecs[i].x + toggleRecs[i].width/2 - MeasureText(processText[i], 10)/2), (int) toggleRecs[i].y + 11, 10, ((i == currentProcess) || (i == mouseHoverRec)) ? DARKBLUE : DARKGRAY);
+                DrawText( processText[i], (int)( toggleRecs[i].x + toggleRecs[i].width/2 - (float)MeasureText(processText[i], 10)/2), (int) toggleRecs[i].y + 11, 10, ((i == currentProcess) || (i == mouseHoverRec)) ? DARKBLUE : DARKGRAY);
             }
 
             DrawTexture(texture, screenWidth - texture.width - 60, screenHeight/2 - texture.height/2, WHITE);
diff --git a/raylib/examples/textures/textures_image_text.c b/raylib/examples/textures/textures_image_text.c
--- a/raylib/examples/textures/textures_image_text.c
+++ b/raylib/examples/textures/textures_image_text.c
@@ -38,7 +38,7 @@
     Texture2D texture = LoadTextureFromImage(parrots);  // Image converted to texture, uploaded to GPU memory (VRAM)
     UnloadImage(parrots);   // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
 
-    Vector2 position = { (float)(screenWidth/2 - texture.width/2), (float)(screenHeight/2 - texture.height/2 - 20) };
+    Vector2 position = { (float)screenWidth/2 - (float)texture.width/2, (float)screenHeight/2 - (float)texture.height/2 - 20 };
 
     bool showFont = false;
 
diff --git a/raylib/examples/textures/textures_magnifying_glass.c b/raylib/examples/textures/textures_magnifying_glass.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/textures/textures_magnifying_glass.c
@@ -0,0 +1,134 @@
+/*******************************************************************************************
+*
+*   raylib textures example - magnifying glass
+*
+*   Example complexity rating: [★★★☆] 3/4
+*
+*   Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+*   Example contributed by Luke Vaughan (@badram) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2026 Luke Vaughan (@badram)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rlgl.h" // for rlSetBlendFactorsSeparate()
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [textures] example - magnifying glass");
+
+    Texture2D bunny = LoadTexture("resources/raybunny.png");
+    Texture2D parrots = LoadTexture("resources/parrots.png");
+
+    // Use image draw to generate a mask texture instead of loading it from a file.
+    Image circle = GenImageColor(256, 256, BLANK);
+    ImageDrawCircle(&circle, 128, 128, 128, WHITE);
+    Texture2D mask = LoadTextureFromImage(circle); // Copy the mask image from RAM to VRAM
+    UnloadImage(circle); // Unload the image from RAM
+
+    RenderTexture2D magnifiedWorld = LoadRenderTexture(256, 256);
+
+    Camera2D camera = { 0 };
+    // Set magnifying glass zoom
+    camera.zoom = 2;
+    // Offset by half the size of the magnifying glass to counteract drawing the texture centered on the mouse position
+    camera.offset = (Vector2){128, 128};
+
+
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        Vector2 mPos = GetMousePosition();
+        camera.target = mPos;
+
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            // Draw the normal version of the world
+            DrawTexture(parrots, 144, 33, WHITE);
+            DrawText("Use the magnifying glass to find hidden bunnies!", 154, 6, 20, BLACK);
+
+            // Render to a the magnifying glass
+            BeginTextureMode(magnifiedWorld);
+                ClearBackground(RAYWHITE);
+
+                BeginMode2D(camera);
+                    // Draw the same things in the magnified world as were in the normal version
+                    DrawTexture(parrots, 144, 33, WHITE);
+                    DrawText("Use the magnifying glass to find hidden bunnies!", 154, 6, 20, BLACK);
+
+                    // Draw bunnies only in the magnified world.
+                    // BLEND_MULTIPLIED lets them take on the color of the image below them.
+                    BeginBlendMode(BLEND_MULTIPLIED);
+                        DrawTexture(bunny, 250, 350, WHITE);
+                        DrawTexture(bunny, 500, 100, WHITE);
+                        DrawTexture(bunny, 420, 300, WHITE);
+                        DrawTexture(bunny, 650, 10, WHITE);
+                    EndBlendMode();
+                EndMode2D();
+
+                // Mask the magnifying glass view texture to a circle
+                // To make the mask affect only alpha, a CUSTOM blend mode is used with SEPARATE color/alpha functions
+                BeginBlendMode(BLEND_CUSTOM_SEPARATE);
+                    // C: Color, A: Alpha, s: source (texture to draw), d: destination (texture drawn to)
+                    //   glSrcRGB: RL_ZERO      - Cs * 0 = 0  - discard source rgb because we don't want to draw our texture's colors at all
+                    //   glDstRGB: RL_ONE       - Cd * 1 = Cd - use destination colors unmodified
+                    //   glSrcAlpha: RL_ONE     - As * 1 = As - use source alpha unmodified
+                    //   glDstAlpha: RL_ZERO    - Ad * 0 = 0  - discard destination alpha
+                    //   glEqRGB: RL_FUNC_ADD   - Cs(0) + Cd = Cd - destination color is unmodified
+                    //   glEqAlpha: RL_FUNC_ADD - As + Ad(0) = As - destination alpha is set to source alpha
+                    rlSetBlendFactorsSeparate(RL_ZERO, RL_ONE, RL_ONE, RL_ZERO, RL_FUNC_ADD, RL_FUNC_ADD);
+                    DrawTexture(mask, 0, 0, WHITE);
+                EndBlendMode();
+            EndTextureMode();
+
+            // Draw magnifiedWorld to screen, centered on cursor
+            DrawTextureRec(magnifiedWorld.texture, (Rectangle){0, 0, 256, -256}, (Vector2){mPos.x - 128, mPos.y - 128}, WHITE);
+
+            // Draw the outer ring of the magnifying glass
+            DrawRing(mPos, 126, 130, 0, 360, 64, BLACK);
+
+            // Draw floating specular highlight on the glass
+            float rx = mPos.x/800;
+            float ry = mPos.y/800;
+            DrawCircle((int)(mPos.x - 64*rx) - 32, (int)(mPos.y - 64*ry) - 32, 4, ColorAlpha(WHITE, 0.5));
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadTexture(parrots);
+    UnloadTexture(bunny);
+    UnloadTexture(mask);
+    UnloadRenderTexture(magnifiedWorld);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
diff --git a/raylib/examples/textures/textures_portal_window.c b/raylib/examples/textures/textures_portal_window.c
new file mode 100644
--- /dev/null
+++ b/raylib/examples/textures/textures_portal_window.c
@@ -0,0 +1,242 @@
+/*******************************************************************************************
+*
+*   raylib [textures] example - portal window
+*
+*   Example demonstrates rendering a second scene to a texture and projecting it onto a
+*   quad to create the illusion of a portal window looking into another place. The second
+*   scene is rendered with an off-axis ("oblique frustum") projection matched to the
+*   viewer's actual position relative to the window, so the illusion holds up correctly
+*   as the player moves and looks around, rather than only looking right from one spot
+*
+*   Example complexity rating: [★★★★] 4/4
+*
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
+*
+*   Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2025 PanicTitan (@PanicTitan)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+#include "rlgl.h"
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+// Begin portal mode 3D view
+static void BeginPortalMode3D(Vector3 eye, Vector3 bottomLeft, Vector3 bottomRight, Vector3 topLeft, float nearPlane, float farPlane);
+// End portal 3D mode and returns to default 2D orthographic mode
+static void EndPortalMode3D(void);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [textures] example - portal window");
+
+    // Camera to navigate the "real world" (Dimension A)
+    Camera3D camera = { 0 };
+    camera.position = (Vector3){ 0.0f, 2.5f, 7.0f };
+    camera.target = (Vector3){ 0.0f, 1.8f, 0.0f };
+    camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    // The archway opening, in Dimension A world space (used both to draw the frame and
+    // as the window rectangle the oblique projection is built from)
+    Vector3 archBottomLeft  = { -1.5f, 0.0f, 0.0f };
+    Vector3 archBottomRight = {  1.5f, 0.0f, 0.0f };
+    Vector3 archTopLeft     = { -1.5f, 4.0f, 0.0f };
+
+    // The archway sits at portalA and looks out onto portalB, far away in world space.
+    // Every frame, Dimension B gets rendered to a texture using the same relative eye
+    // and window position, shifted by the offset between the two portals
+    Vector3 portalA = { 0.0f, 0.0f, 0.0f };
+    Vector3 portalB = { 0.0f, 0.0f, -60.0f };
+    RenderTexture2D portalView = LoadRenderTexture(480, 640);
+
+    DisableCursor();        // Lock cursor for first-person free camera controls
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera, CAMERA_FREE);
+        float time = (float)GetTime();
+
+        // Eye and window corners, shifted into Dimension B so they match the player's
+        // actual position and viewing angle relative to the archway
+        Vector3 offset = Vector3Subtract(portalB, portalA);
+        Vector3 eyeInB = Vector3Add(camera.position, offset);
+        Vector3 blInB = Vector3Add(archBottomLeft, offset);
+        Vector3 brInB = Vector3Add(archBottomRight, offset);
+        Vector3 tlInB = Vector3Add(archTopLeft, offset);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        // Render Dimension B into an offscreen texture, using an oblique projection so
+        // its perspective lines up with the archway exactly as the real camera sees it
+        BeginTextureMode(portalView);
+
+            ClearBackground((Color){ 10, 5, 20, 255 });
+
+            BeginPortalMode3D(eyeInB, blInB, brInB, tlInB, 0.05f, 100.0f);
+
+                DrawGrid(30, 0.8f);
+
+                // Floating pulsing core sphere
+                Vector3 corePos = Vector3Add(portalB, (Vector3){ 0.0f, 2.0f + sinf(time * 2.5f) * 0.4f, -4.0f });
+                DrawSphere(corePos, 1.2f, PURPLE);
+                DrawSphereWires(corePos, 1.25f, 16, 16, MAGENTA);
+
+                // Orbiting cubes
+                for (int i = 0; i < 4; i++)
+                {
+                    float angle = time * 1.5f + i * (PI / 2.0f);
+                    Vector3 pos = Vector3Add(portalB, (Vector3){
+                        sinf(angle) * 2.5f,
+                        2.0f + cosf(time * 3.0f + i) * 0.5f,
+                        -4.0f + cosf(angle) * 2.5f });
+
+                    DrawCube(pos, 0.5f, 0.5f, 0.5f, LIME);
+                    DrawCubeWires(pos, 0.52f, 0.52f, 0.52f, DARKGREEN);
+                }
+
+            EndPortalMode3D();
+
+        EndTextureMode();
+
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                DrawGrid(20, 1.0f);
+
+                // Side pillars
+                DrawCube((Vector3){ -3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, DARKGRAY);
+                DrawCubeWires((Vector3){ -3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, ORANGE);
+                DrawCube((Vector3){ 3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, DARKGRAY);
+                DrawCubeWires((Vector3){ 3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, ORANGE);
+
+                // Golden archway frame and solid base
+                DrawCubeWires((Vector3){ 0.0f, 2.0f, 0.0f }, 3.2f, 4.2f, 0.2f, GOLD);
+                DrawCube((Vector3){ 0.0f, 0.05f, 0.0f }, 3.4f, 0.1f, 0.6f, MAROON);
+
+                // Solid backing wall, only ever seen if looking at the archway from behind
+                DrawCube((Vector3){ 0.0f, 2.0f, -0.05f }, 3.1f, 4.1f, 0.05f, MAROON);
+
+                // The portal opening itself: a plain quad textured with the Dimension B
+                // render, filling the archway exactly, so nothing "leaks" outside its shape
+                rlSetTexture(portalView.texture.id);
+                rlBegin(RL_QUADS);
+                    rlColor4ub(255, 255, 255, 255);
+                    rlNormal3f(0.0f, 0.0f, 1.0f);
+                    rlTexCoord2f(0.0f, 0.0f); rlVertex3f(archBottomLeft.x, archBottomLeft.y, archBottomLeft.z);
+                    rlTexCoord2f(1.0f, 0.0f); rlVertex3f(archBottomRight.x, archBottomRight.y, archBottomRight.z);
+                    rlTexCoord2f(1.0f, 1.0f); rlVertex3f(archBottomRight.x, 4.0f, archBottomRight.z);
+                    rlTexCoord2f(0.0f, 1.0f); rlVertex3f(archTopLeft.x, archTopLeft.y, archTopLeft.z);
+                rlEnd();
+                rlSetTexture(0);
+
+            EndMode3D();
+
+            // HUD overlay
+            DrawRectangle(15, 15, 520, 100, Fade(BLACK, 0.75f));
+            DrawRectangleLines(15, 15, 520, 100, GOLD);
+            DrawText("PORTAL WINDOW", 28, 25, 20, GOLD);
+            DrawText("Look through the golden arch into Dimension B", 28, 52, 20, RAYWHITE);
+            DrawText("Controls: Mouse to look | WASD to move", 28, 80, 20, GRAY);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadRenderTexture(portalView);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Starts a 3D mode using an off-axis ("oblique frustum") projection, built directly from
+// an eye point and 3 corners of a rectangular window, instead of a fovy centered straight
+// ahead of the camera. This is the standard technique for rendering a scene as seen through
+// a window that isn't necessarily faced head-on (also used for multi-monitor and VR
+// rendering) - the key difference from a normal Camera3D is that the frustum is allowed
+// to be asymmetric, so perspective lines through the window line up correctly from any
+// eye position, instead of behaving like a flat image pasted onto the window
+static void BeginPortalMode3D(Vector3 eye, Vector3 bottomLeft, Vector3 bottomRight, Vector3 topLeft, float nearPlane, float farPlane)
+{
+    Vector3 right = Vector3Normalize(Vector3Subtract(bottomRight, bottomLeft));
+    Vector3 up = Vector3Normalize(Vector3Subtract(topLeft, bottomLeft));
+    Vector3 normal = Vector3Normalize(Vector3CrossProduct(right, up));
+
+    // Vectors from the eye to 3 corners of the window, used to project the window onto
+    // the near plane and read off how far it extends left/right/bottom/top of the eye
+    Vector3 toBL = Vector3Subtract(bottomLeft, eye);
+    Vector3 toBR = Vector3Subtract(bottomRight, eye);
+    Vector3 toTL = Vector3Subtract(topLeft, eye);
+
+    float dist = -Vector3DotProduct(toBL, normal);
+    if (dist < 0.01f) dist = 0.01f; // Keep the eye from crossing the window plane
+
+    float scale = nearPlane/dist;
+
+    rlDrawRenderBatchActive();
+
+    rlMatrixMode(RL_PROJECTION);
+    rlPushMatrix();
+    rlSetMatrixProjection(MatrixFrustum(
+        Vector3DotProduct(right, toBL)*scale, Vector3DotProduct(right, toBR)*scale,
+        Vector3DotProduct(up, toBL)*scale, Vector3DotProduct(up, toTL)*scale,
+        nearPlane, farPlane));
+
+    // View orientation is fixed to the window's own plane (looking straight through it
+    // along its normal), NOT aimed at any target - that's what the asymmetric frustum
+    // above is for, and is what lets the eye move off to one side without distorting
+    rlMatrixMode(RL_MODELVIEW);
+    rlLoadIdentity();
+    rlMultMatrixf(MatrixToFloat(MatrixLookAt(eye, Vector3Subtract(eye, normal), up)));
+
+    rlEnableDepthTest();
+}
+
+// End portal 3D mode and returns to default 2D orthographic mode
+// NOTE: Similar implementation to EndMode3D()
+static void EndPortalMode3D(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
+    rlPopMatrix();                  // Restore previous matrix (projection) from matrix stack
+
+    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    rlDisableDepthTest();           // Disable DEPTH_TEST for 2D
+}
diff --git a/raylib/examples/textures/textures_raw_data.c b/raylib/examples/textures/textures_raw_data.c
--- a/raylib/examples/textures/textures_raw_data.c
+++ b/raylib/examples/textures/textures_raw_data.c
@@ -17,8 +17,6 @@
 
 #include "raylib.h"
 
-#include <stdlib.h>         // Required for: malloc() and free()
-
 //------------------------------------------------------------------------------------
 // Program main entry point
 //------------------------------------------------------------------------------------
@@ -39,26 +37,31 @@
     UnloadImage(fudesumiRaw);                                // Unload CPU (RAM) image data
 
     // Generate a checked texture by code
-    int width = 960;
-    int height = 480;
+    int imWidth = 960;
+    int imHeight = 480;
 
     // Dynamic memory allocation to store pixels data (Color type)
-    Color *pixels = (Color *)malloc(width*height*sizeof(Color));
+    // WARNING: Using raylib provided MemAlloc() that uses default raylib
+    // internal memory allocator, so this data can be freed using UnloadImage()
+    // that also uses raylib internal memory de-allocator
+    Color *pixels = (Color *)MemAlloc(imWidth*imHeight*sizeof(Color));
 
-    for (int y = 0; y < height; y++)
+    for (int y = 0; y < imHeight; y++)
     {
-        for (int x = 0; x < width; x++)
+        for (int x = 0; x < imWidth; x++)
         {
-            if (((x/32+y/32)/1)%2 == 0) pixels[y*width + x] = ORANGE;
-            else pixels[y*width + x] = GOLD;
+            if (((x/32+y/32)/1)%2 == 0) pixels[y*imWidth + x] = ORANGE;
+            else pixels[y*imWidth + x] = GOLD;
         }
     }
 
     // Load pixels data into an image structure and create texture
+    // NOTE: We can assign pixels directly to data because Color is R8G8B8A8
+    // data structure defining that pixelformat, format must be set properly
     Image checkedIm = {
-        .data = pixels,             // We can assign pixels directly to data
-        .width = width,
-        .height = height,
+        .data = pixels,
+        .width = imWidth,
+        .height = imHeight,
         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
         .mipmaps = 1
     };
diff --git a/raylib/examples/textures/textures_screen_buffer.c b/raylib/examples/textures/textures_screen_buffer.c
--- a/raylib/examples/textures/textures_screen_buffer.c
+++ b/raylib/examples/textures/textures_screen_buffer.c
@@ -52,6 +52,7 @@
         float hue = t*t;
         float saturation = t;
         float value = t;
+
         palette[i] = ColorFromHSV(250.0f + 150.0f*hue, saturation, value);
     }
 
@@ -66,11 +67,9 @@
         // Grow flameRoot
         for (int x = 2; x < flameWidth; x++)
         {
-            unsigned char flame = flameRootBuffer[x];
-            if (flame == 255) continue;
+            int flame = (int)flameRootBuffer[x];
             flame += GetRandomValue(0, 2);
-            if (flame > 255) flame = 255;
-            flameRootBuffer[x] = flame;
+            flameRootBuffer[x] = (flame > 255)? 255: (unsigned char)flame;
         }
 
         // Transfer flameRoot to indexBuffer
@@ -83,8 +82,7 @@
         // Clear top row, because it can't move any higher
         for (int x = 0; x < imageWidth; x++)
         {
-            if (indexBuffer[x] == 0) continue;
-            indexBuffer[x] = 0;
+            if (indexBuffer[x] != 0) indexBuffer[x] = 0;
         }
 
         // Skip top row, it is already cleared
@@ -94,18 +92,22 @@
             {
                 unsigned int i = x + y*imageWidth;
                 unsigned char colorIndex = indexBuffer[i];
-                if (colorIndex == 0) continue;
 
-                // Move pixel a row above
-                indexBuffer[i] = 0;
-                int moveX = GetRandomValue(0, 2) - 1;
-                int newX = x + moveX;
-                if (newX < 0 || newX >= imageWidth) continue;
+                if (colorIndex != 0)
+                {
+                    // Move pixel a row above
+                    indexBuffer[i] = 0;
+                    int moveX = GetRandomValue(0, 2) - 1;
+                    int newX = x + moveX;
 
-                unsigned int iabove = i - imageWidth + moveX;
-                int decay = GetRandomValue(0, 3);
-                colorIndex -= (decay < colorIndex)? decay : colorIndex;
-                indexBuffer[iabove] = colorIndex;
+                    if ((newX > 0) && (newX < imageWidth))
+                    {
+                        unsigned int iabove = i - imageWidth + moveX;
+                        int decay = GetRandomValue(0, 3);
+                        colorIndex -= (decay < colorIndex)? decay : colorIndex;
+                        indexBuffer[iabove] = colorIndex;
+                    }
+                }
             }
         }
 
@@ -117,6 +119,7 @@
                 unsigned int i = x + y*imageWidth;
                 unsigned char colorIndex = indexBuffer[i];
                 Color col = palette[colorIndex];
+
                 ImageDrawPixel(&screenImage, x, y, col);
             }
         }
@@ -127,7 +130,7 @@
         // Draw
         //----------------------------------------------------------------------------------
         BeginDrawing();
-            
+
             ClearBackground(RAYWHITE);
 
             DrawTextureEx(screenTexture, (Vector2){ 0, 0 }, 0.0f, 2.0f, WHITE);
diff --git a/raylib/examples/textures/textures_sprite_button.c b/raylib/examples/textures/textures_sprite_button.c
--- a/raylib/examples/textures/textures_sprite_button.c
+++ b/raylib/examples/textures/textures_sprite_button.c
@@ -39,7 +39,7 @@
     Rectangle sourceRec = { 0, 0, (float)button.width, frameHeight };
 
     // Define button bounds on screen
-    Rectangle btnBounds = { screenWidth/2.0f - button.width/2.0f, screenHeight/2.0f - button.height/NUM_FRAMES/2.0f, (float)button.width, frameHeight };
+    Rectangle btnBounds = { screenWidth/2.0f - button.width/2.0f, screenHeight/2.0f - (float)button.height/NUM_FRAMES/2.0f, (float)button.width, frameHeight };
 
     int btnState = 0;               // Button state: 0-NORMAL, 1-MOUSE_HOVER, 2-PRESSED
     bool btnAction = false;         // Button action should be activated
diff --git a/raylib/examples/textures/textures_sprite_explosion.c b/raylib/examples/textures/textures_sprite_explosion.c
--- a/raylib/examples/textures/textures_sprite_explosion.c
+++ b/raylib/examples/textures/textures_sprite_explosion.c
@@ -39,8 +39,8 @@
     Texture2D explosion = LoadTexture("resources/explosion.png");
 
     // Init variables for animation
-    float frameWidth = (float)(explosion.width/NUM_FRAMES_PER_LINE);   // Sprite one frame rectangle width
-    float frameHeight = (float)(explosion.height/NUM_LINES);           // Sprite one frame rectangle height
+    float frameWidth = (float)explosion.width/NUM_FRAMES_PER_LINE;   // Sprite one frame rectangle width
+    float frameHeight = (float)explosion.height/NUM_LINES;           // Sprite one frame rectangle height
     int currentFrame = 0;
     int currentLine = 0;
 
diff --git a/raylib/examples/textures/textures_sprite_stacking.c b/raylib/examples/textures/textures_sprite_stacking.c
--- a/raylib/examples/textures/textures_sprite_stacking.c
+++ b/raylib/examples/textures/textures_sprite_stacking.c
@@ -4,7 +4,7 @@
 *
 *   Example complexity rating: [★★☆☆] 2/4
 *
-*   Example originally created with raylib 5.6-dev, last time updated with raylib 6.0
+*   Example originally created with raylib 6.0, last time updated with raylib 6.0
 *
 *   Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
 *
diff --git a/raylib/projects/4coder/main.c b/raylib/projects/4coder/main.c
deleted file mode 100644
--- a/raylib/projects/4coder/main.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <math.h>
-#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/raylib/projects/Geany/core_basic_window.c b/raylib/projects/Geany/core_basic_window.c
--- a/raylib/projects/Geany/core_basic_window.c
+++ b/raylib/projects/Geany/core_basic_window.c
@@ -19,7 +19,7 @@
     int screenHeight = 450;
 
     InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
-    
+
     SetTargetFPS(60);
     //--------------------------------------------------------------------------------------
 
@@ -44,7 +44,7 @@
     }
 
     // De-Initialization
-    //--------------------------------------------------------------------------------------   
+    //--------------------------------------------------------------------------------------
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp_parser.c b/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp_parser.c
--- a/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp_parser.c
+++ b/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp_parser.c
@@ -15,9 +15,9 @@
             <Param name="float alpha" />
         </Overload>
     </KeyWord>
-    
+
     NOTE: Generated XML text should be copied inside raylib\Notepad++\plugins\APIs\c.xml
-    
+
     WARNING: Be careful with functions that split parameters into several lines, it breaks the process!
 
     LICENSE: zlib/libpng
@@ -42,13 +42,13 @@
     {
         FILE *rFile = fopen(argv[1], "rt");
         FILE *rxmlFile = fopen("raylib_npp.xml", "wt");
-        
+
         if ((rFile == NULL) || (rxmlFile == NULL))
         {
             printf("File could not be opened.\n");
             return 0;
         }
-        
+
         char *buffer = (char *)calloc(MAX_BUFFER_SIZE, 1);
         int count = 0;
 
@@ -56,7 +56,7 @@
         {
             // Read one full line
             fgets(buffer, MAX_BUFFER_SIZE, rFile);
-            
+
             if (buffer[0] == '/') fprintf(rxmlFile, "        <!--%.*s -->\n", strlen(buffer) - 3, buffer + 2);
             else if (buffer[0] == '\n') fprintf(rxmlFile, "%s", buffer);      // Direct copy of code comments
             else if (strncmp(buffer, "RLAPI", 5) == 0)      // raylib function declaration
@@ -65,33 +65,33 @@
                 char funcTypeAux[64];
                 char funcName[64];
                 char funcDesc[256];
-                
+
                 char params[128];
                 char paramType[16][16];
                 char paramName[16][32];
-                
+
                 int index = 0;
                 char *ptr = NULL;
-                
+
                 sscanf(buffer, "RLAPI %s %[^(]s", funcType, funcName);
-                
+
                 if (strcmp(funcType, "const") == 0)
-                {            
+                {
                     sscanf(buffer, "RLAPI %s %s %[^(]s", funcType, funcTypeAux, funcName);
                     strcat(funcType, " ");
                     strcat(funcType, funcTypeAux);
                 }
-                
+
                 ptr = strchr(buffer, '/');
                 index = (int)(ptr - buffer);
-                
+
                 sscanf(buffer + index, "%[^\n]s", funcDesc);        // Read function comment after declaration
-                
+
                 ptr = strchr(buffer, '(');
-                
+
                 if (ptr != NULL) index = (int)(ptr - buffer);
                 else printf("Character not found!\n");
-                
+
                 sscanf(buffer + (index + 1), "%[^)]s", params);     // Read what's inside '(' and ')'
 
                 // Scan params string for number of func params, type and name
@@ -102,23 +102,23 @@
                 if ((funcName[0] == '*') && (funcName[1] == '*')) fprintf(rxmlFile, "        <KeyWord name=\"%s\" func=\"yes\">\n", funcName + 2);
                 else if (funcName[0] == '*') fprintf(rxmlFile, "        <KeyWord name=\"%s\" func=\"yes\">\n", funcName + 1);
                 else fprintf(rxmlFile, "        <KeyWord name=\"%s\" func=\"yes\">\n", funcName);
-                
+
                 fprintf(rxmlFile, "            <Overload retVal=\"%s\" descr=\"%s\">", funcType, funcDesc + 3);
-                 
+
                 bool paramsVoid = false;
-                
+
                 char paramConst[8][16];
 
                 while (paramPtr[paramsCount] != NULL)
                 {
                     sscanf(paramPtr[paramsCount], "%s %s\n", paramType[paramsCount], paramName[paramsCount]);
-                      
+
                     if (strcmp(paramType[paramsCount], "void") == 0)
                     {
                         paramsVoid = true;
                         break;
                     }
-                    
+
                     if ((strcmp(paramType[paramsCount], "const") == 0) || (strcmp(paramType[paramsCount], "unsigned") == 0))
                     {
                         sscanf(paramPtr[paramsCount], "%s %s %s\n", paramConst[paramsCount], paramType[paramsCount], paramName[paramsCount]);
@@ -130,17 +130,17 @@
                     paramsCount++;
                     paramPtr[paramsCount] = strtok(NULL, ",");
                 }
-                
+
                 fprintf(rxmlFile, "%s</Overload>\n", paramsVoid ? "" : "\n            ");
                 fprintf(rxmlFile, "        </KeyWord>\n");
 
                 count++;
                 printf("Function processed %02i: %s\n", count, funcName);
-                
+
                 memset(buffer, 0, MAX_BUFFER_SIZE);
             }
         }
-        
+
         free(buffer);
         fclose(rFile);
         fclose(rxmlFile);
diff --git a/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h b/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h
--- a/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h
+++ b/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h
@@ -49,7 +49,7 @@
 RLAPI const char *GetMonitorName(int monitor);                    // Get the human-readable, UTF-8 encoded name of the specified monitor
 RLAPI void SetClipboardText(const char *text);                    // Set clipboard text content
 RLAPI const char *GetClipboardText(void);                         // Get clipboard text content
-RLAPI Image GetClipboardImage(void);                              // Get clipboard image
+RLAPI Image GetClipboardImage(void);                              // Get clipboard image content
 RLAPI void EnableEventWaiting(void);                              // Enable waiting for events on EndDrawing(), no automatic event polling
 RLAPI void DisableEventWaiting(void);                             // Disable waiting for events on EndDrawing(), automatic events polling
 
@@ -91,10 +91,10 @@
 RLAPI bool IsShaderValid(Shader shader);                                   // Check if a shader is valid (loaded on GPU)
 RLAPI int GetShaderLocation(Shader shader, const char *uniformName);       // Get shader uniform location
 RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName);  // Get shader attribute location
-RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType);               // Set shader uniform value
-RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count);   // Set shader uniform value vector
-RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat);         // Set shader uniform value (matrix 4x4)
-RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value for texture (sampler2d)
+RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
+RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
+RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat);  // Set shader uniform value (matrix 4x4)
+RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d)
 RLAPI void UnloadShader(Shader shader);                                    // Unload shader from GPU memory (VRAM)
 
 // Screen-space-related functions
@@ -109,99 +109,106 @@
 RLAPI Matrix GetCameraMatrix2D(Camera2D camera);                        // Get camera 2d transform matrix
 
 // Timing-related functions
-RLAPI void SetTargetFPS(int fps);                                 // Set target FPS (maximum)
-RLAPI float GetFrameTime(void);                                   // Get time in seconds for last frame drawn (delta time)
-RLAPI double GetTime(void);                                       // Get elapsed time in seconds since InitWindow()
-RLAPI int GetFPS(void);                                           // Get current FPS
+RLAPI void SetTargetFPS(int fps);                       // Set target FPS (maximum)
+RLAPI float GetFrameTime(void);                         // Get time in seconds for last frame drawn (delta time)
+RLAPI double GetTime(void);                             // Get elapsed time in seconds since InitWindow()
+RLAPI int GetFPS(void);                                 // Get current FPS
 
 // Custom frame control functions
 // NOTE: Those functions are intended for advanced users that want full control over the frame processing
 // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
 // To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
-RLAPI void SwapScreenBuffer(void);                                // Swap back buffer with front buffer (screen drawing)
-RLAPI void PollInputEvents(void);                                 // Register all input events
-RLAPI void WaitTime(double seconds);                              // Wait for some time (halt program execution)
+RLAPI void SwapScreenBuffer(void);                      // Swap back buffer with front buffer (screen drawing)
+RLAPI void PollInputEvents(void);                       // Register all input events
+RLAPI void WaitTime(double seconds);                    // Wait for some time (halt program execution)
 
 // Random values generation functions
-RLAPI void SetRandomSeed(unsigned int seed);                      // Set the seed for the random number generator
-RLAPI int GetRandomValue(int min, int max);                       // Get a random value between min and max (both included)
+RLAPI void SetRandomSeed(unsigned int seed);            // Set the seed for the random number generator
+RLAPI int GetRandomValue(int min, int max);             // Get a random value between min and max (both included)
 RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated
-RLAPI void UnloadRandomSequence(int *sequence);                   // Unload random values sequence
+RLAPI void UnloadRandomSequence(int *sequence);         // Unload random values sequence
 
 // Misc. functions
-RLAPI void TakeScreenshot(const char *fileName);                  // Takes a screenshot of current screen (filename extension defines format)
-RLAPI void SetConfigFlags(unsigned int flags);                    // Setup init configuration flags (view FLAGS)
-RLAPI void OpenURL(const char *url);                              // Open URL with default system browser (if available)
+RLAPI void TakeScreenshot(const char *fileName);                // Takes a screenshot of current screen (filename extension defines format)
+RLAPI void SetConfigFlags(unsigned int flags);                  // Setup init configuration flags (view FLAGS)
+RLAPI void OpenURL(const char *url);                            // Open URL with default system browser (if available)
 
-// NOTE: Following functions implemented in module [utils]
-//------------------------------------------------------------------
-RLAPI void TraceLog(int logLevel, const char *text, ...);         // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
-RLAPI void SetTraceLogLevel(int logLevel);                        // Set the current threshold (minimum) log level
-RLAPI void *MemAlloc(unsigned int size);                          // Internal memory allocator
-RLAPI void *MemRealloc(void *ptr, unsigned int size);             // Internal memory reallocator
-RLAPI void MemFree(void *ptr);                                    // Internal memory free
+// Logging system
+RLAPI void SetTraceLogLevel(int logLevel);                      // Set the current threshold (minimum) log level
+RLAPI void TraceLog(int logLevel, const char *text, ...);       // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
+RLAPI void SetTraceLogCallback(TraceLogCallback callback);      // Set custom trace log
 
-// Set custom callbacks
-// WARNING: Callbacks setup is intended for advanced users
-RLAPI void SetTraceLogCallback(TraceLogCallback callback);         // Set custom trace log
-RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader
-RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver
-RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
-RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
+// Memory management, using internal allocators
+RLAPI void *MemAlloc(unsigned int size);                        // Internal memory allocator
+RLAPI void *MemRealloc(void *ptr, unsigned int size);           // Internal memory reallocator
+RLAPI void MemFree(void *ptr);                                  // Internal memory free
 
-// Files management functions
+// File system management functions
 RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
-RLAPI void UnloadFileData(unsigned char *data);                   // Unload file data allocated by LoadFileData()
+RLAPI void UnloadFileData(unsigned char *data);                     // Unload file data allocated by LoadFileData()
 RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success
 RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
-RLAPI char *LoadFileText(const char *fileName);                   // Load text data from file (read), returns a '\0' terminated string
-RLAPI void UnloadFileText(char *text);                            // Unload file text data allocated by LoadFileText()
-RLAPI bool SaveFileText(const char *fileName, char *text);        // Save text data to file (write), string must be '\0' terminated, returns true on success
-//------------------------------------------------------------------
+RLAPI char *LoadFileText(const char *fileName);                     // Load text data from file (read), returns a '\0' terminated string
+RLAPI void UnloadFileText(char *text);                              // Unload file text data allocated by LoadFileText()
+RLAPI bool SaveFileText(const char *fileName, const char *text);    // Save text data to file (write), string must be '\0' terminated, returns true on success
 
-// File system functions
-RLAPI bool FileExists(const char *fileName);                      // Check if file exists
-RLAPI bool DirectoryExists(const char *dirPath);                  // Check if a directory path exists
-RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav)
-RLAPI int GetFileLength(const char *fileName);                    // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
-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 *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 bool ChangeDirectory(const char *dir);                      // Change working directory, return true on success
-RLAPI bool IsPathFile(const char *path);                          // Check if a given path is a file or 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
-RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
-RLAPI void UnloadDirectoryFiles(FilePathList files);              // Unload filepaths
-RLAPI bool IsFileDropped(void);                                   // Check if a file has been dropped into window
-RLAPI FilePathList LoadDroppedFiles(void);                        // Load dropped filepaths
-RLAPI void UnloadDroppedFiles(FilePathList files);                // Unload dropped filepaths
-RLAPI long GetFileModTime(const char *fileName);                  // Get file modification time (last write time)
+// File access custom callbacks
+// WARNING: Callbacks setup is intended for advanced users
+RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback);  // Set custom file binary data loader
+RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback);  // Set custom file binary data saver
+RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback);  // Set custom file text data loader
+RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback);  // Set custom file text data saver
 
+RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists)
+RLAPI int FileRemove(const char *fileName);                         // Remove file (if exists)
+RLAPI int FileCopy(const char *srcPath, const char *dstPath);       // Copy file from one path to another, dstPath created if it doesn't exist
+RLAPI int FileMove(const char *srcPath, const char *dstPath);       // Move file from one directory to another, dstPath created if it doesn't exist
+RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file
+RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file
+RLAPI bool FileExists(const char *fileName);                        // Check if file exists
+RLAPI bool DirectoryExists(const char *dirPath);                    // Check if a directory path exists
+RLAPI bool IsFileExtension(const char *fileName, const char *ext);  // Check file extension (recommended include point: .png, .wav)
+RLAPI int GetFileLength(const char *fileName);                      // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
+RLAPI long GetFileModTime(const char *fileName);                    // Get file modification time (last write time)
+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 *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 bool ChangeDirectory(const char *dirPath);                    // Change working directory, return true on success
+RLAPI bool IsPathFile(const char *path);                            // Check if a given path is a file or 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*"
+RLAPI void UnloadDirectoryFiles(FilePathList files);                // Unload filepaths
+RLAPI bool IsFileDropped(void);                                     // Check if a file has been dropped into window
+RLAPI FilePathList LoadDroppedFiles(void);                          // Load dropped filepaths
+RLAPI void UnloadDroppedFiles(FilePathList files);                  // Unload dropped filepaths
+RLAPI unsigned int GetDirectoryFileCount(const char *dirPath);      // Get the file count in a directory
+RLAPI unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs); // 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
+
 // Compression/Encoding functionality
 RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize);        // Compress data (DEFLATE algorithm), memory must be MemFree()
 RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize);  // Decompress data (DEFLATE algorithm), memory must be MemFree()
-RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize);               // Encode data to Base64 string, memory must be MemFree()
-RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize);                    // Decode Base64 string data, memory must be MemFree()
-RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize);     // Compute CRC32 hash code
-RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize);      // Compute MD5 hash code, returns static int[4] (16 bytes)
-RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize);     // Compute SHA1 hash code, returns static int[5] (20 bytes)
-
+RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize);               // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
+RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize);                             // Decode Base64 string (expected NULL terminated), memory must be MemFree()
+RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
+RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize);  // Compute MD5 hash code, returns static int[4] (16 bytes)
+RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
+RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes)
 
 // Automation events functionality
-RLAPI AutomationEventList LoadAutomationEventList(const char *fileName);                // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
-RLAPI void UnloadAutomationEventList(AutomationEventList list);                         // Unload automation events list from file
-RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName);   // Export automation events list as text file
-RLAPI void SetAutomationEventList(AutomationEventList *list);                           // Set automation event list to record to
-RLAPI void SetAutomationEventBaseFrame(int frame);                                      // Set automation event internal base frame to start recording
-RLAPI void StartAutomationEventRecording(void);                                         // Start recording automation events (AutomationEventList must be set)
-RLAPI void StopAutomationEventRecording(void);                                          // Stop recording automation events
-RLAPI void PlayAutomationEvent(AutomationEvent event);                                  // Play a recorded automation event
+RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
+RLAPI void UnloadAutomationEventList(AutomationEventList list);   // Unload automation events list from file
+RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file
+RLAPI void SetAutomationEventList(AutomationEventList *list);     // Set automation event list to record to
+RLAPI void SetAutomationEventBaseFrame(int frame);                // Set automation event internal base frame to start recording
+RLAPI void StartAutomationEventRecording(void);                   // Start recording automation events (AutomationEventList must be set)
+RLAPI void StopAutomationEventRecording(void);                    // Stop recording automation events
+RLAPI void PlayAutomationEvent(AutomationEvent event);            // Play a recorded automation event
 
 //------------------------------------------------------------------------------------
 // Input Handling Functions (Module: core)
@@ -215,20 +222,20 @@
 RLAPI bool IsKeyUp(int key);                                  // Check if a key is NOT being pressed
 RLAPI int GetKeyPressed(void);                                // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
 RLAPI int GetCharPressed(void);                               // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
+RLAPI const char *GetKeyName(int key);                        // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)
 RLAPI void SetExitKey(int key);                               // Set a custom key to exit program (default is ESC)
-RLAPI const char *GetKeyName(int key);                        // Get name of a QWERTY key on the current keyboard layout (eg returns string "q" for KEY_A on an AZERTY keyboard)
 
 // Input-related functions: gamepads
-RLAPI bool IsGamepadAvailable(int gamepad);                                        // Check if a gamepad is available
-RLAPI const char *GetGamepadName(int gamepad);                                     // Get gamepad internal name id
-RLAPI bool IsGamepadButtonPressed(int gamepad, int button);                        // Check if a gamepad button has been pressed once
-RLAPI bool IsGamepadButtonDown(int gamepad, int button);                           // Check if a gamepad button is being pressed
-RLAPI bool IsGamepadButtonReleased(int gamepad, int button);                       // Check if a gamepad button has been released once
-RLAPI bool IsGamepadButtonUp(int gamepad, int button);                             // Check if a gamepad button is NOT being pressed
-RLAPI int GetGamepadButtonPressed(void);                                           // Get the last gamepad button pressed
-RLAPI int GetGamepadAxisCount(int gamepad);                                        // Get gamepad axis count for a gamepad
-RLAPI float GetGamepadAxisMovement(int gamepad, int axis);                         // Get axis movement value for a gamepad axis
-RLAPI int SetGamepadMappings(const char *mappings);                                // Set internal gamepad mappings (SDL_GameControllerDB)
+RLAPI bool IsGamepadAvailable(int gamepad);                   // Check if a gamepad is available
+RLAPI const char *GetGamepadName(int gamepad);                // Get gamepad internal name id
+RLAPI bool IsGamepadButtonPressed(int gamepad, int button);   // Check if a gamepad button has been pressed once
+RLAPI bool IsGamepadButtonDown(int gamepad, int button);      // Check if a gamepad button is being pressed
+RLAPI bool IsGamepadButtonReleased(int gamepad, int button);  // Check if a gamepad button has been released once
+RLAPI bool IsGamepadButtonUp(int gamepad, int button);        // Check if a gamepad button is NOT being pressed
+RLAPI int GetGamepadButtonPressed(void);                      // Get the last gamepad button pressed
+RLAPI int GetGamepadAxisCount(int gamepad);                   // Get axis count for a gamepad
+RLAPI float GetGamepadAxisMovement(int gamepad, int axis);    // Get movement value for a gamepad axis
+RLAPI int SetGamepadMappings(const char *mappings);           // Set internal gamepad mappings (SDL_GameControllerDB)
 RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
 
 // Input-related functions: mouse
@@ -257,19 +264,19 @@
 //------------------------------------------------------------------------------------
 // Gestures and Touch Handling Functions (Module: rgestures)
 //------------------------------------------------------------------------------------
-RLAPI void SetGesturesEnabled(unsigned int flags);      // Enable a set of gestures using flags
-RLAPI bool IsGestureDetected(unsigned int gesture);     // Check if a gesture have been detected
-RLAPI int GetGestureDetected(void);                     // Get latest detected gesture
-RLAPI float GetGestureHoldDuration(void);               // Get gesture hold time in seconds
-RLAPI Vector2 GetGestureDragVector(void);               // Get gesture drag vector
-RLAPI float GetGestureDragAngle(void);                  // Get gesture drag angle
-RLAPI Vector2 GetGesturePinchVector(void);              // Get gesture pinch delta
-RLAPI float GetGesturePinchAngle(void);                 // Get gesture pinch angle
+RLAPI void SetGesturesEnabled(unsigned int flags);            // Enable a set of gestures using flags
+RLAPI bool IsGestureDetected(unsigned int gesture);           // Check if a gesture have been detected
+RLAPI int GetGestureDetected(void);                           // Get latest detected gesture
+RLAPI float GetGestureHoldDuration(void);                     // Get gesture hold time in seconds
+RLAPI Vector2 GetGestureDragVector(void);                     // Get gesture drag vector
+RLAPI float GetGestureDragAngle(void);                        // Get gesture drag angle
+RLAPI Vector2 GetGesturePinchVector(void);                    // Get gesture pinch delta
+RLAPI float GetGesturePinchAngle(void);                       // Get gesture pinch angle
 
 //------------------------------------------------------------------------------------
 // Camera System Functions (Module: rcamera)
 //------------------------------------------------------------------------------------
-RLAPI void UpdateCamera(Camera *camera, int mode);      // Update camera position for selected mode
+RLAPI void UpdateCamera(Camera *camera, int mode);            // Update camera position for selected mode
 RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation
 
 //------------------------------------------------------------------------------------
@@ -278,9 +285,9 @@
 // Set texture and rectangle to be used on shapes drawing
 // NOTE: It can be useful when using basic shapes and one single font,
 // defining a font char white rectangle would allow drawing everything in a single draw call
-RLAPI void SetShapesTexture(Texture2D texture, Rectangle source);       // Set texture and rectangle to be used on shapes drawing
-RLAPI Texture2D GetShapesTexture(void);                                 // Get texture that is used for shapes drawing
-RLAPI Rectangle GetShapesTextureRectangle(void);                        // Get texture source rectangle that is used for shapes drawing
+RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
+RLAPI Texture2D GetShapesTexture(void);                 // Get texture that is used for shapes drawing
+RLAPI Rectangle GetShapesTextureRectangle(void);        // Get texture source rectangle that is used for shapes drawing
 
 // Basic shapes drawing functions
 RLAPI void DrawPixel(int posX, int posY, Color color);                                                   // Draw a pixel using geometry [Can be slow, use with care]
@@ -290,24 +297,27 @@
 RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color);                       // Draw a line (using triangles/quads)
 RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color);                            // Draw lines sequence (using gl lines)
 RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color);                   // Draw line segment cubic-bezier in-out interpolation
+RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color);   // Draw a dashed line
 RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color);                              // Draw a color-filled circle
-RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color);      // Draw a piece of a circle
-RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
-RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer);         // Draw a gradient-filled circle
 RLAPI void DrawCircleV(Vector2 center, float radius, Color color);                                       // Draw a color-filled circle (Vector version)
+RLAPI void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer);                   // Draw a gradient-filled circle
+RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
+RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
 RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);                         // Draw circle outline
 RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color);                                  // Draw circle outline (Vector version)
 RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color);             // Draw ellipse
+RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color);                      // Draw ellipse (Vector version)
 RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color);        // Draw ellipse outline
+RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color);                 // Draw ellipse outline (Vector version)
 RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
-RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color);    // Draw ring outline
+RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
 RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color);                        // Draw a color-filled rectangle
 RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color);                                  // Draw a color-filled rectangle (Vector version)
 RLAPI void DrawRectangleRec(Rectangle rec, Color color);                                                 // Draw a color-filled rectangle
 RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color);                 // Draw a color-filled rectangle with pro parameters
 RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom);   // Draw a vertical-gradient-filled rectangle
 RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right);   // Draw a horizontal-gradient-filled rectangle
-RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors
+RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
 RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color);                   // Draw rectangle outline
 RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color);                            // Draw rectangle outline with extended parameters
 RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color);              // Draw rectangle with rounded edges
@@ -322,11 +332,11 @@
 RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters
 
 // Splines drawing functions
-RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color);                  // Draw spline: Linear, minimum 2 points
-RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color);                   // Draw spline: B-Spline, minimum 4 points
-RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color);              // Draw spline: Catmull-Rom, minimum 4 points
-RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color);         // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
-RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color);             // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
+RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color);            // Draw spline: Linear, minimum 2 points
+RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color);             // Draw spline: B-Spline, minimum 4 points
+RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color);        // Draw spline: Catmull-Rom, minimum 4 points
+RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color);   // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
+RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color);       // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
 RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color);                    // Draw spline segment: Linear, 2 points
 RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points
 RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points
@@ -369,7 +379,7 @@
 RLAPI bool IsImageValid(Image image);                                                                    // Check if an image is valid (data and parameters)
 RLAPI void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 RLAPI bool ExportImage(Image image, const char *fileName);                                               // Export image data to file, returns true on success
-RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize);              // Export image to memory buffer
+RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize);              // Export image to memory buffer, memory must be MemFree()
 RLAPI bool ExportImageAsCode(Image image, const char *fileName);                                         // Export image as code file defining an array of bytes, returns true on success
 
 // Image generation functions
@@ -399,7 +409,7 @@
 RLAPI void ImageBlurGaussian(Image *image, int blurSize);                                                // Apply Gaussian blur using a box blur approximation
 RLAPI void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize);                    // Apply custom square convolution kernel to image
 RLAPI void ImageResize(Image *image, int newWidth, int newHeight);                                       // Resize image (Bicubic scaling algorithm)
-RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight);                                      // Resize image (Nearest-Neighbor scaling algorithm)
+RLAPI void ImageResizeNN(Image *image, int newWidth, int newHeight);                                     // Resize image (Nearest-Neighbor scaling algorithm)
 RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
 RLAPI void ImageMipmaps(Image *image);                                                                   // Compute all mipmap levels for a provided image
 RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp);                            // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
@@ -440,8 +450,8 @@
 RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);               // Draw triangle within an image
 RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
 RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);          // Draw triangle outline within an image
-RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color);               // Draw a triangle fan defined by points within an image (first vertex is the center)
-RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color);             // Draw a triangle strip defined by points within an image
+RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color);         // Draw a triangle fan defined by points within an image (first vertex is the center)
+RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color);       // Draw a triangle strip defined by points within an image
 RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint);             // Draw a source image within a destination image (tint applied to source)
 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)
@@ -456,8 +466,8 @@
 RLAPI void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory (VRAM)
 RLAPI bool IsRenderTextureValid(RenderTexture2D target);                                                 // Check if a render texture is valid (loaded in GPU)
 RLAPI void UnloadRenderTexture(RenderTexture2D target);                                                  // Unload render texture from GPU memory (VRAM)
-RLAPI void UpdateTexture(Texture2D texture, const void *pixels);                                         // Update GPU texture with new data
-RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels);                       // Update GPU texture rectangle with new data
+RLAPI void UpdateTexture(Texture2D texture, const void *pixels);                                         // Update GPU texture with new data (pixels should be able to fill texture)
+RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels);                       // Update GPU texture rectangle with new data (pixels and rec should fit in texture)
 
 // Texture configuration functions
 RLAPI void GenTextureMipmaps(Texture2D *texture);                                                        // Generate GPU mipmaps for a texture
@@ -498,11 +508,11 @@
 // Font loading/unloading functions
 RLAPI Font GetFontDefault(void);                                                            // Get the default Font
 RLAPI Font LoadFont(const char *fileName);                                                  // Load font from file into GPU memory (VRAM)
-RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // 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
+RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // 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
 RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar);                        // Load font from Image (XNA style)
-RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
+RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
 RLAPI bool IsFontValid(Font font);                                                          // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
-RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use
+RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type, int *glyphCount); // Load font data for further use
 RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
 RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount);                               // Unload font chars info data (RAM)
 RLAPI void UnloadFont(Font font);                                                           // Unload font from GPU memory (VRAM)
@@ -520,42 +530,51 @@
 RLAPI void SetTextLineSpacing(int spacing);                                                 // Set vertical line spacing when drawing with line-breaks
 RLAPI int MeasureText(const char *text, int fontSize);                                      // Measure string width for default font
 RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing);    // Measure string size for Font
+RLAPI Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, float fontSize, float spacing); // Measure string size for an existing array of codepoints for Font
 RLAPI int GetGlyphIndex(Font font, int codepoint);                                          // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
 RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint);                                     // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found
 RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint);                                 // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
 
 // Text codepoints management functions (unicode characters)
-RLAPI char *LoadUTF8(const int *codepoints, int length);                // Load UTF-8 text encoded from codepoints array
-RLAPI void UnloadUTF8(char *text);                                      // Unload UTF-8 text encoded from codepoints array
-RLAPI int *LoadCodepoints(const char *text, int *count);                // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
-RLAPI void UnloadCodepoints(int *codepoints);                           // Unload codepoints data from memory
-RLAPI int GetCodepointCount(const char *text);                          // Get total number of codepoints in a UTF-8 encoded string
-RLAPI int GetCodepoint(const char *text, int *codepointSize);           // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
-RLAPI int GetCodepointNext(const char *text, int *codepointSize);       // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
-RLAPI int GetCodepointPrevious(const char *text, int *codepointSize);   // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
-RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size);        // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
+RLAPI char *LoadUTF8(const int *codepoints, int length);                                    // Load UTF-8 text encoded from codepoints array
+RLAPI void UnloadUTF8(char *text);                                                          // Unload UTF-8 text encoded from codepoints array
+RLAPI int *LoadCodepoints(const char *text, int *count);                                    // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
+RLAPI void UnloadCodepoints(int *codepoints);                                               // Unload codepoints data from memory
+RLAPI int GetCodepointCount(const char *text);                                              // Get total number of codepoints in a UTF-8 encoded string
+RLAPI int GetCodepoint(const char *text, int *codepointSize);                               // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
+RLAPI int GetCodepointNext(const char *text, int *codepointSize);                           // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
+RLAPI int GetCodepointPrevious(const char *text, int *codepointSize);                       // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
+RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size);                            // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
 
 // Text strings management functions (no UTF-8 strings, only byte chars)
-// NOTE: Some strings allocate memory internally for returned strings, just be careful!
+// WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use
+// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree()
+RLAPI char **LoadTextLines(const char *text, int *count);                                   // Load text as separate lines ('\n')
+RLAPI void UnloadTextLines(char **text, int lineCount);                                     // Unload text lines
 RLAPI int TextCopy(char *dst, const char *src);                                             // Copy one string to another, returns bytes copied
 RLAPI bool TextIsEqual(const char *text1, const char *text2);                               // Check if two text string are equal
 RLAPI unsigned int TextLength(const char *text);                                            // Get text length, checks for '\0' ending
 RLAPI const char *TextFormat(const char *text, ...);                                        // Text formatting with variables (sprintf() style)
 RLAPI const char *TextSubtext(const char *text, int position, int length);                  // Get a piece of a text string
-RLAPI char *TextReplace(const char *text, const char *replace, const char *by);             // Replace text string (WARNING: memory must be freed!)
-RLAPI char *TextInsert(const char *text, const char *insert, int position);                 // Insert text in a position (WARNING: memory must be freed!)
-RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter);        // Join text strings with delimiter
-RLAPI const char **TextSplit(const char *text, char delimiter, int *count);                 // Split text into multiple strings
-RLAPI void TextAppend(char *text, const char *append, int *position);                       // Append text at specific position and move cursor!
-RLAPI int TextFindIndex(const char *text, const char *find);                                // Find first text occurrence within a string
-RLAPI const char *TextToUpper(const char *text);                      // Get upper case version of provided string
-RLAPI const char *TextToLower(const char *text);                      // Get lower case version of provided string
-RLAPI const char *TextToPascal(const char *text);                     // Get Pascal case notation version of provided string
-RLAPI const char *TextToSnake(const char *text);                      // Get Snake case notation version of provided string
-RLAPI const char *TextToCamel(const char *text);                      // Get Camel case notation version of provided string
-
-RLAPI int TextToInteger(const char *text);                            // Get integer value from text (negative values not supported)
-RLAPI float TextToFloat(const char *text);                            // Get float value from text (negative values not supported)
+RLAPI const char *TextRemoveSpaces(const char *text);                                       // Remove text spaces, concat words
+RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end);           // Get text between two strings
+RLAPI char *TextReplace(const char *text, const char *search, const char *replacement);     // Replace text string with new string
+RLAPI char *TextReplaceAlloc(const char *text, const char *search, const char *replacement); // Replace text string with new string, memory must be MemFree()
+RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings
+RLAPI char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings, memory must be MemFree()
+RLAPI char *TextInsert(const char *text, const char *insert, int position);                 // Insert text in a defined byte position
+RLAPI char *TextInsertAlloc(const char *text, const char *insert, int position);            // Insert text in a defined byte position, memory must be MemFree()
+RLAPI char *TextJoin(char **textList, int count, const char *delimiter);                    // Join text strings with delimiter
+RLAPI char **TextSplit(const char *text, char delimiter, int *count);                       // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings
+RLAPI void TextAppend(char *text, const char *append, int *position);                       // Append text at specific position and move cursor
+RLAPI int TextFindIndex(const char *text, const char *search);                              // Find first text occurrence within a string, -1 if not found
+RLAPI char *TextToUpper(const char *text);                                                  // Get upper case version of provided string
+RLAPI char *TextToLower(const char *text);                                                  // Get lower case version of provided string
+RLAPI char *TextToPascal(const char *text);                                                 // Get Pascal case notation version of provided string
+RLAPI char *TextToSnake(const char *text);                                                  // Get Snake case notation version of provided string
+RLAPI char *TextToCamel(const char *text);                                                  // Get Camel case notation version of provided string
+RLAPI int TextToInteger(const char *text);                                                  // Get integer value from text
+RLAPI float TextToFloat(const char *text);                                                  // Get float value from text
 
 //------------------------------------------------------------------------------------
 // Basic 3d Shapes Drawing Functions (Module: models)
@@ -600,10 +619,8 @@
 RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
 RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint);          // Draw a model wires (with texture if set)
 RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
-RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
-RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters
 RLAPI void DrawBoundingBox(BoundingBox box, Color color);                                   // Draw bounding box (wires)
-RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint);   // Draw a billboard texture
+RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
 RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
 RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
 
@@ -641,21 +658,20 @@
 
 // Model animations loading/unloading functions
 RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount);            // Load model animations from file
-RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame);               // Update model animation pose (CPU)
-RLAPI void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame);          // Update model animation mesh bone matrices (GPU skinning)
-RLAPI void UnloadModelAnimation(ModelAnimation anim);                                       // Unload animation data
+RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, float frame);             // Update model animation pose (vertex buffers and bone matrices)
+RLAPI void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend); // Update model animation pose, blending two animations
 RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount);                // Unload animation array data
 RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim);                         // Check model animation skeleton match
 
 // Collision detection functions
-RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2);   // Check collision between two spheres
-RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2);                                 // Check collision between two bounding boxes
-RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius);                  // Check collision between box and sphere
-RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius);                    // Get collision info between ray and sphere
-RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box);                                    // Get collision info between ray and box
-RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform);                       // Get collision info between ray and mesh
-RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3);            // Get collision info between ray and triangle
-RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4);    // Get collision info between ray and quad
+RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
+RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2);                         // Check collision between two bounding boxes
+RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius);          // Check collision between box and sphere
+RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius);            // Get collision info between ray and sphere
+RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box);                            // Get collision info between ray and box
+RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform);               // Get collision info between ray and mesh
+RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3);    // Get collision info between ray and triangle
+RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad
 
 //------------------------------------------------------------------------------------
 // Audio Loading and Playing Functions (Module: audio)
@@ -677,7 +693,7 @@
 RLAPI Sound LoadSoundFromWave(Wave wave);                             // Load sound from wave data
 RLAPI Sound LoadSoundAlias(Sound source);                             // Create a new sound that shares the same sample data as the source sound, does not own the sound data
 RLAPI bool IsSoundValid(Sound sound);                                 // Checks if a sound is valid (data loaded and buffers initialized)
-RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data
+RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
 RLAPI void UnloadWave(Wave wave);                                     // Unload wave data
 RLAPI void UnloadSound(Sound sound);                                  // Unload sound
 RLAPI void UnloadSoundAlias(Sound alias);                             // Unload a sound alias (does not deallocate sample data)
@@ -692,7 +708,7 @@
 RLAPI bool IsSoundPlaying(Sound sound);                               // Check if a sound is currently playing
 RLAPI void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 RLAPI void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
-RLAPI void SetSoundPan(Sound sound, float pan);                       // Set pan for a sound (0.5 is center)
+RLAPI void SetSoundPan(Sound sound, float pan);                       // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
 RLAPI Wave WaveCopy(Wave wave);                                       // Copy a wave to a new wave
 RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame);       // Crop a wave to defined frames range
 RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
@@ -713,7 +729,7 @@
 RLAPI void SeekMusicStream(Music music, float position);              // Seek music to a position (in seconds)
 RLAPI void SetMusicVolume(Music music, float volume);                 // Set volume for music (1.0 is max level)
 RLAPI void SetMusicPitch(Music music, float pitch);                   // Set pitch for a music (1.0 is base level)
-RLAPI void SetMusicPan(Music music, float pan);                       // Set pan for a music (0.5 is center)
+RLAPI void SetMusicPan(Music music, float pan);                       // Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
 RLAPI float GetMusicTimeLength(Music music);                          // Get music time length (in seconds)
 RLAPI float GetMusicTimePlayed(Music music);                          // Get current music time played (in seconds)
 
@@ -730,7 +746,7 @@
 RLAPI void StopAudioStream(AudioStream stream);                       // Stop audio stream
 RLAPI void SetAudioStreamVolume(AudioStream stream, float volume);    // Set volume for audio stream (1.0 is max level)
 RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch);      // Set pitch for audio stream (1.0 is base level)
-RLAPI void SetAudioStreamPan(AudioStream stream, float pan);          // Set pan for audio stream (0.5 is centered)
+RLAPI void SetAudioStreamPan(AudioStream stream, float pan);          // Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered)
 RLAPI void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams
 RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
 
@@ -739,4 +755,3 @@
 
 RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)
 RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
-
diff --git a/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c b/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c
deleted file mode 100644
--- a/raylib/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 <jni.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/resource.h>
-
-#include "android_native_app_glue.h"
-#include <android/log.h>
-
-#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/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h b/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h
deleted file mode 100644
--- a/raylib/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 <poll.h>
-#include <pthread.h>
-#include <sched.h>
-
-#include <android/configuration.h>
-#include <android/looper.h>
-#include <android/native_activity.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Интерфейс NativeActivity, предоставленный <android/native_activity.h>,
- * основан на наборе предоставленных приложением обратных вызовов, которые вызываются
- *основным потоком действия при возникновении определенных событий.
- *
- * Это означает, что ни один из данных обратных вызовов _не_ _должен_ блокироваться, иначе
- * существует риск принудительного закрытия приложения системой. Эта модель программирования
- * прямая, простая, но имеет ограничения.
- *
- * Статическая библиотека 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/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c b/raylib/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c
deleted file mode 100644
--- a/raylib/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 <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5)
-*
-*   Copyright (c) 2021 <user_name> (@<user_github>)
-
-*   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/raylib/projects/Zig/src/core_basic_window.c b/raylib/projects/Zig/src/core_basic_window.c
new file mode 100644
--- /dev/null
+++ b/raylib/projects/Zig/src/core_basic_window.c
@@ -0,0 +1,83 @@
+/*******************************************************************************************
+*
+*   raylib [core] example - Basic window (adapted for HTML5 platform)
+*
+*   This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP
+*   As you will notice, code structure is slightly different to the other examples...
+*   To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning
+*
+*   This example has been created using raylib 1.3 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2015 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#if defined(PLATFORM_WEB)
+    #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+int screenWidth = 800;
+int screenHeight = 450;
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+void UpdateDrawFrame(void);     // Update and Draw one frame
+
+//----------------------------------------------------------------------------------
+// Program main entry point
+//----------------------------------------------------------------------------------
+int main()
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
+
+#if defined(PLATFORM_WEB)
+    emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
+#else
+    SetTargetFPS(60);   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        UpdateDrawFrame();
+    }
+#endif
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+void UpdateDrawFrame(void)
+{
+    // Update
+    //----------------------------------------------------------------------------------
+    // TODO: Update your variables here
+    //----------------------------------------------------------------------------------
+
+    // Draw
+    //----------------------------------------------------------------------------------
+    BeginDrawing();
+
+        ClearBackground(RAYWHITE);
+
+        DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
+
+    EndDrawing();
+    //----------------------------------------------------------------------------------
+}
diff --git a/raylib/src/config.h b/raylib/src/config.h
--- a/raylib/src/config.h
+++ b/raylib/src/config.h
@@ -2,8 +2,10 @@
 *
 *   raylib configuration flags
 *
-*   This file defines all the configuration flags for the different raylib modules
+*   This file defines the configuration flags for different raylib features per-module
 *
+*   NOTE: Additional values are configured per-module and can be set on compile time
+*
 *   LICENSE: zlib/libpng
 *
 *   Copyright (c) 2018-2026 Ahmad Fatoum and Ramon Santamaria (@raysan5)
@@ -28,282 +30,353 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
+#if !defined(EXTERNAL_CONFIG_FLAGS)
+
 //------------------------------------------------------------------------------------
 // Module selection - Some modules could be avoided
 // Mandatory modules: rcore, rlgl
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
-    #define SUPPORT_MODULE_RSHAPES          1
-    #define SUPPORT_MODULE_RTEXTURES        1
-    #define SUPPORT_MODULE_RTEXT            1       // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
-    #define SUPPORT_MODULE_RMODELS          1
-    #define SUPPORT_MODULE_RAUDIO           1
+#ifndef SUPPORT_MODULE_RSHAPES
+    #define SUPPORT_MODULE_RSHAPES      1
 #endif
+#ifndef SUPPORT_MODULE_RTEXTURES
+    #define SUPPORT_MODULE_RTEXTURES    1
+#endif
+#ifndef SUPPORT_MODULE_RTEXT
+    #define SUPPORT_MODULE_RTEXT        1       // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
+#endif
+#ifndef SUPPORT_MODULE_RMODELS
+    #define SUPPORT_MODULE_RMODELS      1
+#endif
+#ifndef SUPPORT_MODULE_RAUDIO
+    #define SUPPORT_MODULE_RAUDIO       1
+#endif
 
 //------------------------------------------------------------------------------------
 // Module: rcore - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
-// Standard file io library (stdio.h) included
-#define SUPPORT_STANDARD_FILEIO         1
-// Show TRACELOG() output messages
-#define SUPPORT_TRACELOG                1
-// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
-#define SUPPORT_CAMERA_SYSTEM           1
-// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
-#define SUPPORT_GESTURES_SYSTEM         1
-// Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64
-#define SUPPORT_RPRAND_GENERATOR        1
-// Mouse gestures are directly mapped like touches and processed by gestures system
-#define SUPPORT_MOUSE_GESTURES          1
-// Reconfigure standard input to receive key inputs, works with SSH connection
-#define SUPPORT_SSH_KEYBOARD_RPI        1
-// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
-// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
-#define SUPPORT_WINMM_HIGHRES_TIMER     1
-// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
-//#define SUPPORT_BUSY_WAIT_LOOP          1
-// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
-#define SUPPORT_PARTIALBUSY_WAIT_LOOP    1
-// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
-// WARNING: It also requires SUPPORT_IMAGE_EXPORT and SUPPORT_FILEFORMAT_PNG flags
-#define SUPPORT_SCREEN_CAPTURE          1
-// Support CompressData() and DecompressData() functions
-#define SUPPORT_COMPRESSION_API         1
-// Support automatic generated events, loading and recording of those events when required
-#define SUPPORT_AUTOMATION_EVENTS       1
-// Support custom frame control, only for advanced users
-// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
-// Enabling this flag allows manual control of the frame processes, use at your own risk
-//#define SUPPORT_CUSTOM_FRAME_CONTROL    1
-// Support for clipboard image loading
-// NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows)
-#define SUPPORT_CLIPBOARD_IMAGE         1
+#ifndef SUPPORT_TRACELOG
+    // Show TRACELOG() output messages
+    #define SUPPORT_TRACELOG                1
 #endif
-
-// NOTE: Clipboard image loading requires support for some image file formats
-// TODO: Those defines should probably be removed from here, letting the user manage them
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
-    #ifndef SUPPORT_MODULE_RTEXTURES
-        #define SUPPORT_MODULE_RTEXTURES 1
-    #endif
-    #ifndef STBI_REQUIRED
-        #define STBI_REQUIRED
-    #endif
-    #ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows
-        #define SUPPORT_FILEFORMAT_BMP 1
-    #endif
-    #ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu
-        #define SUPPORT_FILEFORMAT_PNG 1
-    #endif
-    #ifndef SUPPORT_FILEFORMAT_JPG
-        #define SUPPORT_FILEFORMAT_JPG 1
-    #endif
+#ifndef SUPPORT_CAMERA_SYSTEM
+    // Camera module is included (rcamera.h) and multiple predefined
+    // cameras are available: free, 1st/3rd person, orbital
+    #define SUPPORT_CAMERA_SYSTEM           1
 #endif
-
-#if defined(SUPPORT_TRACELOG)
-    #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
-#else
-    #define TRACELOG(level, ...) (void)0
+#ifndef SUPPORT_GESTURES_SYSTEM
+    // Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
+    #define SUPPORT_GESTURES_SYSTEM         1
 #endif
+#ifndef SUPPORT_RPRAND_GENERATOR
+    // Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64
+    #define SUPPORT_RPRAND_GENERATOR        1
+#endif
+#ifndef SUPPORT_MOUSE_GESTURES
+    // Mouse gestures are directly mapped like touches and processed by the gestures system
+    #define SUPPORT_MOUSE_GESTURES          1
+#endif
+#ifndef SUPPORT_SSH_KEYBOARD_RPI
+    // Reconfigure standard input to receive key inputs, works with SSH connection
+    #define SUPPORT_SSH_KEYBOARD_RPI        1
+#endif
+#ifndef SUPPORT_WINMM_HIGHRES_TIMER
+    // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
+    // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
+    #define SUPPORT_WINMM_HIGHRES_TIMER     1
+#endif
+#if !SUPPORT_BUSY_WAIT_LOOP && !SUPPORT_PARTIALBUSY_WAIT_LOOP
+    // Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
+    #define SUPPORT_BUSY_WAIT_LOOP          0       // Disabled by default
+#endif
+#if !SUPPORT_PARTIALBUSY_WAIT_LOOP && !SUPPORT_BUSY_WAIT_LOOP
+    // Use a partial-busy wait loop, in this case frame sleeps for most of the time,
+    // but then runs a busy loop at the end for accuracy
+    #define SUPPORT_PARTIALBUSY_WAIT_LOOP   1
+#endif
+#ifndef SUPPORT_SCREEN_CAPTURE
+    // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
+    // WARNING: It requires SUPPORT_FILEFORMAT_PNG flag
+    #define SUPPORT_SCREEN_CAPTURE          1
+#endif
+#ifndef SUPPORT_COMPRESSION_API
+    // Support CompressData() and DecompressData() functions
+    #define SUPPORT_COMPRESSION_API         1
+#endif
+#ifndef SUPPORT_AUTOMATION_EVENTS
+    // Support automatic generated events, loading and recording of those events when required
+    #define SUPPORT_AUTOMATION_EVENTS       1
+#endif
+#ifndef SUPPORT_CUSTOM_FRAME_CONTROL
+    // Support custom frame control, only for advanced users
+    // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
+    // Enabling this flag allows manual control of the frame processes, use at your own risk
+    #define SUPPORT_CUSTOM_FRAME_CONTROL    0       // Disabled by default
+#endif
+#ifndef SUPPORT_CLIPBOARD_IMAGE
+    // Support for clipboard image loading
+    // NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows)
+    // WARNING: It requires support for some additional flags:
+    //  - SUPPORT_MODULE_RTEXTURES
+    //  - SUPPORT_FILEFORMAT_BMP (Windows clipboard)
+    //  - SUPPORT_FILEFORMAT_PNG (Wayland clipboard)
+    //  - SUPPORT_FILEFORMAT_JPG
+    #define SUPPORT_CLIPBOARD_IMAGE         1
+#endif
 
 // rcore: Configuration values
+// NOTE: Below values are already defined inside [rcore.c] so there is no need to be
+// redefined here, in case it must be done, uncomment the required line and update
+// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
 //------------------------------------------------------------------------------------
-#define MAX_TRACELOG_MSG_LENGTH       256       // Max length of one trace-log message
-#define MAX_FILEPATH_CAPACITY        8192       // Maximum file paths capacity
-#define MAX_FILEPATH_LENGTH          4096       // Maximum length for filepaths (Linux PATH_MAX default value)
-
-#define MAX_KEYBOARD_KEYS             512       // Maximum number of keyboard keys supported
-#define MAX_MOUSE_BUTTONS               8       // Maximum number of mouse buttons supported
-#define MAX_GAMEPADS                    4       // Maximum number of gamepads supported
-#define MAX_GAMEPAD_AXES                8       // Maximum number of axes supported (per gamepad)
-#define MAX_GAMEPAD_BUTTONS            32       // Maximum number of buttons supported (per gamepad)
-#define MAX_GAMEPAD_VIBRATION_TIME      2.0f    // Maximum vibration time in seconds
-#define MAX_TOUCH_POINTS               10       // Maximum number of touch points supported
-#define MAX_KEY_PRESSED_QUEUE          16       // Maximum number of keys in the key input queue
-#define MAX_CHAR_PRESSED_QUEUE         16       // Maximum number of characters in the char input queue
-
-#define MAX_DECOMPRESSION_SIZE         64       // Max size allocated for decompression in MB
-
-#define MAX_AUTOMATION_EVENTS       16384       // Maximum number of automation events to record
+//#define MAX_TRACELOG_MSG_LENGTH       256       // Max length of one trace-log message
+//#define MAX_FILEPATH_CAPACITY        8192       // Maximum file paths capacity
+//#define MAX_FILEPATH_LENGTH          4096       // Maximum length for filepaths (Linux PATH_MAX default value)
+//#define MAX_KEYBOARD_KEYS             512       // Maximum number of keyboard keys supported
+//#define MAX_MOUSE_BUTTONS               8       // Maximum number of mouse buttons supported
+//#define MAX_GAMEPADS                    4       // Maximum number of gamepads supported
+//#define MAX_GAMEPAD_AXES                8       // Maximum number of axes supported (per gamepad)
+//#define MAX_GAMEPAD_BUTTONS            32       // Maximum number of buttons supported (per gamepad)
+//#define MAX_GAMEPAD_VIBRATION_TIME      2.0f    // Maximum vibration time in seconds
+//#define MAX_TOUCH_POINTS               10       // Maximum number of touch points supported
+//#define MAX_KEY_PRESSED_QUEUE          16       // Maximum number of keys in the key input queue
+//#define MAX_CHAR_PRESSED_QUEUE         16       // Maximum number of characters in the char input queue
+//#define MAX_DECOMPRESSION_SIZE         64       // Max size allocated for decompression in MB
+//#define MAX_AUTOMATION_EVENTS       16384       // Maximum number of automation events to record
+//------------------------------------------------------------------------------------
 
 //------------------------------------------------------------------------------------
 // Module: rlgl - Configuration values
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
-// Enable OpenGL Debug Context (only available on OpenGL 4.3)
-//#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT       1
-
-// Show OpenGL extensions and capabilities detailed logs on init
-//#define RLGL_SHOW_GL_DETAILS_INFO              1
-
-#define RL_SUPPORT_MESH_GPU_SKINNING           1      // GPU skinning, comment if your GPU does not support more than 8 VBOs
+#ifndef RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
+    // Request OpenGL debug context (only available on OpenGL 4.3)
+    #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT       0
 #endif
-
-//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS    4096    // Default internal render batch elements limits
-#define RL_DEFAULT_BATCH_BUFFERS               1      // Default number of batch buffers (multi-buffering)
-#define RL_DEFAULT_BATCH_DRAWCALLS           256      // Default number of batch draw calls (by state changes: mode, texture)
-#define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS     4      // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
-
-#define RL_MAX_MATRIX_STACK_SIZE              32      // Maximum size of internal Matrix stack
-
-#define RL_MAX_SHADER_LOCATIONS               32      // Maximum number of shader locations supported
+#ifndef RLGL_SHOW_GL_DETAILS_INFO
+    // Show OpenGL detailed info on initialization,
+    // supported GL extensions and GL capabilities
+    #define RLGL_SHOW_GL_DETAILS_INFO              0
+#endif
 
-#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
+// rlgl: Configuration values
+// NOTE: Below values are already defined inside [rlgl.h] so there is no need to be
+// redefined here, in case it must be done, uncomment the required line and update
+// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
+//------------------------------------------------------------------------------------
+//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS    4096      // Default internal render batch elements limits
+//#define RL_DEFAULT_BATCH_BUFFERS               1      // Default number of batch buffers (multi-buffering)
+//#define RL_DEFAULT_BATCH_DRAWCALLS           256      // Default number of batch draw calls (by state changes: mode, texture)
+//#define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS     4      // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
+//#define RL_MAX_MATRIX_STACK_SIZE              32      // Maximum size of internal Matrix stack
+//#define RL_MAX_SHADER_LOCATIONS               32      // Maximum number of shader locations supported
+//#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
 
 // 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
-#if defined(RL_SUPPORT_MESH_GPU_SKINNING)
-    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS     7
-    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
-#endif
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9
+// 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 names to set location points
-// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
-#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
+// 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
+// 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
+//#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
 
-#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_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)
+//#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 (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)
 //------------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------------
 // Module: rshapes - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
-// Use QUADS instead of TRIANGLES for drawing when possible
-// Some lines-based shapes could still use lines
-#define SUPPORT_QUADS_DRAW_MODE         1
+#ifndef SUPPORT_QUADS_DRAW_MODE
+    // Use QUADS instead of TRIANGLES for drawing when possible
+    // Some lines-based shapes could still use lines
+    #define SUPPORT_QUADS_DRAW_MODE         1
 #endif
 
-// rshapes: Configuration values
 //------------------------------------------------------------------------------------
-#define SPLINE_SEGMENT_DIVISIONS       24       // Spline segments subdivisions
-
-//------------------------------------------------------------------------------------
 // Module: rtextures - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
 // Selected desired fileformats to be supported for image data loading
-#define SUPPORT_FILEFORMAT_PNG      1
-//#define SUPPORT_FILEFORMAT_BMP      1
-//#define SUPPORT_FILEFORMAT_TGA      1
-//#define SUPPORT_FILEFORMAT_JPG      1
-#define SUPPORT_FILEFORMAT_GIF      1
-#define SUPPORT_FILEFORMAT_QOI      1
-//#define SUPPORT_FILEFORMAT_PSD      1
-#define SUPPORT_FILEFORMAT_DDS      1
-//#define SUPPORT_FILEFORMAT_HDR      1
-//#define SUPPORT_FILEFORMAT_PIC          1
-//#define SUPPORT_FILEFORMAT_KTX      1
-//#define SUPPORT_FILEFORMAT_ASTC     1
-//#define SUPPORT_FILEFORMAT_PKM      1
-//#define SUPPORT_FILEFORMAT_PVR      1
+#ifndef SUPPORT_FILEFORMAT_PNG
+    #define SUPPORT_FILEFORMAT_PNG      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_BMP
+    // NOTE: BMP support required for clipboard images on Windows
+    #define SUPPORT_FILEFORMAT_BMP      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_TGA
+    #define SUPPORT_FILEFORMAT_TGA      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_JPG
+    #define SUPPORT_FILEFORMAT_JPG      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_GIF
+    #define SUPPORT_FILEFORMAT_GIF      1
+#endif
+#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
+#ifndef SUPPORT_FILEFORMAT_DDS
+    #define SUPPORT_FILEFORMAT_DDS      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_HDR
+    #define SUPPORT_FILEFORMAT_HDR      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_PIC
+    #define SUPPORT_FILEFORMAT_PIC      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_PNM
+    #define SUPPORT_FILEFORMAT_PNM      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_KTX
+    #define SUPPORT_FILEFORMAT_KTX      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_ASTC
+    #define SUPPORT_FILEFORMAT_ASTC     0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_PKM
+    #define SUPPORT_FILEFORMAT_PKM      0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_PVR
+    #define SUPPORT_FILEFORMAT_PVR      0       // Disabled by default
+#endif
 
-// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
-#define SUPPORT_IMAGE_EXPORT            1
-// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
-#define SUPPORT_IMAGE_GENERATION        1
-// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
-// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
-#define SUPPORT_IMAGE_MANIPULATION      1
+#ifndef SUPPORT_IMAGE_EXPORT
+    // Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
+    // NOTE: Image export requires stb_image_write.h library
+    #define SUPPORT_IMAGE_EXPORT        1
 #endif
+#ifndef SUPPORT_IMAGE_GENERATION
+    // Support procedural image generation functionality: gradient, spot, perlin-noise, cellular...
+    // NOTE: Perlin noise requires stb_perlin.h library
+    #define SUPPORT_IMAGE_GENERATION    1
+#endif
 
 //------------------------------------------------------------------------------------
 // Module: rtext - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
-// Default font is loaded on window initialization to be available for the user to render simple text
-// NOTE: If enabled, uses external module functions to load default raylib font
-#define SUPPORT_DEFAULT_FONT            1
 // Selected desired font fileformats to be supported for loading
-#define SUPPORT_FILEFORMAT_TTF          1
-#define SUPPORT_FILEFORMAT_FNT          1
-//#define SUPPORT_FILEFORMAT_BDF          1
-
-// Support text management functions
-// If not defined, still some functions are supported: TextLength(), TextFormat()
-#define SUPPORT_TEXT_MANIPULATION       1
-
-// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
-// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
-// drawing text and shapes with a single draw call [SetShapesTexture()]
-#define SUPPORT_FONT_ATLAS_WHITE_REC    1
-
-// Support conservative font atlas size estimation
-//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE    1
+#ifndef SUPPORT_FILEFORMAT_TTF
+    #define SUPPORT_FILEFORMAT_TTF      1
 #endif
-
-// rtext: Configuration values
-//------------------------------------------------------------------------------------
-#define MAX_TEXT_BUFFER_LENGTH       1024       // Size of internal static buffers used on some functions:
-                                                // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
-#define MAX_TEXTSPLIT_COUNT           128       // Maximum number of substrings to split: TextSplit()
+#ifndef SUPPORT_FILEFORMAT_FNT
+    #define SUPPORT_FILEFORMAT_FNT      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_BDF
+    #define SUPPORT_FILEFORMAT_BDF      0       // Disabled by default
+#endif
 
 //------------------------------------------------------------------------------------
 // Module: rmodels - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
 // Selected desired model fileformats to be supported for loading
-#define SUPPORT_FILEFORMAT_OBJ          1
-#define SUPPORT_FILEFORMAT_MTL          1
-#define SUPPORT_FILEFORMAT_IQM          1
-#define SUPPORT_FILEFORMAT_GLTF         1
-#define SUPPORT_FILEFORMAT_VOX          1
-#define SUPPORT_FILEFORMAT_M3D          1
-// Support procedural mesh generation functions, uses external par_shapes.h library
-// NOTE: Some generated meshes DO NOT include generated texture coordinates
-#define SUPPORT_MESH_GENERATION         1
+#ifndef SUPPORT_FILEFORMAT_OBJ
+    #define SUPPORT_FILEFORMAT_OBJ      1
 #endif
-
-// rmodels: Configuration values
-//------------------------------------------------------------------------------------
-#define MAX_MATERIAL_MAPS              12       // Maximum number of shader maps supported
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-#define MAX_MESH_VERTEX_BUFFERS         9       // Maximum vertex buffers (VBO) per mesh
-#else
-#define MAX_MESH_VERTEX_BUFFERS         7       // Maximum vertex buffers (VBO) per mesh
+#ifndef SUPPORT_FILEFORMAT_MTL
+    #define SUPPORT_FILEFORMAT_MTL      1
 #endif
+#ifndef SUPPORT_FILEFORMAT_IQM
+    #define SUPPORT_FILEFORMAT_IQM      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_GLTF
+    #define SUPPORT_FILEFORMAT_GLTF     1
+#endif
+#ifndef SUPPORT_FILEFORMAT_VOX
+    #define SUPPORT_FILEFORMAT_VOX      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_M3D
+    #define SUPPORT_FILEFORMAT_M3D      1
+#endif
+#ifndef SUPPORT_MESH_GENERATION
+    // Support procedural mesh generation functions, uses external par_shapes.h library
+    // NOTE: Some generated meshes DO NOT include generated texture coordinates
+    #define SUPPORT_MESH_GENERATION     1
+#endif
+#ifndef SUPPORT_GPU_SKINNING
+    // GPU skinning disabled by default, some GPUs do not support more than 8 VBOs
+    #define SUPPORT_GPU_SKINNING        0
+#endif
 
 //------------------------------------------------------------------------------------
 // Module: raudio - Configuration Flags
 //------------------------------------------------------------------------------------
-#if !defined(EXTERNAL_CONFIG_FLAGS)
 // Desired audio fileformats to be supported for loading
-#define SUPPORT_FILEFORMAT_WAV          1
-#define SUPPORT_FILEFORMAT_OGG          1
-#define SUPPORT_FILEFORMAT_MP3          1
-#define SUPPORT_FILEFORMAT_QOA          1
-//#define SUPPORT_FILEFORMAT_FLAC         1
-#define SUPPORT_FILEFORMAT_XM           1
-#define SUPPORT_FILEFORMAT_MOD          1
+#ifndef SUPPORT_FILEFORMAT_WAV
+    #define SUPPORT_FILEFORMAT_WAV      1
 #endif
+#ifndef SUPPORT_FILEFORMAT_OGG
+    #define SUPPORT_FILEFORMAT_OGG      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_MP3
+    #define SUPPORT_FILEFORMAT_MP3      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_QOA
+    #define SUPPORT_FILEFORMAT_QOA      1
+#endif
+#ifndef SUPPORT_FILEFORMAT_FLAC
+    #define SUPPORT_FILEFORMAT_FLAC     0       // Disabled by default
+#endif
+#ifndef SUPPORT_FILEFORMAT_XM
+    #define SUPPORT_FILEFORMAT_XM       1
+#endif
+#ifndef SUPPORT_FILEFORMAT_MOD
+    #define SUPPORT_FILEFORMAT_MOD      1
+#endif
 
 // raudio: Configuration values
+// NOTE: Below values are already defined inside [rlgl.h] so there is no need to be
+// redefined here, in case it must be done, uncomment the required line and update
+// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
 //------------------------------------------------------------------------------------
-#define AUDIO_DEVICE_FORMAT    ma_format_f32    // Device output format (miniaudio: float-32bit)
-#define AUDIO_DEVICE_CHANNELS              2    // Device output channels: stereo
-#define AUDIO_DEVICE_SAMPLE_RATE           0    // Device sample rate (device default)
+//#define AUDIO_DEVICE_FORMAT     ma_format_f32    // Device output format (miniaudio: float-32bit)
+//#define AUDIO_DEVICE_CHANNELS               2    // Device output channels: stereo
+//#define AUDIO_DEVICE_SAMPLE_RATE            0    // Device sample rate (device default)
+//#define AUDIO_DEVICE_PERIOD_SIZE_IN_FRAMES  0    // Device period size (controls latency, 0 defaults to 10ms)
+//#define MAX_AUDIO_BUFFER_POOL_CHANNELS     16    // Maximum number of audio pool channels
+//------------------------------------------------------------------------------------
+#endif // !EXTERNAL_CONFIG_FLAGS
 
-#define MAX_AUDIO_BUFFER_POOL_CHANNELS    16    // Maximum number of audio pool channels
+// NOTE: Following macro depends on config flag that can
+// be externally defined, so, it needs to be outside EXTERNAL_CONFIG_FLAGS
+#if SUPPORT_TRACELOG
+    #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
+#else
+    #define TRACELOG(level, ...) (void)0
+#endif
 
 #endif // CONFIG_H
diff --git a/raylib/src/external/RGFW.h b/raylib/src/external/RGFW.h
deleted file mode 100644
--- a/raylib/src/external/RGFW.h
+++ /dev/null
@@ -1,11074 +0,0 @@
-/*
-*
-*	RGFW 1.7.5-dev
-
-* Copyright (C) 2022-25 ColleagueRiley
-*
-* libpng license
-*
-* 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.
-*
-*
-*/
-
-/*
-	(MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
-	#define RGFW_IMPLEMENTATION - makes it so source code is included with header
-*/
-
-/*
-	#define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
-	#define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
-	#define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
-	#define RGFW_BUFFER - (optional) draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
-	#define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
-	#define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api)
-									This version doesn't work for desktops (I'm pretty sure)
-	#define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
-	#define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
-	#define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
-	#define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
-	#define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
-	#define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
-
-	#define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress)
-	#define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
-	#define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
-	#define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
-	#define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
-	#define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
-	#define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) use XCursor, but don't link it in code, (you'll have to link it with -lXcursor)
-	#define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use Xext, but don't link it in code, (you'll have to link it with -lXext)
-    #define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm (timeBeginPeriod), but don't link it in code, (you'll have to link it with -lwinmm)
-	#define RGFW_NO_WINMM (optional) (windows only) don't use winmm
-	#define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
-	#define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
-	#define RGFW_NO_DWM (windows only) - do not use or link dwmapi
-	#define RGFW_USE_XDL (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 dynamically during runtime (must include XDL.h along with RGFW)
-	#define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
-	#define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
-	#define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included)
-	#define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time
-    #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue)
-
-	#define RGFW_ALLOC x  - choose the default allocation function (defaults to standard malloc)
-	#define RGFW_FREE x  - choose the default deallocation function (defaults to standard free)
-	#define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
-
-	#define RGFW_EXPORT - use when building RGFW
-	#define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
-
-	#define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
-	#define RGFW_bool x - choose what type to use for bool, by default u32 is used
-*/
-
-/*
-Example to get you started :
-
-linux : gcc main.c -lX11 -lXrandr -lGL
-windows : gcc main.c -lopengl32 -lgdi32
-macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit
-
-#define RGFW_IMPLEMENTATION
-#include "RGFW.h"
-
-u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF,    0xFF, 0x00, 0x00, 0xFF,     0xFF, 0x00, 0x00, 0xFF,   0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,     0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
-
-int main() {
-	RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0);
-
-	RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
-
-	while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
-		while (RGFW_window_checkEvent(win)) {
-		    if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape))
-			    break;
-        }
-
-		RGFW_window_swapBuffers(win);
-
-		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-		glClear(GL_COLOR_BUFFER_BIT);
-	}
-
-	RGFW_window_close(win);
-}
-
-	compiling :
-
-	if you wish to compile the library all you have to do is create a new file with this in it
-
-	rgfw.c
-	#define RGFW_IMPLEMENTATION
-	#include "RGFW.h"
-
-	You may also want to add
-	`#define RGFW_EXPORT` when compiling and
-	`#define RGFW_IMPORT`when linking RGFW on it's own:
-	this reduces inline functions and prevents bloat in the object file
-
-	then you can use gcc (or whatever compile you wish to use) to compile the library into object file
-
-	ex. gcc -c RGFW.c -fPIC
-
-	after you compile the library into an object file, you can also turn the object file into an static or shared library
-
-	(commands ar and gcc can be replaced with whatever equivalent your system uses)
-
-	static : ar rcs RGFW.a RGFW.o
-	shared :
-		windows:
-			gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
-		linux:
-			gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
-		macos:
-			gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
-*/
-
-
-
-/*
-	Credits :
-		EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
-
-		stb - This project is heavily inspired by the stb single header files
-
-		GLFW:
-			certain parts of winapi and X11 are very poorly documented,
-			GLFW's source code was referenced and used throughout the project.
-
-		contributors : (feel free to put yourself here if you contribute)
-		krisvers -> code review
-		EimaMei (SaCode) -> code review
-		Code-Nycticebus -> bug fixes
-		Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
-		AICDG (@THISISAGOODNAME) -> vulkan support (example)
-		@Easymode -> support, testing/debugging, bug fixes and reviews
-		Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
-		@lesleyrs -> bug fix, review (OpenGL)
-        Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
-		@DarekParodia -> code review (X11) (C++)
-*/
-
-#if _MSC_VER
-	#pragma comment(lib, "gdi32")
-	#pragma comment(lib, "shell32")
-	#pragma comment(lib, "User32")
-    #pragma warning( push )
-	#pragma warning( disable : 4996 4191 4127)
-    #if _MSC_VER < 600
-        #define RGFW_C89
-    #endif
-#else
-    #if defined(__STDC__) && !defined(__STDC_VERSION__)
-        #define RGFW_C89
-    #endif
-#endif
-
-#ifndef RGFW_USERPTR
-	#define RGFW_USERPTR NULL
-#endif
-
-#ifndef RGFW_UNUSED
-	#define RGFW_UNUSED(x) (void)(x)
-#endif
-
-#ifndef RGFW_ROUND
-	#define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
-#endif
-
-#ifndef RGFW_ALLOC
-	#include <stdlib.h>
-	#define RGFW_ALLOC malloc
-	#define RGFW_FREE free
-#endif
-
-#ifndef RGFW_ASSERT
-	#include <assert.h>
-	#define RGFW_ASSERT assert
-#endif
-
-#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET)
-	#include <string.h>
-#endif
-
-#ifndef RGFW_MEMSET
-	#define RGFW_MEMSET(ptr, value, num) memset(ptr, value, num)
-#endif
-
-#ifndef RGFW_MEMCPY
-	#define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
-#endif
-
-#ifndef RGFW_STRNCMP
-	#define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
-#endif
-
-#ifndef RGFW_STRNCPY
-	#define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
-#endif
-
-#ifndef RGFW_STRSTR
-	#define RGFW_STRSTR(str, substr) strstr(str, substr)
-#endif
-
-#ifndef RGFW_STRTOL
-	/* required for X11 XDnD and X11 Monitor DPI */
-	#include <stdlib.h>
-	#define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
-	#define RGFW_ATOF(num) atof(num)
-#endif
-
-#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
-	#define RGFW_NO_MONITOR
-	#define RGFW_NO_PASSTHROUGH
-#endif
-
-#if defined(RGFW_EXPORT) ||  defined(RGFW_IMPORT)
-	#if defined(_WIN32)
-		#if defined(__TINYC__) && (defined(RGFW_EXPORT) ||  defined(RGFW_IMPORT))
-			#define __declspec(x) __attribute__((x))
-		#endif
-
-		#if defined(RGFW_EXPORT)
-			#define RGFWDEF __declspec(dllexport)
-		#else
-			#define RGFWDEF __declspec(dllimport)
-		#endif
-	#else
-		#if defined(RGFW_EXPORT)
-			#define RGFWDEF __attribute__((visibility("default")))
-		#endif
-	#endif
-    #ifndef RGFWDEF
-        #define RGFWDEF
-    #endif
-#endif
-
-#ifndef RGFWDEF
-	#ifdef RGFW_C89
-		#define RGFWDEF __inline
-	#else
-		#define RGFWDEF inline
-	#endif
-#endif
-
-#ifndef RGFW_ENUM
-	#define RGFW_ENUM(type, name) type name; enum
-#endif
-
-
-#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
-	extern "C" {
-#endif
-
-	/* makes sure the header file part is only defined once by default */
-#ifndef RGFW_HEADER
-
-#define RGFW_HEADER
-
-#include <stddef.h>
-#ifndef RGFW_INT_DEFINED
-	#ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
-		typedef unsigned char       u8;
-		typedef signed char         i8;
-		typedef unsigned short     u16;
-		typedef signed short 	   i16;
-		typedef unsigned long int  u32;
-		typedef signed long int    i32;
-		typedef unsigned long long u64;
-		typedef signed long long   i64;
-	#else /* use stdint standard types instead of c "standard" types */
-		#include <stdint.h>
-
-		typedef uint8_t     u8;
-		typedef int8_t      i8;
-		typedef uint16_t   u16;
-		typedef int16_t    i16;
-		typedef uint32_t   u32;
-		typedef int32_t    i32;
-		typedef uint64_t   u64;
-		typedef int64_t    i64;
-	#endif
-	#define RGFW_INT_DEFINED
-#endif
-
-#ifndef RGFW_BOOL_DEFINED
-    #define RGFW_BOOL_DEFINED
-    typedef u8 RGFW_bool;
-#endif
-
-#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */
-#define RGFW_TRUE (RGFW_bool)1
-#define RGFW_FALSE (RGFW_bool)0
-
-/* these OS macros look better & are standardized */
-/* plus it helps with cross-compiling */
-
-#ifdef __EMSCRIPTEN__
-	#define RGFW_WASM
-
-	#if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
-		#define RGFW_OPENGL
-	#endif
-
-	#ifdef RGFW_EGL
-		#undef RGFW_EGL
-	#endif
-
-	#include <emscripten/html5.h>
-	#include <emscripten/key_codes.h>
-
-	#ifdef RGFW_WEBGPU
-		#include <emscripten/html5_webgpu.h>
-	#endif
-#endif
-
-#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
-	#define RGFW_MACOS_X11
-	#define RGFW_UNIX
-	#undef __APPLE__
-#endif
-
-#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */
-	#define RGFW_WINDOWS
-	/* make sure the correct architecture is defined */
-	#if defined(_WIN64)
-		#define _AMD64_
-		#undef _X86_
-	#else
-		#undef _AMD64_
-		#ifndef _X86_
-			#define _X86_
-		#endif
-	#endif
-
-	#ifndef RGFW_NO_XINPUT
-		#ifdef __MINGW32__ /* try to find the right header */
-			#include <xinput.h>
-		#else
-			#include <XInput.h>
-		#endif
-	#endif
-#endif
-#if defined(RGFW_WAYLAND)
-	#define RGFW_DEBUG /* wayland will be in debug mode by default for now */
-    #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA)
-		#define RGFW_EGL
-		#define RGFW_OPENGL
-		#include <wayland-egl.h>
-	#endif
-
-	#define RGFW_UNIX
-	#include <wayland-client.h>
-#endif
-#if !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11))  && !defined(RGFW_WASM)  && !defined(RGFW_CUSTOM_BACKEND)
-	#define RGFW_MACOS_X11
-	#define RGFW_X11
-	#define RGFW_UNIX
-	#include <X11/Xlib.h>
-	#include <X11/Xutil.h>
-#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11)  && !defined(RGFW_WASM)  && !defined(RGFW_CUSTOM_BACKEND)
-	#define RGFW_MACOS
-	#if !defined(RGFW_BUFFER_BGR)
-		#define RGFW_BUFFER_BGR
-	#else
-		#undef RGFW_BUFFER_BGR
-	#endif
-#endif
-
-#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
-	#define RGFW_EGL
-#endif
-
-#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
-	#define RGFW_OPENGL
-#endif
-
-#ifdef RGFW_EGL
-	#include <EGL/egl.h>
-#elif defined(RGFW_OSMESA)
-	#ifdef RGFW_WINDOWS
-	#define OEMRESOURCE
-	#include <GL/gl.h>
-    	#ifndef GLAPIENTRY
-	#define GLAPIENTRY APIENTRY
-	#endif
-    	#ifndef GLAPI
-	#define GLAPI WINGDIAPI
-    	#endif
-	#endif
-
-	#ifndef __APPLE__
-		#include <GL/osmesa.h>
-	#else
-		#include <OpenGL/osmesa.h>
-	#endif
-#endif
-
-#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
-    #pragma comment(lib, "opengl32")
-#endif
-
-#if defined(RGFW_OPENGL) && defined(RGFW_X11)
-	#ifndef GLX_MESA_swap_control
-		#define  GLX_MESA_swap_control
-	#endif
-	#include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
-#endif
-
-#define RGFW_COCOA_FRAME_NAME NULL
-
-/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions)
-	this is mostly used to allow you to force the use of XWayland
-*/
-RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
-RGFWDEF RGFW_bool RGFW_usingWayland(void);
-/*
-	regular RGFW stuff
-*/
-
-#define RGFW_key u8
-
-typedef RGFW_ENUM(u8, RGFW_eventType) {
-	/*! event codes */
-	RGFW_eventNone = 0, /*!< no event has been sent */
- 	RGFW_keyPressed, /* a key has been pressed */
-	RGFW_keyReleased, /*!< a key has been released */
-	/*! key event note
-		the code of the key pressed is stored in
-		RGFW_event.key
-		!!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
-
-		while a string version is stored in
-		RGFW_event.KeyString
-
-		RGFW_event.keyMod holds the current keyMod
-		this means if CapsLock, NumLock are active or not
-	*/
-	RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
-	RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
-	RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
-	/*! mouse event note
-		the x and y of the mouse can be found in the vector, RGFW_event.point
-
-		RGFW_event.button holds which mouse button was pressed
-	*/
-	RGFW_gamepadConnected, /*!< a gamepad was connected */
-	RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */
-	RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */
-	RGFW_gamepadButtonReleased, /*!< a gamepad button was released */
-	RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */
-	/*! gamepad event note
-		RGFW_event.gamepad holds which gamepad was altered, if any
-		RGFW_event.button holds which gamepad button was pressed
-
-		RGFW_event.axis holds the data of all the axises
-		RGFW_event.axisesCount says how many axises there are
-	*/
-	RGFW_windowMoved, /*!< the window was moved (by the user) */
-	RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
-	RGFW_focusIn, /*!< window is in focus now */
-	RGFW_focusOut, /*!< window is out of focus now */
-	RGFW_mouseEnter, /* mouse entered the window */
-	RGFW_mouseLeave, /* mouse left the window */
-	RGFW_windowRefresh, /* The window content needs to be refreshed */
-
-	/* attribs change event note
-		The event data is sent straight to the window structure
-		with win->r.x, win->r.y, win->r.w and win->r.h
-	*/
-	RGFW_quit, /*!< the user clicked the quit button */
-	RGFW_DND, /*!< a file has been dropped into the window */
-	RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */
-	/* dnd data note
-		The x and y coords of the drop are stored in the vector RGFW_event.point
-
-		RGFW_event.droppedFilesCount holds how many files were dropped
-
-		This is also the size of the array which stores all the dropped file string,
-		RGFW_event.droppedFiles
-	*/
-	RGFW_windowMaximized, /*!< the window was maximized */
-	RGFW_windowMinimized, /*!< the window was minimized */
-	RGFW_windowRestored, /*!< the window was restored */
-	RGFW_scaleUpdated /*!< content scale factor changed */
-};
-
-/*! mouse button codes (RGFW_event.button) */
-typedef RGFW_ENUM(u8, RGFW_mouseButton) {
-	RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
-	RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
-	RGFW_mouseRight, /*!< right mouse button is pressed */
-	RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */
-	RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */
-	RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
-	RGFW_mouseFinal
-};
-
-#ifndef RGFW_MAX_PATH
-#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
-#endif
-#ifndef RGFW_MAX_DROPS
-#define RGFW_MAX_DROPS 260 /* max items you can drop at once */
-#endif
-
-#define RGFW_BIT(x) (1 << x)
-
-/* for RGFW_event.lockstate */
-typedef RGFW_ENUM(u8, RGFW_keymod) {
-	RGFW_modCapsLock = RGFW_BIT(0),
-	RGFW_modNumLock  = RGFW_BIT(1),
-	RGFW_modControl  = RGFW_BIT(2),
-	RGFW_modAlt = RGFW_BIT(3),
-	RGFW_modShift  = RGFW_BIT(4),
-	RGFW_modSuper = RGFW_BIT(5),
-	RGFW_modScrollLock = RGFW_BIT(6)
-};
-
-/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */
-typedef RGFW_ENUM(u8, RGFW_gamepadCodes) {
-	RGFW_gamepadNone = 0, /*!< or PS X button */
-	RGFW_gamepadA, /*!< or PS X button */
-	RGFW_gamepadB, /*!< or PS circle button */
-	RGFW_gamepadY, /*!< or PS triangle button */
-	RGFW_gamepadX, /*!< or PS square button */
-	RGFW_gamepadStart, /*!< start button */
-	RGFW_gamepadSelect, /*!< select button */
-	RGFW_gamepadHome, /*!< home button */
-	RGFW_gamepadUp, /*!< dpad up */
-	RGFW_gamepadDown, /*!< dpad down */
-	RGFW_gamepadLeft, /*!< dpad left */
-	RGFW_gamepadRight, /*!< dpad right */
-	RGFW_gamepadL1, /*!< left bump */
-	RGFW_gamepadL2, /*!< left trigger */
-	RGFW_gamepadR1, /*!< right bumper */
-	RGFW_gamepadR2, /*!< right trigger */
-	RGFW_gamepadL3,  /* left thumb stick */
-	RGFW_gamepadR3, /*!< right thumb stick */
-	RGFW_gamepadFinal
-};
-
-/*! basic vector type, if there's not already a point/vector type of choice */
-#ifndef RGFW_point
-	typedef struct RGFW_point { i32 x, y; } RGFW_point;
-#endif
-
-/*! basic rect type, if there's not already a rect type of choice */
-#ifndef RGFW_rect
-	typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect;
-#endif
-
-/*! basic area type, if there's not already a area type of choice */
-#ifndef RGFW_area
-	typedef struct RGFW_area { u32 w, h; } RGFW_area;
-#endif
-
-#if defined(__cplusplus) && !defined(__APPLE__)
-#define RGFW_POINT(x, y) {(i32)x, (i32)y}
-#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h}
-#define RGFW_AREA(w, h) {(u32)w, (u32)h}
-#else
-#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
-#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
-#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
-#endif
-
-#ifndef RGFW_NO_MONITOR
-	/* monitor mode data | can be changed by the user (with functions)*/
-	typedef struct RGFW_monitorMode {
-		RGFW_area area; /*!< monitor workarea size */
-		u32 refreshRate; /*!< monitor refresh rate */
-		u8 red, blue, green;
-	} RGFW_monitorMode;
-
-	/*! structure for monitor data */
-	typedef struct RGFW_monitor {
-		i32 x, y; /*!< x - y of the monitor workarea */
-		char name[128]; /*!< monitor name */
-		float scaleX, scaleY; /*!< monitor content scale */
-		float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI)  */
-		float physW, physH; /*!< monitor physical size in inches */
-
-		RGFW_monitorMode mode;
-	} RGFW_monitor;
-
-	/*! get an array of all the monitors (max 6) */
-	RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len);
-	/*! get the primary monitor */
-	RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
-
-	typedef RGFW_ENUM(u8, RGFW_modeRequest) {
-		RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
-		RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
-		RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
-		RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
-	};
-
-	/*! request a specific mode */
-	RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request);
-	/*! check if 2 monitor modes are the same */
-	RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request);
-#endif
-
-/* RGFW mouse loading */
-typedef void RGFW_mouse;
-
-/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */
-RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels);
-/*!< frees RGFW_mouse data */
-RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
-
-/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */
-/*! Event structure for checking/getting events */
-typedef struct RGFW_event {
-	RGFW_eventType type; /*!< which event has been sent?*/
-	RGFW_point point; /*!< mouse x, y of event (or drop point) */
-	RGFW_point vector; /*!< raw mouse movement */
-	float scaleX, scaleY; /*!< DPI scaling */
-
-	RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
-	u8 keyChar; /*!< mapped key char of the event */
-
-	RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
-	RGFW_keymod keyMod;
-
-	u8 button; /* !< which mouse (or gamepad) button was pressed */
-	double scroll; /*!< the raw mouse scroll value */
-
-	u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */
-	u8 axisesCount; /*!< number of axises */
-
-	u8 whichAxis; /* which axis was effected */
-	RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */
-
-	/*! drag and drop data */
-	/* 260 max paths with a max length of 260 */
-	char** droppedFiles; /*!< dropped files */
-	size_t droppedFilesCount; /*!< house many files were dropped */
-
-	void* _win; /*!< the window this event applies too (for event queue events) */
-} RGFW_event;
-
-/*! source data for the window (used by the APIs) */
-#ifdef RGFW_WINDOWS
-typedef struct RGFW_window_src {
-	HWND window; /*!< source window */
-	HDC hdc; /*!< source HDC */
-	i32 wOffset; /*!< width offset for window */
-	i32 hOffset; /*!< height offset for window */
-	HICON hIconSmall, hIconBig; /*!< source window icons */
-	#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
-		HGLRC ctx; /*!< source graphics context */
-	#elif defined(RGFW_OSMESA)
-		OSMesaContext ctx;
-	#elif defined(RGFW_EGL)
-		EGLSurface EGL_surface;
-		EGLDisplay EGL_display;
-		EGLContext EGL_context;
-	#endif
-
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-		HDC hdcMem;
-		HBITMAP bitmap;
-		u8* bitmapBits;
-	#endif
-	RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */
-} RGFW_window_src;
-#elif defined(RGFW_UNIX)
-typedef struct RGFW_window_src {
-#if defined(RGFW_X11)
-	Display* display; /*!< source display */
-	Window window; /*!< source window */
-	#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
-		GLXContext ctx; /*!< source graphics context */
-        GLXFBConfig bestFbc; 
-	#elif defined(RGFW_OSMESA)
-		OSMesaContext ctx;
-	#elif defined(RGFW_EGL)
-		EGLSurface EGL_surface;
-		EGLDisplay EGL_display;
-		EGLContext EGL_context;
-	#endif
-
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-			XImage* bitmap;
-	#endif
-	GC gc;
-	XVisualInfo visual;
-    #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
-        i64 counter_value;
-        XID counter;
-    #endif
-    RGFW_rect r;
-#endif /* RGFW_X11 */
-#if defined(RGFW_WAYLAND)
-	struct wl_display* wl_display;
-	struct wl_surface* surface;
-	struct wl_buffer* wl_buffer;
-	struct wl_keyboard* keyboard;
-
-	struct wl_compositor* compositor;
-	struct xdg_surface* xdg_surface;
-	struct xdg_toplevel* xdg_toplevel;
-	struct zxdg_toplevel_decoration_v1* decoration;
-	struct xdg_wm_base* xdg_wm_base;
-	struct wl_shm* shm;
-	struct wl_seat *seat;
-	u8* buffer;
-	#if defined(RGFW_EGL)
-		struct wl_egl_window* eglWindow;
-	#endif
-	#if defined(RGFW_EGL) && !defined(RGFW_X11)
-			EGLSurface EGL_surface;
-			EGLDisplay EGL_display;
-			EGLContext EGL_context;
-	#elif defined(RGFW_OSMESA) && !defined(RGFW_X11)
-		OSMesaContext ctx;
-	#endif
-#endif /* RGFW_WAYLAND */
-} RGFW_window_src;
-#endif /* RGFW_UNIX */
-#if defined(RGFW_MACOS)
-typedef struct RGFW_window_src {
-	void* window;
-#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
-		void* ctx; /*!< source graphics context */
-#elif defined(RGFW_OSMESA)
-		OSMesaContext ctx;
-#elif defined(RGFW_EGL)
-		EGLSurface EGL_surface;
-		EGLDisplay EGL_display;
-		EGLContext EGL_context;
-#endif
-
-	void* view; /* apple viewpoint thingy */
-	void* mouse;
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-#endif
-} RGFW_window_src;
-#elif defined(RGFW_WASM)
-typedef struct RGFW_window_src {
-	#if defined(RGFW_WEBGPU)
-		WGPUInstance ctx;
-        WGPUDevice device;
-        WGPUQueue queue;
-	#elif defined(RGFW_OSMESA)
-		OSMesaContext ctx;
-	#else
-		EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
-	#endif
-} RGFW_window_src;
-#endif
-
-/*! Optional arguments for making a windows */
-typedef RGFW_ENUM(u32, RGFW_windowFlags) {
-	RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */
-	RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */
-	RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */
-	RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */
-	RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */
-	RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */
-	RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */
-	RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */
-	RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */
-	RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */
-	RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */
-	RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */
-	RGFW_windowMaximize = RGFW_BIT(12),
-	RGFW_windowCenterCursor = RGFW_BIT(13),
-	RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */
-	RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */
-	RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */
-	RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */
-	RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */
-	RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize
-};
-
-typedef struct RGFW_window {
-	RGFW_window_src src; /*!< src window data */
-
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
-	/* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
-	RGFW_area bufferSize;
-#endif
-	void* userPtr; /* ptr for usr data */
-
-	RGFW_event event; /*!< current event */
-
-	RGFW_rect r; /*!< the x, y, w and h of the struct */
-    
-    /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
-    RGFW_key exitKey;     
-	RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
-    
-	u32 _flags; /*!< windows flags (for RGFW to check) */
-	RGFW_rect _oldRect; /*!< rect before fullscreen */
-} RGFW_window; /*!< window structure for managing the window */
-
-#if defined(RGFW_X11) || defined(RGFW_MACOS)
-	typedef u64 RGFW_thread; /*!< thread type unix */
-#else
-	typedef void* RGFW_thread; /*!< thread type for windows */
-#endif
-
-/*! scale monitor to window size */
-RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win);
-
-/** * @defgroup Window_management
-* @{ */
-
-
-/*!
- * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
- * by default the class name will == the root window's name
-*/
-RGFWDEF void RGFW_setClassName(const char* name);
-RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */
-
-/*! (cocoa only) change directory to resource folder */
-RGFWDEF void RGFW_moveToMacOSResourceDir(void);
-
-/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */
-
-RGFWDEF RGFW_window* RGFW_createWindow(
-	const char* name, /* name of the window */
-	RGFW_rect rect, /* rect of window */
-	RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/
-); /*!< function to create a window and struct */
-
-RGFWDEF RGFW_window* RGFW_createWindowPtr(
-	const char* name, /* name of the window */
-	RGFW_rect rect, /* rect of window */
-	RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */
-	RGFW_window* win /* ptr to the window struct you want to use */
-); /*!< function to create a window (without allocating a window struct) */
-
-RGFWDEF void RGFW_window_initBuffer(RGFW_window* win);
-RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area);
-RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area);
-
-/*! set the window flags (will undo flags if they don't match the old ones) */
-RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
-
-/*! get the size of the screen to an area struct */
-RGFWDEF RGFW_area RGFW_getScreenSize(void);
-
-
-/*!
-	this function checks an *individual* event (and updates window structure attributes)
-	this means, using this function without a while loop may cause event lag
-
-	ex.
-
-	while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
-
-	this function is optional if you choose to use event callbacks,
-	although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
-*/
-
-RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
-
-/*!
-	for RGFW_window_eventWait and RGFW_window_checkEvents
-	waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL`
-			  if waitMS == 0, the loop will not wait for events
-			  if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
-			  if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
-*/
-typedef RGFW_ENUM(i32, RGFW_eventWait) {
-	RGFW_eventNoWait = 0,
-	RGFW_eventWaitNext = -1
-};
-
-/*! sleep until RGFW gets an event or the timer ends (defined by OS) */
-RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
-
-/*!
-	check all the events until there are none left.
-	This should only be used if you're using callbacks only
-*/
-RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
-
-/*!
-	tell RGFW_window_eventWait to stop waiting (to be ran from another thread)
-*/
-RGFWDEF void RGFW_stopCheckEvents(void);
-
-/*! window managment functions */
-RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
-
-/*! move a window to a given point */
-RGFWDEF void RGFW_window_move(RGFW_window* win,
-	RGFW_point v /*!< new pos */
-);
-
-#ifndef RGFW_NO_MONITOR
-	/*! move window to a specific monitor */
-	RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
-#endif
-
-/*! resize window to a current size/area */
-RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
-	RGFW_area a /*!< new size */
-);
-
-/*! set window aspect ratio */
-RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a);
-/*! set the minimum dimensions of a window */
-RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
-/*! set the maximum dimensions of a window */
-RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
-
-RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */
-RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */
-RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */
-RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */
-RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */
-RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */
-RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
-RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
-RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */
-RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */
-
-RGFWDEF RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win);
-
-/*! if the window should have a border or not (borderless) based on bool value of `border` */
-RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
-RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
-
-/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/
-RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
-/*! check if DND is allowed */
-RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
-
-
-#ifndef RGFW_NO_PASSTHROUGH
-	/*! turn on / off mouse passthrough */
-	RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
-#endif
-
-/*! rename window to a given string */
-RGFWDEF void RGFW_window_setName(RGFW_window* win,
-	const char* name
-);
-
-RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */
-	u8* icon /*!< icon bitmap */,
-	RGFW_area a /*!< width and height of the bitmap */,
-	i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
-); /*!< image MAY be resized by default, set both the taskbar and window icon */
-
-typedef RGFW_ENUM(u8, RGFW_icon) {
-	RGFW_iconTaskbar = RGFW_BIT(0),
-	RGFW_iconWindow = RGFW_BIT(1),
-	RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
-};
-RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type);
-
-/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */
-RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
-
-/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */
-RGFWDEF	RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
-
-RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
-/*
-	Locks cursor at the center of the window
-	win->event.point becomes raw mouse movement data
-
-	this is useful for a 3D camera
-*/
-RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
-/*! if the mouse is held by RGFW */
-RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win);
-/*! stop holding the mouse and let it move freely */
-RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
-
-/*! hide the window */
-RGFWDEF void RGFW_window_hide(RGFW_window* win);
-/*! show the window */
-RGFWDEF void RGFW_window_show(RGFW_window* win);
-
-/*
-	makes it so `RGFW_window_shouldClose` returns true or overrides a window close
-	by modifying window flags
-*/
-RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
-
-/*! where the mouse is on the screen */
-RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
-
-/*! where the mouse is on the window */
-RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
-
-/*! show the mouse or hide the mouse */
-RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
-/*! if the mouse is hidden */
-RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win);
-/*! move the mouse to a given point */
-RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
-
-/*! if the window should close (RGFW_close was sent or escape was pressed) */
-RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
-/*! if the window is fullscreen */
-RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
-/*! if the window is hidden */
-RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
-/*! if the window is minimized */
-RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
-/*! if the window is maximized */
-RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
-/*! if the window is floating */
-RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
-/** @} */
-
-/** * @defgroup Monitor
-* @{ */
-
-#ifndef RGFW_NO_MONITOR
-/*
-	scale the window to the monitor.
-	This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation
-*/
-RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
-/*! get the struct of the window's monitor  */
-RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
-#endif
-
-/** @} */
-
-/** * @defgroup Input
-* @{ */
-
-/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus. */
-RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/
-
-RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */
-
-RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */
-RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */
-
-/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
-RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */);
-
-/*! if a mouse button is pressed */
-RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
-/*! if a mouse button is held */
-RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
-/*! if a mouse button was released */
-RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
-/*! if a mouse button was pressed (checks previous state only) */
-RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
-/** @} */
-
-/** * @defgroup Clipboard
-* @{ */
-typedef ptrdiff_t RGFW_ssize_t;
-
-RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
-/*! read clipboard data or send a NULL str to just get the length of the clipboard data */
-RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
-RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
-/** @} */
-
-
-
-/** * @defgroup error handling
-* @{ */
-typedef RGFW_ENUM(u8, RGFW_debugType) {
-	RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
-};
-
-typedef RGFW_ENUM(u8, RGFW_errorCode) {
-	RGFW_noError = 0, /*!< no error */
-	RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
-	RGFW_errWayland,
-	RGFW_errDirectXContext,
-	RGFW_errIOKit,
-	RGFW_errClipboard,
-	RGFW_errFailedFuncLoad,
-	RGFW_errBuffer,
-	RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
-	RGFW_warningWayland, RGFW_warningOpenGL
-};
-
-typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext;
-
-#if defined(__cplusplus) && !defined(__APPLE__)
-#define RGFW_DEBUG_CTX(win, err) {win, NULL, err}
-#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0}
-#else
-#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err}
-#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0}
-#endif
-
-typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
-RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func);
-RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
-/** @} */
-
-/**
-
-
-	event callbacks.
-	These are completely optional, so you can use the normal
-	RGFW_checkEvent() method if you prefer that
-
-* @defgroup Callbacks
-* @{
-*/
-
-/*! RGFW_windowMoved, the window and its new rect value  */
-typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r);
-/*! RGFW_windowResized, the window and its new rect value  */
-typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r);
-/*! RGFW_windowRestored, the window and its new rect value  */
-typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r);
-/*! RGFW_windowMaximized, the window and its new rect value  */
-typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r);
-/*! RGFW_windowMinimized, the window and its new rect value  */
-typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r);
-/*! RGFW_quit, the window that was closed */
-typedef void (* RGFW_windowQuitfunc)(RGFW_window* win);
-/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */
-typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus);
-/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
-typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status);
-/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse  */
-typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector);
-/*! RGFW_DNDInit, the window, the point of the drop on the windows */
-typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
-/*! RGFW_windowRefresh, the window that needs to be refreshed */
-typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win);
-/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */
-typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed);
-/*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release)  */
-typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed);
-/*! RGFW_gamepadButtonPressed, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
-typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed);
-/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */
-typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis);
-/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */
-typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected);
-/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */
-typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount);
-/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */
-typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY);
-
-/*! set callback for a window move event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func);
-/*! set callback for a window resize event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func);
-/*! set callback for a window quit event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func);
-/*! set callback for a mouse move event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func);
-/*! set callback for a window refresh event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func);
-/*! set callback for a window focus change event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
-/*! set callback for a mouse notify event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func);
-/*! set callback for a drop event event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
-/*! set callback for a start of a drop event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
-/*! set callback for a key (press / release) event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
-/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func);
-/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func);
-/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func);
-/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */
-RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func);
-/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */
-RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func);
-/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */
-RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func);
-/*! set call back for when window is restored. Returns the previous callback function (if it was set) */
-RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func);
-/*! set callback for when the DPI changes. Returns previous callback function (if it was set)  */
-RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func);
-/** @} */
-
-/** * @defgroup Threads
-* @{ */
-
-#ifndef RGFW_NO_THREADS
-/*! threading functions */
-
-/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */
-/*
-	I'd suggest you use sili's threading functions instead
-	if you're going to use sili
-	which is a good idea generally
-*/
-
-#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND)
-	typedef void* (* RGFW_threadFunc_ptr)(void*);
-#else
-	typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
-#endif
-
-RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */
-RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */
-RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
-RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority  */
-#endif
-
-/** @} */
-
-/** * @defgroup gamepad
-* @{ */
-
-typedef RGFW_ENUM(u8, RGFW_gamepadType) {
-	RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown
-};
-
-/*! gamepad count starts at 0*/
-RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
-RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
-RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
-RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
-RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis);
-RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller);
-RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win);
-RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller);
-
-/** @} */
-
-/** * @defgroup graphics_API
-* @{ */
-
-/*!< make the window the current opengl drawing context
-
-	NOTE:
- 	if you want to switch the graphics context's thread,
-	you have to run RGFW_window_makeCurrent(NULL); on the old thread
-	then RGFW_window_makeCurrent(valid_window) on the new thread
-*/
-RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
-
-/*! get current RGFW window graphics context */
-RGFWDEF RGFW_window* RGFW_getCurrent(void);
-
-/* supports openGL, directX, OSMesa, EGL and software rendering */
-RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
-RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
-/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval)  */
-RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win);
-
-typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */
-
-/*! native API functions */
-#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
-/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */
-RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win);
-/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */
-RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win);
-
-/*! OpenGL init hints */
-typedef RGFW_ENUM(u8, RGFW_glHints)  {
-	RGFW_glStencil = 0,  /*!< set stencil buffer bit size (8 by default) */
-	RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */
-	RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */
-	RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */
-	RGFW_glDoubleBuffer, /*!< request double buffering */
-	RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */
-	RGFW_glDepth,
-	RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */
-	RGFW_glSRGB, /*!< request sRGA */
-	RGFW_glRobustness, /*!< request a robust context */
-	RGFW_glDebug, /*!< request opengl debugging */
-	RGFW_glNoError, /*!< request no opengl errors */
-	RGFW_glReleaseBehavior,
-	RGFW_glProfile,
-	RGFW_glMajor, RGFW_glMinor,
-	RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */
-	RGFW_releaseFlush = 0,  RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */
-	RGFW_glCore = 0,  RGFW_glCompatibility /*!< RGFW_glProfile options */
-};
-RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value);
-RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len);	/*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */
-RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
-RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
-RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval  */
-void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/
-
-RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len);	/*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */
-#endif
-#ifdef RGFW_VULKAN
-	#if defined(RGFW_WAYLAND) && defined(RGFW_X11)
-    	#define VK_USE_PLATFORM_WAYLAND_KHR
-		#define VK_USE_PLATFORM_XLIB_KHR
-        #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
-    #elif defined(RGFW_WAYLAND)
-		#define VK_USE_PLATFORM_WAYLAND_KHR
-		#define VK_USE_PLATFORM_XLIB_KHR
-        #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
-    #elif defined(RGFW_X11)
-		#define VK_USE_PLATFORM_XLIB_KHR
-		#define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
-	#elif defined(RGFW_WINDOWS)
-		#define VK_USE_PLATFORM_WIN32_KHR
-		#define OEMRESOURCE
-		#define RGFW_VK_SURFACE "VK_KHR_win32_surface"
-	#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
-		#define VK_USE_PLATFORM_MACOS_MVK
-		#define RGFW_VK_SURFACE "VK_MVK_macos_surface"
-	#else
-		#define RGFW_VK_SURFACE NULL
-	#endif
-
-/* if you don't want to use the above macros */
-RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */
-
-#include <vulkan/vulkan.h>
-
-RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
-RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
-#endif
-#ifdef RGFW_DIRECTX
-#ifndef RGFW_WINDOWS
-	#undef RGFW_DIRECTX
-#else
-	#define OEMRESOURCE
-	#include <dxgi.h>
-
-	#ifndef __cplusplus
-		#define __uuidof(T) IID_##T
-	#endif
-RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
-#endif
-#endif
-
-/** @} */
-
-/** * @defgroup Supporting
-* @{ */
-
-/*! optional init/deinit function */
-RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */
-RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */
-
-RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open  */
-RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */
-RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
-RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */
-RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */
-RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */
-
-/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
-RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap);
-
-/*!< change which window is the root window */
-RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
-RGFWDEF RGFW_window* RGFW_getRootWindow(void);
-
-/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */
-/* these are all used internally by RGFW */
-void RGFW_eventQueuePush(RGFW_event event);
-RGFW_event* RGFW_eventQueuePop(RGFW_window* win);
-
-/* for C++ / C89 */
-#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); }
-
-/*!
-	key codes and mouse icon enums
-*/
-#undef RGFW_key
-typedef RGFW_ENUM(u8, RGFW_key) {
-	RGFW_keyNULL = 0,
-	RGFW_escape = '\033',
-	RGFW_backtick = '`',
-	RGFW_0 = '0',
-	RGFW_1 = '1',
-	RGFW_2 = '2',
-	RGFW_3 = '3',
-	RGFW_4 = '4',
-	RGFW_5 = '5',
-	RGFW_6 = '6',
-	RGFW_7 = '7',
-	RGFW_8 = '8',
-	RGFW_9 = '9',
-
-	RGFW_minus = '-',
-	RGFW_equals = '=',
-	RGFW_backSpace = '\b',
-	RGFW_tab = '\t',
-	RGFW_space = ' ',
-
-	RGFW_a = 'a',
-	RGFW_b = 'b',
-	RGFW_c = 'c',
-	RGFW_d = 'd',
-	RGFW_e = 'e',
-	RGFW_f = 'f',
-	RGFW_g = 'g',
-	RGFW_h = 'h',
-	RGFW_i = 'i',
-	RGFW_j = 'j',
-	RGFW_k = 'k',
-	RGFW_l = 'l',
-	RGFW_m = 'm',
-	RGFW_n = 'n',
-	RGFW_o = 'o',
-	RGFW_p = 'p',
-	RGFW_q = 'q',
-	RGFW_r = 'r',
-	RGFW_s = 's',
-	RGFW_t = 't',
-	RGFW_u = 'u',
-	RGFW_v = 'v',
-	RGFW_w = 'w',
-	RGFW_x = 'x',
-	RGFW_y = 'y',
-	RGFW_z = 'z',
-
-	RGFW_period = '.',
-	RGFW_comma = ',',
-	RGFW_slash = '/',
-	RGFW_bracket = '[',
-    RGFW_closeBracket = ']',   
-    RGFW_semicolon = ';',
-	RGFW_apostrophe = '\'',
-	RGFW_backSlash = '\\',
-	RGFW_return = '\n',
-	RGFW_enter = RGFW_return,
-
-	RGFW_delete = '\177', /* 127 */
-
-	RGFW_F1,
-	RGFW_F2,
-	RGFW_F3,
-	RGFW_F4,
-	RGFW_F5,
-	RGFW_F6,
-	RGFW_F7,
-	RGFW_F8,
-	RGFW_F9,
-	RGFW_F10,
-	RGFW_F11,
-	RGFW_F12,
-
-	RGFW_capsLock,
-	RGFW_shiftL,
-	RGFW_controlL,
-	RGFW_altL,
-	RGFW_superL,
-	RGFW_shiftR,
-	RGFW_controlR,
-	RGFW_altR,
-	RGFW_superR,
-	RGFW_up,
-	RGFW_down,
-	RGFW_left,
-	RGFW_right,
-	RGFW_insert,
-	RGFW_end,
-	RGFW_home,
-	RGFW_pageUp,
-	RGFW_pageDown,
-
-	RGFW_numLock,
-	RGFW_KP_Slash,
-	RGFW_multiply,
-	RGFW_KP_Minus,
-	RGFW_KP_1,
-	RGFW_KP_2,
-	RGFW_KP_3,
-	RGFW_KP_4,
-	RGFW_KP_5,
-	RGFW_KP_6,
-	RGFW_KP_7,
-	RGFW_KP_8,
-	RGFW_KP_9,
-	RGFW_KP_0,
-	RGFW_KP_Period,
-	RGFW_KP_Return,
-	RGFW_scrollLock,
-    RGFW_printScreen,
-    RGFW_pause,
-    RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
- };
-
-
-/*! converts api keycode to the RGFW unmapped/physical key */
-RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode);
-/*! converts RGFW keycode to the unmapped/physical api key */
-RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode);
-/*! converts RGFW keycode to the mapped keychar */
-RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode);
-
-typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
-	RGFW_mouseNormal = 0,
-	RGFW_mouseArrow,
-	RGFW_mouseIbeam,
-	RGFW_mouseCrosshair,
-	RGFW_mousePointingHand,
-	RGFW_mouseResizeEW,
-	RGFW_mouseResizeNS,
-	RGFW_mouseResizeNWSE,
-	RGFW_mouseResizeNESW,
-	RGFW_mouseResizeAll,
-	RGFW_mouseNotAllowed,
-    RGFW_mouseIconFinal = 16 /* padding for alignment */
-};
-/** @} */
-
-#endif /* RGFW_HEADER */
-#if defined(RGFW_X11) || defined(RGFW_WAYLAND)
-	#define RGFW_OS_BASED_VALUE(l, w, m, h) l
-#elif defined(RGFW_WINDOWS)
-	#define RGFW_OS_BASED_VALUE(l, w, m, h) w
-#elif defined(RGFW_MACOS)
-	#define RGFW_OS_BASED_VALUE(l, w, m, h) m
-#elif defined(RGFW_WASM)
-	#define RGFW_OS_BASED_VALUE(l, w, m, h) h
-#endif
-
-
-#ifdef RGFW_IMPLEMENTATION
-RGFW_bool RGFW_useWaylandBool = 1;
-void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland;  }
-RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; }
-
-#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND)
-#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland
-#define RGFW_WAYLAND_LABEL wayland:; 
-#else
-#define RGFW_GOTO_WAYLAND(fallback)
-#define RGFW_WAYLAND_LABEL 
-#endif
-
-char* RGFW_clipboard_data;
-void RGFW_clipboard_switch(char* newstr);
-void RGFW_clipboard_switch(char* newstr) {
-	if (RGFW_clipboard_data != NULL)
-		RGFW_FREE(RGFW_clipboard_data);
-	RGFW_clipboard_data =  newstr;
-}
-
-#define RGFW_CHECK_CLIPBOARD() \
-	if (size <= 0 && RGFW_clipboard_data != NULL) \
-		return (const char*)RGFW_clipboard_data; \
-	else if (size <= 0) \
-		return "\0";
-
-const char* RGFW_readClipboard(size_t* len) {
-	RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
-    RGFW_CHECK_CLIPBOARD();
-    char* str = (char*)RGFW_ALLOC((size_t)size);
-    RGFW_ASSERT(str != NULL);
-    str[0] = '\0';
-
-    size = RGFW_readClipboardPtr(str, (size_t)size);
-
-    RGFW_CHECK_CLIPBOARD();
-
-	if (len != NULL) *len = (size_t)size;
-
-	RGFW_clipboard_switch(str);
-	return (const char*)str;
-}
-
-RGFW_debugfunc RGFW_debugCallback = NULL;
-RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) {
-	RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback;
-	RGFW_debugCallback = func;
-	return RGFW_debugCallbackPrev;
-}
-
-#ifdef RGFW_DEBUG
-#include <stdio.h>
-#endif
-
-void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) {
-	if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg);
-	#ifdef RGFW_DEBUG
-	switch (type) {
-		case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break;
-		case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break;
-		case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break;
-		default: break;
-	}
-
-	switch (err) {
-		#ifdef RGFW_BUFFER
-		case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break;
-		#endif
-		case RGFW_infoMonitor: printf(": scale (%s):\n   rect: {%i, %i, %i, %i}\n   physical size:%f %f\n   scale: %f %f\n   pixelRatio: %f\n   refreshRate: %i\n   depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break;
-		case RGFW_infoWindow: printf("  with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break;
-		case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break;
-		default: printf("\n");
-	}
-	#endif
-}
-
-u64 RGFW_timerOffset = 0;
-void RGFW_setTime(double time) {
-    RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq());
-}
-
-double RGFW_getTime(void) {
-	return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq());
-}
-
-u64 RGFW_getTimeNS(void) {
-	return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq());
-}
-
-/*
-RGFW_IMPLEMENTATION starts with generic RGFW defines
-
-This is the start of keycode data
-*/
-
-
-
-/*
-	the c++ compiler doesn't support setting up an array like,
-	we'll have to do it during runtime using a function & this messy setup
-*/
-
-#ifndef RGFW_CUSTOM_BACKEND
-
-#if !defined(__cplusplus) && !defined(RGFW_C89)
-#define RGFW_NEXT ,
-#define RGFW_MAP
-#else
-#define RGFW_NEXT ;
-#define RGFW_MAP RGFW_keycodes
-#endif
-
-u32 RGFW_apiKeycodes[RGFW_keyLast] = { 0 };
-
-u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = {
-#if defined(__cplusplus) || defined(RGFW_C89)
-	0
-};
-void RGFW_init_keys(void);
-void RGFW_init_keys(void) {
-#endif
-	RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick 		RGFW_NEXT
-
-	RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 					RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1						RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2						RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3						RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4						RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period             			RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma               			RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash               			RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket      			RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket             RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon                 RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe                 			RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL,
-	#if !defined(RGFW_MACOS) && !defined(RGFW_WASM)
-	RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR,
-	RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR,
-	#endif
-	RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9                 		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 111, DOM_VK_F12)] = RGFW_F12               RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right              RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end                  		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp                		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown            RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape                   		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home                    		RGFW_NEXT
-	RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock               RGFW_NEXT
-    RGFW_MAP [RGFW_OS_BASED_VALUE(107, 0x137, 105, DOM_VK_PRINTSCREEN)] = RGFW_printScreen              RGFW_NEXT
-    RGFW_MAP [RGFW_OS_BASED_VALUE(128, 0x045, 113, DOM_VK_PAUSE)] = RGFW_pause               RGFW_NEXT
-#if defined(__cplusplus) || defined(RGFW_C89)
-}
-#else
-};
-#endif
-
-#undef RGFW_NEXT
-#undef RGFW_MAP
-
-u32 RGFW_apiKeyToRGFW(u32 keycode) {
-    #if defined(__cplusplus) || defined(RGFW_C89)
-	if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) {
-		RGFW_init_keys();
-	}
-	#endif
-
-	/* make sure the key isn't out of bounds */
-	if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
-		return 0;
-
-	return RGFW_keycodes[keycode];
-}
-
-u32 RGFW_rgfwToApiKey(u32 keycode) {
-	if (RGFW_apiKeycodes[RGFW_backtick] != RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)) {
-        for (u32 i = 0; i < RGFW_keyLast; i++) {
-            for (u32 y = 0; y < sizeof(RGFW_keycodes); y++) {
-                if (RGFW_keycodes[y] == i) {
-                    RGFW_apiKeycodes[i] = y;
-                    break;
-                }
-            }
-        }
-    }
-
-	/* make sure the key isn't out of bounds */
-	if (keycode > sizeof(RGFW_apiKeycodes) / sizeof(u32))
-		return 0;
-
-	return RGFW_apiKeycodes[keycode];
-}
-#endif /* RGFW_CUSTOM_BACKEND */
-
-typedef struct {
-	RGFW_bool current  : 1;
-	RGFW_bool prev  : 1;
-} RGFW_keyState;
-
-RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} };
-
-RGFWDEF void RGFW_resetKeyPrev(void);
-void RGFW_resetKeyPrev(void) {
-	size_t i; /*!< reset each previous state  */
-    for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0;
-}
-RGFWDEF void RGFW_resetKey(void);
-void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); }
-/*
-	this is the end of keycode data
-*/
-
-/* gamepad data */
-RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */
-RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */
-
-RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */
-i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */
-char RGFW_gamepads_name[4][128]; /*!< gamepad names */
-u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */
-
-/*
-	event callback defines start here
-*/
-
-
-/*
-	These exist to avoid the
-	if (func == NULL) check
-	for (allegedly) better performance
-
-	RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning
-*/
-static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
-static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
-static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
-static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
-static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
-static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
-static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
-static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
-static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);}
-static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
-static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
-static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);}
-static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
-static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
-static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); }
-static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);}
-static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
-static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); }
-
-#define RGFW_CALLBACK_DEFINE(x, x2) \
-RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \
-RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \
-    RGFW_##x##func prev = RGFW_##x##Callback; \
-    RGFW_##x##Callback = func; \
-    return prev; \
-}
-RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized)
-RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized)
-RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored)
-RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved)
-RGFW_CALLBACK_DEFINE(windowResized, WindowResized)
-RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit)
-RGFW_CALLBACK_DEFINE(mousePos, MousePos)
-RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh)
-RGFW_CALLBACK_DEFINE(focus, Focus)
-RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify)
-RGFW_CALLBACK_DEFINE(dnd, Dnd)
-RGFW_CALLBACK_DEFINE(dndInit, DndInit)
-RGFW_CALLBACK_DEFINE(key, Key)
-RGFW_CALLBACK_DEFINE(mouseButton, MouseButton)
-RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton)
-RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis)
-RGFW_CALLBACK_DEFINE(gamepad, Gamepad)
-RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated)
-#undef RGFW_CALLBACK_DEFINE
-
-void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
-	RGFW_window_eventWait(win, waitMS);
-
-	while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
-		if (win->event.type == RGFW_quit) return;
-	}
-
-	#ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */
-		RGFW_sleep(0);
-	#endif
-}
-
-void RGFW_window_checkMode(RGFW_window* win);
-void RGFW_window_checkMode(RGFW_window* win) {
-	if (RGFW_window_isMinimized(win)) {
-		win->_flags |= RGFW_windowMinimize;
-		RGFW_windowMinimizedCallback(win, win->r);
-	} else if (RGFW_window_isMaximized(win)) {
-		win->_flags |= RGFW_windowMaximize;
-		RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
-		RGFW_windowMaximizedCallback(win, win->r);
-	} else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
-				(win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) {
-		win->_flags &= ~(u32)RGFW_windowMinimize;
-		if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize;
-		RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
-		RGFW_windowRestoredCallback(win, win->r);
-	}
-}
-
-/*
-no more event call back defines
-*/
-
-#define SET_ATTRIB(a, v) { \
-    RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
-    attribs[index++] = a; \
-    attribs[index++] = v; \
-}
-
-#define RGFW_EVENT_PASSED 		RGFW_BIT(24) /* if a queued event was passed */
-#define RGFW_EVENT_QUIT 		RGFW_BIT(25) /* the window close button was pressed */
-#define RGFW_HOLD_MOUSE			RGFW_BIT(26) /*!< hold the moues still */
-#define RGFW_MOUSE_LEFT 		RGFW_BIT(27) /* if mouse left the window */
-#define RGFW_WINDOW_ALLOC 		RGFW_BIT(28) /* if window was allocated by RGFW */
-#define RGFW_BUFFER_ALLOC 		RGFW_BIT(29) /* if window.buffer was allocated by RGFW */
-#define RGFW_WINDOW_INIT 		RGFW_BIT(30) /* if window.buffer was allocated by RGFW */
-#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE |  RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus)
-
-RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) {
-	RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
-	RGFW_ASSERT(win != NULL);
-    win->_flags = RGFW_WINDOW_ALLOC;
-    return RGFW_createWindowPtr(name, rect, flags, win);
-}
-
-#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
-	#define XDL_IMPLEMENTATION
-	#include "XDL.h"
-#endif
-
-#define RGFW_MAX_EVENTS 32
-typedef struct RGFW_globalStruct {
-    RGFW_window* root;
-    RGFW_window* current;
-    i32 windowCount;
-    i32 eventLen;
-    i32 eventIndex;
-
-    #ifdef RGFW_X11
-        Display* display;
-        Window helperWindow;
-    	char* clipboard; /* for writing to the clipboard selection */
-	    size_t clipboard_len;
-    #endif
-    #ifdef RGFW_WAYLAND
-	    struct wl_display* wl_display;
-    #endif
-    #if defined(RGFW_X11) || defined(RGFW_WINDOWS) || defined(RGFW_WAYLAND)
-        RGFW_mouse* hiddenMouse;
-    #endif
-    RGFW_event events[RGFW_MAX_EVENTS];
-
-} RGFW_globalStruct;
-#if !defined(RGFW_C89) && !defined(__cplusplus)
-RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0};
-#define _RGFW_init RGFW_TRUE
-#else
-RGFW_bool _RGFW_init = RGFW_FALSE;
-RGFW_globalStruct _RGFW;
-#endif
-
-void RGFW_eventQueuePush(RGFW_event event) {
-	if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return;
-	_RGFW.events[_RGFW.eventLen] = event;
-    _RGFW.eventLen++;
-}
-
-RGFW_event* RGFW_eventQueuePop(RGFW_window* win) {
-	RGFW_event* ev; 
-    if (_RGFW.eventLen == 0) return NULL;
-
-	ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex];
-
-    _RGFW.eventLen--;
-    if (_RGFW.eventLen >= 0 && _RGFW.eventIndex < _RGFW.eventLen) {
-		_RGFW.eventIndex++;
-    } else if (_RGFW.eventLen == 0) {
-        _RGFW.eventIndex = 0;
-    }
-
-	if (ev->_win != win && ev->_win != NULL) {
-        RGFW_eventQueuePush(*ev);
-        return NULL;
-	}
-
-    ev->droppedFilesCount = win->event.droppedFilesCount;
-	ev->droppedFiles = win->event.droppedFiles;
-	return ev;
-}
-
-RGFW_event* RGFW_window_checkEventCore(RGFW_window* win);
-RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) {
-	RGFW_event* ev;
-    RGFW_ASSERT(win != NULL);
-    if (win->event.type == 0 && _RGFW.eventLen == 0)
-		RGFW_resetKeyPrev();
-
-	if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) {
-        static RGFW_event event;
-        event = win->event;
-        RGFW_window_close(win);
-	    return &event;
-    }
-
-	if (win->event.type != RGFW_DNDInit) win->event.type = 0;
-
-	/* check queued events */
-	ev = RGFW_eventQueuePop(win);
-	if (ev != NULL) {
-		if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE);
-		win->event = *ev;
-    }
-	else return NULL;
-
-	return &win->event;
-}
-
-
-RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags);
-void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; }
-RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; }
-
-/* do a basic initialization for RGFW_window, this is to standard it for each OS */
-void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) {
-	RGFW_UNUSED(flags);
-    if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
-    _RGFW.windowCount++;
-
-    /* rect based the requested flags */
-	if (_RGFW.root == NULL) {
-		RGFW_setRootWindow(win);
-		RGFW_setTime(0);
-	}
-
-	if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0;
-
-	/* set and init the new window's data */
-	win->r = rect;
-	win->exitKey = RGFW_escape;
-	win->event.droppedFilesCount = 0;
-
-	win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC);
-    win->_flags |= flags;
-	win->event.keyMod = 0;
-	win->_lastMousePoint.x = 0; 
-	win->_lastMousePoint.y = 0; 
-
-	win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS);
-	RGFW_ASSERT(win->event.droppedFiles != NULL);
-     
-    { 
-        u32 i;
-        for (i = 0; i < RGFW_MAX_DROPS; i++)
-		    win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH));
-    }
-}
-
-void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) {
-	RGFW_windowFlags cmpFlags = win->_flags;
-	if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0;
-
-	#ifndef RGFW_NO_MONITOR
-	if (flags & RGFW_windowScaleToMonitor)			RGFW_window_scaleToMonitor(win);
-	#endif
-
-	if (flags & RGFW_windowCenter)					RGFW_window_center(win);
-	if (flags & RGFW_windowCenterCursor)
-		RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
-	if (flags & RGFW_windowNoBorder)				RGFW_window_setBorder(win, 0);
-	else RGFW_window_setBorder(win, 1);
-	if (flags & RGFW_windowFullscreen)				RGFW_window_setFullscreen(win, RGFW_TRUE);
-	else if (cmpFlags & RGFW_windowFullscreen) 	RGFW_window_setFullscreen(win, 0);
-	if (flags & RGFW_windowMaximize)				RGFW_window_maximize(win);
-	else if (cmpFlags & RGFW_windowMaximize) 	RGFW_window_restore(win);
-	if (flags & RGFW_windowMinimize)				RGFW_window_minimize(win);
-	else if (cmpFlags & RGFW_windowMinimize) 	RGFW_window_restore(win);
-	if (flags & RGFW_windowHideMouse)				RGFW_window_showMouse(win, 0);
-	else if (cmpFlags & RGFW_windowHideMouse)  	RGFW_window_showMouse(win, 1);
-	if (flags & RGFW_windowHide)				RGFW_window_hide(win);
-	else if (cmpFlags & RGFW_windowHide)  		RGFW_window_show(win);
-	if (flags & RGFW_windowCocoaCHDirToRes)			RGFW_moveToMacOSResourceDir();
-	if (flags & RGFW_windowFloating)				RGFW_window_setFloating(win, 1);
-	else if (cmpFlags & RGFW_windowFloating)		RGFW_window_setFloating(win, 0);
-	if (flags & RGFW_windowFocus)					RGFW_window_focus(win);
-
-	if (flags & RGFW_windowNoResize) {
-	    RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h));
-	    RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h));
-	} else if (cmpFlags & RGFW_windowNoResize) {
-		RGFW_window_setMaxSize(win, RGFW_AREA(0, 0));
-		RGFW_window_setMinSize(win, RGFW_AREA(0, 0));
-	}
-
-	win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS);
-}
-
-RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win) {
-    return RGFW_BOOL(win->_flags |= RGFW_windowOpenglSoftware);
-}
-
-RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
-#ifdef RGFW_WASM
-    return RGFW_TRUE;
-#else
-    return RGFW_BOOL(win->_flags & RGFW_windowFocus);
-#endif
-}
-
-void RGFW_window_initBuffer(RGFW_window* win) {
-    RGFW_area area = RGFW_getScreenSize();
-    if ((win->_flags & RGFW_windowNoResize))
-        area = RGFW_AREA(win->r.w, win->r.h);
-
-    RGFW_window_initBufferSize(win, area);
-}
-
-void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) {
-#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA)
-    win->_flags |= RGFW_BUFFER_ALLOC;
-	#ifndef RGFW_WINDOWS
-        u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4);
-        RGFW_ASSERT(buffer != NULL);
-
-        RGFW_window_initBufferPtr(win, buffer, area);
-    #else /* windows's bitmap allocs memory for us */
-	RGFW_window_initBufferPtr(win, (u8*)NULL, area);
-	#endif
-#else
-    RGFW_UNUSED(win); RGFW_UNUSED(area);
-#endif
-}
-
-#ifdef RGFW_MACOS
-RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
-RGFWDEF void* RGFW_cocoaGetLayer(void);
-#endif
-
-const char* RGFW_className = NULL;
-void RGFW_setClassName(const char* name) { RGFW_className = name; }
-
-#ifndef RGFW_X11
-void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
-#endif
-
-RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = {  {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
-
-RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) {
-	return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win));
-}
-RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) {
-	return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win));
-}
-RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) {
-	return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
-}
-RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) {
-	return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
-}
-
-RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	return win->_lastMousePoint;
-}
-
-RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) {
-	return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win));
-}
-
-RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) {
-	return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win));
-}
-
-RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) {
-	return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
-}
-
-RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) {
-	return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
-}
-
-RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) {
-	return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
-}
-
-void RGFW_window_makeCurrent(RGFW_window* win) {
-    _RGFW.current = win;
-#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
-    RGFW_window_makeCurrent_OpenGL(win);
-#endif
-}
-
-RGFW_window* RGFW_getCurrent(void) {
-    return _RGFW.current;
-}
-
-void RGFW_window_swapBuffers(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_window_swapBuffers_software(win);
-#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
-	RGFW_window_swapBuffers_OpenGL(win);
-#endif
-}
-
-RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value);
-void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) {
-	if (value)
-		*data |= bit;
-	else if (!value && (*(data) & bit))
-		*data ^= bit;
-}
-
-void RGFW_window_center(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_area screenR = RGFW_getScreenSize();
-	RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2));
-}
-
-RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) {
-	RGFW_monitorMode mode;
-    RGFW_ASSERT(win != NULL);
-
-	mode.area.w = (u32)win->r.w;
-	mode.area.h = (u32)win->r.h;
-	return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale);
-}
-
-void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
-void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
-    if (bpp == 32) bpp = 24;
-    mode->red = mode->green = mode->blue = (u8)(bpp / 3);
-
-    u32 delta = bpp - (mode->red * 3); /* handle leftovers */
-    if (delta >= 1) mode->green = mode->green + 1;
-    if (delta == 2) mode->red = mode->red + 1;
-}
-
-RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) {
-	return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) &&
-			((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) &&
-			((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB)));
-}
-
-RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
-	return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey)));
-}
-
-void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
-	if (shouldClose)  {
-		win->_flags |= RGFW_EVENT_QUIT;
-		RGFW_windowQuitCallback(win);
-	} else {
-		win->_flags &= ~(u32)RGFW_EVENT_QUIT;
-	}
-}
-
-#ifndef RGFW_NO_MONITOR
-void RGFW_window_scaleToMonitor(RGFW_window* win) {
-	RGFW_monitor monitor = RGFW_window_getMonitor(win);
-	if (monitor.scaleX == 0 && monitor.scaleY == 0)
-		return;
-
-	RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h)));
-}
-
-void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
-	RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y));
-}
-#endif
-
-RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
-	return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth);
-}
-
-RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
-RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
-
-
-RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); }
-
-void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
-	if (!area.w && !area.h)
-		area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
-
-	win->_flags |= RGFW_HOLD_MOUSE;
-    RGFW_captureCursor(win, win->r);
-	RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
-}
-
-void RGFW_window_mouseUnhold(RGFW_window* win) {
-	win->_flags &= ~(u32)RGFW_HOLD_MOUSE;
-	RGFW_releaseCursor(win);
-}
-
-u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) {
-	double deltaTime = RGFW_getTime() - startTime;
-	if (deltaTime == 0) return 0;
-
-	double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */
-	if (fpsCap && fps > fpsCap) {
-		double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */
-		double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */
-
-		if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000));
-	}
-
-	return (u32) fps;
-}
-
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) {
-	#if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
-	u32 x, y;
-	for (y = 0; y < (u32)win->r.h; y++) {
-		for (x = 0; x < (u32)win->r.w; x++) {
-			u32 index = (y * 4 * win->bufferSize.w) + x * 4;
-
-			u8 red = data[index];
-			data[index] = win->buffer[index + 2];
-			data[index + 2] = red;
-		}
-	}
-    #elif defined(RGFW_OSMESA)
-	u32 y;
-	for(y = 0; y < (u32)win->r.h; y++){
-		u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w;
-		u32 index_to = y * 4 * win->bufferSize.w;
-		memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w);
-	}
-    #else
-	RGFW_UNUSED(win); RGFW_UNUSED(data);
-	#endif
-}
-#endif
-
-u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
-	RGFW_UNUSED(win);
-	return RGFW_gamepadPressed[c][button].current;
-}
-u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
-	RGFW_UNUSED(win);
-	return RGFW_gamepadPressed[c][button].prev;
-}
-u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
-	RGFW_UNUSED(win);
-	return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
-}
-u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
-	RGFW_UNUSED(win);
-	return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
-}
-
-RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) {
-	RGFW_UNUSED(win);
-	return RGFW_gamepadAxes[controller][whichAxis];
-}
-const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) {
-	RGFW_UNUSED(win);
-	return (const char*)RGFW_gamepads_name[controller];
-}
-
-size_t RGFW_getGamepadCount(RGFW_window* win) {
-	RGFW_UNUSED(win);
-	return RGFW_gamepadCount;
-}
-
-RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) {
-	RGFW_UNUSED(win);
-	return RGFW_gamepads_type[controller];
-}
-
-RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
-void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
-	if (value) win->event.keyMod |= mod;
-	else win->event.keyMod &= ~mod;
-}
-
-RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
-void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
-	RGFW_updateKeyMod(win, RGFW_modCapsLock, capital);
-	RGFW_updateKeyMod(win, RGFW_modNumLock, numlock);
-	RGFW_updateKeyMod(win, RGFW_modControl, control);
-	RGFW_updateKeyMod(win, RGFW_modAlt, alt);
-	RGFW_updateKeyMod(win, RGFW_modShift, shift);
-	RGFW_updateKeyMod(win, RGFW_modSuper, super);
-	RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll);
-}
-
-RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
-void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
-	RGFW_updateKeyModsPro(win, capital, numlock,
-					RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR),
-					RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR),
-					RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR),
-					RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR),
-					scroll);
-}
-
-RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
-void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
-	if (show && (win->_flags & RGFW_windowHideMouse))
-		win->_flags ^= RGFW_windowHideMouse;
-	else if (!show && !(win->_flags & RGFW_windowHideMouse))
-		win->_flags |= RGFW_windowHideMouse;
-}
-
-RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) {
-	return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse);
-}
-
-RGFW_bool RGFW_window_borderless(RGFW_window* win) {
-	return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder);
-}
-
-RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); }
-RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); }
-
-void RGFW_window_focusLost(RGFW_window* win) {
-    /* standard routines for when a window looses focus */
-	_RGFW.root->_flags &= ~(u32)RGFW_windowFocus;
-	if ((win->_flags & RGFW_windowFullscreen))
-			RGFW_window_minimize(win);
-
-    for (size_t key = 0; key < RGFW_keyLast; key++) {
-        if (RGFW_isPressed(NULL, (u8)key) == RGFW_FALSE) continue;
-	    RGFW_keyboard[key].current = RGFW_FALSE; 
-        u8 keyChar = RGFW_rgfwToKeyChar((u32)key);
-        RGFW_keyCallback(win, (u8)key, keyChar, win->event.keyMod, RGFW_FALSE);
-        RGFW_eventQueuePushEx(e.type = RGFW_keyReleased;
-                                e.key = (u8)key;
-                                e.keyChar = keyChar;
-                                e.repeat = RGFW_FALSE;
-                                e.keyMod = win->event.keyMod;
-                                e._win = win);
-    }
-    
-    RGFW_resetKey();
-}
-
-#ifndef RGFW_WINDOWS
-void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
-	RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
-}
-#endif
-
-#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
-#ifndef __USE_POSIX199309
-	#define __USE_POSIX199309
-#endif
-#include <time.h>
-struct timespec;
-#endif
-
-#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
-void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
-	RGFW_window_showMouseFlags(win, show);
-	if (show == 0)
-		RGFW_window_setMouse(win, _RGFW.hiddenMouse);
-	else
-		RGFW_window_setMouseDefault(win);
-}
-#endif
-
-#ifndef RGFW_MACOS
-void RGFW_moveToMacOSResourceDir(void) { }
-#endif
-
-/*
-	graphics API specific code (end of generic code)
-	starts here
-*/
-
-
-/*
-	OpenGL defines start here   (Normal, EGL, OSMesa)
-*/
-
-#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
-
-#ifdef RGFW_WINDOWS
-	#define WIN32_LEAN_AND_MEAN
-	#define OEMRESOURCE
-	#include <windows.h>
-#endif
-
-#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
-	#include <GL/gl.h>
-#elif defined(__APPLE__)
-	#ifndef GL_SILENCE_DEPRECATION
-		#define GL_SILENCE_DEPRECATION
-	#endif
-	#include <OpenGL/gl.h>
-	#include <OpenGL/OpenGL.h>
-#endif
-
-/* EGL, normal OpenGL only */
-#ifndef RGFW_EGL
-i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8,
-#else
-i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0,
-#endif
-	0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0};
-
-void RGFW_setGLHint(RGFW_glHints hint, i32 value) {
-	if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value;
-}
-
-RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
-    const char *start = extensions;
-    const char *where; 
-    const char* terminator;
-
-    if (extensions == NULL || ext == NULL)
-        return RGFW_FALSE;
-
-    where = strstr(extensions, ext);
-    while (where) {
-        terminator = where + len;
-        if ((where == start || *(where - 1) == ' ') &&
-            (*terminator == ' ' || *terminator == '\0')) {
-            return RGFW_TRUE;
-        }
-        where = RGFW_STRSTR(terminator, ext);
-    }
-
-    return RGFW_FALSE;
-}
-
-RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) {
-    #ifdef GL_NUM_EXTENSIONS
-    if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
-        i32 i;
-        GLint count = 0;
-
-        RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi");
-        RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv");
-        if (RGFW_glGetIntegerv) 
-            ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
-
-        for (i = 0; RGFW_glGetStringi && i < count;  i++) {
-            const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
-            if (en && RGFW_STRNCMP(en, extension, len) == 0)
-                return RGFW_TRUE;
-        }
-    } else 
-#endif
-    {
-        RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString");
-            
-        if (RGFW_glGetString) {
-            const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS);
-            if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len))
-                return RGFW_TRUE;
-        }
-    }
-
-    return RGFW_extensionSupportedPlatform(extension, len);
-}
-
-/* OPENGL normal only (no EGL / OSMesa) */
-#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM)
-
-#define RGFW_GL_RENDER_TYPE 		RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE,    	0x2003,		73, 0)
-	#define RGFW_GL_ALPHA_SIZE 		RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE,       	0x201b,		11,     0)
-	#define RGFW_GL_DEPTH_SIZE 		RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE,       	0x2022,		12,     0)
-	#define RGFW_GL_DOUBLEBUFFER 		RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER,     	0x2011, 	5,  0)
-	#define RGFW_GL_STENCIL_SIZE 		RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE,	 	0x2023,	13,     0)
-	#define RGFW_GL_SAMPLES			RGFW_OS_BASED_VALUE(GLX_SAMPLES, 		 	0x2042,	    55,     0)
-	#define RGFW_GL_STEREO 			RGFW_OS_BASED_VALUE(GLX_STEREO,	 		 	0x2012,			6,  0)
-	#define RGFW_GL_AUX_BUFFERS		RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS,	    0x2024,	7, 		    0)
-
-#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
-	#define RGFW_GL_DRAW 			RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE,	 	0x2001,					0, 0)
-	#define RGFW_GL_DRAW_TYPE 		RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE,     	0x2013,						0, 0)
-	#define RGFW_GL_FULL_FORMAT		RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR,   	 	0x2027,						0, 0)
-	#define RGFW_GL_RED_SIZE		RGFW_OS_BASED_VALUE(GLX_RED_SIZE,         	0x2015,						0, 0)
-	#define RGFW_GL_GREEN_SIZE		RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE,       	0x2017,						0, 0)
-	#define RGFW_GL_BLUE_SIZE		RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 	 		0x2019,						0, 0)
-	#define RGFW_GL_USE_RGBA		RGFW_OS_BASED_VALUE(GLX_RGBA_BIT,   	 	0x202B,						0, 0)
-	#define RGFW_GL_ACCUM_RED_SIZE 	RGFW_OS_BASED_VALUE(14,   	 	0x201E,						0, 0)
-	#define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15,   	 	0x201F,						0, 0)
-	#define RGFW_GL_ACCUM_BLUE_SIZE	 RGFW_OS_BASED_VALUE(16,   	 	0x2020,						0, 0)
-	#define RGFW_GL_ACCUM_ALPHA_SIZE	 RGFW_OS_BASED_VALUE(17,   	 	0x2021,						0, 0)
-	#define RGFW_GL_SRGB	 RGFW_OS_BASED_VALUE(0x20b2,   	 	0x3089,						0, 0)
-	#define RGFW_GL_NOERROR	 RGFW_OS_BASED_VALUE(0x31b3,   	 	0x31b3,						0, 0)
-	#define RGFW_GL_FLAGS	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB,   	 	0x2094,						0, 0)
-	#define RGFW_GL_RELEASE_BEHAVIOR	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,   	 	0x2097 ,						0, 0)
-	#define RGFW_GL_CONTEXT_RELEASE	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB,   	 	0x2098,						0, 0)
-	#define RGFW_GL_CONTEXT_NONE	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB,   	 	0x0000,						0, 0)
-	#define RGFW_GL_FLAGS	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB,   	 	0x2094,						0, 0)
-	#define RGFW_GL_DEBUG_BIT	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB,   	 	0x2094,						0, 0)
-	#define RGFW_GL_ROBUST_BIT	 RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,   	 	0x00000004,						0, 0)
-#endif
-
-#ifdef RGFW_WINDOWS
-	#define WGL_SUPPORT_OPENGL_ARB                    0x2010
-	#define WGL_COLOR_BITS_ARB                        0x2014
-	#define WGL_NUMBER_PIXEL_FORMATS_ARB 			0x2000
-	#define WGL_CONTEXT_MAJOR_VERSION_ARB             0x2091
-	#define WGL_CONTEXT_MINOR_VERSION_ARB             0x2092
-	#define WGL_CONTEXT_PROFILE_MASK_ARB              0x9126
-	#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
-	#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
-	#define WGL_SAMPLE_BUFFERS_ARB               0x2041
-	#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
-	#define WGL_PIXEL_TYPE_ARB                        0x2013
-	#define WGL_TYPE_RGBA_ARB                         0x202B
-
-	#define WGL_TRANSPARENT_ARB   					  0x200A
-#endif
-
-/*  The window'ing api needs to know how to render the data we (or opengl) give it
-	MacOS and Windows do this using a structure called a "pixel format"
-	X11 calls it a "Visual"
-	This function returns the attributes for the format we want */
-i32* RGFW_initFormatAttribs(void);
-i32* RGFW_initFormatAttribs(void) {
-	static i32 attribs[] = {
-							#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
-							RGFW_GL_RENDER_TYPE,
-							RGFW_GL_FULL_FORMAT,
-							RGFW_GL_DRAW, 1,
-							RGFW_GL_DRAW_TYPE     , RGFW_GL_USE_RGBA,
-							#endif
-
-							#ifdef RGFW_X11
-							GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
-							#endif
-
-							#ifdef RGFW_MACOS
-							72,
-							8, 24,
-							#endif
-
-							#ifdef RGFW_WINDOWS
-							WGL_SUPPORT_OPENGL_ARB,		1,
-							WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
-							WGL_COLOR_BITS_ARB,	 32,
-							#endif
-							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-	};
-
-	size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27;
-
-	#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
-		if (attVal) { \
-			attribs[index] = attrib;\
-			attribs[index + 1] = attVal;\
-			index += 2;\
-		}
-
-		#if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING)
-		RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching);
-		#endif
-
-        RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
-
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
-        RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]);
-
-	#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
-	#endif
-
-	#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]);
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]);
-
-		if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
-			RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE);
-		} else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) {
-			RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE);
-		}
-
-		i32 flags = 0;
-		if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT;
-		if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT;
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags);
-	#else
-		i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] +  RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4;
-		RGFW_GL_ADD_ATTRIB(14, accumSize);
-	#endif
-
-	#ifndef RGFW_X11
-		RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
-	#endif
-
-	#ifdef RGFW_MACOS
-		if (_RGFW.root->_flags & RGFW_windowOpenglSoftware) {
-			RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
-		} else {
-			attribs[index] = RGFW_GL_RENDER_TYPE;
-			index += 1;
-		}
-	#endif
-
-	#ifdef RGFW_MACOS
-		/* macOS has the surface attribs and the opengl attribs connected for some reason
-			maybe this is to give macOS more control to limit openGL/the opengl version? */
-
-		attribs[index] = 99;
-		attribs[index + 1] = 0x1000;
-
-
-		if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
-			attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200);
-		}
-	#endif
-
-	RGFW_GL_ADD_ATTRIB(0, 0);
-
-	return attribs;
-}
-
-/* EGL only (no OSMesa nor normal OPENGL) */
-#elif defined(RGFW_EGL)
-
-#include <EGL/egl.h>
-
-#if defined(RGFW_LINK_EGL)
-	typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
-
-	PFNEGLINITIALIZEPROC eglInitializeSource;
-	PFNEGLGETCONFIGSPROC eglGetConfigsSource;
-	PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource;
-	PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
-	PFNEGLCREATECONTEXTPROC eglCreateContextSource;
-	PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
-	PFNEGLGETDISPLAYPROC eglGetDisplaySource;
-	PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
-	PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
-	PFNEGLBINDAPIPROC eglBindAPISource;
-	PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
-	PFNEGLTERMINATEPROC eglTerminateSource;
-	PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
-
-	#define eglInitialize eglInitializeSource
-	#define eglGetConfigs eglGetConfigsSource
-	#define eglChooseConfig eglChooseConfigSource
-	#define eglCreateWindowSurface eglCreateWindowSurfaceSource
-	#define eglCreateContext eglCreateContextSource
-	#define eglMakeCurrent eglMakeCurrentSource
-	#define eglGetDisplay eglGetDisplaySource
-	#define eglSwapBuffers eglSwapBuffersSource
-	#define eglSwapInterval eglSwapIntervalSource
-	#define eglBindAPI eglBindAPISource
-	#define eglDestroyContext eglDestroyContextSource
-	#define eglTerminate eglTerminateSource
-	#define eglDestroySurface eglDestroySurfaceSource;
-#endif
-
-
-#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
-#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
-
-#ifndef RGFW_GL_ADD_ATTRIB
-#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
-	if (attVal) { \
-		attribs[index] = attrib;\
-		attribs[index + 1] = attVal;\
-		index += 2;\
-	}
-#endif
-
-
-void RGFW_window_initOpenGL(RGFW_window* win) {
-#if defined(RGFW_LINK_EGL)
-	eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
-	eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
-	eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig");
-	eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
-	eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
-	eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
-	eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
-	eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
-	eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
-	eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
-	eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
-	eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
-	eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
-
-	RGFW_ASSERT(eglInitializeSource != NULL &&
-	            eglGetConfigsSource != NULL &&
-	            eglChooseConfigSource != NULL &&
-	            eglCreateWindowSurfaceSource != NULL &&
-	            eglCreateContextSource != NULL &&
-	            eglMakeCurrentSource != NULL &&
-	            eglGetDisplaySource != NULL &&
-	            eglSwapBuffersSource != NULL &&
-	            eglSwapIntervalsSource != NULL &&
-	            eglBindAPISource != NULL &&
-	            eglDestroyContextSource != NULL &&
-	            eglTerminateSource != NULL &&
-	            eglDestroySurfaceSource != NULL);
-#endif /* RGFW_LINK_EGL */
-
-#ifdef RGFW_WAYLAND
-    if (RGFW_useWaylandBool)
-        win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
-#endif
-
-	#ifdef RGFW_WINDOWS
-	win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
-	#elif defined(RGFW_MACOS)
-	win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
-	#elif defined(RGFW_WAYLAND)
-	if (RGFW_useWaylandBool)
-		win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display);
-    else
-    #endif
-    #ifdef RGFW_X11
-		win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
-    #else 
-    {}
-    #endif
-    #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) 
-        win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
-	#endif
-
-	EGLint major, minor;
-
-	eglInitialize(win->src.EGL_display, &major, &minor);
-
-	#ifndef EGL_OPENGL_ES1_BIT
-	#define EGL_OPENGL_ES1_BIT 0x1
-	#endif
-
-	EGLint egl_config[24] = {
-		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-		EGL_RENDERABLE_TYPE,
-		#ifdef RGFW_OPENGL_ES1
-		EGL_OPENGL_ES1_BIT,
-		#elif defined(RGFW_OPENGL_ES3)
-		EGL_OPENGL_ES3_BIT,
-		#elif defined(RGFW_OPENGL_ES2)
-		EGL_OPENGL_ES2_BIT,
-		#else
-		EGL_OPENGL_BIT,
-		#endif
-		EGL_NONE, EGL_NONE
-	};
-
-	{
-		size_t index = 7;
-		EGLint* attribs = egl_config;
-
-		RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
-		RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
-		RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
-		RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
-		RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
-
-		if (RGFW_GL_HINTS[RGFW_glSRGB])
-			RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]);
-
-		RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
-	}
-
-	EGLConfig config;
-	EGLint numConfigs;
-	eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
-
-	#if defined(RGFW_MACOS)
-		void* layer = RGFW_cocoaGetLayer();
-
-		RGFW_window_cocoaSetLayer(win, layer);
-
-		win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
-	#elif defined(RGFW_WINDOWS)
-		win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
-	#elif defined(RGFW_WAYLAND)
-		if (RGFW_useWaylandBool)
-			win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL);
-		else
-    #endif
-    #ifdef RGFW_X11
-            win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
-    #else
-    {}
-    #endif
-    #if !defined(RGFW_X11) && !defined(RGFW_WAYLAND) && !defined(RGFW_MACOS)
-		win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
-	#endif
-
-	EGLint attribs[12];
-	size_t index = 0;
-
-#ifdef RGFW_OPENGL_ES1
-    RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1);
-#elif defined(RGFW_OPENGL_ES2)
-    RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2);
-#elif defined(RGFW_OPENGL_ES3)
-    RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3);
-#endif
-
-    RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
-	RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
-
-    if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
-		RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
-
-	if (RGFW_GL_HINTS[RGFW_glMajor]) {
-		RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]);
-		RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]);
-
-		if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) {
-			RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
-		}
-		else {
-			RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
-		}
-	}
-
-	RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]);
-	RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]);
-	if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
-		RGFW_GL_ADD_ATTRIB(0x2097, 0x2098);
-	} else {
-		RGFW_GL_ADD_ATTRIB(0x2096, 0x0000);
-	}
-
-	RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
-
-	#if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
-	eglBindAPI(EGL_OPENGL_ES_API);
-	#else
-	eglBindAPI(EGL_OPENGL_API);
-	#endif
-
-	win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
-
-	if (win->src.EGL_context == NULL) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context");
-		return;
-	}
-
-	eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
-	eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized");
-}
-
-void RGFW_window_freeOpenGL(RGFW_window* win) {
-	if (win->src.EGL_display == NULL) return;
-
-	eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
-	eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
-	eglTerminate(win->src.EGL_display);
-    win->src.EGL_display = NULL;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed");
-}
-
-void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
-    if (win == NULL)
-        eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    else {
-        eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
-    }
-}
-
-void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); }
-
-void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); }
-
-#ifdef RGFW_APPLE
-void* RGFWnsglFramework = NULL;
-#elif defined(RGFW_WINDOWS)
-HMODULE RGFW_wgl_dll = NULL;
-#endif
-
-RGFW_proc RGFW_getProcAddress(const char* procname) {
-	#if defined(RGFW_WINDOWS)
-	RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
-
-		if (proc)
-			return proc;
-	#endif
-
-	return (RGFW_proc) eglGetProcAddress(procname);
-}
-
-RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
-    const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS);
-    return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); 
-}
-
-void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
-	RGFW_ASSERT(win != NULL);
-
-	eglSwapInterval(win->src.EGL_display, swapInterval);
-
-}
-
-#endif /* RGFW_EGL */
-
-/*
-	end of RGFW_EGL defines
-*/
-#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
-
-/*
-	RGFW_VULKAN defines
-*/
-#ifdef RGFW_VULKAN
-#ifdef RGFW_MACOS
-#include <objc/message.h>
-#endif
-
-const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) {
-    static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
-    arr[1] = RGFW_VK_SURFACE;
-    if (count != NULL) *count = 2;
-
-    return (const char**)arr;
-}
-
-VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
-    RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
-	RGFW_ASSERT(surface != NULL);
-
-    *surface = VK_NULL_HANDLE;
-
-#ifdef RGFW_X11
-    RGFW_GOTO_WAYLAND(0);
-    VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window };
-    return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
-#endif
-#if defined(RGFW_WAYLAND)
-RGFW_WAYLAND_LABEL
-    VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface };
-    return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
-#elif defined(RGFW_WINDOWS)
-    VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
-
-    return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
-#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
-    void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
-    VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView };
-
-    return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
-#endif
-}
-
-
-RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
-    RGFW_ASSERT(instance);
-	if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init();
-#ifdef RGFW_X11
-    RGFW_GOTO_WAYLAND(0);
-	Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display));
-    if (_RGFW.root)
-        visual = _RGFW.root->src.visual.visual;
-
-    RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual));
-    return out;
-#endif
-#if defined(RGFW_WAYLAND)
-RGFW_WAYLAND_LABEL
-    RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display);
-    return wlout;
-#elif defined(RGFW_WINDOWS)
-#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
-    return RGFW_FALSE; /* TODO */
-#endif
-}
-#endif /* end of RGFW_vulkan */
-
-/*
-This is where OS specific stuff starts
-*/
-
-
-#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX)
-	int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
-
-	#if defined(__linux__)
-		#include <linux/joystick.h>
-		#include <fcntl.h>
-		#include <unistd.h>
-		#include <errno.h>
-
-		u32 RGFW_linux_updateGamepad(RGFW_window* win);
-		u32 RGFW_linux_updateGamepad(RGFW_window* win) {
-			/* check for new gamepads */
-			static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"};
-			static u8 RGFW_rawGamepads[6];
-            {
-                u16 i;
-                for (i = 0; i < 6; i++) {
-                    u16 index = RGFW_gamepadCount;
-                    if (RGFW_rawGamepads[i]) {
-                        struct input_id device_info;
-                        if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) {
-                            if (errno == ENODEV) {
-                                RGFW_rawGamepads[i] = 0;
-                            }
-                        }
-                        continue;
-                    }
-
-                    i32 js = open(str[i], O_RDONLY);
-
-                    if (js <= 0)
-                        break;
-
-                    if (RGFW_gamepadCount >= 4) {
-                        close(js);
-                        break;
-                    }
-
-                    RGFW_rawGamepads[i] = 1;
-
-                    int axes, buttons;
-                    if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) {
-                        close(js);
-                        continue;
-                    }
-
-                    if (buttons <= 5 || buttons >= 30) {
-                        close(js);
-                        continue;
-                    }
-
-                    RGFW_gamepadCount++;
-
-                    RGFW_gamepads[index] = js;
-
-                    ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]);
-                    RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0;
-
-                    u8 j;
-                    for (j = 0; j < 16; j++) {
-                        RGFW_gamepadPressed[index][j].prev = 0;
-                        RGFW_gamepadPressed[index][j].current = 0;
-                    }
-
-                    win->event.type = RGFW_gamepadConnected;
-
-                    RGFW_gamepads_type[index] = RGFW_gamepadUnknown;
-                    if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box"))
-                        RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft;
-                    else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5"))
-                        RGFW_gamepads_type[index] = RGFW_gamepadSony;
-                    else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo"))
-                        RGFW_gamepads_type[index] = RGFW_gamepadNintendo;
-                    else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech"))
-                        RGFW_gamepads_type[index] = RGFW_gamepadLogitech;
-
-                    win->event.gamepad = index;
-                    RGFW_gamepadCallback(win, index, 1);
-                    return 1;
-                }
-            }
-			/* check gamepad events */
-			u8 i;
-
-			for (i = 0; i < RGFW_gamepadCount; i++) {
-				struct js_event e;
-				if (RGFW_gamepads[i] == 0)
-					continue;
-
-				i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0);
-				fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK);
-
-				ssize_t bytes;
-				while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) {
-					switch (e.type) {
-						case JS_EVENT_BUTTON: {
-							size_t typeIndex = 0;
-							if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1;
-							else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2;
-
-							win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased;
-							u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */
-									RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
-									RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight,
-								},{ /* xbox */
-									RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart,
-									RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
-							    },{ /* Logitech */
-									RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
-									RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
-								}
-							};
-
-							win->event.button = RGFW_linux2RGFW[typeIndex][e.number];
-							win->event.gamepad = i;
-							if (win->event.button == 255) break;
-
-							RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current;
-							RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value);
-							RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value));
-
-							return 1;
-						}
-						case JS_EVENT_AXIS: {
-							size_t axis = e.number / 2;
-							if (axis == 2) axis = 1;
-
-							ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount);
-							win->event.axisesCount = 2;
-
-							if (axis < 3) {
-								if (e.number == 0 || e.number == 3)
-									RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100);
-								else if (e.number == 1 || e.number == 4) {
-									RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100);
-								}
-							}
-
-							win->event.axis[axis] = RGFW_gamepadAxes[i][axis];
-							win->event.type = RGFW_gamepadAxisMove;
-							win->event.gamepad = i;
-							win->event.whichAxis = (u8)axis;
-							RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis);
-							return 1;
-						}
-						default: break;
-					}
-				}
-				if (bytes == -1 && errno == ENODEV) {
-					RGFW_gamepadCount--;
-					close(RGFW_gamepads[i]);
-					RGFW_gamepads[i] = 0;
-
-					win->event.type = RGFW_gamepadDisconnected;
-					win->event.gamepad = i;
-					RGFW_gamepadCallback(win, i, 0);
-					return 1;
-				}
-			}
-			return 0;
-		}
-
-	#endif
-#endif
-
-
-
-/*
-
-	Start of Wayland defines
-
-
-*/
-
-#ifdef RGFW_WAYLAND
-/*
-Wayland TODO: (out of date)
-- fix RGFW_keyPressed lock state
-
-	RGFW_windowMoved, 		the window was moved (by the user)
-	RGFW_windowResized  	the window was resized (by the user), [on WASM this means the browser was resized]
-	RGFW_windowRefresh	 	The window content needs to be refreshed
-
-	RGFW_DND 				a file has been dropped into the window
-	RGFW_DNDInit
-
-- window args:
-	#define RGFW_windowNoResize	 			the window cannot be resized  by the user
-	#define RGFW_windowAllowDND     			the window supports drag and drop
-	#define RGFW_scaleToMonitor 			scale the window to the screen
-
-- other missing functions functions ("TODO wayland") (~30 functions)
-- fix buffer rendering weird behavior
-*/
-#include <errno.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <xkbcommon/xkbcommon.h>
-#include <xkbcommon/xkbcommon-keysyms.h>
-#include <dirent.h>
-#include <linux/kd.h>
-#include <wayland-cursor.h>
-
-RGFW_window* RGFW_key_win = NULL;
-
-/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
-#include "xdg-shell.h"
-#include "xdg-decoration-unstable-v1.h"
-
-struct xkb_context *xkb_context;
-struct xkb_keymap *keymap = NULL;
-struct xkb_state *xkb_state = NULL;
-enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
-struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
-
-struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
-struct wl_surface* RGFW_cursor_surface = NULL;
-struct wl_cursor_image* RGFW_cursor_image = NULL;
-
-void xdg_wm_base_ping_handler(void *data,
-        struct xdg_wm_base *wm_base, uint32_t serial)
-{
-	RGFW_UNUSED(data);
-    xdg_wm_base_pong(wm_base, serial);
-}
-
-const struct xdg_wm_base_listener xdg_wm_base_listener = {
-    .ping = xdg_wm_base_ping_handler,
-};
-
-RGFW_bool RGFW_wl_configured = 0;
-
-void xdg_surface_configure_handler(void *data,
-        struct xdg_surface *xdg_surface, uint32_t serial)
-{
-	RGFW_UNUSED(data);
-    xdg_surface_ack_configure(xdg_surface, serial);
-	RGFW_wl_configured = 1;
-}
-
-const struct xdg_surface_listener xdg_surface_listener = {
-    .configure = xdg_surface_configure_handler,
-};
-
-void xdg_toplevel_configure_handler(void *data,
-        struct xdg_toplevel *toplevel, int32_t width, int32_t height,
-        struct wl_array *states)
-{
-	RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states);
-    RGFW_UNUSED(width); RGFW_UNUSED(height);
-}
-
-void xdg_toplevel_close_handler(void *data,
-        struct xdg_toplevel *toplevel)
-{
-	RGFW_UNUSED(data);
-	RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
-	if (win == NULL)
-		win = RGFW_key_win;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
-	RGFW_windowQuitCallback(win);
-}
-
-void shm_format_handler(void *data,
-        struct wl_shm *shm, uint32_t format)
-{
-	RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
-}
-
-const struct wl_shm_listener shm_listener = {
-    .format = shm_format_handler,
-};
-
-const struct xdg_toplevel_listener xdg_toplevel_listener = {
-    .configure = xdg_toplevel_configure_handler,
-    .close = xdg_toplevel_close_handler,
-};
-
-RGFW_window* RGFW_mouse_win = NULL;
-
-void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
-	RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
-	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
-	RGFW_mouse_win = win;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter;
-									e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
-									e._win = win);
-
-	RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE);
-}
-void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
-	RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
-	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
-	if (RGFW_mouse_win == win)
-		RGFW_mouse_win = NULL;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave;
-									e.point = win->event.point;
-									e._win = win);
-
-	RGFW_mouseNotifyCallback(win,  win->event.point, RGFW_FALSE);
-}
-void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
-	RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
-
-	RGFW_ASSERT(RGFW_mouse_win != NULL);
-	RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
-									e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y));
-									e._win = RGFW_mouse_win);
-
-	RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector);
-}
-void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
-	RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
-	RGFW_ASSERT(RGFW_mouse_win != NULL);
-
-	u32 b = (button - 0x110);
-
-	/* flip right and middle button codes */
-	if (b == 1) b = 2;
-	else if (b == 2) b = 1;
-
-	RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
-	RGFW_mouseButtons[b].current = RGFW_BOOL(state);
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state);
-									e.point = RGFW_mouse_win->event.point;
-									e.button = (u8)b;
-									e._win = RGFW_mouse_win);
-	RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state));
-}
-void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
-	RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time);  RGFW_UNUSED(axis);
-	RGFW_ASSERT(RGFW_mouse_win != NULL);
-
-	double scroll = - wl_fixed_to_double(value);
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
-									e.point = RGFW_mouse_win->event.point;
-									e.button = RGFW_mouseScrollUp + (scroll < 0);
-									e.scroll = scroll;
-									e._win = RGFW_mouse_win);
-
-	RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
-}
-
-void RGFW_doNothing(void) { }
-
-void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
-	RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
-
-	char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
-	xkb_keymap_unref (keymap);
-	keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
-
-	munmap (keymap_string, size);
-	close (fd);
-	xkb_state_unref (xkb_state);
-	xkb_state = xkb_state_new (keymap);
-}
-void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
-	RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
-
-	RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
-
-	RGFW_key_win->_flags |= RGFW_windowFocus;
-	RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = RGFW_key_win);
-	RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
-
-	if ((RGFW_key_win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(RGFW_key_win, RGFW_AREA(RGFW_key_win->r.w, RGFW_key_win->r.h));
-}
-void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
-	RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
-
-	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
-	if (RGFW_key_win == win)
-		RGFW_key_win = NULL;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
-	RGFW_focusCallback(win, RGFW_FALSE);
-    RGFW_window_focusLost(win);
-}
-void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
-	RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
-
-	if (RGFW_key_win == NULL) return;
-
-	xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8);
-
-	u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8);
-	RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current;
-	RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state);
-
-	RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state);
-									e.key = (u8)RGFWkey;
-									e.keyChar = (u8)keysym;
-									e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey);
-									e._win = RGFW_key_win);
-
-	RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock")));
-	RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state));
-}
-void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
-	RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
-	xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
-}
-struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *, 
-int,  int))&RGFW_doNothing};
-
-void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
-	RGFW_UNUSED(data);
-    static struct wl_pointer_listener pointer_listener = {&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void*, struct wl_pointer*, uint32_t, uint32_t))&RGFW_doNothing};
-
-    if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
-		struct wl_pointer *pointer = wl_seat_get_pointer (seat);
-		wl_pointer_add_listener (pointer, &pointer_listener, NULL);
-	}
-	if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
-		struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
-		wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
-	}
-}
-struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
-
-void wl_global_registry_handler(void *data,
-		struct wl_registry *registry, uint32_t id, const char *interface,
-		uint32_t version)
-{
-	RGFW_window* win = (RGFW_window*)data;
-	RGFW_UNUSED(version);
-    if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
-		win->src.compositor = wl_registry_bind(registry,
-			id, &wl_compositor_interface, 4);
-	} else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
-		win->src.xdg_wm_base = wl_registry_bind(registry,
-		id, &xdg_wm_base_interface, 1);
-	} else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
-		decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
-    } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
-        win->src.shm = wl_registry_bind(registry,
-            id, &wl_shm_interface, 1);
-        wl_shm_add_listener(win->src.shm, &shm_listener, NULL);
-	} else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
-		win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
-		wl_seat_add_listener(win->src.seat, &seat_listener, NULL);
-	}
-}
-
-void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
-const struct wl_registry_listener registry_listener = {
-	.global = wl_global_registry_handler,
-	.global_remove = wl_global_registry_remove,
-};
-
-void decoration_handle_configure(void *data,
-		struct zxdg_toplevel_decoration_v1 *decoration,
-		enum zxdg_toplevel_decoration_v1_mode mode) {
-	RGFW_UNUSED(data); RGFW_UNUSED(decoration);
-	RGFW_current_mode = mode;
-}
-
-const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
-	.configure = decoration_handle_configure,
-};
-
-void randname(char *buf) {
-	struct timespec ts;
-	clock_gettime(CLOCK_REALTIME, &ts);
-	long r = ts.tv_nsec;
-
-    int i;
-    for (i = 0; i < 6; ++i) {
-		buf[i] = (char)('A'+(r&15)+(r&16)*2);
-		r >>= 5;
-	}
-}
-
-size_t wl_stringlen(char* name) {
-	size_t i = 0;
-    while (name[i]) { i++; }
-	return i;
-}
-
-int anonymous_shm_open(void) {
-	char name[] = "/RGFW-wayland-XXXXXX";
-	int retries = 100;
-
-	do {
-		randname(name + wl_stringlen(name) - 6);
-
-		--retries;
-		/* shm_open guarantees that O_CLOEXEC is set */
-		int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
-		if (fd >= 0) {
-			shm_unlink(name);
-			return fd;
-		}
-	} while (retries > 0 && errno == EEXIST);
-
-	return -1;
-}
-
-int create_shm_file(off_t size) {
-	int fd = anonymous_shm_open();
-	if (fd < 0) {
-		return fd;
-	}
-
-	if (ftruncate(fd, size) < 0) {
-		close(fd);
-		return -1;
-	}
-
-	return fd;
-}
-
-void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
-	RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time);
-
-	#ifdef RGFW_BUFFER
-		RGFW_window* win = (RGFW_window*)data;
-		wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
-		wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
-		wl_surface_commit(win->src.surface);
-	#endif
-}
-
-const struct wl_callback_listener wl_surface_frame_listener = {
-	.done = wl_surface_frame_done,
-};
-#endif /* RGFW_WAYLAND */
-/*
-	End of Wayland defines
-*/
-
-/*
-
-
-Start of Linux / Unix defines
-
-
-*/
-
-#ifdef RGFW_UNIX
-#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
-#include <X11/Xcursor/Xcursor.h>
-#endif
-
-#include <dlfcn.h>
-
-#ifndef RGFW_NO_DPI
-#include <X11/extensions/Xrandr.h>
-#include <X11/Xresource.h>
-#endif
-
-#include <X11/Xatom.h>
-#include <X11/keysymdef.h>
-#include <X11/extensions/sync.h>
-#include <unistd.h>
-
-#include <X11/XKBlib.h> /* for converting keycode to string */
-#include <X11/cursorfont.h> /* for hiding */
-#include <X11/extensions/shapeconst.h>
-#include <X11/extensions/shape.h>
-#include <X11/extensions/XInput2.h>
-
-#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
-#include <poll.h>
-
-/* atoms needed for drag and drop */
-Atom XdndAware, XtextPlain, XtextUriList;
-Atom RGFW_XUTF8_STRING = 0;
-
-Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0;
-
-#if defined(RGFW_X11) && !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
-	typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
-	typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
-	typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
-#endif
-#if defined(RGFW_OPENGL) && defined(RGFW_X11)
-	typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
-#endif
-
-#if !defined(RGFW_NO_X11_XI_PRELOAD) && defined(RGFW_X11)
-	typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
-	PFN_XISelectEvents XISelectEventsSRC = NULL;
-	#define XISelectEvents XISelectEventsSRC
-
-	void* X11Xihandle = NULL;
-#endif
-
-#if !defined(RGFW_NO_X11_EXT_PRELOAD) && defined(RGFW_X11)
-	typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
-	PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
-    #define XSyncIntToValue XSyncIntToValueSRC
-
-	typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
-	PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
-    #define XSyncSetCounter XSyncSetCounterSRC
-
-	typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
-	PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
-    #define XSyncCreateCounter XSyncCreateCounterSRC
-
-	typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
-	PFN_XShapeCombineMask XShapeCombineMaskSRC;
-    #define XShapeCombineMask XShapeCombineMaskSRC
-
-	typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
-    PFN_XShapeCombineRegion XShapeCombineRegionSRC;
-    #define XShapeCombineRegion XShapeCombineRegionSRC
-	void* X11XEXThandle = NULL;
-#endif
-
-#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) && defined(RGFW_X11)
-	PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
-	PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
-	PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
-
-	#define XcursorImageLoadCursor XcursorImageLoadCursorSRC
-	#define XcursorImageCreate XcursorImageCreateSRC
-	#define XcursorImageDestroy XcursorImageDestroySRC
-
-	void* X11Cursorhandle = NULL;
-#endif
-
-#ifdef RGFW_X11
-const char* RGFW_instName = NULL;
-void RGFW_setXInstName(const char* name) { RGFW_instName = name; }
-#endif
-
-#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
-RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
-    const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display));
-    return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); 
-}
-RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); }
-#endif
-
-void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
-	RGFW_GOTO_WAYLAND(0);
-
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	win->buffer = (u8*)buffer;
-	win->bufferSize = area;
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer");
-	#ifdef RGFW_X11
-		#ifdef RGFW_OSMESA
-				win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
-				OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
-				OSMesaPixelStore(OSMESA_Y_UP, 0);
-		#endif
-
-		win->src.bitmap = XCreateImage(
-			win->src.display, win->src.visual.visual, (u32)win->src.visual.depth,
-			ZPixmap, 0, NULL, area.w, area.h, 32, 0
-		);
-	#endif
-	#ifdef RGFW_WAYLAND
-		RGFW_WAYLAND_LABEL {}
-		u32 size = (u32)(win->r.w * win->r.h * 4);
-		int fd = create_shm_file(size);
-		if (fd < 0) {
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer.");
-			exit(1);
-        }
-
-		win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-		if (win->src.buffer == MAP_FAILED) {
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!");
-			close(fd);
-			exit(1);
-		}
-
-		win->_flags |= RGFW_BUFFER_ALLOC;
-
-		struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size);
-		win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
-			WL_SHM_FORMAT_ARGB8888);
-		wl_shm_pool_destroy(pool);
-
-		close(fd);
-
-		wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
-		wl_surface_commit(win->src.surface);
-
-		u8 color[] = {0x00, 0x00, 0x00, 0xFF};
-
-		size_t i;
-		for (i = 0; i < area.w * area.h * 4; i += 4) {
-			RGFW_MEMCPY(&win->buffer[i], color, 4);
-		}
-
-		RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4));
-
-		#if defined(RGFW_OSMESA)
-				win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
-				OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
-				OSMesaPixelStore(OSMESA_Y_UP, 0);
-		#endif
-	#endif
-#else
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL{}
-	#endif
-
-	RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area);
-#endif
-}
-
-#define RGFW_LOAD_ATOM(name) \
-	static Atom name = 0; \
-	if (name == 0) name = XInternAtom(_RGFW.display, #name, False);
-
-void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
-	RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
-
-	RGFW_GOTO_WAYLAND(0);
-	#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
-
-	struct __x11WindowHints {
-		unsigned long flags, functions, decorations, status;
-		long input_mode;
-	} hints;
-	hints.flags = 2;
-	hints.decorations = border;
-
-	XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32,
-				PropModeReplace, (u8*)&hints, 5
-	);
-
-	if (RGFW_window_isHidden(win) == 0) {
-		RGFW_window_hide(win);
-		RGFW_window_show(win);
-	}
-
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(win); RGFW_UNUSED(border);
-	#endif
-}
-
-void RGFW_releaseCursor(RGFW_window* win) {
-RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	XUngrabPointer(win->src.display, CurrentTime);
-
-	/* disable raw input */
-	unsigned char mask[] = { 0 };
-	XIEventMask em;
-	em.deviceid = XIAllMasterDevices;
-	em.mask_len = sizeof(mask);
-	em.mask = mask;
-
-	XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
-RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	/* enable raw input */
-	unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
-	XISetMask(mask, XI_RawMotion);
-
-	XIEventMask em;
-	em.deviceid = XIAllMasterDevices;
-	em.mask_len = sizeof(mask);
-	em.mask = mask;
-
-	XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
-
-	XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
-	RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(win); RGFW_UNUSED(r);
-#endif
-}
-
-#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
-#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
-	void* ptr = dlsym(proc, #name); \
-	if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \
-}
-
-#ifdef RGFW_X11
-void RGFW_window_getVisual(RGFW_window* win) {
-#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
-		i32* visual_attribs = RGFW_initFormatAttribs();
-		i32 fbcount;
-		GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount);
-
-		i32 best_fbc = -1;
-		i32 best_depth = 0;
-		i32 best_samples = 0;
-
-		if (fbcount == 0) {
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs");
-			return;
-		}
-
-        i32 i;
-		for (i = 0; i < fbcount; i++) {
-			XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]);
-			if (vi == NULL)
-				continue;
-
-			i32 samp_buf, samples;
-			glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
-			glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples);
-
-			if (best_fbc == -1) best_fbc = i;
-			if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32)  && best_depth == 0) {
-				best_fbc = i;
-				best_depth = vi->depth;
-			}
-			if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) {
-				best_fbc = i;
-				best_depth = vi->depth;
-				best_samples = samples;
-			}
-			XFree(vi);
-		}
-
-		if (best_fbc == -1) {
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual");
-			return;
-        }		
-
-		win->src.bestFbc = fbc[best_fbc];
-		XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc);
-		if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent))
-			RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth");
-
-		if (best_samples < RGFW_GL_HINTS[RGFW_glSamples])
-			RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling");
-
-        int configCaveat;
-        if (glXGetFBConfigAttrib(win->src.display, win->src.bestFbc, GLX_CONFIG_CAVEAT, &configCaveat) == Success &&
-            configCaveat == GLX_SLOW_CONFIG) {
-                win->_flags |= RGFW_windowOpenglSoftware;
-        }
-
-		XFree(fbc);
-        win->src.visual = *vi;
-		XFree(vi);
-#else
-	win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display));
-	win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
-	if (win->_flags & RGFW_windowTransparent) {
-		XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */
-		if (win->src.visual.depth != 32)
-		RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth");
-	}
-#endif
-}
-#endif
-#ifndef RGFW_EGL
-void RGFW_window_initOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-        i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
-		context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
-		if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore)
-			context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
-		else
-			context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
-
-		if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
-			context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
-			context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor];
-			context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
-			context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor];
-		}
-
-		glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
-		glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
-			glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
-
-		GLXContext ctx = NULL;
-		if (_RGFW.root != NULL && _RGFW.root != win) {
-			ctx = _RGFW.root->src.ctx;
-            RGFW_window_makeCurrent_OpenGL(_RGFW.root);
-        }
-
-		if (glXCreateContextAttribsARB == NULL) {
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context");
-			win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
-		}
-		else {
-				win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs);
-				XSync(win->src.display, False);
-				if (win->src.ctx == NULL) {
-					RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context");
-					win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
-            }
-		}
-        
-        glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);    
-        RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_window_freeOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-	if (win->src.ctx == NULL) return;
-	glXDestroyContext(win->src.display, win->src.ctx);
-	win->src.ctx = NULL;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
-#else
-RGFW_UNUSED(win);
-#endif
-}
-#endif
-
-
-i32 RGFW_init(void) {
-    RGFW_GOTO_WAYLAND(1);
-#if defined(RGFW_C89) || defined(__cplusplus)
-    if (_RGFW_init) return 0; 
-    _RGFW_init = RGFW_TRUE;    
-    _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
-#endif
-
-#ifdef RGFW_X11
-    if (_RGFW.windowCount != -1) return 0;
-    #ifdef RGFW_USE_XDL
-		XDL_init();
-	#endif
-
-	#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
-	#if defined(__CYGWIN__)
-				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
-	#elif defined(__OpenBSD__) || defined(__NetBSD__)
-				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
-	#else
-				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
-	#endif
-		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
-		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
-		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
-	#endif
-
-	#if !defined(RGFW_NO_X11_XI_PRELOAD)
-	#if defined(__CYGWIN__)
-			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
-	#elif defined(__OpenBSD__) || defined(__NetBSD__)
-			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
-	#else
-			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
-	#endif
-			RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
-	#endif
-
-	#if !defined(RGFW_NO_X11_EXT_PRELOAD)
-	#if defined(__CYGWIN__)
-			RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
-	#elif defined(__OpenBSD__) || defined(__NetBSD__)
-	        RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
-	#else
-			RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
-	#endif
-			RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
-			RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
-			RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
-    	    RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
-	        RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
-    #endif
-
-	XInitThreads(); /*!< init X11 threading */
-    _RGFW.display = XOpenDisplay(0);
-    XSetWindowAttributes wa;
-    RGFW_MEMSET(&wa, 0, sizeof(wa));
-    wa.event_mask = PropertyChangeMask;
-    _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0,
-                                        InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa);
-
-    _RGFW.windowCount = 0;
-    u8 RGFW_blk[] = { 0, 0, 0, 0 };
-	_RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
-	_RGFW.clipboard = NULL;
-
-    XkbComponentNamesRec rec;
-    XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd);
-    XkbDescPtr evdesc;
-    u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])];
-
-    XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc);
-
-    RGFW_MEMSET(&rec, 0, sizeof(rec));
-    rec.keycodes = (char*)"evdev";
-    evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
-    /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
-    if(evdesc != NULL && desc != NULL){
-        for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){
-    	    old[i] = RGFW_keycodes[i];
-    	    RGFW_keycodes[i] = 0;
-        }
-        for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
-    	    for(int j = desc->min_key_code; j <= desc->max_key_code; j++){
-    		if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
-    			RGFW_keycodes[j] = old[i];
-    			break;
-    		}
-    	    }
-        }
-	XkbFreeKeyboard(desc, 0, True);
-	XkbFreeKeyboard(evdesc, 0, True);
-    }
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL
-    _RGFW.wl_display = wl_display_connect(NULL);
-#endif
-    _RGFW.windowCount = 0;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
-    return 0;
-}
-
-
-RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
-	RGFW_window_basic_init(win, rect, flags);
-
-#ifdef RGFW_WAYLAND
-	win->src.compositor = NULL;
-#endif
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */
-
-    win->src.display = XOpenDisplay(NULL);
-    RGFW_window_getVisual(win);
-
-    /* make X window attrubutes */
-	XSetWindowAttributes swa;
-    RGFW_MEMSET(&swa, 0, sizeof(swa));
-
-	Colormap cmap;
-	swa.colormap = cmap = XCreateColormap(win->src.display,
-		DefaultRootWindow(win->src.display),
-		win->src.visual.visual, AllocNone);
-	swa.event_mask = event_mask;
-
-	/* create the window */
-    win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h,
-		0, win->src.visual.depth, InputOutput, win->src.visual.visual,
-		CWColormap | CWBorderPixel | CWEventMask, &swa);
-
-	XFreeColors(win->src.display, cmap, NULL, 0, 0);
-
-	win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
-
-	/* In your .desktop app, if you set the property
-	    StartupWMClass=RGFW that will assoicate the launcher icon
-	     with your application - robrohan */
-	if (RGFW_className == NULL)
-		RGFW_className = (char*)name;
-
-	XClassHint hint;
-	hint.res_class = (char*)RGFW_className;
-	if (RGFW_instName == NULL)	hint.res_name = (char*)name;
-	else 						hint.res_name = (char*)RGFW_instName;
-	XSetClassHint(win->src.display, win->src.window, &hint);
-
-	#ifndef RGFW_NO_MONITOR
-	if (flags & RGFW_windowScaleToMonitor)
-		RGFW_window_scaleToMonitor(win);
-	#endif
-	XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
-
-	/* make it so the user can't close the window until the program does */
-	if (wm_delete_window == 0) {
-		wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
-		RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
-		RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
-	}
-
-	XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
-	/* set the background */
-	RGFW_window_setName(win, name);
-
-	XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */
-
-	if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
-		win->_flags |= RGFW_windowAllowDND;
-
-		/* actions */
-		XtextUriList = XInternAtom(win->src.display, "text/uri-list", False);
-		XtextPlain = XInternAtom(win->src.display, "text/plain", False);
-		XdndAware = XInternAtom(win->src.display, "XdndAware", False);
-		const u8 version = 5;
-
-		XChangeProperty(win->src.display, win->src.window,
-			XdndAware, 4, 32,
-			PropModeReplace, &version, 1); /*!< turns on drag and drop */
-	}
-
-#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
-    RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
-    RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
-    Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window};
-    XSetWMProtocols(win->src.display, win->src.window, protcols, 2);
-
-    XSyncValue initial_value;
-    XSyncIntToValue(&initial_value, 0);
-    win->src.counter = XSyncCreateCounter(win->src.display, initial_value);
-
-    XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1);
-#endif
-
-	if ((flags & RGFW_windowNoInitAPI) == 0) {
-		RGFW_window_initOpenGL(win);
-        RGFW_window_initBuffer(win);
-    }
-
-    RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
-	RGFW_window_setMouseDefault(win);
-	RGFW_window_setFlags(win, flags);
-    
-    win->src.r = win->r;
-
-	RGFW_window_show(win);
-    return win; /*return newly created window */
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental");
-
-	win->src.wl_display = _RGFW.wl_display;
-	if (win->src.wl_display == NULL) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display");
-		#ifdef RGFW_X11
-			RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11");
-			RGFW_useWayland(0);
-			return RGFW_createWindowPtr(name, rect, flags, win);
-		#endif
-		return NULL;
-	}
-
-
-	#ifdef RGFW_X11
-        win->src.display = _RGFW.display;
-		win->src.window = _RGFW.helperWindow;
-        XMapWindow(_RGFW.display, win->src.window);
-		XFlush(win->src.display);
-		if (wm_delete_window == 0) {
-			wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
-			RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
-			RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
-		}
-	#endif
-
-	struct wl_registry *registry = wl_display_get_registry(win->src.wl_display);
-	wl_registry_add_listener(registry, &registry_listener, win);
-
-	wl_display_roundtrip(win->src.wl_display);
-	wl_display_dispatch(win->src.wl_display);
-
-	if (win->src.compositor == NULL) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor.");
-		return NULL;
-	}
-
-	if (RGFW_wl_cursor_theme == NULL) {
-		RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm);
-		RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor);
-
-		struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
-		RGFW_cursor_image = cursor->images[0];
-		struct wl_buffer* cursor_buffer	= wl_cursor_image_get_buffer(RGFW_cursor_image);
-
-		wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
-		wl_surface_commit(RGFW_cursor_surface);
-	}
-
-	xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL);
-
-	xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
-
-	win->src.surface = wl_compositor_create_surface(win->src.compositor);
-	wl_surface_set_user_data(win->src.surface, win);
-
-	win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface);
-	xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
-
-	xdg_wm_base_set_user_data(win->src.xdg_wm_base, win);
-
-	win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
-	xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
-	xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
-
-	xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
-
-	if (!(flags & RGFW_windowNoBorder)) {
-		win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
-					decoration_manager, win->src.xdg_toplevel);
-	}
-
-	wl_display_roundtrip(win->src.wl_display);
-
-	wl_surface_commit(win->src.surface);
-	RGFW_window_show(win);
-
-	/* wait for the surface to be configured */
-	while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { }
-
-    if ((flags & RGFW_windowNoInitAPI) == 0) {
-        RGFW_window_initOpenGL(win);
-        RGFW_window_initBuffer(win);
-    }
-	struct wl_callback* callback = wl_surface_frame(win->src.surface);
-	wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
-	wl_surface_commit(win->src.surface);
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
-
-	#ifndef RGFW_NO_MONITOR
-	if (flags & RGFW_windowScaleToMonitor)
-		RGFW_window_scaleToMonitor(win);
-	#endif
-    
-    RGFW_window_setName(win, name);
-	RGFW_window_setMouseDefault(win);
-	RGFW_window_setFlags(win, flags);
-	return win; /* return newly created window */
-#endif
-}
-
-RGFW_area RGFW_getScreenSize(void) {
-	RGFW_GOTO_WAYLAND(1);
-	RGFW_init();
-
-	#ifdef RGFW_X11
-	Screen* scrn = DefaultScreenOfDisplay(_RGFW.display);
-	return RGFW_AREA(scrn->width, scrn->height);
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */
-	#endif
-}
-
-RGFW_point RGFW_getGlobalMousePoint(void) {
-	RGFW_init();
-	RGFW_point RGFWMouse = RGFW_POINT(0, 0);
-    RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-	i32 x, y;
-	u32 z;
-	Window window1, window2;
-	XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
-	return RGFWMouse;
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-    return RGFWMouse;
-#endif
-}
-
-RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
-void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
-#ifdef RGFW_X11
-    RGFW_LOAD_ATOM(ATOM_PAIR);
-	RGFW_LOAD_ATOM(MULTIPLE);
-	RGFW_LOAD_ATOM(TARGETS);
-	RGFW_LOAD_ATOM(SAVE_TARGETS);
-
-    const XSelectionRequestEvent* request = &event->xselectionrequest;
-    const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING };
-    const int formatCount = sizeof(formats) / sizeof(formats[0]);
-
-    if (request->target == TARGETS) {
-        const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING };
-
-        XChangeProperty(_RGFW.display, request->requestor, request->property,
-                        XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
-    }  else if (request->target == MULTIPLE) {
-		Atom* targets = NULL;
-
-		Atom actualType = 0;
-		int actualFormat = 0;
-		unsigned long count = 0, bytesAfter = 0;
-
-		XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX,
-							False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
-
-		unsigned long i;
-		for (i = 0; i < (u32)count; i += 2) {
-			if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING)
-				XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i],
-					8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len);
-			else
-				targets[i + 1] = None;
-		}
-
-		XChangeProperty(_RGFW.display,
-			request->requestor, request->property, ATOM_PAIR, 32,
-			PropModeReplace, (u8*) targets, (i32)count);
-
-		XFlush(_RGFW.display);
-		XFree(targets);
-	} else if (request->target == SAVE_TARGETS)
-        XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
-    else {
-        int i;
-        for (i = 0;  i < formatCount;  i++) {
-			if (request->target != formats[i])
-				continue;
-			XChangeProperty(_RGFW.display, request->requestor, request->property, request->target,
-								8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len);
-		}
-	}
-
-    XEvent reply = { SelectionNotify };
-    reply.xselection.property = request->property;
-    reply.xselection.display = request->display;
-    reply.xselection.requestor = request->requestor;
-    reply.xselection.selection = request->selection;
-    reply.xselection.target = request->target;
-    reply.xselection.time = request->time;
-
-    XSendEvent(_RGFW.display, request->requestor, False, 0, &reply);
-#endif
-}
-
-char* RGFW_strtok(char* str, const char* delimStr);
-char* RGFW_strtok(char* str, const char* delimStr) {
-    static char* static_str = NULL;
-
-    if (str != NULL)
-        static_str = str;
-
-    if (static_str == NULL) {
-        return NULL;
-    }
-
-    while (*static_str != '\0') {
-        RGFW_bool delim = 0;
-        const char* d;
-        for (d = delimStr; *d != '\0'; d++) {
-            if (*static_str == *d) {
-                delim = 1;
-                break;
-            }
-        }
-        if (!delim)
-            break;
-        static_str++;
-    }
-
-    if (*static_str == '\0')
-        return NULL;
-
-    char* token_start = static_str;
-    while (*static_str != '\0') {
-        int delim = 0;
-        const char* d;
-        for (d = delimStr; *d != '\0'; d++) {
-            if (*static_str == *d) {
-                delim = 1;
-                break;
-            }
-        }
-
-        if (delim) {
-            *static_str = '\0';
-            static_str++;
-            break;
-        }
-        static_str++;
-    }
-
-    return token_start;
-}
-
-i32 RGFW_XHandleClipboardSelectionHelper(void);
-
-
-u8 RGFW_rgfwToKeyChar(u32 key) {
-    u32 keycode = RGFW_rgfwToApiKey(key);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    Window root = DefaultRootWindow(_RGFW.display);
-    Window ret_root, ret_child;
-    int root_x, root_y, win_x, win_y;
-    unsigned int mask;
-    XQueryPointer(_RGFW.display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
-    KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW.display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
-
-    if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
-        sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
-    if ((u8)sym != (u32)sym)
-        sym = 0;
-
-    return (u8)sym;
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL RGFW_UNUSED(keycode);
-    return (u8)key;
-#endif
-}
-
-RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
-    RGFW_XHandleClipboardSelectionHelper();
-
-    if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
-    RGFW_event* ev = RGFW_window_checkEventCore(win);
-	if (ev) return ev;
-
-	#if defined(__linux__) && !defined(RGFW_NO_LINUX)
-		if (RGFW_linux_updateGamepad(win)) return &win->event;
-	#endif
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(XdndTypeList);
-	RGFW_LOAD_ATOM(XdndSelection);
-	RGFW_LOAD_ATOM(XdndEnter);
-	RGFW_LOAD_ATOM(XdndPosition);
-	RGFW_LOAD_ATOM(XdndStatus);
-	RGFW_LOAD_ATOM(XdndLeave);
-	RGFW_LOAD_ATOM(XdndDrop);
-	RGFW_LOAD_ATOM(XdndFinished);
-	RGFW_LOAD_ATOM(XdndActionCopy);
-    RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
-    RGFW_LOAD_ATOM(WM_PROTOCOLS);
-	XPending(win->src.display);
-
-	XEvent E; /*!< raw X11 event */
-
-    /* if there is no unread qued events, get a new one */
-	if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading))
-		&& win->event.type != RGFW_quit
-	)
-		XNextEvent(win->src.display, &E);
-	else {
-		return NULL;
-	}
-
-	win->event.type = 0;
-
-	/* xdnd data */
-	static Window source = 0;
-	static long version = 0;
-	static i32 format = 0;
-
-	XEvent reply = { ClientMessage };
-
-	switch (E.type) {
-	case KeyPress:
-	case KeyRelease: {
-		win->event.repeat = RGFW_FALSE;
-		/* check if it's a real key release */
-		if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */
-			XEvent NE;
-			XPeekEvent(win->src.display, &NE);
-
-			if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */
-				win->event.repeat = RGFW_TRUE;
-		}
-
-		/* set event key data */
-		win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
-		win->event.keyChar = (u8)RGFW_rgfwToKeyChar(win->event.key);
-
-		RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
-
-		/* get keystate data */
-		win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
-
-        XKeyboardState keystate;
-		XGetKeyboardControl(win->src.display, &keystate);
-
-		RGFW_keyboard[win->event.key].current = (E.type == KeyPress);
-
-		XkbStateRec state;
-		XkbGetState(win->src.display, XkbUseCoreKbd, &state);
-		RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
-
-		RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress));
-		break;
-	}
-	case ButtonPress:
-	case ButtonRelease:
-		if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */
-			XFlush(win->src.display);
-			return RGFW_window_checkEvent(win);
-		}
-
-		win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */
-		win->event.button = (u8)(E.xbutton.button - 1);
-		switch(win->event.button) {
-			case RGFW_mouseScrollUp:
-				win->event.scroll = 1;
-				break;
-			case RGFW_mouseScrollDown:
-				win->event.scroll = -1;
-				break;
-			default: break;
-		}
-
-		RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-
-		if (win->event.repeat == RGFW_FALSE)
-			win->event.repeat = RGFW_isPressed(win, win->event.key);
-
-		RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
-		RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
-		break;
-
-	case MotionNotify:
-		win->event.point.x = E.xmotion.x;
-		win->event.point.y = E.xmotion.y;
-
-		win->event.vector.x = win->event.point.x - win->_lastMousePoint.x;
-		win->event.vector.y = win->event.point.y - win->_lastMousePoint.y;
-		win->_lastMousePoint = win->event.point;
-
-		win->event.type = RGFW_mousePosChanged;
-		RGFW_mousePosCallback(win, win->event.point, win->event.vector);
-		break;
-
-	case GenericEvent: {
-		/* MotionNotify is used for mouse events if the mouse isn't held */
-		if (!(win->_flags & RGFW_HOLD_MOUSE)) {
-			XFreeEventData(win->src.display, &E.xcookie);
-			break;
-		}
-
-		XGetEventData(win->src.display, &E.xcookie);
-		if (E.xcookie.evtype == XI_RawMotion) {
-			XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
-			if (raw->valuators.mask_len == 0) {
-				XFreeEventData(win->src.display, &E.xcookie);
-				break;
-			}
-
-			double deltaX = 0.0f;
-			double deltaY = 0.0f;
-
-			/* check if relative motion data exists where we think it does */
-			if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
-				deltaX += raw->raw_values[0];
-			if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
-				deltaY += raw->raw_values[1];
-
-			win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY);
-			win->event.point.x = win->_lastMousePoint.x + win->event.vector.x;
-			win->event.point.y = win->_lastMousePoint.y + win->event.vector.y;
-			win->_lastMousePoint = win->event.point;
-
-			RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
-
-			win->event.type = RGFW_mousePosChanged;
-			RGFW_mousePosCallback(win, win->event.point, win->event.vector);
-		}
-
-		XFreeEventData(win->src.display, &E.xcookie);
-		break;
-	}
-
-	case Expose: {
-		win->event.type = RGFW_windowRefresh;
-		RGFW_windowRefreshCallback(win);
-
-#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
-        XSyncValue value;
-        XSyncIntToValue(&value, (i32)win->src.counter_value);
-        XSyncSetCounter(win->src.display, win->src.counter, value);
-#endif
-        break;
-    }
-	case MapNotify: case UnmapNotify: 		RGFW_window_checkMode(win); break;
-	case ClientMessage: {
-		/* if the client closed the window */
-		if (E.xclient.data.l[0] == (long)wm_delete_window) {
-			win->event.type = RGFW_quit;
-			RGFW_window_setShouldClose(win, RGFW_TRUE);
-			RGFW_windowQuitCallback(win);
-			break;
-		}
-#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
-        if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
-		    RGFW_windowRefreshCallback(win);
-            win->src.counter_value = 0;
-            win->src.counter_value |= E.xclient.data.l[2];
-            win->src.counter_value |= (E.xclient.data.l[3] << 32);
-
-            XSyncValue value;
-            XSyncIntToValue(&value, (i32)win->src.counter_value);
-            XSyncSetCounter(win->src.display, win->src.counter, value);
-            break;
-        }
-#endif
-        if ((win->_flags & RGFW_windowAllowDND) == 0)
-			break;
-
-        reply.xclient.window = source;
-		reply.xclient.format = 32;
-		reply.xclient.data.l[0] = (long)win->src.window;
-		reply.xclient.data.l[1] = 0;
-		reply.xclient.data.l[2] = None;
-
-		if (E.xclient.message_type == XdndEnter) {
-            if (version > 5)
-				break;
-
-			unsigned long count;
-			Atom* formats;
-			Atom real_formats[6];
-			Bool list = E.xclient.data.l[1] & 1;
-
-			source = (unsigned long int)E.xclient.data.l[0];
-			version = E.xclient.data.l[1] >> 24;
-			format = None;
-			if (list) {
-				Atom actualType;
-				i32 actualFormat;
-				unsigned long bytesAfter;
-
-				XGetWindowProperty(
-					win->src.display, source, XdndTypeList,
-					0, LONG_MAX, False, 4,
-					&actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
-				);
-			} else {
-				count = 0;
-
-                size_t i;
-				for (i = 2; i < 5; i++) {
-					if (E.xclient.data.l[i] != None) {
-						real_formats[count] = (unsigned long int)E.xclient.data.l[i];
-						count += 1;
-					}
-				}
-
-				formats = real_formats;
-			}
-
-            size_t i;
-			for (i = 0; i < count; i++) {
-				if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
-					format = (int)formats[i];
-					break;
-				}
-			}
-
-			if (list) {
-				XFree(formats);
-			}
-
-			break;
-		}
-
-		if (E.xclient.message_type == XdndPosition) {
-            const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
-			const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
-			Window dummy;
-			i32 xpos, ypos;
-
-			if (version > 5)
-				break;
-
-			XTranslateCoordinates(
-				win->src.display, XDefaultRootWindow(win->src.display), win->src.window,
-				xabs, yabs, &xpos, &ypos, &dummy
-			);
-
-			win->event.point.x = xpos;
-			win->event.point.y = ypos;
-
-			reply.xclient.window = source;
-			reply.xclient.message_type = XdndStatus;
-
-			if (format) {
-				reply.xclient.data.l[1] = 1;
-				if (version >= 2)
-					reply.xclient.data.l[4] = (long)XdndActionCopy;
-			}
-
-			XSendEvent(win->src.display, source, False, NoEventMask, &reply);
-			XFlush(win->src.display);
-			break;
-		}
-		if (E.xclient.message_type != XdndDrop)
-			break;
-
-		if (version > 5)
-			break;
-
-	        size_t i;
-		for (i = 0; i < win->event.droppedFilesCount; i++)
-			win->event.droppedFiles[i][0] = '\0';
-
-		win->event.droppedFilesCount = 0;
-
-
-		win->event.type = RGFW_DNDInit;
-
-		if (format) {
-			Time time = (version >= 1)
-				? (Time)E.xclient.data.l[2]
-				: CurrentTime;
-
-			XConvertSelection(
-				win->src.display, XdndSelection, (Atom)format,
-				XdndSelection, win->src.window, time
-			);
-		} else if (version >= 2) {
-			XEvent new_reply = { ClientMessage };
-
-			XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
-			XFlush(win->src.display);
-		}
-
-		RGFW_dndInitCallback(win, win->event.point);
-	} break;
-	case SelectionRequest:
-		RGFW_XHandleClipboardSelection(&E);
-		XFlush(win->src.display);
-		return RGFW_window_checkEvent(win);
-	case SelectionNotify: {
-		/* this is only for checking for xdnd drops */
-        if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND))
-			break;
-		char* data;
-		unsigned long result;
-
-		Atom actualType;
-		i32 actualFormat;
-		unsigned long bytesAfter;
-
-		XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
-
-		if (result == 0)
-			break;
-
-		const char* prefix = (const char*)"file://";
-
-		char* line;
-
-		win->event.droppedFilesCount = 0;
-		win->event.type = RGFW_DND;
-
-		while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
-			char path[RGFW_MAX_PATH];
-
-			data = NULL;
-
-			if (line[0] == '#')
-				continue;
-
-			char* l;
-			for (l = line; 1; l++) {
-				if ((l - line) > 7)
-					break;
-				else if (*l != prefix[(l - line)])
-					break;
-				else if (*l == '\0' && prefix[(l - line)] == '\0') {
-					line += 7;
-					while (*line != '/')
-						line++;
-					break;
-				} else if (*l == '\0')
-					break;
-			}
-
-			win->event.droppedFilesCount++;
-
-			size_t index = 0;
-			while (*line) {
-				if (line[0] == '%' && line[1] && line[2]) {
-					const char digits[3] = { line[1], line[2], '\0' };
-					path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
-					line += 2;
-				} else
-					path[index] = *line;
-
-				index++;
-				line++;
-			}
-			path[index] = '\0';
-			RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
-		}
-
-		RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
-		if (data)
-			XFree(data);
-
-		if (version >= 2) {
-            XEvent new_reply = { ClientMessage };
-            new_reply.xclient.window = source;
-            new_reply.xclient.message_type = XdndFinished;
-            new_reply.xclient.format = 32;
-			new_reply.xclient.data.l[1] = (long int)result;
-			new_reply.xclient.data.l[2] = (long int)XdndActionCopy;
-            XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
-			XFlush(win->src.display);
-		}
-		break;
-	}
-	case FocusIn:
-		if ((win->_flags & RGFW_windowFullscreen))
-			XMapRaised(win->src.display, win->src.window);
-
-		win->_flags |= RGFW_windowFocus;
-		win->event.type = RGFW_focusIn;
-		RGFW_focusCallback(win, 1);
-
-
-	    if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
-        break;
-	case FocusOut:
-        win->event.type = RGFW_focusOut;
-		RGFW_focusCallback(win, 0);
-        RGFW_window_focusLost(win);
-		break;
-	case PropertyNotify: RGFW_window_checkMode(win); break;
-	case EnterNotify: {
-		win->event.type = RGFW_mouseEnter;
-		win->event.point.x = E.xcrossing.x;
-		win->event.point.y = E.xcrossing.y;
-		RGFW_mouseNotifyCallback(win, win->event.point, 1);
-		break;
-	}
-
-	case LeaveNotify: {
-		win->event.type = RGFW_mouseLeave;
-		RGFW_mouseNotifyCallback(win, win->event.point, 0);
-		break;
-	}
-
-	case ConfigureNotify: {
-		/* detect resize */
-		RGFW_window_checkMode(win);
-		if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) {
-			win->event.type = RGFW_windowResized;
-			win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height);
-			RGFW_windowResizedCallback(win, win->r);
-			break;
-		}
-
-		/* detect move */
-		if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) {
-			win->event.type = RGFW_windowMoved;
-            win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h);
-			RGFW_windowMovedCallback(win, win->r);
-			break;
-		}
-
-		break;
-	}
-	default:
-		XFlush(win->src.display);
-		return RGFW_window_checkEvent(win);
-	}
-	XFlush(win->src.display);
-	if (win->event.type) return &win->event;
-	else return NULL;
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	if ((win->_flags & RGFW_windowHide) == 0)
-        wl_display_roundtrip(win->src.wl_display);
-	return NULL;
-#endif
-}
-
-void RGFW_window_move(RGFW_window* win, RGFW_point v) {
-	RGFW_ASSERT(win != NULL);
-	win->r.x = v.x;
-	win->r.y = v.y;
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	XMoveWindow(win->src.display, win->src.window, v.x, v.y);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	RGFW_ASSERT(win != NULL);
-
-	if (win->src.compositor) {
-		struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat);
-			if (!pointer) {
-				return;
-			}
-
-		wl_display_flush(win->src.wl_display);
-	}
-#endif
-}
-
-
-void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-	win->r.w = (i32)a.w;
-	win->r.h = (i32)a.h;
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	XResizeWindow(win->src.display, win->src.window, a.w, a.h);
-
-	if ((win->_flags & RGFW_windowNoResize)) {
-		XSizeHints sh;
-		sh.flags = (1L << 4) | (1L << 5);
-		sh.min_width = sh.max_width = (i32)a.w;
-		sh.min_height = sh.max_height = (i32)a.h;
-
-		XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
-	}
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	if (win->src.compositor) {
-		xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
-		#ifdef RGFW_OPENGL
-		wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0);
-		#endif
-	}
-#endif
-}
-
-void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-
-	if (a.w == 0 && a.h == 0)
-		return;
-#ifdef RGFW_X11
-	XSizeHints hints;
-	long flags;
-
-	XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
-
-	hints.flags |= PAspect;
-
-	hints.min_aspect.x = hints.max_aspect.x = (i32)a.w;
-	hints.min_aspect.y = hints.max_aspect.y = (i32)a.h;
-
-	XSetWMNormalHints(win->src.display, win->src.window, &hints);
-    return;
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL 
-#endif
-}
-
-void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    long flags;
-	XSizeHints hints;
-    RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
-
-	XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
-
-	hints.flags |= PMinSize;
-
-	hints.min_width = (i32)a.w;
-	hints.min_height = (i32)a.h;
-
-	XSetWMNormalHints(win->src.display, win->src.window, &hints);
-    return;
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
-#endif
-}
-
-void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    long flags;
-	XSizeHints hints;
-    RGFW_MEMSET(&hints, 0, sizeof(XSizeHints));
-
-	XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
-
-	hints.flags |= PMaxSize;
-
-	hints.max_width = (i32)a.w;
-	hints.max_height = (i32)a.h;
-
-	XSetWMNormalHints(win->src.display, win->src.window, &hints);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL RGFW_UNUSED(a);
-#endif
-}
-
-#ifdef RGFW_X11
-void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
-void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_LOAD_ATOM(_NET_WM_STATE);
-	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
-	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
-
-	XEvent xev = {0};
-	xev.type = ClientMessage;
-	xev.xclient.window = win->src.window;
-	xev.xclient.message_type = _NET_WM_STATE;
-	xev.xclient.format = 32;
-	xev.xclient.data.l[0] = maximized;
-	xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
-	xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
-	xev.xclient.data.l[3] = 0;
-	xev.xclient.data.l[4] = 0;
-
-	XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-}
-#endif
-
-void RGFW_window_maximize(RGFW_window* win) {
-	win->_oldRect = win->r;
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11 
-    RGFW_toggleXMaximized(win, 1);
-    return;
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-    return;
-#endif
-}
-
-void RGFW_window_focus(RGFW_window* win) {
-	RGFW_ASSERT(win);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    XWindowAttributes attr;
-    XGetWindowAttributes(win->src.display, win->src.window, &attr);
-    if (attr.map_state != IsViewable) return;
-
-	XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime);
-	XFlush(win->src.display);
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL;
-#endif
-}
-
-void RGFW_window_raise(RGFW_window* win) {
-	RGFW_ASSERT(win);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    XRaiseWindow(win->src.display, win->src.window);
-	XMapRaised(win->src.display, win->src.window);
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL;
-#endif
-}
-
-#ifdef RGFW_X11
-void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
-void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_LOAD_ATOM(_NET_WM_STATE);
-
-	XEvent xev = {0};
-    xev.xclient.type = ClientMessage;
-    xev.xclient.serial = 0;
-    xev.xclient.send_event = True;
-    xev.xclient.message_type = _NET_WM_STATE;
-    xev.xclient.window = win->src.window;
-    xev.xclient.format = 32;
-    xev.xclient.data.l[0] = fullscreen;
-    xev.xclient.data.l[1] = (long int)netAtom;
-    xev.xclient.data.l[2] = 0;
-
-    XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
-}
-#endif
-
-void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-    if (fullscreen) {
-		win->_flags |= RGFW_windowFullscreen;
-		win->_oldRect = win->r;
-	}
-	else win->_flags &= ~(u32)RGFW_windowFullscreen;
-#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
-
-	RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
-
-	XRaiseWindow(win->src.display, win->src.window);
-	XMapRaised(win->src.display, win->src.window);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL;
-#endif
-}
-
-void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
-    RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
-	RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL RGFW_UNUSED(floating);
-#endif
-}
-
-void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    const u32 value = (u32) (0xffffffffu * (double) opacity);
-	RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
-    XChangeProperty(win->src.display, win->src.window,
-					NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL RGFW_UNUSED(opacity);
-#endif
-}
-
-void RGFW_window_minimize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-	if (RGFW_window_isMaximized(win)) return;
-
-	win->_oldRect = win->r;
-#ifdef RGFW_X11
-    XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display));
-	XFlush(win->src.display);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL;
-#endif
-}
-
-void RGFW_window_restore(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    RGFW_toggleXMaximized(win, 0);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-#endif
-	win->r = win->_oldRect;
-	RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
-	RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
-	
-    RGFW_window_show(win);
-#ifdef RGFW_X11	
-    XFlush(win->src.display);
-#endif
-}
-
-RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    RGFW_LOAD_ATOM(_NET_WM_STATE);
-	RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
-
-	Atom actual_type;
-	int actual_format;
-	unsigned long nitems, bytes_after;
-	Atom* prop_return = NULL;
-
-	int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
-									&actual_type, &actual_format, &nitems, &bytes_after,
-									(unsigned char **)&prop_return);
-
-	if (status != Success || actual_type != XA_ATOM)
-		return RGFW_FALSE;
-
-    unsigned long i;
-	for (i = 0; i < nitems; i++)
-		if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
-
-	if (prop_return)
-		XFree(prop_return);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL RGFW_UNUSED(win);
-#endif
-	return RGFW_FALSE;
-}
-
-void RGFW_window_setName(RGFW_window* win, const char* name) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-	#ifdef RGFW_X11
-	XStoreName(win->src.display, win->src.window, name);
-
-	RGFW_LOAD_ATOM(_NET_WM_NAME);
-
-    char buf[256];
-    RGFW_MEMSET(buf, 0, sizeof(buf));
-    RGFW_STRNCPY(buf, name, sizeof(buf) - 1);
-
-    XChangeProperty(
-		win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING,
-		8, PropModeReplace, (u8*)buf, sizeof(buf)
-	);
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	if (win->src.compositor)
-		xdg_toplevel_set_title(win->src.xdg_toplevel, name);
-	#endif
-}
-
-#ifndef RGFW_NO_PASSTHROUGH
-void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    if (passthrough) {
-		Region region = XCreateRegion();
-		XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
-		XDestroyRegion(region);
-
-		return;
-	}
-
-	XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL RGFW_UNUSED(passthrough);
-#endif
-}
-#endif /* RGFW_NO_PASSTHROUGH */
-
-RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(_NET_WM_ICON);
-	if (icon == NULL || (channels != 3 && channels != 4)) {
-		RGFW_bool res = (RGFW_bool)XChangeProperty(
-			win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
-			PropModeReplace, (u8*)NULL, 0
-		);
-		return res;
-	}
-
-	i32 count = (i32)(2 + (a.w * a.h));
-
-	unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
-    RGFW_ASSERT(data != NULL);
-
-    data[0] = (unsigned long)a.w;
-	data[1] = (unsigned long)a.h;
-
-	unsigned long* target = &data[2];
-	u32 x, y;
-
-	for (x = 0; x < a.w; x++) {
-		for (y = 0; y < a.h; y++) {
-			size_t i = y * a.w + x;
-			u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
-
-			target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) |
-						(unsigned long)((icon[i * 4 + 1]) <<  8) |
-						(unsigned long)((icon[i * 4 + 2]) <<  0) |
-						(unsigned long)(alpha << 24);
-		}
-	}
-
-	RGFW_bool res = RGFW_TRUE;
-	if (type & RGFW_iconTaskbar) {
-		res = (RGFW_bool)XChangeProperty(
-			win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
-			PropModeReplace, (u8*)data, count
-		);
-	}
-
-	if (type & RGFW_iconWindow) {
-		XWMHints wm_hints;
-		wm_hints.flags = IconPixmapHint;
-
-		i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
-		XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)),
-									(u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0);
-
-		wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth);
-		XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h);
-		image->data = NULL;
-		XDestroyImage(image);
-
-		XSetWMHints(win->src.display, win->src.window, &wm_hints);
-	}
-
-	RGFW_FREE(data);
-	XFlush(win->src.display);
-	return RGFW_BOOL(res);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL  RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type);
-	return RGFW_FALSE;
-#endif
-}
-
-RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
-    RGFW_ASSERT(icon);
-	RGFW_ASSERT(channels == 3 || channels == 4);
-	RGFW_GOTO_WAYLAND(0);
-
-#ifdef RGFW_X11
-#ifndef RGFW_NO_X11_CURSOR
-	RGFW_init();
-    XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h);
-	native->xhot = 0;
-	native->yhot = 0;
-
-	XcursorPixel* target = native->pixels;
-    size_t x, y;
-    for (x = 0; x < a.w; x++) {
-		for (y = 0; y < a.h; y++) {
-			size_t i = y * a.w + x;
-			u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
-
-			target[i] = (u32)((icon[i * 4 + 0]) << 16)
-				| (u32)((icon[i * 4 + 1]) << 8)
-				| (u32)((icon[i * 4 + 2]) << 0)
-				| (u32)(alpha << 24);
-		}
-	}
-
-	Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native);
-	XcursorImageDestroy(native);
-
-	return (void*)cursor;
-#else
-	RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels);
-	return NULL;
-#endif
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels);
-	return NULL; /* TODO */
-#endif
-}
-
-void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
-RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	RGFW_ASSERT(win && mouse);
-	XDefineCursor(win->src.display, win->src.window, (Cursor)mouse);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(win); RGFW_UNUSED(mouse);
-#endif
-}
-
-void RGFW_freeMouse(RGFW_mouse* mouse) {
-RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	RGFW_ASSERT(mouse);
-	XFreeCursor(_RGFW.display, (Cursor)mouse);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(mouse);
-#endif
-}
-
-void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
-RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-	RGFW_ASSERT(win != NULL);
-
-	XEvent event;
-	XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
-		&event.xbutton.root, &event.xbutton.window,
-		&event.xbutton.x_root, &event.xbutton.y_root,
-		&event.xbutton.x, &event.xbutton.y,
-		&event.xbutton.state);
-
-	win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
-	if (event.xbutton.x == p.x && event.xbutton.y == p.y)
-		return;
-
-	XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(win); RGFW_UNUSED(p);
-#endif
-}
-
-RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
-	return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
-}
-
-RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
-
-	if (mouse > (sizeof(mouseIconSrc) / sizeof(u8)))
-		return RGFW_FALSE;
-
-	mouse = mouseIconSrc[mouse];
-
-	Cursor cursor = XCreateFontCursor(win->src.display, mouse);
-	XDefineCursor(win->src.display, win->src.window, (Cursor) cursor);
-
-	XFreeCursor(win->src.display, (Cursor) cursor);
-	return RGFW_TRUE;
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL { }
-	static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
-
-	struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
-	RGFW_cursor_image = wlcursor->images[0];
-	struct wl_buffer* cursor_buffer	= wl_cursor_image_get_buffer(RGFW_cursor_image);
-
-	wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
-	wl_surface_commit(RGFW_cursor_surface);
-	return RGFW_TRUE;
-    
-#endif
-}
-
-void RGFW_window_hide(RGFW_window* win) {
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	XUnmapWindow(win->src.display, win->src.window);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	wl_surface_attach(win->src.surface, NULL, 0, 0);
-	wl_surface_commit(win->src.surface);
-	win->_flags |= RGFW_windowHide;
-#endif
-}
-
-void RGFW_window_show(RGFW_window* win) {
-	win->_flags &= ~(u32)RGFW_windowHide;
-	if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
-	RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-	XMapWindow(win->src.display, win->src.window);
-#endif
-#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-	/* wl_surface_attach(win->src.surface, win->rc., 0, 0); */
-	wl_surface_commit(win->src.surface);
-#endif
-}
-
-RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
-	RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-	RGFW_init();
-	if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
-		if (str != NULL)
-			RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1);
-		_RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0';
-		return (RGFW_ssize_t)_RGFW.clipboard_len - 1;
-	}
-
-	XEvent event;
-	int format;
-	unsigned long N, sizeN;
-	char* data;
-	Atom target;
-
-	RGFW_LOAD_ATOM(XSEL_DATA);
-
-	XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime);
-	XSync(_RGFW.display, 0);
-	while (1) {
-		XNextEvent(_RGFW.display, &event);
-		if (event.type != SelectionNotify) continue;
-
-		if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0)
-			return -1;
-		break;
-	}
-
-	XGetWindowProperty(event.xselection.display, event.xselection.requestor,
-			event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
-			&format, &sizeN, &N, (u8**) &data);
-
-	RGFW_ssize_t size;
-	if (sizeN > strCapacity && str != NULL)
-		size = -1;
-
-	if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) {
-		RGFW_MEMCPY(str, data, sizeN);
-		str[sizeN] = '\0';
-		XFree(data);
-	} else if (str != NULL) size = -1;
-
-	XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
-	size = (RGFW_ssize_t)sizeN;
-
-    return size;
-	#endif
-	#if defined(RGFW_WAYLAND) 
-	RGFW_WAYLAND_LABEL RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); 
-	return 0;
-	#endif
-}
-
-i32 RGFW_XHandleClipboardSelectionHelper(void) {
-#ifdef RGFW_X11
-    RGFW_LOAD_ATOM(SAVE_TARGETS);
-
-    XEvent event;
-    XPending(_RGFW.display);
-
-    if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading))
-        XNextEvent(_RGFW.display, &event);
-    else
-        return 0;
-
-    switch (event.type) {
-        case SelectionRequest:
-            RGFW_XHandleClipboardSelection(&event);
-            return 0;
-        case SelectionNotify:
-            if (event.xselection.target == SAVE_TARGETS)
-                return 0;
-            break;
-        default: break;
-    }
-
-    return 0;
-#else
-    return 1;
-#endif
-}
-
-void RGFW_writeClipboard(const char* text, u32 textLen) {
-	RGFW_GOTO_WAYLAND(1);
-	#ifdef RGFW_X11
-	RGFW_LOAD_ATOM(SAVE_TARGETS);
-    RGFW_init();
-
-    /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
-	XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime);
-	if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) {
-    	RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection");
-		return;
-	}
-
-	if (_RGFW.clipboard)
-		RGFW_FREE(_RGFW.clipboard);
-
-	_RGFW.clipboard = (char*)RGFW_ALLOC(textLen);
-	RGFW_ASSERT(_RGFW.clipboard != NULL);
-
-	RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1);
-	_RGFW.clipboard[textLen - 1] = '\0';
-	_RGFW.clipboard_len = textLen;
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-    RGFW_UNUSED(text); RGFW_UNUSED(textLen);
-	#endif
-}
-
-RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11     
-
-	XWindowAttributes windowAttributes;
-	XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
-
-	return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-    return RGFW_FALSE;
-#endif
-}
-
-RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11     
-    RGFW_LOAD_ATOM(WM_STATE);
-
-	Atom actual_type;
-	i32 actual_format;
-	unsigned long nitems, bytes_after;
-	unsigned char* prop_data;
-
-	i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False,
-		AnyPropertyType, &actual_type, &actual_format,
-		&nitems, &bytes_after, &prop_data);
-
-	if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
-		XFree(prop_data);
-		return RGFW_TRUE;
-	}
-
-	if (prop_data != NULL)
-		XFree(prop_data);
-
-	XWindowAttributes windowAttributes;
-	XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
-    return windowAttributes.map_state != IsViewable;
-#endif
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-    return RGFW_FALSE;
-#endif
-}
-
-RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-    RGFW_GOTO_WAYLAND(0);
-#ifdef RGFW_X11
-    RGFW_LOAD_ATOM(_NET_WM_STATE);
-	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
-	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
-
-	Atom actual_type;
-	i32 actual_format;
-	unsigned long nitems, bytes_after;
-	unsigned char* prop_data;
-
-	i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False,
-		XA_ATOM, &actual_type, &actual_format,
-		&nitems, &bytes_after, &prop_data);
-
-	if (status != Success) {
-		if (prop_data != NULL)
-			XFree(prop_data);
-
-		return RGFW_FALSE;
-	}
-
-	u64 i;
-	for (i = 0; i < nitems; ++i) {
-		if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
-			prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
-			XFree(prop_data);
-			return RGFW_TRUE;
-		}
-	}
-
-	if (prop_data != NULL)
-		XFree(prop_data);
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL;
-#endif
-	return RGFW_FALSE;
-}
-
-#ifndef RGFW_NO_DPI
-u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi);
-u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) {
-    if (mi.hTotal == 0 || mi.vTotal == 0) return 0;
-	return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal));
-}
-#endif
-
-
-#ifdef RGFW_X11
-static float XGetSystemContentDPI(Display* display, i32 screen) {
-	float dpi = 96.0f;
-
-	#ifndef RGFW_NO_DPI
-		RGFW_UNUSED(screen);
-		char* rms = XResourceManagerString(display);
-		XrmDatabase db = NULL;
-		if (rms) db = XrmGetStringDatabase(rms);
-
-		if (rms && db) {
-			XrmValue value;
-			char* type = NULL;
-
-			if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
-				dpi = (float)RGFW_ATOF(value.addr);
-			XrmDestroyDatabase(db);
-		}
-	#else
-		dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4));
-	#endif
-
-	return dpi;
-}
-#endif
-
-RGFW_monitor RGFW_XCreateMonitor(i32 screen);
-RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
-	RGFW_monitor monitor;
-    RGFW_init();
-
-	RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-    Display* display = _RGFW.display;
-
-	if (screen == -1) screen = DefaultScreen(display);
-
-	Screen* scrn = DefaultScreenOfDisplay(display);
-	RGFW_area size = RGFW_AREA(scrn->width, scrn->height);
-
-	monitor.x = 0;
-	monitor.y = 0;
-	monitor.mode.area = RGFW_AREA(size.w, size.h);
-	monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f;
-	monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f;
-
-	RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode);
-
-	char* name = XDisplayName((const char*)display);
-	RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1);
-	monitor.name[sizeof(monitor.name) - 1] = '\0';
-
-	float dpi = XGetSystemContentDPI(display, screen);
-	monitor.pixelRatio = dpi >= 192.0f ? 2 : 1;
-	monitor.scaleX = (float) (dpi) / 96.0f;
-	monitor.scaleY = (float) (dpi) / 96.0f;
-
-	#ifndef RGFW_NO_DPI
-		XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
-		monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]);
-
-		XRRCrtcInfo* ci = NULL;
-		int crtc = screen;
-
-		if (sr->ncrtc > crtc) {
-			ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
-		}
-	#endif
-
-	#ifndef RGFW_NO_DPI
-		XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
-
-		if (info == NULL || ci == NULL) {
-			XRRFreeScreenResources(sr);
-			RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
-			return monitor;
-		}
-
-
-		float physW = (float)info->mm_width / 25.4f;
-		float physH = (float)info->mm_height / 25.4f;
-
-		RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
-		monitor.name[sizeof(monitor.name) - 1] = '\0';
-
-	if ((u8)physW && (u8)physH) {
-		monitor.physW = physW;
-		monitor.physH = physH;
-	}
-
-	monitor.x = ci->x;
-	monitor.y = ci->y;
-
-	if (ci->width && ci->height) {
-		monitor.mode.area.w = (u32)ci->width;
-		monitor.mode.area.h = (u32)ci->height;
-	}
-	#endif
-
-	#ifndef RGFW_NO_DPI
-		XRRFreeCrtcInfo(ci);
-		XRRFreeScreenResources(sr);
-	#endif
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
-    return monitor;
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL  RGFW_UNUSED(screen);
-    RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
-    return monitor;
-#endif
-}
-
-RGFW_monitor* RGFW_getMonitors(size_t* len) {
-	static RGFW_monitor monitors[7];
-
-	RGFW_GOTO_WAYLAND(1);
-	#ifdef RGFW_X11
-    RGFW_init();
-
-	Display* display = _RGFW.display;
-	i32 max = ScreenCount(display);
-
-	i32 i;
-	for (i = 0; i < max && i < 6; i++)
-		monitors[i] = RGFW_XCreateMonitor(i);
-
-	if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6));
-
-	return monitors;
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL RGFW_UNUSED(len);
-    return monitors; /* TODO WAYLAND */
-	#endif
-}
-
-RGFW_monitor RGFW_getPrimaryMonitor(void) {
-	RGFW_GOTO_WAYLAND(1);
-	#ifdef RGFW_X11
-	return RGFW_XCreateMonitor(-1);
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL return (RGFW_monitor){ 0 }; /* TODO WAYLAND */
-	#endif
-}
-
-RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
-	RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-	#ifndef RGFW_NO_DPI
-    RGFW_init();
-    XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display));
-	if (screenRes == NULL) return RGFW_FALSE;
-
-    int i;
-    for (i = 0; i < screenRes->ncrtc; i++) {
-		XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]);
-		if (!crtcInfo) continue;
-
-		if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) {
-			RRMode rmode = None;
-            int index;
-            for (index = 0; index < screenRes->nmode; index++) {
-				RGFW_monitorMode foundMode;
-				foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height);
-				foundMode.refreshRate =  RGFW_XCalculateRefreshRate(screenRes->modes[index]);
-				RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode);
-
-				if (RGFW_monitorModeCompare(mode, foundMode, request)) {
-					rmode = screenRes->modes[index].id;
-
-					RROutput output = screenRes->outputs[i];
-					XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output);
-					if (info) {
-						XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i],
-										CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1);
-						XRRFreeOutputInfo(info);
-						XRRFreeCrtcInfo(crtcInfo);
-						XRRFreeScreenResources(screenRes);
-						return RGFW_TRUE;
-					}
-				}
-			}
-
-			XRRFreeCrtcInfo(crtcInfo);
-			XRRFreeScreenResources(screenRes);
-			return RGFW_FALSE;
-		}
-
-		XRRFreeCrtcInfo(crtcInfo);
-	}
-
-    XRRFreeScreenResources(screenRes);
-	return RGFW_FALSE;
-	#endif
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request);
-#endif
-	return RGFW_FALSE;
-}
-
-RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
-    RGFW_monitor mon;
-    RGFW_MEMSET(&mon, 0, sizeof(mon));
-
-    RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(1);
-#ifdef RGFW_X11
-	XWindowAttributes attrs;
-    if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) {
-        return mon;
-    }
-
-	i32 i;
-	for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) {
-		Screen* screen = ScreenOfDisplay(win->src.display, i);
-        if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) &&
-            attrs.y >= 0 && attrs.y < XHeightOfScreen(screen))
-            	return RGFW_XCreateMonitor(i);
-	}
-#endif
-#ifdef RGFW_WAYLAND
-RGFW_WAYLAND_LABEL
-#endif
-    return mon;
-
-}
-
-#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
-void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
-	if (win == NULL)
-		glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
-	else
-		glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
-}
-void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext();  }
-void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); }
-#endif
-
-void RGFW_window_swapBuffers_software(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_GOTO_WAYLAND(0);
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	#ifdef RGFW_X11
-		win->src.bitmap->data = (char*) win->buffer;
-		RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data);
-		XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h);
-		win->src.bitmap->data = NULL;
-		return;
-	#endif
-	#ifdef RGFW_WAYLAND
-	RGFW_WAYLAND_LABEL
-        #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
-		RGFW_RGB_to_BGR(win, win->src.buffer);
-		#else
-        size_t y;
-		for (y = 0; y < win->r.h; y++) {
-			u32 index = (y * 4 * win->r.w);
-			u32 index2 = (y * 4 * win->bufferSize.w);
-			RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4);
-		}
-		#endif
-
-		wl_surface_frame_done(win, NULL, 0);
-		wl_surface_commit(win->src.surface);
-	#endif
-#else
-#ifdef RGFW_WAYLAND
-    RGFW_WAYLAND_LABEL
-#endif
-    RGFW_UNUSED(win);
-#endif
-}
-
-#if !defined(RGFW_EGL)
-
-void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
-	RGFW_ASSERT(win != NULL);
-
-	#if defined(RGFW_OPENGL)
-	// cached pfn to avoid calling glXGetProcAddress more than once
-	static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123;
-    static int (*pfn2)(int) = NULL;
-
-	if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) {
-		pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"));
-		if (pfn == NULL)  {
-            const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
-            u32 i;
-            for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++)
-    		    pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i]));
-
-            if (pfn2 != NULL) {
-        		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function");
-            } else {
-        		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
-            }
-        }
-    }
-	if (pfn != NULL)
-		pfn(win->src.display, win->src.window, swapInterval);
-    else if (pfn2 != NULL) {
-        pfn2(swapInterval);
-    }
-	#else
-	RGFW_UNUSED(swapInterval);
-	#endif
-}
-#endif
-
-void RGFW_deinit(void) {
-    if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return;
-    #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
-#ifdef RGFW_X11
-	/* to save the clipboard on the x server after the window is closed */
-	RGFW_LOAD_ATOM(CLIPBOARD_MANAGER);
-	RGFW_LOAD_ATOM(SAVE_TARGETS);
-	if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
-		XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime);
-        while (RGFW_XHandleClipboardSelectionHelper());
-	}
-	if (_RGFW.clipboard) {
-		RGFW_FREE(_RGFW.clipboard);
-		_RGFW.clipboard = NULL;
-	}
-
-    RGFW_freeMouse(_RGFW.hiddenMouse);
-
-    XDestroyWindow(_RGFW.display, (Drawable) _RGFW.helperWindow); /*!< close the window */
-    XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */
-
-    #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
-        RGFW_FREE_LIBRARY(X11Cursorhandle);
-    #endif
-    #if !defined(RGFW_NO_X11_XI_PRELOAD)
-        RGFW_FREE_LIBRARY(X11Xihandle);
-    #endif
-
-    #ifdef RGFW_USE_XDL
-        XDL_close();
-    #endif
-
-    #if !defined(RGFW_NO_X11_EXT_PRELOAD)
-        RGFW_FREE_LIBRARY(X11XEXThandle);
-    #endif
-#endif
-#ifdef RGFW_WAYLAND
-	wl_display_disconnect(_RGFW.wl_display);
-#endif
-    #ifndef RGFW_NO_LINUX
-    if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
-        close(RGFW_eventWait_forceStop[0]);
-        close(RGFW_eventWait_forceStop[1]);
-    }
-
-    u8 i;
-    for (i = 0; i < RGFW_gamepadCount; i++) {
-        if(RGFW_gamepads[i])
-            close(RGFW_gamepads[i]);
-    }
-    #endif
-
-    _RGFW.root = NULL;
-    _RGFW.windowCount = -1;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
-}
-
-void RGFW_window_close(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
-
-	RGFW_GOTO_WAYLAND(0);
-	#ifdef RGFW_X11
-    /* ungrab pointer if it was grabbed */
-	if (win->_flags & RGFW_HOLD_MOUSE)
-		XUngrabPointer(win->src.display, CurrentTime);
-
-    #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-		if (win->buffer != NULL) {
-			if ((win->_flags & RGFW_BUFFER_ALLOC))
-				RGFW_FREE(win->buffer);
-			XDestroyImage((XImage*) win->src.bitmap);
-		}
-	#endif
-
-    XFreeGC(win->src.display, win->src.gc);
-    XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */
-    win->src.window = 0;
-    XCloseDisplay(win->src.display);
-
-    RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
-    _RGFW.windowCount--;
-    if (_RGFW.windowCount == 0) RGFW_deinit();
-
-	RGFW_clipboard_switch(NULL);
-	RGFW_FREE(win->event.droppedFiles);
-    if ((win->_flags & RGFW_WINDOW_ALLOC)) {
-		RGFW_FREE(win);
-        win = NULL;
-    }
-	return;
-	#endif
-
-	#ifdef RGFW_WAYLAND
-		RGFW_WAYLAND_LABEL
-
-	    RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
-
-        xdg_toplevel_destroy(win->src.xdg_toplevel);
-        xdg_surface_destroy(win->src.xdg_surface);
-		wl_surface_destroy(win->src.surface);
-
-		_RGFW.windowCount--;
-        if (_RGFW.windowCount == 0) RGFW_deinit();
-
-		#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-			wl_buffer_destroy(win->src.wl_buffer);
-			if ((win->_flags & RGFW_BUFFER_ALLOC))
-				RGFW_FREE(win->buffer);
-
-			munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4));
-		#endif
-
-		RGFW_clipboard_switch(NULL);
-		RGFW_FREE(win->event.droppedFiles);
-        if ((win->_flags & RGFW_WINDOW_ALLOC)) {
-			RGFW_FREE(win);
-            win = NULL;
-        }
-	#endif
-}
-
-
-/*
-	End of X11 linux / wayland / unix defines
-*/
-
-#include <fcntl.h>
-#include <poll.h>
-#include <unistd.h>
-
-void RGFW_stopCheckEvents(void) {
-
-	RGFW_eventWait_forceStop[2] = 1;
-	while (1) {
-		const char byte = 0;
-		const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
-		if (result == 1 || result == -1)
-			break;
-	}
-}
-
-void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
-	if (waitMS == 0) return;
-
-	u8 i;
-	if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
-		if (pipe(RGFW_eventWait_forceStop) != -1) {
-			fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
-			fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
-			fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
-			fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
-		}
-	}
-
-	struct pollfd fds[] = {
-		#ifdef RGFW_WAYLAND
-		{ wl_display_get_fd(win->src.wl_display), POLLIN, 0 },
-		#else
-		{ ConnectionNumber(win->src.display), POLLIN, 0 },
-        #endif
-        #ifdef RGFW_X11
-		{ ConnectionNumber(_RGFW.display), POLLIN, 0 },
-        #endif
-        { RGFW_eventWait_forceStop[0], POLLIN, 0 },
-		#if defined(__linux__)
-		{ -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 },  {-1, POLLIN, 0}
-		#endif
-	};
-
-	u8 index = 2;
-#ifdef RGFW_X11
-    index++;
-#endif
-
-	#if defined(__linux__) || defined(__NetBSD__)
-		for (i = 0; i < RGFW_gamepadCount; i++) {
-			if (RGFW_gamepads[i] == 0)
-				continue;
-
-			fds[index].fd = RGFW_gamepads[i];
-			index++;
-		}
-	#endif
-
-
-	u64 start = RGFW_getTimeNS();
-
-
-	#ifdef RGFW_WAYLAND
-		while (wl_display_dispatch(win->src.wl_display) <= 0
-	#else
-		while (XPending(win->src.display) == 0
-	#endif
-    #ifdef RGFW_X11
-        && XPending(_RGFW.display) == 0
-    #endif
-    ) {
-		if (poll(fds, index, waitMS) <= 0)
-			break;
-
-		if (waitMS != RGFW_eventWaitNext)
-			waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6;
-	}
-
-	/* drain any data in the stop request */
-	if (RGFW_eventWait_forceStop[2]) {
-		char data[64];
-		(void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
-
-		RGFW_eventWait_forceStop[2] = 0;
-	}
-}
-
-i32 RGFW_getClock(void);
-i32 RGFW_getClock(void) {
-	static i32 clock = -1;
-	if (clock != -1) return clock;
-
-	#if defined(_POSIX_MONOTONIC_CLOCK)
-	struct timespec ts;
-	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
-		clock = CLOCK_MONOTONIC;
-	#else
-		clock = CLOCK_REALTIME;
-	#endif
-
-	return clock;
-}
-
-u64 RGFW_getTimerFreq(void) { return 1000000000LLU; }
-u64 RGFW_getTimerValue(void) {
-	struct timespec ts;
-	clock_gettime(CLOCK_REALTIME, &ts);
-    return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec;
-}
-#endif /* end of wayland or X11 defines */
-
-
-
-/*
-
-	Start of Windows defines
-
-
-*/
-
-#ifdef RGFW_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#define OEMRESOURCE
-#include <windows.h>
-
-#include <processthreadsapi.h>
-#include <windowsx.h>
-#include <shellapi.h>
-#include <shellscalingapi.h>
-#include <wchar.h>
-#include <locale.h>
-#include <winuser.h>
-
-#ifndef WM_DPICHANGED
-#define WM_DPICHANGED       0x02E0
-#endif
-
-#ifndef RGFW_NO_XINPUT
-	typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
-	PFN_XInputGetState XInputGetStateSRC = NULL;
-	#define XInputGetState XInputGetStateSRC
-
-	typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
-	PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
-	#define XInputGetKeystroke XInputGetKeystrokeSRC
-
-	HMODULE RGFW_XInput_dll = NULL;
-#endif
-
-char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source);
-
-#define GL_FRONT				0x0404
-#define GL_BACK					0x0405
-#define GL_LEFT					0x0406
-#define GL_RIGHT				0x0407
-
-typedef int (*PFN_wglGetSwapIntervalEXT)(void);
-PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
-#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
-
-
-void* RGFWgamepadApi = NULL;
-
-/* these two wgl functions need to be preloaded */
-typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
-PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
-
-#ifndef RGFW_EGL
-	HMODULE RGFW_wgl_dll = NULL;
-#endif
-
-#ifndef RGFW_NO_LOAD_WGL
-	typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
-	typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
-	typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
-	typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
-	typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
-	typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
-	typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
-
-	PFN_wglCreateContext wglCreateContextSRC;
-	PFN_wglDeleteContext wglDeleteContextSRC;
-	PFN_wglGetProcAddress wglGetProcAddressSRC;
-	PFN_wglMakeCurrent wglMakeCurrentSRC;
-	PFN_wglGetCurrentDC wglGetCurrentDCSRC;
-	PFN_wglGetCurrentContext wglGetCurrentContextSRC;
-	PFN_wglShareLists wglShareListsSRC;
-
-	#define wglCreateContext wglCreateContextSRC
-	#define wglDeleteContext wglDeleteContextSRC
-	#define wglGetProcAddress wglGetProcAddressSRC
-	#define wglMakeCurrent wglMakeCurrentSRC
-	#define wglGetCurrentDC wglGetCurrentDCSRC
-	#define wglGetCurrentContext wglGetCurrentContextSRC
-	#define wglShareLists wglShareListsSRC
-#endif
-
-#if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
-RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) {
-    const char* extensions = NULL;
-
-    RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB");
-    RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT");
-
-    if (proc)
-        extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
-    else if (proc2)
-        extensions = ((const char*(*)(void))proc2)();
-
-    return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); 
-}
-
-RGFW_proc RGFW_getProcAddress(const char* procname) {
-    RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
-    if (proc)
-        return proc;
-
-    return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
-}
-
-typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
-PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
-
-typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
-PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
-#endif
-
-#ifndef RGFW_NO_DWM
-HMODULE RGFW_dwm_dll = NULL;
-typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
-typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
-PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
-#endif
-void RGFW_win32_makeWindowTransparent(RGFW_window* win);
-void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
-	if (!(win->_flags & RGFW_windowTransparent)) return;
-
-	#ifndef RGFW_NO_DWM
-	if (DwmEnableBlurBehindWindowSRC != NULL) {
-			DWM_BLURBEHIND bb = {0, 0, 0, 0};
-			bb.dwFlags = 0x1;
-			bb.fEnable = TRUE;
-			bb.hRgnBlur = NULL;
-			DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
-
-	} else
-	#endif
-	{
-		SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
-		SetLayeredWindowAttributes(win->src.window, 0, 128,  LWA_ALPHA);
-	}
-}
-
-LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
-LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
-    RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
-	if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
-
-	RECT windowRect;
-	GetWindowRect(hWnd, &windowRect);
-
-	switch (message) {
-		case WM_CLOSE:
-		case WM_QUIT:
-			RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
-			RGFW_windowQuitCallback(win);
-			return 0;
-		case WM_ACTIVATE: {
-			RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
-			if (inFocus) win->_flags |= RGFW_windowFocus;
-			else 		win->_flags &= ~ (u32)RGFW_windowFocus;
-			RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win);
-
-			RGFW_focusCallback(win, inFocus);
-            RGFW_window_focusLost(win);
-
-			if ((win->_flags & RGFW_windowFullscreen) == 0)
-				return DefWindowProcW(hWnd, message, wParam, lParam);
-
-			win->_flags &= ~(u32)RGFW_EVENT_PASSED;
-			if (inFocus == RGFW_FALSE) RGFW_window_minimize(win);
-			else RGFW_window_setFullscreen(win, 1);
-			return DefWindowProcW(hWnd, message, wParam, lParam);
-		}
-		case WM_MOVE:
-			win->r.x = windowRect.left;
-			win->r.y = windowRect.top;
-			RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
-			RGFW_windowMovedCallback(win, win->r);
-			return DefWindowProcW(hWnd, message, wParam, lParam);
-		case WM_SIZE: {
-			if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) {
-				double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h;
-
-				int width = (windowRect.right - windowRect.left) - win->src.wOffset;
-				int height = (windowRect.bottom - windowRect.top) - win->src.hOffset;
-				int newHeight = (int)(width / aspectRatio);
-				int newWidth = (int)(height * aspectRatio);
-
-				if (win->r.w > windowRect.right - windowRect.left ||
-					win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset))
-				{
-					if (newHeight > height) windowRect.right = windowRect.left + newWidth;
-					else windowRect.bottom = windowRect.top + newHeight;
-				} else {
-					if (newHeight < height) windowRect.right = windowRect.left + newWidth;
-					else windowRect.bottom = windowRect.top + newHeight;
-				}
-
-				RGFW_window_resize(win, RGFW_AREA((u32)(windowRect.right - windowRect.left) - (u32)win->src.wOffset,
-												(u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset));
-			}
-
-			win->r.w = (windowRect.right -  windowRect.left) - (i32)win->src.wOffset;
-			win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset;
-			RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
-			RGFW_windowResizedCallback(win, win->r);
-			RGFW_window_checkMode(win);
-			return DefWindowProcW(hWnd, message, wParam, lParam);
-		}
-		#ifndef RGFW_NO_MONITOR
-		case WM_DPICHANGED: {
-			if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
-
-			const float scaleX = HIWORD(wParam) / (float) 96;
-            const float scaleY = LOWORD(wParam) / (float) 96;
-			RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
-			RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win);
-			return DefWindowProcW(hWnd, message, wParam, lParam);
-		}
-		#endif
-		case WM_GETMINMAXINFO: {
-			MINMAXINFO* mmi = (MINMAXINFO*) lParam;
-			mmi->ptMinTrackSize.x = (LONG)(win->src.minSize.w + win->src.wOffset);
-			mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset);
-			if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
-				return DefWindowProcW(hWnd, message, wParam, lParam);
-
-			mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSize.w + win->src.wOffset);
-			mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset);
-			return DefWindowProcW(hWnd, message, wParam, lParam);
-		}
-		case WM_PAINT: {
-            PAINTSTRUCT ps;
-            BeginPaint(hWnd, &ps);
-            RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
-            RGFW_windowRefreshCallback(win);
-            EndPaint(hWnd, &ps);
-
-            return DefWindowProcW(hWnd, message, wParam, lParam);
-		}
-		#if(_WIN32_WINNT >= 0x0600)
-		case WM_DWMCOMPOSITIONCHANGED:
-		case WM_DWMCOLORIZATIONCOLORCHANGED:
-			RGFW_win32_makeWindowTransparent(win);
-			break;
-		#endif
-/* based on sokol_app.h */
-#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
-        case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
-        case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break;
-        case WM_TIMER: RGFW_windowRefreshCallback(win); break;
-#endif
-        case WM_NCLBUTTONDOWN: {
-            /* workaround for half-second pause when starting to move window
-                see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
-            */
-            POINT point = { 0, 0 };
-            if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
-                break;
-
-            ScreenToClient(win->src.window, &point);
-            PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16));
-            break;
-        }
-		default: break;
-	}
-	return DefWindowProcW(hWnd, message, wParam, lParam);
-}
-
-#ifndef RGFW_NO_DPI
-	HMODULE RGFW_Shcore_dll = NULL;
-	typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
-	PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
-	#define GetDpiForMonitor GetDpiForMonitorSRC
-#endif
-
-#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
-	HMODULE RGFW_winmm_dll = NULL;
-	typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
-	typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
-	PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
-	#define timeBeginPeriod timeBeginPeriodSRC
-	#define timeEndPeriod timeEndPeriodSRC
-#elif !defined(RGFW_NO_WINMM)
-	__declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
-	__declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
-#endif
-#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
-                                        name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
-                                        RGFW_ASSERT(name##SRC != NULL); \
-                                    }
-
-#ifndef RGFW_NO_XINPUT
-void RGFW_loadXInput(void);
-void RGFW_loadXInput(void) {
-	u32 i;
-	static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"};
-
-	for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL);  i++) {
-		RGFW_XInput_dll = LoadLibraryA(names[i]);
-		RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState);
-		RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke);
-	}
-
-	if (XInputGetStateSRC == NULL)
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState");
-	if (XInputGetKeystrokeSRC == NULL)
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke");
-}
-#endif
-
-void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	win->buffer = buffer;
-	win->bufferSize = area;
-
-	BITMAPV5HEADER bi;
-	ZeroMemory(&bi, sizeof(bi));
-	bi.bV5Size = sizeof(bi);
-	bi.bV5Width = (i32)area.w;
-	bi.bV5Height = -((LONG) area.h);
-	bi.bV5Planes = 1;
-	bi.bV5BitCount = 32;
-	bi.bV5Compression = BI_RGB;
-
-	win->src.bitmap = CreateDIBSection(win->src.hdc,
-		(BITMAPINFO*) &bi, DIB_RGB_COLORS,
-		(void**) &win->src.bitmapBits,
-		NULL, (DWORD) 0);
-
-	if (win->buffer == NULL)
-		win->buffer = win->src.bitmapBits;
-
-	win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
-	SelectObject(win->src.hdcMem, win->src.bitmap);
-
-	#if defined(RGFW_OSMESA)
-	win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
-	OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
-	OSMesaPixelStore(OSMESA_Y_UP, 0);
-	#endif
-	#else
-	RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
-	#endif
-}
-
-void RGFW_releaseCursor(RGFW_window* win) {
-	RGFW_UNUSED(win);
-	ClipCursor(NULL);
-	const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
-	RegisterRawInputDevices(&id, 1, sizeof(id));
-}
-
-void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
-	RGFW_UNUSED(win); RGFW_UNUSED(rect);
-
-	RECT clipRect;
-	GetClientRect(win->src.window, &clipRect);
-	ClientToScreen(win->src.window, (POINT*) &clipRect.left);
-	ClientToScreen(win->src.window, (POINT*) &clipRect.right);
-	ClipCursor(&clipRect);
-
-	const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
-	RegisterRawInputDevices(&id, 1, sizeof(id));
-}
-
-#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
-
-#ifdef RGFW_DIRECTX
-int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
-    RGFW_ASSERT(win && pFactory && pDevice && swapchain);
-
-    static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
-    swapChainDesc.BufferCount = 2;
-    swapChainDesc.BufferDesc.Width = win->r.w;
-    swapChainDesc.BufferDesc.Height = win->r.h;
-    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
-    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
-    swapChainDesc.OutputWindow = (HWND)win->src.window;
-    swapChainDesc.SampleDesc.Count = 1;
-    swapChainDesc.SampleDesc.Quality = 0;
-    swapChainDesc.Windowed = TRUE;
-    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
-
-    HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
-    if (FAILED(hr)) {
-        RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!");
-        return -2;
-    }
-
-    return 0;
-}
-#endif
-
-void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
-void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
-#ifdef RGFW_OPENGL
-     if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
-		return;
-
-	HDC dummy_dc = GetDC(dummyWin);
-	u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
-
-	PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};
-
-	int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
-	SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
-
-	HGLRC dummy_context = wglCreateContext(dummy_dc);
-	wglMakeCurrent(dummy_dc, dummy_context);
-
-	wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
-	wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
-
-    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
-    if (wglSwapIntervalEXT == NULL) {
-        RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
-    }
-
-	wglMakeCurrent(dummy_dc, 0);
-	wglDeleteContext(dummy_context);
-	ReleaseDC(dummyWin, dummy_dc);
-#else
-	RGFW_UNUSED(dummyWin);
-#endif
-}
-
-#ifndef RGFW_EGL
-void RGFW_window_initOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-	PIXELFORMATDESCRIPTOR pfd;
-	pfd.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
-	pfd.nVersion     = 1;
-	pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
-	pfd.iPixelType   = PFD_TYPE_RGBA;
-	pfd.iLayerType   = PFD_MAIN_PLANE;
-	pfd.cColorBits   = 32;
-	pfd.cAlphaBits   = 8;
-	pfd.cDepthBits   = 24;
-	pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil];
-	pfd.cAuxBuffers  = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers];
-	if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO;
-
-	/* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
-	if (win->_flags & RGFW_windowOpenglSoftware)
-		pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
-
-	/* get pixel format, default to a basic pixel format */
-	int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
-	if (wglChoosePixelFormatARB != NULL) {
-		i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs();
-
-		int new_pixel_format;
-		UINT num_formats;
-		wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
-		if (!num_formats)
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL");
-		else pixel_format = new_pixel_format;
-	}
-
-	PIXELFORMATDESCRIPTOR suggested;
-	if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
-		!SetPixelFormat(win->src.hdc, pixel_format, &pfd))
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format");
-    
-    if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) {
-        win->_flags |= RGFW_windowOpenglSoftware;
-    }
-
-	if (wglCreateContextAttribsARB != NULL) {
-		/* create opengl/WGL context for the specified version */
-		u32 index = 0;
-		i32 attribs[40];
-
-		if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) {
-			SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
-		}
-		else {
-			SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
-		}
-
-		if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
-			SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]);
-			SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]);
-		}
-
-		SET_ATTRIB(0, 0);
-
-		win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
-	} else { /* fall back to a default context (probably opengl 2 or something) */
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context");
-		win->src.ctx = wglCreateContext(win->src.hdc);
-	}
-
-	ReleaseDC(win->src.window, win->src.hdc);
-	win->src.hdc = GetDC(win->src.window);
-	wglMakeCurrent(win->src.hdc, win->src.ctx);
-
-	if (_RGFW.root != win)
-		wglShareLists(_RGFW.root->src.ctx, win->src.ctx);
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_window_freeOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-	if (win->src.ctx == NULL) return;
-	wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
-	win->src.ctx = NULL;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-#endif
-
-
-i32 RGFW_init(void) {
-#if defined(RGFW_C89) || defined(__cplusplus)
-    if (_RGFW_init) return 0; 
-    _RGFW_init = RGFW_TRUE;
-    _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
-#endif
-
-    #ifndef RGFW_NO_XINPUT
-		if (RGFW_XInput_dll == NULL)
-			RGFW_loadXInput();
-	#endif
-
-#ifndef RGFW_NO_DPI
-	#if (_WIN32_WINNT >= 0x0600)
-		SetProcessDPIAware();
-	#endif
-#endif
-
-	#ifndef RGFW_NO_WINMM
-		#ifndef RGFW_NO_LOAD_WINMM
-			RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
-			RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
-			RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
-		#endif
-		timeBeginPeriod(1);
-	#endif
-
-	#ifndef RGFW_NO_DWM
-	RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
-	RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
-	#endif
-
-	RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
-	#ifndef RGFW_NO_LOAD_WGL
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
-		RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
-	#endif
-
-	u8 RGFW_blk[] = { 0, 0, 0, 0 };
-	_RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
-
-    _RGFW.windowCount = 0;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
-    return 1;
-}
-
-RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
-	if (name[0] == 0) name = (char*) " ";
-
-	RGFW_window_basic_init(win, rect, flags);
-
-	win->src.hIconSmall = win->src.hIconBig = NULL;
-	win->src.maxSize = RGFW_AREA(0, 0);
-	win->src.minSize = RGFW_AREA(0, 0);
-	win->src.aspectRatio = RGFW_AREA(0, 0);
-
-	HINSTANCE inh = GetModuleHandleA(NULL);
-
-	#ifndef __cplusplus
-	WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */
-	#else
-	WNDCLASSW Class = { };
-	#endif
-
-	if (RGFW_className == NULL)
-		RGFW_className = (char*)name;
-
-	wchar_t wide_class[256];
-	MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255);
-
-	Class.lpszClassName = wide_class;
-	Class.hInstance = inh;
-	Class.hCursor = LoadCursor(NULL, IDC_ARROW);
-	Class.lpfnWndProc = WndProcW;
-	Class.cbClsExtra = sizeof(RGFW_window*);
-
-	Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
-	if (Class.hIcon == NULL)
-		Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
-
-	RegisterClassW(&Class);
-
-	DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
-
-	RECT windowRect, clientRect;
-
-	if (!(flags & RGFW_windowNoBorder)) {
-		window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME;
-
-		if (!(flags & RGFW_windowNoResize))
-			window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
-	} else
-		window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
-
-	wchar_t wide_name[256];
-	MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
-	HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
-
-	GetWindowRect(dummyWin, &windowRect);
-	GetClientRect(dummyWin, &clientRect);
-
-	RGFW_win32_loadOpenGLFuncs(dummyWin);
-	DestroyWindow(dummyWin);
-
-	win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top);
-	win->src.wOffset = (u32)(windowRect.right - windowRect.left) - (u32)(clientRect.right - clientRect.left);
-	win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w + (i32)win->src.wOffset, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0);
-	SetPropW(win->src.window, L"RGFW", win);
-	RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */
-
-	if (flags & RGFW_windowAllowDND) {
-		win->_flags |= RGFW_windowAllowDND;
-		RGFW_window_setDND(win, 1);
-	}
-	win->src.hdc = GetDC(win->src.window);
-
-	if ((flags & RGFW_windowNoInitAPI) == 0) {
-        RGFW_window_initOpenGL(win);
-        RGFW_window_initBuffer(win);
-    }
-
-	RGFW_window_setFlags(win, flags);
-	RGFW_win32_makeWindowTransparent(win);
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
-    RGFW_window_show(win);
-
-    return win;
-}
-
-void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
-	RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
-	LONG style = GetWindowLong(win->src.window, GWL_STYLE);
-
-
-	if (border == 0) {
-		SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
-		SetWindowPos(
-			win->src.window, HWND_TOP, 0, 0, 0, 0,
-			SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
-		);
-	}
-	else {
-		style |= WS_OVERLAPPEDWINDOW;
-		if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
-		SetWindowPos(
-			win->src.window, HWND_TOP, 0, 0, 0, 0,
-			SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
-		);
-	}
-}
-
-void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
-	RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
-	DragAcceptFiles(win->src.window, allow);
-}
-
-RGFW_area RGFW_getScreenSize(void) {
-	HDC dc = GetDC(NULL);
-	RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES));
-	ReleaseDC(NULL, dc);
-	return area;
-}
-
-RGFW_point RGFW_getGlobalMousePoint(void) {
-	POINT p;
-	GetCursorPos(&p);
-
-	return RGFW_POINT(p.x, p.y);
-}
-
-void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-	win->src.aspectRatio = a;
-}
-
-void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-	win->src.minSize = a;
-}
-
-void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-	win->src.maxSize = a;
-}
-
-void RGFW_window_focus(RGFW_window* win) {
-	RGFW_ASSERT(win);
-    SetForegroundWindow(win->src.window);
-    SetFocus(win->src.window);
-}
-
-void RGFW_window_raise(RGFW_window* win) {
-	RGFW_ASSERT(win);
-	BringWindowToTop(win->src.window);
-	SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
-}
-
-void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
-	RGFW_ASSERT(win != NULL);
-
-	if (fullscreen == RGFW_FALSE) {
-		RGFW_window_setBorder(win, 1);
-		SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w + (i32)win->src.wOffset, win->_oldRect.h + (i32)win->src.hOffset,
-			 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
-
-		win->_flags &= ~(u32)RGFW_windowFullscreen;
-		win->r = win->_oldRect;
-		return;
-	}
-
-	win->_oldRect = win->r;
-	win->_flags |= RGFW_windowFullscreen;
-
-	RGFW_monitor mon  = RGFW_window_getMonitor(win);
-	RGFW_window_setBorder(win, 0);
-
-    SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
-    RGFW_monitor_scaleToWindow(mon, win);
-
-	win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h);
-}
-
-void RGFW_window_maximize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_window_hide(win);
-	ShowWindow(win->src.window, SW_MAXIMIZE);
-}
-
-void RGFW_window_minimize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	ShowWindow(win->src.window, SW_MINIMIZE);
-}
-
-void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
-    RGFW_ASSERT(win != NULL);
-    if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-    else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-}
-
-void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
-	SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
-	SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
-}
-
-void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
-
-RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
-	return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
-}
-
-u8 RGFW_xinput2RGFW[] = {
-	RGFW_gamepadA, /* or PS X button */
-	RGFW_gamepadB, /* or PS circle button */
-	RGFW_gamepadX, /* or PS square button */
-	RGFW_gamepadY, /* or PS triangle button */
-	RGFW_gamepadR1, /* right bumper */
-	RGFW_gamepadL1, /* left bump */
-	RGFW_gamepadL2, /* left trigger */
-	RGFW_gamepadR2, /* right trigger */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	RGFW_gamepadUp, /* dpad up */
-	RGFW_gamepadDown, /* dpad down */
-	RGFW_gamepadLeft, /* dpad left */
-	RGFW_gamepadRight, /* dpad right */
-	RGFW_gamepadStart, /* start button */
-	RGFW_gamepadSelect,/* select button */
-	RGFW_gamepadL3,
-	RGFW_gamepadR3,
-};
-i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e);
-i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) {
-	#ifndef RGFW_NO_XINPUT
-
-	RGFW_UNUSED(win);
-    u16 i;
-	for (i = 0; i < 4; i++) {
-		XINPUT_KEYSTROKE keystroke;
-
-		if (XInputGetKeystroke == NULL)
-			return 0;
-
-		DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
-
-		if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
-			if (result != ERROR_SUCCESS)
-				return 0;
-
-			if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS)
-				continue;
-
-			/* gamepad + 1 = RGFW_gamepadButtonReleased */
-			e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
-			e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
-			RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current;
-			RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
-
-			RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed);
-			return 1;
-		}
-
-		XINPUT_STATE state;
-		if (XInputGetState == NULL ||
-			XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
-		) {
-			if (RGFW_gamepads[i] == 0)
-				continue;
-
-			RGFW_gamepads[i] = 0;
-			RGFW_gamepadCount--;
-
-			win->event.type = RGFW_gamepadDisconnected;
-			win->event.gamepad = (u16)i;
-			RGFW_gamepadCallback(win, i, 0);
-			return 1;
-		}
-
-		if (RGFW_gamepads[i] == 0) {
-			RGFW_gamepads[i] = 1;
-			RGFW_gamepadCount++;
-
-			char str[] = "Microsoft X-Box (XInput device)";
-			RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str));
-			RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0';
-			win->event.type = RGFW_gamepadConnected;
-			win->event.gamepad = i;
-			RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
-
-			RGFW_gamepadCallback(win, i, 1);
-			return 1;
-		}
-
-#define INPUT_DEADZONE  ( 0.24f * (float)(0x7FFF) )  /* Default to 24% of the +/- 32767 range.   This is a reasonable default value but can be altered if needed. */
-
-		if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
-			state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
-			(state.Gamepad.sThumbLY < INPUT_DEADZONE &&
-				state.Gamepad.sThumbLY > -INPUT_DEADZONE))
-		{
-			state.Gamepad.sThumbLX = 0;
-			state.Gamepad.sThumbLY = 0;
-		}
-
-		if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
-			state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
-			(state.Gamepad.sThumbRY < INPUT_DEADZONE &&
-				state.Gamepad.sThumbRY > -INPUT_DEADZONE))
-		{
-			state.Gamepad.sThumbRX = 0;
-			state.Gamepad.sThumbRY = 0;
-		}
-
-		e->axisesCount = 2;
-		RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100);
-		RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100);
-
-		if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){
-			win->event.whichAxis = 0;
-
-			e->type = RGFW_gamepadAxisMove;
-			e->axis[0] = axis1;
-			RGFW_gamepadAxes[i][0] = e->axis[0];
-
-			RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
-			return 1;
-		}
-
-		if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
-			win->event.whichAxis = 1;
-			e->type = RGFW_gamepadAxisMove;
-			e->axis[1] = axis2;
-			RGFW_gamepadAxes[i][1] = e->axis[1];
-
-			RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
-			return 1;
-		}
-	}
-
-	#endif
-
-	return 0;
-}
-
-void RGFW_stopCheckEvents(void) {
-	PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0);
-}
-
-void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
-	RGFW_UNUSED(win);
-	MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
-}
-
-u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
-    UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode);  // Should return a Windows VK_* code
-    BYTE keyboardState[256] = {0};
-
-    if (!GetKeyboardState(keyboardState))
-        return (u8)rgfw_keycode;
-
-    UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
-    HKL layout = GetKeyboardLayout(0);
-
-    wchar_t charBuffer[2] = {0};
-    int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
-
-    if (result <= 0)
-        return (u8)rgfw_keycode;
-
-    return (u8)charBuffer[0];
-}
-
-RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
-    if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
-    RGFW_event* ev = RGFW_window_checkEventCore(win);
-	if (ev) {
-        return ev;
-    }
-
-    static HDROP drop;
-	if (win->event.type == RGFW_DNDInit) {
-		if (win->event.droppedFilesCount) {
-			u32 i;
-			for (i = 0; i < win->event.droppedFilesCount; i++)
-				win->event.droppedFiles[i][0] = '\0';
-		}
-
-		win->event.droppedFilesCount = 0;
-		win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
-
-		u32 i;
-		for (i = 0; i < win->event.droppedFilesCount; i++) {
-			UINT length = DragQueryFileW(drop, i, NULL, 0);
-			if (length == 0)
-				continue;
-
-			WCHAR buffer[RGFW_MAX_PATH * 2];
-			if (length > (RGFW_MAX_PATH * 2) - 1)
-				length = RGFW_MAX_PATH * 2;
-
-			DragQueryFileW(drop, i, buffer, length + 1);
-
-			char* str = RGFW_createUTF8FromWideStringWin32(buffer);
-			if (str != NULL)
-				RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1);
-
-			win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
-		}
-
-		DragFinish(drop);
-		RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
-
-		win->event.type = RGFW_DND;
-		return &win->event;
-	}
-
-	if (RGFW_checkXInput(win, &win->event))
-		return &win->event;
-
-	static BYTE keyboardState[256];
-	GetKeyboardState(keyboardState);
-
-    MSG msg;
-    if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
-        if (msg.hwnd != win->src.window && msg.hwnd != NULL) {
-            TranslateMessage(&msg);
-            DispatchMessageA(&msg);
-            return RGFW_window_checkEvent(win);
-        }
-    } else {
-        return NULL;
-    }
-
-    switch (msg.message) {
-		case WM_MOUSELEAVE:
-			win->event.type = RGFW_mouseLeave;
-			win->_flags |= RGFW_MOUSE_LEFT;
-			RGFW_mouseNotifyCallback(win, win->event.point, 0);
-			break;
-		case WM_SYSKEYUP: case WM_KEYUP: {
-			i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
-			if (scancode == 0)
-				scancode = (i32)MapVirtualKeyW((UINT)msg.wParam, MAPVK_VK_TO_VSC);
-
-			switch (scancode) {
-				case 0x54: scancode = 0x137; break; /*  Alt+PrtS */
-				case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
-				case 0x136: scancode = 0x36; break; /*  CJK IME sets the extended bit for right Shift */
-				default: break;
-			}
-
-			win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
-
-			if (msg.wParam == VK_CONTROL) {
-				if (HIWORD(msg.lParam) & KF_EXTENDED)
-					win->event.key = RGFW_controlR;
-				else win->event.key = RGFW_controlL;
-			}
-
-			wchar_t charBuffer;
-			ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL);
-
-			win->event.keyChar = (u8)charBuffer;
-
-			RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
-			win->event.type = RGFW_keyReleased;
-			RGFW_keyboard[win->event.key].current = 0;
-
-			RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
-
-			RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
-			break;
-		}
-		case WM_SYSKEYDOWN: case WM_KEYDOWN: {
-            i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
-			if (scancode == 0)
-				scancode = (i32)MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC);
-
-			switch (scancode) {
-				case 0x54: scancode = 0x137; break; /*  Alt+PrtS */
-				case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
-				case 0x136: scancode = 0x36; break; /*  CJK IME sets the extended bit for right Shift */
-				default: break;
-			}
-
-			win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
-			if (msg.wParam == VK_CONTROL) {
-				if (HIWORD(msg.lParam) & KF_EXTENDED)
-					win->event.key = RGFW_controlR;
-				else win->event.key = RGFW_controlL;
-			}
-
-			wchar_t charBuffer;
-			ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL);
-			win->event.keyChar = (u8)charBuffer;
-
-			RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
-
-			win->event.type = RGFW_keyPressed;
-			win->event.repeat = RGFW_isPressed(win, win->event.key);
-			RGFW_keyboard[win->event.key].current = 1;
-			RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
-
-			RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
-			break;
-		}
-		case WM_MOUSEMOVE: {
-			if ((win->_flags & RGFW_HOLD_MOUSE))
-				break;
-
-			win->event.type = RGFW_mousePosChanged;
-
-			i32 x = GET_X_LPARAM(msg.lParam);
-			i32 y = GET_Y_LPARAM(msg.lParam);
-
-			RGFW_mousePosCallback(win, win->event.point, win->event.vector);
-
-			if (win->_flags & RGFW_MOUSE_LEFT) {
-				win->_flags &= ~(u32)RGFW_MOUSE_LEFT;
-				win->event.type = RGFW_mouseEnter;
-				RGFW_mouseNotifyCallback(win, win->event.point, 1);
-			}
-
-			win->event.point.x = x;
-			win->event.point.y = y;
-			win->_lastMousePoint = RGFW_POINT(x, y);
-
-			break;
-		}
-		case WM_INPUT: {
-			if (!(win->_flags & RGFW_HOLD_MOUSE))
-				break;
-
-			unsigned size = sizeof(RAWINPUT);
-			static RAWINPUT raw;
-
-			GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
-
-			if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
-				break;
-
-			if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
-				POINT pos = {0, 0};
-				int width, height;
-
-				if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
-					pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
-					pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
-					width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
-					height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
-				}
-				else {
-					width = GetSystemMetrics(SM_CXSCREEN);
-					height = GetSystemMetrics(SM_CYSCREEN);
-				}
-
-				pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
-				pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
-				ScreenToClient(win->src.window, &pos);
-
-				win->event.vector.x = pos.x - win->_lastMousePoint.x;
-				win->event.vector.y = pos.y - win->_lastMousePoint.y;
-			} else {
-				win->event.vector.x = raw.data.mouse.lLastX;
-				win->event.vector.y = raw.data.mouse.lLastY;
-			}
-
-			win->event.type = RGFW_mousePosChanged;
-			win->_lastMousePoint.x += win->event.vector.x;
-			win->_lastMousePoint.y += win->event.vector.y;
-			win->event.point = win->_lastMousePoint;
-			RGFW_mousePosCallback(win, win->event.point, win->event.vector);
-			break;
-		}
-		case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN:
-			if (msg.message == WM_XBUTTONDOWN)
-				win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
-			else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft :
-									 (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle;
-
-			win->event.type = RGFW_mouseButtonPressed;
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 1;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
-			break;
-		case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP:
-			if (msg.message == WM_XBUTTONUP)
-				win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
-			else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft :
-									 (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle;
-			win->event.type = RGFW_mouseButtonReleased;
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 0;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
-			break;
-		case WM_MOUSEWHEEL:
-			if (msg.wParam > 0)
-				win->event.button = RGFW_mouseScrollUp;
-			else
-				win->event.button = RGFW_mouseScrollDown;
-
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 1;
-
-			win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
-
-			win->event.type = RGFW_mouseButtonPressed;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
-			break;
-		case WM_DROPFILES: {
-			win->event.type = RGFW_DNDInit;
-
-			drop = (HDROP) msg.wParam;
-			POINT pt;
-
-			/* Move the mouse to the position of the drop */
-			DragQueryPoint(drop, &pt);
-
-			win->event.point.x = pt.x;
-			win->event.point.y = pt.y;
-
-			RGFW_dndInitCallback(win, win->event.point);
-		}
-			break;
-		default:
-			TranslateMessage(&msg);
-			DispatchMessageA(&msg);
-			return RGFW_window_checkEvent(win);
-	}
-
-    TranslateMessage(&msg);
-	DispatchMessageA(&msg);
-
-	return &win->event;
-}
-
-RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
-}
-
-RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	#ifndef __cplusplus
-	WINDOWPLACEMENT placement = { 0 };
-	#else
-	WINDOWPLACEMENT placement = {  };
-	#endif
-	GetWindowPlacement(win->src.window, &placement);
-	return placement.showCmd == SW_SHOWMINIMIZED;
-}
-
-RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	#ifndef __cplusplus
-	WINDOWPLACEMENT placement = { 0 };
-	#else
-	WINDOWPLACEMENT placement = {  };
-	#endif
-	GetWindowPlacement(win->src.window, &placement);
-	return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
-}
-
-typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo;
-#ifndef RGFW_NO_MONITOR
-RGFW_monitor win32CreateMonitor(HMONITOR src);
-RGFW_monitor win32CreateMonitor(HMONITOR src) {
-	RGFW_monitor monitor;
-	MONITORINFOEX  monitorInfo;
-
-	monitorInfo.cbSize = sizeof(MONITORINFOEX);
-	GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
-
-	/* get the monitor's index */
-	DISPLAY_DEVICEA dd;
-	dd.cb = sizeof(dd);
-
-    DWORD deviceNum;
-	for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
-		if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
-			continue;
-
-		DEVMODEA dm;
-		ZeroMemory(&dm, sizeof(dm));
-		dm.dmSize = sizeof(dm);
-
-		if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
-			monitor.mode.refreshRate = dm.dmDisplayFrequency;
-			RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode);
-		}
-
-		DISPLAY_DEVICEA mdd;
-		mdd.cb = sizeof(mdd);
-
-		if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) {
-			RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1);
-			monitor.name[sizeof(monitor.name) - 1] = '\0';
-			break;
-		}
-	}
-
-
-
-
-	monitor.x = monitorInfo.rcWork.left;
-	monitor.y = monitorInfo.rcWork.top;
-	monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
-	monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
-
-	HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL);
-	/* get pixels per inch */
-	float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
-	float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
-
-	monitor.scaleX = dpiX / 96.0f;
-	monitor.scaleY = dpiY / 96.0f;
-	monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
-
-	monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
-	monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
-	DeleteDC(hdc);
-
-	#ifndef RGFW_NO_DPI
-		RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
-		RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
-
-		if (GetDpiForMonitor != NULL) {
-			u32 x, y;
-			GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
-			monitor.scaleX = (float) (x) / (float) 96.0f;
-			monitor.scaleY = (float) (y) / (float) 96.0f;
-			monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
-		}
-	#endif
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
-	return monitor;
-}
-#endif /* RGFW_NO_MONITOR */
-
-#ifndef RGFW_NO_MONITOR
-BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
-BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-	RGFW_UNUSED(hdcMonitor);
-	RGFW_UNUSED(lprcMonitor);
-
-	RGFW_mInfo* info = (RGFW_mInfo*) dwData;
-
-
-	if (info->iIndex >= 6)
-		return FALSE;
-
-	info->monitors[info->iIndex] = win32CreateMonitor(hMonitor);
-	info->iIndex++;
-
-	return TRUE;
-}
-
-RGFW_monitor RGFW_getPrimaryMonitor(void) {
-	#ifdef __cplusplus
-	return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
-	#else
-	return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
-	#endif
-}
-
-RGFW_monitor* RGFW_getMonitors(size_t* len) {
-	static RGFW_monitor monitors[6];
-	RGFW_mInfo info;
-	info.iIndex = 0;
-	info.monitors = monitors;
-
-	EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info);
-
-	if (len != NULL) *len = (size_t)info.iIndex;
-	return monitors;
-}
-
-RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
-	HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
-	return win32CreateMonitor(src);
-}
-
-RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
-    POINT p = { mon.x, mon.y };
-    HMONITOR src = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
-
-	MONITORINFOEX  monitorInfo;
-	monitorInfo.cbSize = sizeof(MONITORINFOEX);
-	GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
-
-    DISPLAY_DEVICEA dd;
-    dd.cb = sizeof(dd);
-
-    /* Enumerate display devices */
-    DWORD deviceNum;
-    for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
-        if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
-			continue;
-
-        if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0)
-            continue;
-		
-        DEVMODEA dm;
-		ZeroMemory(&dm, sizeof(dm));
-		dm.dmSize = sizeof(dm);
-
-		if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
-			if (request & RGFW_monitorScale) {
-				dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
-				dm.dmPelsWidth = mode.area.w;
-				dm.dmPelsHeight = mode.area.h;
-            }
-
-			if (request & RGFW_monitorRefresh) {
-				dm.dmFields |= DM_DISPLAYFREQUENCY;
-				dm.dmDisplayFrequency = mode.refreshRate;
-			}
-
-			if (request & RGFW_monitorRGB) {
-				dm.dmFields |= DM_BITSPERPEL;
-				dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue);
-			}
-
-			if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
-				if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL)
-					return RGFW_TRUE;
-				return RGFW_FALSE;
-			} else return RGFW_FALSE;
-		}
-	}
-
-	return RGFW_FALSE;
-}
-
-#endif
-HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon);
-HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) {
-    size_t channels = (size_t)c;
-
-	BITMAPV5HEADER bi;
-	ZeroMemory(&bi, sizeof(bi));
-	bi.bV5Size = sizeof(bi);
-	bi.bV5Width = (i32)a.w;
-	bi.bV5Height = -((LONG) a.h);
-	bi.bV5Planes = 1;
-	bi.bV5BitCount = (WORD)(channels * 8);
-	bi.bV5Compression = BI_RGB;
-	HDC dc = GetDC(NULL);
-	u8* target = NULL;
-
-	HBITMAP color = CreateDIBSection(dc,
-		(BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
-		NULL, (DWORD) 0);
-
-    size_t x, y;
-    for (y = 0; y < a.h; y++) {
-        for (x = 0; x < a.w; x++) {
-			size_t index = (y * 4 * (size_t)a.w) + x * channels;
-            target[index] = src[index + 2];
-            target[index + 1] = src[index + 1];
-            target[index + 2] = src[index];
-            target[index + 3] = src[index + 3];
-        }
-    }
-
-    ReleaseDC(NULL, dc);
-
-	HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL);
-
-	ICONINFO ii;
-	ZeroMemory(&ii, sizeof(ii));
-	ii.fIcon = icon;
-	ii.xHotspot = a.w / 2;
-	ii.yHotspot = a.h / 2;
-	ii.hbmMask = mask;
-	ii.hbmColor = color;
-
-	HICON handle = CreateIconIndirect(&ii);
-
-	DeleteObject(color);
-	DeleteObject(mask);
-
-	return handle;
-}
-
-void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
-	HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE);
-	return cursor;
-}
-
-void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
-	RGFW_ASSERT(win && mouse);
-	SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
-	SetCursor((HCURSOR)mouse);
-}
-
-void RGFW_freeMouse(RGFW_mouse* mouse) {
-	RGFW_ASSERT(mouse);
-	DestroyCursor((HCURSOR)mouse);
-}
-
-RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
-	return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
-}
-
-RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
-	RGFW_ASSERT(win != NULL);
-
-	static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
-	if (mouse > (sizeof(mouseIconSrc) / sizeof(u32)))
-		return RGFW_FALSE;
-
-	char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]);
-
-	SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
-	SetCursor(LoadCursorA(NULL, icon));
-	return RGFW_TRUE;
-}
-
-void RGFW_window_hide(RGFW_window* win) {
-	ShowWindow(win->src.window, SW_HIDE);
-}
-
-void RGFW_window_show(RGFW_window* win) {
-	if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
-	ShowWindow(win->src.window, SW_RESTORE);
-}
-
-#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
-void RGFW_deinit(void) {
-    #ifndef RGFW_NO_XINPUT
-    RGFW_FREE_LIBRARY(RGFW_XInput_dll);
-    #endif
-
-    #ifndef RGFW_NO_DPI
-        RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
-    #endif
-
-    #ifndef RGFW_NO_WINMM
-        timeEndPeriod(1);
-        #ifndef RGFW_NO_LOAD_WINMM
-            RGFW_FREE_LIBRARY(RGFW_winmm_dll);
-        #endif
-    #endif
-
-    RGFW_FREE_LIBRARY(RGFW_wgl_dll);
-    _RGFW.root = NULL;
-
-    RGFW_freeMouse(_RGFW.hiddenMouse);
-    _RGFW.windowCount = -1;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
-}
-
-
-void RGFW_window_close(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	#ifdef RGFW_BUFFER
-		DeleteDC(win->src.hdcMem);
-		DeleteObject(win->src.bitmap);
-	#endif
-
-	if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
-	RemovePropW(win->src.window, L"RGFW");
-	ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
-	DestroyWindow(win->src.window); /*!< delete window */
-
-	if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
-	if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
-    _RGFW.windowCount--;
-	if (_RGFW.windowCount == 0) RGFW_deinit();
-
-    RGFW_clipboard_switch(NULL);
-	RGFW_FREE(win->event.droppedFiles);
-	if ((win->_flags & RGFW_WINDOW_ALLOC)) {
-		RGFW_FREE(win);
-        win = NULL;
-    }
-}
-
-void RGFW_window_move(RGFW_window* win, RGFW_point v) {
-	RGFW_ASSERT(win != NULL);
-
-	win->r.x = v.x;
-	win->r.y = v.y;
-	SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
-}
-
-void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-
-	win->r.w = (i32)a.w;
-	win->r.h = (i32)a.h;
-	SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w + (i32)win->src.wOffset, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE);
-}
-
-
-void RGFW_window_setName(RGFW_window* win, const char* name) {
-	RGFW_ASSERT(win != NULL);
-
-	wchar_t wide_name[256];
-	MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
-	SetWindowTextW(win->src.window, wide_name);
-}
-
-#ifndef RGFW_NO_PASSTHROUGH
-void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
-	RGFW_ASSERT(win != NULL);
-	COLORREF key = 0;
-	BYTE alpha = 0;
-	DWORD flags = 0;
-	i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
-
-	if (exStyle & WS_EX_LAYERED)
-		GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
-
-	if (passthrough)
-		exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
-	else {
-		exStyle &= ~WS_EX_TRANSPARENT;
-		if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
-			exStyle &= ~WS_EX_LAYERED;
-	}
-
-	SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
-
-	if (passthrough)
-		SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
-}
-#endif
-
-RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) {
-	RGFW_ASSERT(win != NULL);
-	#ifndef RGFW_WIN95
-		RGFW_UNUSED(channels);
-
-		if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
-		if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
-
-		if (src == NULL) {
-			HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
-			if (type & RGFW_iconWindow)
-				SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
-			if (type & RGFW_iconTaskbar)
-				SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
-			return RGFW_TRUE;
-		}
-
-		if (type & RGFW_iconWindow) {
-			win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE);
-			SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
-		}
-		if (type & RGFW_iconTaskbar) {
-			win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE);
-			SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
-		}
-		return RGFW_TRUE;
-	#else
-		RGFW_UNUSED(src);
-		RGFW_UNUSED(a);
-		RGFW_UNUSED(channels);
-		return RGFW_FALSE;
-	#endif
-}
-
-RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
-	/* Open the clipboard */
-	if (OpenClipboard(NULL) == 0)
-		return -1;
-
-	/* Get the clipboard data as a Unicode string */
-	HANDLE hData = GetClipboardData(CF_UNICODETEXT);
-	if (hData == NULL) {
-		CloseClipboard();
-		return -1;
-	}
-
-	wchar_t* wstr = (wchar_t*) GlobalLock(hData);
-
-	RGFW_ssize_t textLen = 0;
-
-	{
-		setlocale(LC_ALL, "en_US.UTF-8");
-
-		textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
-		if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
-			textLen = 0;
-
-		if (str != NULL && textLen) {
-			if (textLen > 1)
-				wcstombs(str, wstr, (size_t)(textLen));
-
-			str[textLen] = '\0';
-		}
-	}
-
-	/* Release the clipboard data */
-	GlobalUnlock(hData);
-	CloseClipboard();
-
-	return textLen;
-}
-
-void RGFW_writeClipboard(const char* text, u32 textLen) {
-	HANDLE object;
-	WCHAR* buffer;
-
-	object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
-	if (!object)
-		return;
-
-	buffer = (WCHAR*) GlobalLock(object);
-	if (!buffer) {
-		GlobalFree(object);
-		return;
-	}
-
-	MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
-	GlobalUnlock(object);
-
-	if (!OpenClipboard(_RGFW.root->src.window)) {
-		GlobalFree(object);
-		return;
-	}
-
-	EmptyClipboard();
-	SetClipboardData(CF_UNICODETEXT, object);
-	CloseClipboard();
-}
-
-void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
-	RGFW_ASSERT(win != NULL);
-	win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
-	SetCursorPos(p.x, p.y);
-}
-
-#ifdef RGFW_OPENGL
-void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
-	if (win == NULL)
-		wglMakeCurrent(NULL, NULL);
-	else
-		wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
-}
-void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); }
-void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); }
-#endif
-
-#ifndef RGFW_EGL
-void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
-	RGFW_ASSERT(win != NULL);
-#if defined(RGFW_OPENGL)
-    if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval");
-#else
-	RGFW_UNUSED(swapInterval);
-#endif
-}
-#endif
-
-void RGFW_window_swapBuffers_software(RGFW_window* win) {
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	if (win->buffer != win->src.bitmapBits)
-	memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4);
-
-	RGFW_RGB_to_BGR(win, win->src.bitmapBits);
-	BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) {
-	if (source == NULL) {
-		return NULL;
-	}
-	i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
-	if (!size) {
-		return NULL;
-	}
-
-	static char target[RGFW_MAX_PATH * 2];
-	if (size > RGFW_MAX_PATH * 2)
-		size = RGFW_MAX_PATH * 2;
-
-	target[size] = 0;
-
-	if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
-		return NULL;
-	}
-
-	return target;
-}
-
-u64 RGFW_getTimerFreq(void) {
-	static u64 frequency = 0;
-	if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
-
-	return frequency;
-}
-
-u64 RGFW_getTimerValue(void) {
-	u64 value;
-	QueryPerformanceCounter((LARGE_INTEGER*)&value);
-	return value;
-}
-
-void RGFW_sleep(u64 ms) {
-	Sleep((u32)ms);
-}
-
-#ifndef RGFW_NO_THREADS
-
-RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
-void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
-void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
-void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
-
-#endif
-#endif /* RGFW_WINDOWS */
-
-/*
-	End of Windows defines
-*/
-
-
-
-/*
-
-	Start of MacOS defines
-
-
-*/
-
-#if defined(RGFW_MACOS)
-/*
-	based on silicon.h
-	start of cocoa wrapper
-*/
-
-#include <CoreGraphics/CoreGraphics.h>
-#include <ApplicationServices/ApplicationServices.h>
-#include <objc/runtime.h>
-#include <objc/message.h>
-#include <mach/mach_time.h>
-#include <CoreVideo/CoreVideo.h>
-
-typedef CGRect NSRect;
-typedef CGPoint NSPoint;
-typedef CGSize NSSize;
-
-typedef const char* NSPasteboardType;
-typedef unsigned long NSUInteger;
-typedef long NSInteger;
-typedef NSInteger NSModalResponse;
-
-#ifdef __arm64__
-	/* ARM just uses objc_msgSend */
-#define abi_objc_msgSend_stret objc_msgSend
-#define abi_objc_msgSend_fpret objc_msgSend
-#else /* __i386__ */
-	/* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
-#define abi_objc_msgSend_stret objc_msgSend_stret
-#define abi_objc_msgSend_fpret objc_msgSend_fpret
-#endif
-
-#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
-#define objc_msgSend_bool(x, y)			((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
-#define objc_msgSend_void(x, y)			((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
-#define objc_msgSend_void_id(x, y, z)		((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
-#define objc_msgSend_uint(x, y)			((NSUInteger (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
-#define objc_msgSend_void_bool(x, y, z)		((void (*)(id, SEL, BOOL))objc_msgSend)  ((id)(x), (SEL)y, (BOOL)z)
-#define objc_msgSend_bool_void(x, y)		((BOOL (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
-#define objc_msgSend_void_SEL(x, y, z)		((void (*)(id, SEL, SEL))objc_msgSend)  ((id)(x), (SEL)y, (SEL)z)
-#define objc_msgSend_id(x, y)				((id (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
-#define objc_msgSend_id_id(x, y, z)			((id (*)(id, SEL, id))objc_msgSend)  ((id)(x), (SEL)y, (id)z)
-#define objc_msgSend_id_bool(x, y, z)			((BOOL (*)(id, SEL, id))objc_msgSend)  ((id)(x), (SEL)y, (id)z)
-#define objc_msgSend_int(x, y, z) 				((id (*)(id, SEL, int))objc_msgSend)  ((id)(x), (SEL)y, (int)z)
-#define objc_msgSend_arr(x, y, z)				 	((id (*)(id, SEL, int))objc_msgSend)  ((id)(x), (SEL)y, (int)z)
-#define objc_msgSend_ptr(x, y, z) 					((id (*)(id, SEL, void*))objc_msgSend)  ((id)(x), (SEL)y, (void*)z)
-#define objc_msgSend_class(x, y) 					((id (*)(Class, SEL))objc_msgSend)  ((Class)(x), (SEL)y)
-#define objc_msgSend_class_char(x, y, z) 			((id (*)(Class, SEL, char*))objc_msgSend)  ((Class)(x), (SEL)y, (char*)z)
-
-id NSApp = NULL;
-
-#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
-id NSString_stringWithUTF8String(const char* str);
-id NSString_stringWithUTF8String(const char* str) {
-	return ((id(*)(id, SEL, const char*))objc_msgSend)
-		((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
-}
-
-const char* NSString_to_char(id str);
-const char* NSString_to_char(id str) {
-	return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
-}
-
-void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function);
-void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
-	Class selected_class;
-
-	if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) {
-		selected_class = objc_getClass("ViewClass");
-	} else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) {
-		selected_class = objc_getClass("WindowClass");
-	} else {
-		selected_class = objc_getClass(class_name);
-	}
-
-	class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
-}
-
-/* Header for the array. */
-typedef struct siArrayHeader {
-	size_t count;
-	/* TODO(EimaMei): Add a `type_width` later on. */
-} siArrayHeader;
-
-/* Gets the header of the siArray. */
-#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
-#define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
-#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function)
-/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
-#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function)
-
-unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
-unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
-	return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
-}
-
-typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
-	NSBitmapFormatAlphaFirst = 1 << 0,       /* 0 means is alpha last (RGBA, CMYKA, etc.) */
-		NSBitmapFormatAlphaNonpremultiplied = 1 << 1,       /* 0 means is premultiplied */
-		NSBitmapFormatFloatingpointSamples = 1 << 2,  /* 0 is integer */
-
-		NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
-		NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
-		NSBitmapFormatSixteenBitBigEndian = (1 << 10),
-		NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
-};
-
-id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits);
-id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
-	SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
-
-	return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
-		(NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
-}
-
-id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
-id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
-	void* nsclass = objc_getClass("NSColor");
-	SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
-	return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
-		((id)nsclass, func, red, green, blue, alpha);
-}
-
-typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
-	NSOpenGLContextParameterSwapInterval            = 222, /* 1 param.  0 -> Don't sync, 1 -> Sync to vertical retrace     */
-		NSOpenGLContextParametectxaceOrder            = 235, /* 1 param.  1 -> Above Window (default), -1 -> Below Window    */
-		NSOpenGLContextParametectxaceOpacity          = 236, /* 1 param.  1-> Surface is opaque (default), 0 -> non-opaque   */
-		NSOpenGLContextParametectxaceBackingSize      = 304, /* 2 params.  Width/height of surface backing size              */
-		NSOpenGLContextParameterReclaimResources        = 308, /* 0 params.                                                    */
-		NSOpenGLContextParameterCurrentRendererID       = 309, /* 1 param.   Retrieves the current renderer ID                 */
-		NSOpenGLContextParameterGPUVertexProcessing     = 310, /* 1 param.   Currently processing vertices with GPU (get)      */
-		NSOpenGLContextParameterGPUFragmentProcessing   = 311, /* 1 param.   Currently processing fragments with GPU (get)     */
-		NSOpenGLContextParameterHasDrawable             = 314, /* 1 param.   Boolean returned if drawable is attached          */
-		NSOpenGLContextParameterMPSwapsInFlight         = 315, /* 1 param.   Max number of swaps queued by the MP GL engine    */
-
-		NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params.  Set or get the swap rectangle {x, y, w, h} */
-		NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
-		NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
-		NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
-		NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param.   Surface volatile state */
-};
-
-typedef RGFW_ENUM(NSInteger, NSWindowButton) {
-    NSWindowCloseButton            = 0,
-    NSWindowMiniaturizeButton      = 1,
-    NSWindowZoomButton             = 2,
-    NSWindowToolbarButton          = 3,
-    NSWindowDocumentIconButton     = 4,
-    NSWindowDocumentVersionsButton = 6,
-    NSWindowFullScreenButton       = 7,
-};
-void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
-void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
-	((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
-		(context, sel_registerName("setValues:forParameter:"), vals, param);
-}
-void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs);
-void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
-	return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
-		(NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs);
-}
-
-id NSPasteboard_generalPasteboard(void);
-id NSPasteboard_generalPasteboard(void) {
-	return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
-}
-
-id* cstrToNSStringArray(char** strs, size_t len);
-id* cstrToNSStringArray(char** strs, size_t len) {
-	static id nstrs[6];
-	size_t i;
-	for (i = 0; i < len; i++)
-		nstrs[i] = NSString_stringWithUTF8String(strs[i]);
-
-	return nstrs;
-}
-
-const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
-const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
-	SEL func = sel_registerName("stringForType:");
-	id nsstr = NSString_stringWithUTF8String(dataType);
-	id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
-	const char* str = NSString_to_char(nsString);
-	if (len != NULL)
-		*len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
-	return str;
-}
-
-id c_array_to_NSArray(void* array, size_t len);
-id c_array_to_NSArray(void* array, size_t len) {
-	SEL func = sel_registerName("initWithObjects:count:");
-	void* nsclass = objc_getClass("NSArray");
-	return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
-				(NSAlloc(nsclass), func, array, len);
-}
-
-
-void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
-void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
-	id* ntypes = cstrToNSStringArray((char**)newTypes, len);
-
-	id array = c_array_to_NSArray(ntypes, len);
-	objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
-	NSRelease(array);
-}
-
-NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
-NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
-	id* ntypes = cstrToNSStringArray((char**)newTypes, len);
-
-	SEL func = sel_registerName("declareTypes:owner:");
-
-	id array = c_array_to_NSArray(ntypes, len);
-
-	NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
-		(pasteboard, func, array, owner);
-	NSRelease(array);
-
-	return output;
-}
-
-#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
-
-typedef enum NSApplicationActivationPolicy {
-	NSApplicationActivationPolicyRegular,
-	NSApplicationActivationPolicyAccessory,
-	NSApplicationActivationPolicyProhibited
-} NSApplicationActivationPolicy;
-
-typedef RGFW_ENUM(u32, NSBackingStoreType) {
-	NSBackingStoreRetained = 0,
-		NSBackingStoreNonretained = 1,
-		NSBackingStoreBuffered = 2
-};
-
-typedef RGFW_ENUM(u32, NSWindowStyleMask) {
-	NSWindowStyleMaskBorderless = 0,
-		NSWindowStyleMaskTitled = 1 << 0,
-		NSWindowStyleMaskClosable = 1 << 1,
-		NSWindowStyleMaskMiniaturizable = 1 << 2,
-		NSWindowStyleMaskResizable = 1 << 3,
-		NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
-		NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
-		NSWindowStyleMaskFullScreen = 1 << 14,
-		NSWindowStyleMaskFullSizeContentView = 1 << 15,
-		NSWindowStyleMaskUtilityWindow = 1 << 4,
-		NSWindowStyleMaskDocModalWindow = 1 << 6,
-		NSWindowStyleMaskNonactivatingpanel = 1 << 7,
-		NSWindowStyleMaskHUDWindow = 1 << 13
-};
-
-NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */
-
-
-typedef RGFW_ENUM(i32, NSDragOperation) {
-	NSDragOperationNone = 0,
-		NSDragOperationCopy = 1,
-		NSDragOperationLink = 2,
-		NSDragOperationGeneric = 4,
-		NSDragOperationPrivate = 8,
-		NSDragOperationMove = 16,
-		NSDragOperationDelete = 32,
-		NSDragOperationEvery = (int)ULONG_MAX
-};
-
-void* NSArray_objectAtIndex(id array, NSUInteger index) {
-	SEL func = sel_registerName("objectAtIndex:");
-	return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
-}
-
-id NSWindow_contentView(id window) {
-	SEL func = sel_registerName("contentView");
-	return objc_msgSend_id(window, func);
-}
-
-/*
-	End of cocoa wrapper
-*/
-
-#ifdef RGFW_OPENGL
-/* MacOS opengl API spares us yet again (there are no extensions) */
-RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
-CFBundleRef RGFWnsglFramework = NULL;
-
-RGFW_proc RGFW_getProcAddress(const char* procname) {
-	if (RGFWnsglFramework == NULL)
-		RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
-
-	CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
-
-	RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
-
-	CFRelease(symbolName);
-
-	return symbol;
-}
-#endif
-
-id NSWindow_delegate(RGFW_window* win) {
-	return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate"));
-}
-
-u32 RGFW_OnClose(id self) {
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
-	if (win == NULL)
-		return true;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win);
-	RGFW_windowQuitCallback(win);
-
-	return false;
-}
-
-/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
-bool acceptsFirstResponder(void) { return true; }
-bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
-
-NSDragOperation draggingEntered(id self, SEL sel, id sender) {
-	RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
-
-	return NSDragOperationCopy;
-}
-NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
-	RGFW_UNUSED(sel);
-
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL || (!(win->_flags & RGFW_windowAllowDND)))
-		return 0;
-
-	NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
-	RGFW_eventQueuePushEx(e.type = RGFW_DNDInit;
-									e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
-									e._win = win);
-
-	RGFW_dndInitCallback(win, win->event.point);
-	return NSDragOperationCopy;
-}
-bool prepareForDragOperation(id self) {
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL)
-		return true;
-
-	if (!(win->_flags & RGFW_windowAllowDND)) {
-		return false;
-	}
-
-	return true;
-}
-
-void RGFW__osxDraggingEnded(id self, SEL sel, id sender);
-void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);  return; }
-
-/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
-bool performDragOperation(id self, SEL sel, id sender) {
-	RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
-
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-
-	if (win == NULL)
-		return false;
-
-	/* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
-
-	id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
-
-	/* Get the types of data available on the pasteboard */
-	id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
-
-	/* Get the string type for file URLs */
-	id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
-
-	/* Check if the pasteboard contains file URLs */
-	if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard.");
-		return 0;
-	}
-
-	id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
-	int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
-
-	if (count == 0)
-		return 0;
-
-    int i;
-    for (i = 0; i < count; i++) {
-		id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
-		const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
-		RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1);
-		win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
-	}
-	NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
-	
-	win->event.droppedFilesCount = (size_t)count; 
-	RGFW_eventQueuePushEx(e.type = RGFW_DND;
-									e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
-									e.droppedFilesCount = (size_t)count;
-									e._win = win);
-	
-	RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
-
-	return false;
-}
-
-#ifndef RGFW_NO_IOKIT
-#include <IOKit/IOKitLib.h>
-#include <IOKit/hid/IOHIDManager.h>
-
-u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
-    u32 refreshRate = 0;
-    io_iterator_t it;
-    io_service_t service;
-    CFNumberRef indexRef, clockRef, countRef;
-    uint32_t clock, count;
-
-#ifdef kIOMainPortDefault 
-    if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
-#elif defined(kIOMasterPortDefault) 
-    if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
-#endif
-        return RGFW_FALSE;
-
-    while ((service = IOIteratorNext(it)) != 0) {
-        uint32_t index;
-        indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
-        if (indexRef == 0) continue;
-        
-        if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
-            CFRelease(indexRef);
-            break;
-        }
-
-        CFRelease(indexRef);
-    }
-
-    if (service) {
-        clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
-        if (clockRef) {
-            if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
-                countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
-                if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
-                    refreshRate = (u32)RGFW_ROUND(clock / (double) count);
-                    CFRelease(countRef);
-                }
-            }
-            CFRelease(clockRef);
-        }
-    }
-
-    IOObjectRelease(it);
-    return refreshRate;
-}
-
-IOHIDDeviceRef RGFW_osxControllers[4] = {NULL};
-
-size_t findControllerIndex(IOHIDDeviceRef device) {
-    size_t i;
-    for (i = 0; i < 4; i++)
-		if (RGFW_osxControllers[i] == device)
-			return i;
-	return (size_t)-1;
-}
-
-void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
-	RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
-	IOHIDElementRef element = IOHIDValueGetElement(value);
-
-	IOHIDDeviceRef device = IOHIDElementGetDevice(element);
-	size_t index = findControllerIndex(device);
-	if (index == (size_t)-1) return;
-
-	uint32_t usagePage = IOHIDElementGetUsagePage(element);
-	uint32_t usage = IOHIDElementGetUsage(element);
-
-	CFIndex intValue = IOHIDValueGetIntegerValue(value);
-
-	u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{
-		0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart,
-		RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft,
-		RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1,
-		RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome},
-		{0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX,
-		RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1,
-		RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart,
-		RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome}
-	};
-
-	u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0];
-	if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft)
-		RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1];
-
-	switch (usagePage) {
-		case kHIDPage_Button: {
-			u8 button = 0;
-			if (usage < sizeof(RGFW_osx2RGFW))
-				button = RGFW_osx2RGFW[usage];
-
-			RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue);
-			RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current;
-			RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue);
-			RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased;
-											e.button = button;
-											e.gamepad = (u16)index;
-											e._win = _RGFW.root);
-			break;
-		}
-		case kHIDPage_GenericDesktop: {
-			CFIndex logicalMin = IOHIDElementGetLogicalMin(element);
-			CFIndex logicalMax = IOHIDElementGetLogicalMax(element);
-
-			if (logicalMax <= logicalMin) return;
-			if (intValue < logicalMin) intValue = logicalMin;
-			if (intValue > logicalMax) intValue = logicalMax;
-
-			i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin));
-
-			u8 whichAxis = 0;
-			switch (usage) {
-				case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break;
-				case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break;
-				case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break;
-				case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break;
-				default: return;
-			}
-
-            RGFW_event e;
-            e.type = RGFW_gamepadAxisMove;
-            e.gamepad = (u16)index;
-            e.whichAxis = whichAxis;
-            e._win = _RGFW.root;
-            for (size_t i = 0; i < 4; i++)
-                e.axis[i] = RGFW_gamepadAxes[index][i]; 
-
-			RGFW_eventQueuePush(e);
-
-			RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis);
-		}
-	}
-}
-
-void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) {
-	RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
-	CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
-	int usage = 0;
-	if (usageRef)
-		CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage);
-
-	if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
-		return;
-	}
-
-    size_t i;
-    for (i = 0; i < 4; i++) {
-		if (RGFW_osxControllers[i] != NULL)
-			continue;
-
-		RGFW_osxControllers[i] = device;
-
-		IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL);
-
-		CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
-		if (deviceName)
-			CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8);
-
-		RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
-		if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox"))
-			RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
-			RGFW_gamepads_type[i] = RGFW_gamepadSony;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
-			RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
-			RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
-
-		RGFW_gamepads[i] = (u16)i;
-		RGFW_gamepadCount++;
-
-		RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected;
-										e.gamepad = (u16)i;
-										e._win = _RGFW.root);
-
-		RGFW_gamepadCallback(_RGFW.root, (u16)i, 1);
-		break;
-	}
-}
-
-void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {
-	RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device);
-	CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
-	int usage = 0;
-	if (usageRef)
-		CFNumberGetValue(usageRef, kCFNumberIntType, &usage);
-
-	if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
-		return;
-	}
-
-	size_t index = findControllerIndex(device);
-	if (index != (size_t)-1)
-		RGFW_osxControllers[index] = NULL;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected;
-									e.gamepad = (u16)index;
-									e._win = _RGFW.root);
-	RGFW_gamepadCallback(_RGFW.root, (u16)index, 0);
-
-	RGFW_gamepadCount--;
-}
-
-RGFWDEF void RGFW_osxInitIOKit(void);
-void RGFW_osxInitIOKit(void) {
-	IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
-	if (!hidManager) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager.");
-		return;
-	}
-
-	CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable(
-		kCFAllocatorDefault,
-		0,
-		&kCFTypeDictionaryKeyCallBacks,
-		&kCFTypeDictionaryValueCallBacks
-	);
-	if (!matchingDictionary) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit.");
-		CFRelease(hidManager);
-		return;
-	}
-
-	CFDictionarySetValue(
-		matchingDictionary,
-		CFSTR(kIOHIDDeviceUsagePageKey),
-		CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop})
-	);
-
-	IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary);
-
-	IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL);
-	IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL);
-
-	IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
-
-	IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
-
-	/* Execute the run loop once in order to register any initially-attached joysticks */
-	CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
-}
-#endif
-
-void RGFW_moveToMacOSResourceDir(void) {
-	char resourcesPath[256];
-
-	CFBundleRef bundle = CFBundleGetMainBundle();
-	if (!bundle)
-		return;
-
-	CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
-	CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
-
-	if (
-		CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
-		CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
-		) {
-		CFRelease(last);
-		CFRelease(resourcesURL);
-		return;
-	}
-
-	CFRelease(last);
-	CFRelease(resourcesURL);
-
-	chdir(resourcesPath);
-}
-
-
-void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
-	RGFW_UNUSED(sel);
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-	win->_flags |= RGFW_windowMinimize;
-	RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
-	RGFW_windowRestoredCallback(win, win->r);
-
-}
-void RGFW__osxWindowMiniaturize(id self, SEL sel) {
-	RGFW_UNUSED(sel);
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-	win->_flags &= ~(u32)RGFW_windowMinimize;
-	RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win);
-	RGFW_windowMinimizedCallback(win, win->r);
-
-}
-
-void RGFW__osxWindowBecameKey(id self, SEL sel) {
-	RGFW_UNUSED(sel);
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-	win->_flags |= RGFW_windowFocus;
-	RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win);
-
-	RGFW_focusCallback(win, RGFW_TRUE);
-
-	if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h));
-}
-
-void RGFW__osxWindowResignKey(id self, SEL sel) {
-	RGFW_UNUSED(sel);
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-    RGFW_window_focusLost(win);
-    RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win);
-	RGFW_focusCallback(win, RGFW_FALSE);
-}
-
-NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) {
-	RGFW_UNUSED(sel);
-
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return frameSize;
-
-	win->r.w = (i32)frameSize.width;
-	win->r.h = (i32)frameSize.height;
-
-	RGFW_monitor mon = RGFW_window_getMonitor(win);
-	if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) {
-		win->_flags |= RGFW_windowMaximize;
-		RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win);
-		RGFW_windowMaximizedCallback(win, win->r);
-	} else if (win->_flags & RGFW_windowMaximize) {
-		win->_flags &= ~(u32)RGFW_windowMaximize;
-		RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win);
-		RGFW_windowRestoredCallback(win, win->r);
-
-	}
-
-
-	RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win);
-	RGFW_windowResizedCallback(win, win->r);
-	return frameSize;
-}
-
-void RGFW__osxWindowMove(id self, SEL sel) {
-	RGFW_UNUSED(sel);
-
-	RGFW_window* win = NULL;
-	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
-	win->r.x = (i32) frame.origin.x;
-	win->r.y = (i32) frame.origin.y;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win);
-	RGFW_windowMovedCallback(win, win->r);
-}
-
-void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
-	RGFW_UNUSED(_cmd);
-        RGFW_window* win = NULL;
-        object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-	RGFW_monitor mon = RGFW_window_getMonitor(win);
-	RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY);
-	RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win);
-}
-
-void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
-	RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
-        RGFW_window* win = NULL;
-        object_getInstanceVariable(self, "RGFW_window", (void**)&win);
-	if (win == NULL) return;
-
-        RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win);
-        RGFW_windowRefreshCallback(win);
-}
-
-void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-		win->buffer = buffer;
-		win->bufferSize = area;
-		win->_flags |= RGFW_BUFFER_ALLOC;
-	#ifdef RGFW_OSMESA
-		win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
-		OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
-		OSMesaPixelStore(OSMESA_Y_UP, 0);
-	#endif
-	#else
-		RGFW_UNUSED(win);  RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
-	#endif
-}
-
-void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
-	objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer);
-}
-
-void* RGFW_cocoaGetLayer(void) {
-	return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
-}
-
-NSPasteboardType const NSPasteboardTypeURL = "public.url";
-NSPasteboardType const NSPasteboardTypeFileURL  = "public.file-url";
-
-id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) {
-	Class customViewClass;
-	customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0);
-
-	class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L");
-	class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
-	class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "");
-
-	id customView  = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init"));
-	object_setInstanceVariable(customView, "RGFW_window", win);
-
-	return customView;
-}
-
-#ifndef RGFW_EGL
-void RGFW_window_initOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-	void* attrs = RGFW_initFormatAttribs();
-	void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs);
-
-	if (format == NULL) {
-		RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL");
-        win->_flags |= RGFW_windowOpenglSoftware;
-        void* subAttrs = RGFW_initFormatAttribs();
-		format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs);
-
-		if (format == NULL)
-			RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed");
-		else
-			RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering");
-	}
-
-	/* the pixel format can be passed directly to opengl context creation to create a context
-		this is because the format also includes information about the opengl version (which may be a bad thing) */
-
-	win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win),
-							sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format);
-
-	objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
-	win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
-
-	if (win->_flags & RGFW_windowTransparent) {
-		i32 opacity = 0;
-		#define NSOpenGLCPSurfaceOpacity 236
-		NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
-	}
-
-	objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_window_freeOpenGL(RGFW_window* win) {
-#ifdef RGFW_OPENGL
-	if (win->src.ctx == NULL) return;
-	objc_msgSend_void(win->src.ctx, sel_registerName("release"));
-	win->src.ctx = NULL;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-#endif
-
-
-i32 RGFW_init(void) {
-#if defined(RGFW_C89) || defined(__cplusplus)
-    if (_RGFW_init) return 0; 
-    _RGFW_init = RGFW_TRUE;
-    _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
-#endif
-
-    /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
-	Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
-	*/
-	si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose);
-
-	/* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
-	si_func_to_SEL("NSWindow", acceptsFirstResponder);
-	si_func_to_SEL("NSWindow", performKeyEquivalent);
-
-    if (NSApp == NULL) {
-		NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
-
-		((void (*)(id, SEL, NSUInteger))objc_msgSend)
-			(NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
-
-		#ifndef RGFW_NO_IOKIT
-			RGFW_osxInitIOKit();
-		#endif
-	}
-
-    _RGFW.windowCount = 0;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized");
-    return 0;
-}
-
-RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
-	static u8 RGFW_loaded = 0;
-	RGFW_window_basic_init(win, rect, flags);
-
-    /* RR Create an autorelease pool */
-	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
-	pool = objc_msgSend_id(pool, sel_registerName("init"));
-
-	RGFW_window_setMouseDefault(win);
-
-	NSRect windowRect;
-	windowRect.origin.x = win->r.x;
-	windowRect.origin.y = win->r.y;
-	windowRect.size.width = win->r.w;
-	windowRect.size.height = win->r.h;
-
-	NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
-
-	if (!(flags & RGFW_windowNoResize))
-		macArgs |= NSWindowStyleMaskResizable;
-	if (!(flags & RGFW_windowNoBorder))
-		macArgs |= NSWindowStyleMaskTitled;
-	{
-		void* nsclass = objc_getClass("NSWindow");
-		SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
-
-		win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
-			(NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
-	}
-
-	id str = NSString_stringWithUTF8String(name);
-	objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
-
-	if ((flags & RGFW_windowNoInitAPI) == 0) {
-		RGFW_window_initOpenGL(win);
-        RGFW_window_initBuffer(win);
-    }
-
-	#ifdef RGFW_OPENGL
-	else
-	#endif
-	{
-		NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
-		win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect);
-    	}
-
-	void* contentView = NSWindow_contentView((id)win->src.window);
-	objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
-	objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"),  4);
-	objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
-
-	if (flags & RGFW_windowTransparent) {
-		objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
-
-		objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
-			NSColor_colorWithSRGB(0, 0, 0, 0));
-	}
-
-	Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
-
-	class_addIvar(
-		delegateClass, "RGFW_window",
-		sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))),
-		"L"
-	);
-
-	class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
-	class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
-	class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
-	class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
-	class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
-	class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
-	class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
-	class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
-	class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
-	class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
-	class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
-	class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
-	class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
-
-	id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
-
-	if (RGFW_COCOA_FRAME_NAME)
-		objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
-
-	object_setInstanceVariable(delegate, "RGFW_window", win);
-
-	objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate);
-
-	if (flags & RGFW_windowAllowDND) {
-		win->_flags |= RGFW_windowAllowDND;
-
-		NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
-		NSregisterForDraggedTypes((id)win->src.window, types, 3);
-	}
-
-	RGFW_window_setFlags(win, flags);
-
-    /* Show the window */
-	objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
-	((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
-	RGFW_window_show(win);
-
-	if (!RGFW_loaded) {
-		objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
-
-		RGFW_loaded = 1;
-	}
-
-	objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
-
-	objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
-	NSRetain(win->src.window);
-	NSRetain(NSApp);
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new  window was created");
-	return win;
-}
-
-void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
-	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
-	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
-	float offset = 0;
-
-	RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
-	NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView;
-	if (border)
-		storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
-	if (!(win->_flags & RGFW_windowNoResize)) {
-		storeType |= NSWindowStyleMaskResizable;
-	}
-
-	((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
-
-	if (!border) {
-		id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"),  NSWindowMiniaturizeButton);
-		id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
-		objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
-
-		offset = (float)(frame.size.height - content.size.height);
-	}
-
-	RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset));
-	win->r.h -= (i32)offset;
-}
-
-RGFW_area RGFW_getScreenSize(void) {
-	static CGDirectDisplayID display = 0;
-
-	if (display == 0)
-		display = CGMainDisplayID();
-
-	return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
-}
-
-RGFW_point RGFW_getGlobalMousePoint(void) {
-	RGFW_ASSERT(_RGFW.root != NULL);
-
-	CGEventRef e = CGEventCreate(NULL);
-	CGPoint point = CGEventGetLocation(e);
-	CFRelease(e);
-
-	return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
-}
-
-typedef RGFW_ENUM(u32, NSEventType) {        /* various types of events */
-	NSEventTypeLeftMouseDown = 1,
-		NSEventTypeLeftMouseUp = 2,
-		NSEventTypeRightMouseDown = 3,
-		NSEventTypeRightMouseUp = 4,
-		NSEventTypeMouseMoved = 5,
-		NSEventTypeLeftMouseDragged = 6,
-		NSEventTypeRightMouseDragged = 7,
-		NSEventTypeMouseEntered = 8,
-		NSEventTypeMouseExited = 9,
-		NSEventTypeKeyDown = 10,
-		NSEventTypeKeyUp = 11,
-		NSEventTypeFlagsChanged = 12,
-		NSEventTypeAppKitDefined = 13,
-		NSEventTypeSystemDefined = 14,
-		NSEventTypeApplicationDefined = 15,
-		NSEventTypePeriodic = 16,
-		NSEventTypeCursorUpdate = 17,
-		NSEventTypeScrollWheel = 22,
-		NSEventTypeTabletPoint = 23,
-		NSEventTypeTabletProximity = 24,
-		NSEventTypeOtherMouseDown = 25,
-		NSEventTypeOtherMouseUp = 26,
-		NSEventTypeOtherMouseDragged = 27,
-		/* The following event types are available on some hardware on 10.5.2 and later */
-		NSEventTypeGesture  = 29,
-		NSEventTypeMagnify  = 30,
-		NSEventTypeSwipe    = 31,
-		NSEventTypeRotate   = 18,
-		NSEventTypeBeginGesture  = 19,
-		NSEventTypeEndGesture  = 20,
-
-		NSEventTypeSmartMagnify  = 32,
-		NSEventTypeQuickLook  = 33,
-
-		NSEventTypePressure  = 34,
-		NSEventTypeDirectTouch  = 37,
-
-		NSEventTypeChangeMode  = 38,
-};
-
-typedef unsigned long long NSEventMask;
-
-typedef enum NSEventModifierFlags {
-	NSEventModifierFlagCapsLock = 1 << 16,
-	NSEventModifierFlagShift = 1 << 17,
-	NSEventModifierFlagControl = 1 << 18,
-	NSEventModifierFlagOption = 1 << 19,
-	NSEventModifierFlagCommand = 1 << 20,
-	NSEventModifierFlagNumericPad = 1 << 21
-} NSEventModifierFlags;
-
-void RGFW_stopCheckEvents(void) {
-	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
-	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
-
-	id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
-		(objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
-			NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
-
-	((void (*)(id, SEL, id, bool))objc_msgSend)
-		(NSApp, sel_registerName("postEvent:atStart:"), e, 1);
-
-	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
-}
-
-void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
-	RGFW_UNUSED(win);
-
-	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
-	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
-
-	void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
-				(objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
-
-	SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
-	id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
-		(NSApp, eventFunc,
-			ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
-
-	if (e) {
-		((void (*)(id, SEL, id, bool))objc_msgSend)
-			(NSApp, sel_registerName("postEvent:atStart:"), e, 1);
-	}
-
-	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
-}
-
-u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
-    return (u8)rgfw_keycode; /* TODO */
-}
-
-RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
-    if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
-
-    objc_msgSend_void((id)win->src.mouse, sel_registerName("set"));
-    RGFW_event* ev =  RGFW_window_checkEventCore(win);
-	if (ev) {
-		((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
-		return ev;
-	}
-
-	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
-	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
-
-	SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
-
-	void* date = NULL;
-
-	id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
-		(NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
-
-	if (e == NULL) {
-		objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
-		objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
-		((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
-		return NULL;
-	}
-
-	if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
-		((void (*)(id, SEL, id, bool))objc_msgSend)
-			(NSApp, sel_registerName("postEvent:atStart:"), e, 0);
-
-		objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
-		objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
-		((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
-		return NULL;
-	}
-
-	if (win->event.droppedFilesCount) {
-		u32 i;
-		for (i = 0; i < win->event.droppedFilesCount; i++)
-			win->event.droppedFiles[i][0] = '\0';
-	}
-
-	win->event.droppedFilesCount = 0;
-	win->event.type = 0;
-
-	u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type"));
-	switch (type) {
-		case NSEventTypeMouseEntered: {
-			win->event.type = RGFW_mouseEnter;
-			NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
-
-			win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
-			RGFW_mouseNotifyCallback(win, win->event.point, 1);
-			break;
-		}
-
-		case NSEventTypeMouseExited:
-			win->event.type = RGFW_mouseLeave;
-			RGFW_mouseNotifyCallback(win, win->event.point, 0);
-			break;
-
-		case NSEventTypeKeyDown: {
-			u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
-
-			u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
-			if (((u8)mappedKey) == 239)
-				mappedKey = 0;
-
-			win->event.keyChar = (u8)mappedKey;
-
-			win->event.key = (u8)RGFW_apiKeyToRGFW(key);
-			RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
-
-			win->event.type = RGFW_keyPressed;
-			win->event.repeat = RGFW_isPressed(win, win->event.key);
-			RGFW_keyboard[win->event.key].current = 1;
-
-			RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
-			break;
-		}
-
-		case NSEventTypeKeyUp: {
-			u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
-			u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
-			if (((u8)mappedKey) == 239)
-				mappedKey = 0;
-
-			win->event.keyChar = (u8)mappedKey;
-
-			win->event.key = (u8)RGFW_apiKeyToRGFW(key);
-
-			RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
-
-			win->event.type = RGFW_keyReleased;
-
-			RGFW_keyboard[win->event.key].current = 0;
-			RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
-			break;
-		}
-
-		case NSEventTypeFlagsChanged: {
-			u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags"));
-			RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255),
-										((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255),
-										((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0);
-			u8 i;
-			for (i = 0; i < 9; i++)
-				RGFW_keyboard[i + RGFW_capsLock].prev = 0;
-
-			for (i = 0; i < 5; i++) {
-				u32 shift = (1 << (i + 16));
-				u32 key = i + RGFW_capsLock;
-
-				if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) {
-					RGFW_keyboard[key].current = 1;
-
-					if (key != RGFW_capsLock)
-						RGFW_keyboard[key+ 4].current = 1;
-
-					win->event.type = RGFW_keyPressed;
-					win->event.key = (u8)key;
-					break;
-				}
-
-				if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) {
-					RGFW_keyboard[key].current = 0;
-
-					if (key != RGFW_capsLock)
-						RGFW_keyboard[key + 4].current = 0;
-
-					win->event.type = RGFW_keyReleased;
-					win->event.key = (u8)key;
-					break;
-				}
-			}
-
-			RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed);
-
-			break;
-		}
-		case NSEventTypeLeftMouseDragged:
-		case NSEventTypeOtherMouseDragged:
-		case NSEventTypeRightMouseDragged:
-		case NSEventTypeMouseMoved: {
-			win->event.type = RGFW_mousePosChanged;
-			NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
-			win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
-
-			p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
-			p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
-			win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y);
-
-			win->_lastMousePoint = win->event.point;
-			RGFW_mousePosCallback(win, win->event.point, win->event.vector);
-			break;
-		}
-		case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: {
-			u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
-			switch (buttonNumber) {
-				case 0: win->event.button = RGFW_mouseLeft; break;
-				case 1: win->event.button = RGFW_mouseRight; break;
-				case 2: win->event.button = RGFW_mouseMiddle; break;
-				default: win->event.button = (u8)buttonNumber;
-			}
-
-			win->event.type = RGFW_mouseButtonPressed;
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 1;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
-			break;
-		}
-		case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: {
-			u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
-			switch (buttonNumber) {
-				case 0: win->event.button = RGFW_mouseLeft; break;
-				case 1: win->event.button = RGFW_mouseRight; break;
-				case 2: win->event.button = RGFW_mouseMiddle; break;
-				default: win->event.button = (u8)buttonNumber;
-			}
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 0;
-			win->event.type = RGFW_mouseButtonReleased;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
-			break;
-		}
-		case NSEventTypeScrollWheel: {
-			double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
-
-			if (deltaY > 0) {
-				win->event.button = RGFW_mouseScrollUp;
-			}
-			else if (deltaY < 0) {
-				win->event.button = RGFW_mouseScrollDown;
-			}
-
-			RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
-			RGFW_mouseButtons[win->event.button].current = 1;
-
-			win->event.scroll = deltaY;
-
-			win->event.type = RGFW_mouseButtonPressed;
-			RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
-			break;
-		}
-
-		default:
-			objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
-			((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
-			return RGFW_window_checkEvent(win);
-	}
-
-	objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
-	((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
-	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
-	return &win->event;
-}
-
-
-void RGFW_window_move(RGFW_window* win, RGFW_point v) {
-	RGFW_ASSERT(win != NULL);
-
-	win->r.x = v.x;
-	win->r.y = v.y;
-	((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
-		((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
-}
-
-void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
-	RGFW_ASSERT(win != NULL);
-
-	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
-	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
-	float offset = (float)(frame.size.height - content.size.height);
-
-	win->r.w = (i32)a.w;
-	win->r.h = (i32)a.h;
-
-	((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
-		((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true);
-}
-
-void RGFW_window_focus(RGFW_window* win) {
-	RGFW_ASSERT(win);
-	objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
-	((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
-}
-
-void RGFW_window_raise(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
-    	objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
-}
-
-void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
-	RGFW_ASSERT(win != NULL);
-	if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return;
-	if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return;
-
-	if (fullscreen) {
-		win->_oldRect = win->r;
-		RGFW_monitor mon = RGFW_window_getMonitor(win);
-		win->r = RGFW_RECT(0, 0, mon.x, mon.y);
-		win->_flags |= RGFW_windowFullscreen;
-		RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h));
-		RGFW_window_move(win, RGFW_POINT(0, 0));
-	}
-	objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
-
-	if (!fullscreen) {
-		win->r = win->_oldRect;
-		win->_flags &= ~(u32)RGFW_windowFullscreen;
-
-		RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
-		RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
-	}
-}
-
-void RGFW_window_maximize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	if (RGFW_window_isMaximized(win)) return;
-
-	win->_flags |= RGFW_windowMaximize;
-	objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
-}
-
-void RGFW_window_minimize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
-}
-
-void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
-    RGFW_ASSERT(win != NULL);
-    if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
-    else 		  objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
-}
-
-void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
-	objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
-	objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
-
-	if (opacity)
-		objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
-
-}
-
-void RGFW_window_restore(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	if (RGFW_window_isMaximized(win))
-		objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
-
-	objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
-	RGFW_window_show(win);
-}
-
-RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
-	return level > kCGNormalWindowLevelKey;
-}
-
-void RGFW_window_setName(RGFW_window* win, const char* name) {
-	RGFW_ASSERT(win != NULL);
-
-	id str = NSString_stringWithUTF8String(name);
-	objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
-}
-
-#ifndef RGFW_NO_PASSTHROUGH
-void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
-	objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
-}
-#endif
-
-void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
-	if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1);
-
-	((void (*)(id, SEL, NSSize))objc_msgSend)
-		((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h});
-}
-
-void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
-	((void (*)(id, SEL, NSSize))objc_msgSend)
-		((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
-}
-
-void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
-	if (a.w == 0 && a.h == 0) {
-		a = RGFW_getScreenSize();
-	}
-
-	((void (*)(id, SEL, NSSize))objc_msgSend)
-		((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
-}
-
-RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_UNUSED(type);
-
-	if (data == NULL) {
-		objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL);
-		return RGFW_TRUE;
-	}
-
-	/* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */
-	id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels);
-	RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels);
-
-	/* Add ze representation. */
-	id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h}));
-
-	objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
-
-	/* Finally, set the dock image to it. */
-	objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
-	/* Free the garbage. */
-	NSRelease(dock_image);
-	NSRelease(representation);
-
-	return RGFW_TRUE;
-}
-
-id NSCursor_arrowStr(const char* str) {
-	void* nclass = objc_getClass("NSCursor");
-	SEL func = sel_registerName(str);
-	return (id) objc_msgSend_id(nclass, func);
-}
-
-RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
-	if (icon == NULL) {
-		objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
-		return NULL;
-	}
-
-	/* NOTE(EimaMei): Code by yours truly. */
-	/* Make a bitmap representation, then copy the loaded image into it. */
-	id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels);
-	RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels);
-
-	/* Add ze representation. */
-	id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h}));
-
-	objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
-
-	/* Finally, set the cursor image. */
-	id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
-		(NSAlloc(objc_getClass("NSCursor")),  sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
-
-	/* Free the garbage. */
-	NSRelease(cursor_image);
-	NSRelease(representation);
-
-	return (void*)cursor;
-}
-
-void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
-	RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
-	CGDisplayShowCursor(kCGDirectMainDisplay);
-	objc_msgSend_void((id)mouse, sel_registerName("set"));
-	win->src.mouse = mouse;
-}
-
-void RGFW_freeMouse(RGFW_mouse* mouse) {
-	RGFW_ASSERT(mouse);
-	NSRelease((id)mouse);
-}
-
-RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
-	return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
-}
-
-void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
-	RGFW_window_showMouseFlags(win, show);
-	if (show)   CGDisplayShowCursor(kCGDirectMainDisplay);
-	else        CGDisplayHideCursor(kCGDirectMainDisplay);
-}
-
-RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
-	static const char* mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
-	if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*))))
-		return RGFW_FALSE;
-
-	const char* mouseStr = mouseIconSrc[stdMouses];
-	id mouse = NSCursor_arrowStr(mouseStr);
-
-	if (mouse == NULL)
-		return RGFW_FALSE;
-
-	RGFW_UNUSED(win);
-	CGDisplayShowCursor(kCGDirectMainDisplay);
-	objc_msgSend_void(mouse, sel_registerName("set"));
-	win->src.mouse = mouse;
-
-	return RGFW_TRUE;
-}
-
-void RGFW_releaseCursor(RGFW_window* win) {
-	RGFW_UNUSED(win);
-	CGAssociateMouseAndMouseCursorPosition(1);
-}
-
-void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
-	RGFW_UNUSED(win);
-
-	CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)});
-	CGAssociateMouseAndMouseCursorPosition(0);
-}
-
-void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
-	RGFW_UNUSED(win);
-
-	win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y);
-	CGWarpMouseCursorPosition((CGPoint){v.x, v.y});
-}
-
-
-void RGFW_window_hide(RGFW_window* win) {
-	objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
-}
-
-void RGFW_window_show(RGFW_window* win) {
-	if (win->_flags & RGFW_windowFocusOnShow)
-		((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
-
-	((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
-	objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
-}
-
-RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
-	return visible == NO && !RGFW_window_isMinimized(win);
-}
-
-RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
-}
-
-RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
-	return b;
-}
-
-id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) {
-	Class NSScreenClass = objc_getClass("NSScreen");
-
-	id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
-
-	NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
-    NSUInteger i;
-	for (i = 0; i < count; i++) {
-		id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
-		id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
-		id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
-		id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
-
-		if ((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) {
-			return screen;
-		}
-	}
-
-	return NULL;
-}
-
-u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
-
-u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
-	if (mode) {
-		u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode);
-		if (refreshRate != 0)  return refreshRate;
-	}
-
-#ifndef RGFW_NO_IOKIT
-    u32 res = RGFW_osx_getFallbackRefreshRate(display);
-    if (res != 0) return res;
-#else
-    RGFW_UNUSED(display);
-#endif
-    return 60;
-}
-
-RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) {
-	RGFW_monitor monitor;
-
-	const char name[] = "MacOS\0";
-	RGFW_MEMCPY(monitor.name, name, 6);
-
-	CGRect bounds = CGDisplayBounds(display);
-	monitor.x = (i32)bounds.origin.x;
-	monitor.y = (i32)bounds.origin.y;
-	monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height);
-
-	monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
-
-	CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
-	monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode);
-	CFRelease(mode);
-
-	CGSize screenSizeMM = CGDisplayScreenSize(display);
-	monitor.physW = (float)screenSizeMM.width / 25.4f;
-	monitor.physH = (float)screenSizeMM.height / 25.4f;
-
-	float ppi_width = (monitor.mode.area.w/monitor.physW);
-	float ppi_height = (monitor.mode.area.h/monitor.physH);
-
-	monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
-	float dpi = 96.0f * monitor.pixelRatio;
-
-	monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
-	monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
-	return monitor;
-}
-
-
-RGFW_monitor* RGFW_getMonitors(size_t* len) {
-	static CGDirectDisplayID displays[7];
-	u32 count;
-
-	if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
-		return NULL;
-
-	if (count > 6) count = 6;
-
-	static RGFW_monitor monitors[7];
-
-    u32 i;
-	for (i = 0; i < count; i++)
-		monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i]));
-
-	if (len != NULL) *len = count;
-	return monitors;
-}
-
-RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
-    CGPoint point = { mon.x, mon.y };
-
-    CGDirectDisplayID display;
-    uint32_t displayCount = 0;
-    CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount);
-    if (err != kCGErrorSuccess || displayCount != 1)
-		return RGFW_FALSE;
-
-    CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
-
-    if (allModes == NULL)
-        return RGFW_FALSE;
-
-    CFIndex i;
-    for (i = 0; i < CFArrayGetCount(allModes); i++) {
-        CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
-
-		RGFW_monitorMode foundMode;
-		foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode));
-		foundMode.refreshRate =  RGFW_osx_getRefreshRate(display, cmode);
-		foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
-
-		if (RGFW_monitorModeCompare(mode, foundMode, request)) {
-				if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) {
-					CFRelease(allModes);
-					return RGFW_TRUE;
-				}
-				break;
-        }
-    }
-
-    CFRelease(allModes);
-
-	return RGFW_FALSE;
-}
-
-RGFW_monitor RGFW_getPrimaryMonitor(void) {
-	CGDirectDisplayID primary = CGMainDisplayID();
-	return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary));
-}
-
-RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
-	id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
-	id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
-	id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
-	id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
-
-	CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
-
-	return RGFW_NSCreateMonitor(display, screen);
-}
-
-RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
-	size_t clip_len;
-	char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
-	if (clip == NULL) return -1;
-
-	if (str != NULL) {
-		if (strCapacity < clip_len)
-			return 0;
-
-		RGFW_MEMCPY(str, clip, clip_len);
-
-		str[clip_len] = '\0';
-	}
-
-	return (RGFW_ssize_t)clip_len;
-}
-
-void RGFW_writeClipboard(const char* text, u32 textLen) {
-	RGFW_UNUSED(textLen);
-
-	NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
-	NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
-
-	SEL func = sel_registerName("setString:forType:");
-	((bool (*)(id, SEL, id, id))objc_msgSend)
-		(NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString));
-}
-
-	#ifdef RGFW_OPENGL
-	void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
-		if (win != NULL)
-			objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
-		else
-			objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
-	}
-	void* RGFW_getCurrent_OpenGL(void) {
-		return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
-	}
-
-	void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
-		objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
-	}
-	#endif
-
-	#if !defined(RGFW_EGL)
-
-	void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
-		RGFW_ASSERT(win != NULL);
-		#if defined(RGFW_OPENGL)
-
-		NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222);
-		#else
-		RGFW_UNUSED(swapInterval);
-		#endif
-	}
-
-	#endif
-
-void RGFW_window_swapBuffers_software(RGFW_window* win) {
-#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	RGFW_RGB_to_BGR(win, win->buffer);
-	i32 channels = 4;
-	id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
-	NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h};
-	image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
-
-	id rep  = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false,
-							"NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w  * (u32)channels, 8 * (u32)channels);
-	((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep);
-
-	id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
-	((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES);
-	id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer"));
-
-	((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
-	((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES);
-
-	NSRelease(rep);
-	NSRelease(image);
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_deinit(void) {
-    _RGFW.windowCount = -1;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
-}
-
-void RGFW_window_close(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-	NSRelease(win->src.view);
-	if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
-
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-		if ((win->_flags & RGFW_BUFFER_ALLOC))
-			RGFW_FREE(win->buffer);
-	#endif
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized");
-    _RGFW.windowCount--;
-    if (_RGFW.windowCount == 0) RGFW_deinit();
-
-    RGFW_clipboard_switch(NULL);
-	RGFW_FREE(win->event.droppedFiles);
-	if ((win->_flags & RGFW_WINDOW_ALLOC)) {
-		RGFW_FREE(win);
-        win = NULL;
-    }
-}
-
-u64 RGFW_getTimerFreq(void) {
-	static u64 freq = 0;
-	if (freq == 0) {
-		mach_timebase_info_data_t info;
-		mach_timebase_info(&info);
-		freq = (u64)((info.denom * 1e9) / info.numer);
-	}
-
-	return freq;
-}
-
-u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); }
-
-#endif /* RGFW_MACOS */
-
-/*
-	End of MaOS defines
-*/
-
-/*
-	WASM defines
-*/
-
-#ifdef RGFW_WASM
-EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-	RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
-	RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight));
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-	static u8 fullscreen = RGFW_FALSE;
-	static RGFW_rect ogRect;
-
-	if (fullscreen == RGFW_FALSE) {
-		ogRect = _RGFW.root->r;
-	}
-
-	fullscreen = !fullscreen;
-	RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root);
-	_RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight);
-
-	EM_ASM("Module.canvas.focus();");
-
-	if (fullscreen == RGFW_FALSE) {
-		_RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h);
-		/* emscripten_request_fullscreen("#canvas", 0); */
-	} else {
-		#if __EMSCRIPTEN_major__  >= 1 && __EMSCRIPTEN_minor__  >= 29 && __EMSCRIPTEN_tiny__  >= 0
-			EmscriptenFullscreenStrategy FSStrat = {0};
-			FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */
-			FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
-			FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
-			emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
-		#else
-			emscripten_request_fullscreen("#canvas", 1);
-		#endif
-	}
-
-	emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h);
-
-	RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r);
-	return EM_TRUE;
-}
-
-
-
-EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
-
-	RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root);
-	_RGFW.root->_flags |= RGFW_windowFocus;
-	RGFW_focusCallback(_RGFW.root, 1);
-
-	if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h));
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
-
-	RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root);
-    RGFW_window_focusLost(_RGFW.root);
-    RGFW_focusCallback(_RGFW.root, 0);
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-	RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
-									e.point = RGFW_POINT(E->targetX, E->targetY);
-									e.vector = RGFW_POINT(E->movementX, E->movementY);
-									e._win = _RGFW.root);
-
-	_RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY);
-	RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY));
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-	int button = E->button;
-	if (button > 2)
-		button += 2;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
-									e.point = RGFW_POINT(E->targetX, E->targetY);
-									e.vector = RGFW_POINT(E->movementX, E->movementY);
-									e.button = (u8)button;
-									e.scroll = 0;
-									e._win = _RGFW.root);
-	RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
-	RGFW_mouseButtons[button].current = 1;
-
-	RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1);
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-	int button = E->button;
-	if (button > 2)
-		button += 2;
-
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
-									e.point = RGFW_POINT(E->targetX, E->targetY);
-									e.vector = RGFW_POINT(E->movementX, E->movementY);
-									e.button = (u8)button;
-									e.scroll = 0;
-									e._win = _RGFW.root);
-	RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
-	RGFW_mouseButtons[button].current = 0;
-
-	RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0);
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-	int button =  RGFW_mouseScrollUp + (E->deltaY < 0);
-	RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
-									e.button = (u8)button;
-									e.scroll = (double)(E->deltaY < 0 ? 1 : -1);
-									e._win = _RGFW.root);
-	RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
-	RGFW_mouseButtons[button].current = 1;
-	RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1);
-
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-    size_t i;
-    for (i = 0; i < (size_t)E->numTouches; i++) {
-		RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed;
-										e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-										e.button = RGFW_mouseLeft;
-										e._win = _RGFW.root);
-
-	    RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
-	    RGFW_mouseButtons[RGFW_mouseLeft].current = 1;
-
-		_RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-        RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
-	    RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1);
-    }
-
-	return EM_TRUE;
-}
-EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-    size_t i;
-    for (i = 0; i < (size_t)E->numTouches; i++) {
-		RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged;
-			e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-			e.button = RGFW_mouseLeft;
-			e._win = _RGFW.root);
-
-		_RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-        RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
-    }
-    return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-    size_t i;
-    for (i = 0; i < (size_t)E->numTouches; i++) {
-		RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased;
-										e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-										e.button = RGFW_mouseLeft;
-										e._win = _RGFW.root);
-
-		RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
-		RGFW_mouseButtons[RGFW_mouseLeft].current = 0;
-
-		_RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY);
-		RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector);
-		RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0);
-    }
-	return EM_TRUE;
-}
-
-EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
-
-EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
-	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
-
-	if (gamepadEvent->index >= 4)
-		return 0;
-
-	size_t i = gamepadEvent->index;
-	if (gamepadEvent->connected) {
-		RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1);
-		RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0';
-		RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
-		if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box"))
-			RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
-			RGFW_gamepads_type[i] = RGFW_gamepadSony;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
-			RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
-		else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
-			RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
-		RGFW_gamepadCount++;
-	} else {
-		RGFW_gamepadCount--;
-	}
-
-	RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected);
-									e.gamepad = (u16)gamepadEvent->index;
-									e._win = _RGFW.root);
-
-	RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected);
-	RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected;
-
-    return 1; /* The event was consumed by the callback handler */
-}
-
-u32 RGFW_wASMPhysicalToRGFW(u32 hash) {
-	switch(hash) {             /* 0x0000 */
-		case 0x67243A2DU /* Escape             */: return RGFW_escape;               /* 0x0001 */
-		case 0x67251058U /* Digit0             */: return RGFW_0;                    /* 0x0002 */
-		case 0x67251059U /* Digit1             */: return RGFW_1;                    /* 0x0003 */
-		case 0x6725105AU /* Digit2             */: return RGFW_2;                    /* 0x0004 */
-		case 0x6725105BU /* Digit3             */: return RGFW_3;                    /* 0x0005 */
-		case 0x6725105CU /* Digit4             */: return RGFW_4;                    /* 0x0006 */
-		case 0x6725105DU /* Digit5             */: return RGFW_5;                    /* 0x0007 */
-		case 0x6725105EU /* Digit6             */: return RGFW_6;                    /* 0x0008 */
-		case 0x6725105FU /* Digit7             */: return RGFW_7;                    /* 0x0009 */
-		case 0x67251050U /* Digit8             */: return RGFW_8;                    /* 0x000A */
-		case 0x67251051U /* Digit9             */: return RGFW_9;                    /* 0x000B */
-		case 0x92E14DD3U /* Minus              */: return RGFW_minus;                /* 0x000C */
-		case 0x92E1FBACU /* Equal              */: return RGFW_equals;                /* 0x000D */
-		case 0x36BF1CB5U /* Backspace          */: return RGFW_backSpace;            /* 0x000E */
-		case 0x7B8E51E2U  /* Tab                */: return RGFW_tab;                  /* 0x000F */
-		case 0x2C595B51U /* KeyQ               */: return RGFW_q;                    /* 0x0010 */
-		case 0x2C595B57U /* KeyW               */: return RGFW_w;                    /* 0x0011 */
-		case 0x2C595B45U /* KeyE               */: return RGFW_e;                    /* 0x0012 */
-		case 0x2C595B52U /* KeyR               */: return RGFW_r;                    /* 0x0013 */
-		case 0x2C595B54U /* KeyT               */: return RGFW_t;                    /* 0x0014 */
-		case 0x2C595B59U /* KeyY               */: return RGFW_y;                    /* 0x0015 */
-		case 0x2C595B55U /* KeyU               */: return RGFW_u;                    /* 0x0016 */
-		case 0x2C595B4FU /* KeyO               */: return RGFW_o;                    /* 0x0018 */
-		case 0x2C595B50U /* KeyP               */: return RGFW_p;                    /* 0x0019 */
-		case 0x45D8158CU /* BracketLeft        */: return RGFW_closeBracket;         /* 0x001A */
-		case 0xDEEABF7CU /* BracketRight       */: return RGFW_bracket;        /* 0x001B */
-		case 0x92E1C5D2U /* Enter              */: return RGFW_return;                /* 0x001C */
-		case 0xE058958CU /* ControlLeft        */: return RGFW_controlL;         /* 0x001D */
-		case 0x2C595B41U /* KeyA               */: return RGFW_a;                    /* 0x001E */
-		case 0x2C595B53U /* KeyS               */: return RGFW_s;                    /* 0x001F */
-		case 0x2C595B44U /* KeyD               */: return RGFW_d;                    /* 0x0020 */
-		case 0x2C595B46U /* KeyF               */: return RGFW_f;                    /* 0x0021 */
-		case 0x2C595B47U /* KeyG               */: return RGFW_g;                    /* 0x0022 */
-		case 0x2C595B48U /* KeyH               */: return RGFW_h;                    /* 0x0023 */
-		case 0x2C595B4AU /* KeyJ               */: return RGFW_j;                    /* 0x0024 */
-		case 0x2C595B4BU /* KeyK               */: return RGFW_k;                    /* 0x0025 */
-		case 0x2C595B4CU /* KeyL               */: return RGFW_l;                    /* 0x0026 */
-		case 0x2707219EU /* Semicolon          */: return RGFW_semicolon;            /* 0x0027 */
-		case 0x92E0B58DU /* Quote              */: return RGFW_apostrophe;                /* 0x0028 */
-		case 0x36BF358DU /* Backquote          */: return RGFW_backtick;            /* 0x0029 */
-		case 0x26B1958CU /* ShiftLeft          */: return RGFW_shiftL;           /* 0x002A */
-		case 0x36BF2438U /* Backslash          */: return RGFW_backSlash;            /* 0x002B */
-		case 0x2C595B5AU /* KeyZ               */: return RGFW_z;                    /* 0x002C */
-		case 0x2C595B58U /* KeyX               */: return RGFW_x;                    /* 0x002D */
-		case 0x2C595B43U /* KeyC               */: return RGFW_c;                    /* 0x002E */
-		case 0x2C595B56U /* KeyV               */: return RGFW_v;                    /* 0x002F */
-		case 0x2C595B42U /* KeyB               */: return RGFW_b;                    /* 0x0030 */
-		case 0x2C595B4EU /* KeyN               */: return RGFW_n;                    /* 0x0031 */
-		case 0x2C595B4DU /* KeyM               */: return RGFW_m;                    /* 0x0032 */
-		case 0x92E1A1C1U /* Comma              */: return RGFW_comma;                /* 0x0033 */
-		case 0x672FFAD4U /* Period             */: return RGFW_period;               /* 0x0034 */
-		case 0x92E0A438U /* Slash              */: return RGFW_slash;                /* 0x0035 */
-		case 0xC5A6BF7CU /* ShiftRight         */: return RGFW_shiftR;
-		case 0x5D64DA91U /* NumpadMultiply     */: return RGFW_multiply;
-		case 0xC914958CU /* AltLeft            */: return RGFW_altL;             /* 0x0038 */
-		case 0x92E09CB5U /* Space              */: return RGFW_space;                /* 0x0039 */
-		case 0xB8FAE73BU  /* CapsLock           */: return RGFW_capsLock;            /* 0x003A */
-		case 0x7174B789U /* F1                 */: return RGFW_F1;                   /* 0x003B */
-		case 0x7174B78AU /* F2                 */: return RGFW_F2;                   /* 0x003C */
-		case 0x7174B78BU /* F3                 */: return RGFW_F3;                   /* 0x003D */
-		case 0x7174B78CU /* F4                 */: return RGFW_F4;                   /* 0x003E */
-		case 0x7174B78DU /* F5                 */: return RGFW_F5;                   /* 0x003F */
-		case 0x7174B78EU /* F6                 */: return RGFW_F6;                   /* 0x0040 */
-		case 0x7174B78FU /* F7                 */: return RGFW_F7;                   /* 0x0041 */
-		case 0x7174B780U /* F8                 */: return RGFW_F8;                   /* 0x0042 */
-		case 0x7174B781U /* F9                 */: return RGFW_F9;                   /* 0x0043 */
-		case 0x7B8E57B0U  /* F10                */: return RGFW_F10;                  /* 0x0044 */
-		case 0xC925FCDFU /* Numpad7            */: return RGFW_multiply;             /* 0x0047 */
-		case 0xC925FCD0U /* Numpad8            */: return RGFW_KP_8;             /* 0x0048 */
-		case 0xC925FCD1U /* Numpad9            */: return RGFW_KP_9;             /* 0x0049 */
-		case 0x5EA3E8A4U /* NumpadSubtract     */: return RGFW_minus;      /* 0x004A */
-		case 0xC925FCDCU /* Numpad4            */: return RGFW_KP_4;             /* 0x004B */
-		case 0xC925FCDDU /* Numpad5            */: return RGFW_KP_5;             /* 0x004C */
-		case 0xC925FCDEU /* Numpad6            */: return RGFW_KP_6;             /* 0x004D */
-		case 0xC925FCD9U /* Numpad1            */: return RGFW_KP_1;             /* 0x004F */
-		case 0xC925FCDAU /* Numpad2            */: return RGFW_KP_2;             /* 0x0050 */
-		case 0xC925FCDBU /* Numpad3            */: return RGFW_KP_3;             /* 0x0051 */
-		case 0xC925FCD8U /* Numpad0            */: return RGFW_KP_0;             /* 0x0052 */
-		case 0x95852DACU /* NumpadDecimal      */: return RGFW_period;       /* 0x0053 */
-		case 0x7B8E57B1U  /* F11                */: return RGFW_F11;                  /* 0x0057 */
-		case 0x7B8E57B2U  /* F12                */: return RGFW_F12;                  /* 0x0058 */
-		case 0x7393FBACU /* NumpadEqual        */: return RGFW_KP_Return;
-		case 0xB88EBF7CU  /* AltRight           */: return RGFW_altR;            /* 0xE038 */
-		case 0xC925873BU /* NumLock            */: return RGFW_numLock;             /* 0xE045 */
-		case 0x2C595F45U /* Home               */: return RGFW_home;                 /* 0xE047 */
-		case 0xC91BB690U /* ArrowUp            */: return RGFW_up;             /* 0xE048 */
-		case 0x672F9210U /* PageUp             */: return RGFW_pageUp;              /* 0xE049 */
-		case 0x3799258CU /* ArrowLeft          */: return RGFW_left;           /* 0xE04B */
-		case 0x4CE33F7CU /* ArrowRight         */: return RGFW_right;          /* 0xE04D */
-		case 0x7B8E55DCU  /* End                */: return RGFW_end;                  /* 0xE04F */
-		case 0x3799379EU /* ArrowDown          */: return RGFW_down;           /* 0xE050 */
-		case 0xBA90179EU /* PageDown           */: return RGFW_pageDown;            /* 0xE051 */
-		case 0x6723CB2CU /* Insert             */: return RGFW_insert;               /* 0xE052 */
-		case 0x6725C50DU /* Delete             */: return RGFW_delete;               /* 0xE053 */
-		case 0x6723658CU /* OSLeft             */: return RGFW_superL;              /* 0xE05B */
-		case 0x39643F7CU /* MetaRight          */: return RGFW_superR;           /* 0xE05C */
-	}
-
-	return 0;
-}
-
-void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) {
-	const char* iCode = code;
-
-	u32 hash = 0;
-	while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
-
-	u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash);
-
-	u8 mappedKey = (u8)(*((u32*)key));
-
-	if (*((u16*)key) != mappedKey) {
-		mappedKey = 0;
-		if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab;
-	}
-
-	RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased);
-										e.key = (u8)physicalKey;
-										e.keyChar = (u8)mappedKey;
-										e.keyMod = _RGFW.root->event.keyMod;
-										e._win = _RGFW.root);
-
-	RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current;
-	RGFW_keyboard[physicalKey].current = press;
-
-	RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press);
-}
-
-void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
-	RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll);
-}
-
-void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
-	if (!(_RGFW.root->_flags & RGFW_windowAllowDND))
-		return;
-
-	_RGFW.root->event.droppedFilesCount = count; 
-	RGFW_eventQueuePushEx(e.type = RGFW_DND;
-									e.droppedFilesCount = count;
-									e._win = _RGFW.root);
-	RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count);
-}
-
-RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE;
-void RGFW_stopCheckEvents(void) {
-	RGFW_stopCheckEvents_bool = RGFW_TRUE;
-}
-
-void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
-	RGFW_UNUSED(win);
-	if (waitMS == 0) return;
-
-	u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
-
-	while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS)
-		emscripten_sleep(0);
-
-	RGFW_stopCheckEvents_bool = RGFW_FALSE;
-}
-
-void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-		win->buffer = buffer;
-		win->bufferSize = area;
-	#ifdef RGFW_OSMESA
-			win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
-			OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
-			OSMesaPixelStore(OSMESA_Y_UP, 0);
-	#endif
-	#else
-	RGFW_UNUSED(win);  RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
-	#endif
-}
-
-void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
-	/* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
-	/* TODO: find a better way to do this
-	*/
-	RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1);
-	_RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0';
-}
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-
-void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
-
-void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
-    FILE* file = fopen(path, "w+");
-	if (file == NULL)
-		return;
-
-    fwrite(data, sizeof(char), len, file);
-    fclose(file);
-}
-
-void RGFW_window_initOpenGL(RGFW_window* win) {
-#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER)
-	EmscriptenWebGLContextAttributes attrs;
-	attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth];
-	attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha];
-	attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil];
-	attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples];
-	attrs.premultipliedAlpha = EM_TRUE;
-	attrs.preserveDrawingBuffer = EM_FALSE;
-
-	if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
-		attrs.renderViaOffscreenBackBuffer = 0;
-	else
-		attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers];
-
-	attrs.failIfMajorPerformanceCaveat = EM_FALSE;
-	attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor];
-	attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor];
-
-	attrs.enableExtensionsByDefault = EM_TRUE;
-	attrs.explicitSwapControl = EM_TRUE;
-
-	emscripten_webgl_init_context_attributes(&attrs);
-	win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
-	emscripten_webgl_make_context_current(win->src.ctx);
-
-	#ifdef LEGACY_GL_EMULATION
-	EM_ASM("Module.useWebGL = true; GLImmediate.init();");
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
-    #endif
-    glViewport(0, 0, win->r.w, win->r.h);
-#endif
-}
-
-void RGFW_window_freeOpenGL(RGFW_window* win) {
-#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA)
-	if (win->src.ctx == 0) return;
-	emscripten_webgl_destroy_context(win->src.ctx);
-	win->src.ctx = 0;
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
-#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA)
-	if(win->src.ctx == 0) return;
-	OSMesaDestroyContext(win->src.ctx);
-	win->src.ctx = 0;
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-i32 RGFW_init(void) {  
-#if defined(RGFW_C89) || defined(__cplusplus)
-    if (_RGFW_init) return 0; 
-    _RGFW_init = RGFW_TRUE;
-    _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0;
-#endif
-
-    _RGFW.windowCount = 0;  
-    RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); 
-    return 0; 
-}
-
-RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
-    RGFW_window_basic_init(win, rect, flags);
-	RGFW_window_initOpenGL(win);
-
-	#if defined(RGFW_WEBGPU)
-		win->src.ctx = wgpuCreateInstance(NULL);
-		win->src.device = emscripten_webgpu_get_device();
-		win->src.queue = wgpuDeviceGetQueue(win->src.device);
-	#endif
-
-	emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
-	emscripten_set_window_title(name);
-
-	/* load callbacks */
-    emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
-    emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
-    emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
-    emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
-    emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
-    emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
-    emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
-    emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
-    emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
-    emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
-    emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
-    emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
-	emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
-	emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
-
-	if (flags & RGFW_windowAllowDND)  {
-		win->_flags |= RGFW_windowAllowDND;
-	}
-
-	EM_ASM({
-		window.addEventListener("keydown",
-			(event) => {
-				var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
-				Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
-				Module._RGFW_handleKeyEvent(key, code, 1);
-				_free(key); _free(code);
-			},
-		true);
-		window.addEventListener("keyup",
-			(event) => {
-				var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
-				Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
-				Module._RGFW_handleKeyEvent(key, code, 0);
-				_free(key); _free(code);
-			},
-		true);
-	});
-
-    EM_ASM({
-		var canvas = document.getElementById('canvas');
-        canvas.addEventListener('drop', function(e) {
-            e.preventDefault();
-            if (e.dataTransfer.file < 0)
-				return;
-
-			var filenamesArray = [];
-			var count = e.dataTransfer.files.length;
-
-			/* Read and save the files to emscripten's files */
-			var drop_dir = '.rgfw_dropped_files';
-			Module._RGFW_mkdir(drop_dir);
-
-			for (var i = 0; i < count; i++) {
-				var file = e.dataTransfer.files[i];
-
-				var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
-				var reader = new FileReader();
-
-				reader.onloadend = (e) => {
-					if (reader.readyState != 2) {
-						out('failed to read dropped file: '+file.name+': '+reader.error);
-					}
-					else {
-						var data = e.target.result;
-
-						_RGFW_writeFile(path, new Uint8Array(data), file.size);
-					}
-				};
-
-				reader.readAsArrayBuffer(file);
-				/* This works weird on modern opengl */
-				var filename = stringToNewUTF8(path);
-
-				filenamesArray.push(filename);
-
-				Module._RGFW_makeSetValue(i, filename);
-			}
-
-			Module._Emscripten_onDrop(count);
-
-			for (var i = 0; i < count; ++i) {
-				_free(filenamesArray[i]);
-			}
-        }, true);
-
-        canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
-    });
-
-	RGFW_window_setFlags(win, flags);
-
-	if ((flags & RGFW_windowNoInitAPI) == 0) {
-        RGFW_window_initBuffer(win);
-    }
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new  window was created");
-    return win;
-}
-
-u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) {
-    return (u8)rgfw_keycode; /* TODO */
-}
-
-RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
-    if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
-    RGFW_event* ev =  RGFW_window_checkEventCore(win);
-	if (ev) return ev;
-
-	emscripten_sample_gamepad_data();
-	/* check gamepads */
-    int i;
-    for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
-		if (RGFW_gamepads[i] == 0)
-			continue;
-        EmscriptenGamepadEvent gamepadState;
-
-        if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
-			break;
-
-		/* Register buttons data for every connected gamepad */
-        int j;
-        for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
-			u32 map[] = {
-				RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY,
-				RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
-				RGFW_gamepadSelect, RGFW_gamepadStart,
-				RGFW_gamepadL3, RGFW_gamepadR3,
-				RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome
-			};
-
-
-			u32 button = map[j];
-			if (button == 404)
-				continue;
-
-			if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) {
-				if (gamepadState.digitalButton[j])
-					win->event.type = RGFW_gamepadButtonPressed;
-				else
-					win->event.type = RGFW_gamepadButtonReleased;
-
-				win->event.gamepad = i;
-				win->event.button = map[j];
-
-				RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current;
-				RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j];
-
-				RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]);
-				return &win->event;
-			}
-		}
-
-		for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
-			win->event.axisesCount = gamepadState.numAxes / 2;
-			if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) ||
-				RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f)
-			) {
-
-				RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f);
-				RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f);
-				win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)];
-
-				win->event.type = RGFW_gamepadAxisMove;
-				win->event.gamepad = i;
-				win->event.whichAxis = j / 2;
-
-				RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis);
-				return &win->event;
-			}
-		}
-    }
-
-	return NULL;
-}
-
-void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
-	RGFW_UNUSED(win);
-	emscripten_set_canvas_element_size("#canvas", a.w, a.h);
-}
-
-/* NOTE: I don't know if this is possible */
-void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
-/* this one might be possible but it looks iffy */
-RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; }
-
-void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); }
-void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
-
-RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
-	static const char cursors[16][16] = {
-		"default", "default", "text", "crosshair",
-		"pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize",
-		"move", "not-allowed"
-	};
-
-	RGFW_UNUSED(win);
-	EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]);
-	return RGFW_TRUE;
-}
-
-RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
-	return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
-}
-
-void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
-	RGFW_window_showMouseFlags(win, show);
-	if (show)
-		RGFW_window_setMouseDefault(win);
-	else
-		EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
-}
-
-RGFW_point RGFW_getGlobalMousePoint(void) {
-    RGFW_point point;
-    point.x = EM_ASM_INT({
-        return window.mouseX || 0;
-    });
-    point.y = EM_ASM_INT({
-        return window.mouseY || 0;
-    });
-    return point;
-}
-
-void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
-	RGFW_UNUSED(win);
-
-    EM_ASM_({
-        var canvas = document.getElementById('canvas');
-        if ($0) {
-            canvas.style.pointerEvents = 'none';
-        } else {
-            canvas.style.pointerEvents = 'auto';
-        }
-    }, passthrough);
-}
-
-void RGFW_writeClipboard(const char* text, u32 textLen) {
-	RGFW_UNUSED(textLen);
-	EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
-}
-
-
-RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
-	RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
-	/*
-		placeholder code for later
-		I'm not sure if this is possible do the the async stuff
-	*/
-	return 0;
-}
-
-void RGFW_window_swapBuffers_software(RGFW_window* win) {
-#if defined(RGFW_OSMESA)
-	EM_ASM_({
-		var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
-		let context = document.getElementById("canvas").getContext("2d");
-		let image = context.getImageData(0, 0, $1, $2);
-		image.data.set(data);
-		context.putImageData(image, 0, $4 - $2);
-	}, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
-#elif defined(RGFW_BUFFER)
-	EM_ASM_({
-		var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
-		let context = document.getElementById("canvas").getContext("2d");
-		let image = context.getImageData(0, 0, $1, $2);
-		image.data.set(data);
-		context.putImageData(image, 0, 0);
-	}, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
-	emscripten_sleep(0);
-#else
-	RGFW_UNUSED(win);
-#endif
-}
-
-void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
-#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER))
-	if (win == NULL)
-	    emscripten_webgl_make_context_current(0);
-	else
-	    emscripten_webgl_make_context_current(win->src.ctx);
-#endif
-}
-
-
-void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
-#ifndef RGFW_WEBGPU
-	emscripten_webgl_commit_frame();
-
-#endif
-    emscripten_sleep(0);
-}
-
-#ifndef RGFW_WEBGPU
-void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
-#endif
-
-#ifndef RGFW_EGL
-void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
-#endif
-
-void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); }
-
-void RGFW_window_close(RGFW_window* win) {
-	if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
-
-	#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
-	if ((win->_flags & RGFW_BUFFER_ALLOC))
-		RGFW_FREE(win->buffer);
-	#endif
-
-	RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
-    _RGFW.windowCount--;
-    if (_RGFW.windowCount == 0) RGFW_deinit();
-
-    RGFW_clipboard_switch(NULL);
-	RGFW_FREE(win->event.droppedFiles);
-	if ((win->_flags & RGFW_WINDOW_ALLOC)) {
-	    RGFW_FREE(win);
-        win = NULL;
-    }
-}
-
-int RGFW_innerWidth(void) {   return EM_ASM_INT({ return window.innerWidth; });  }
-int RGFW_innerHeight(void) {  return EM_ASM_INT({ return window.innerHeight; });  }
-
-RGFW_area RGFW_getScreenSize(void) {
-	return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
-}
-
-RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) {
-#ifdef RGFW_OPENGL
-    return EM_ASM_INT({
-        var ext = UTF8ToString($0, $1);
-        var canvas = document.querySelector('canvas');
-        var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
-        if (!gl) return 0;
-
-        var supported = gl.getSupportedExtensions();
-        return supported && supported.includes(ext) ? 1 : 0;
-    }, extension, len);
-#else
-    return RGFW_FALSE;
-#endif
-}
-
-RGFW_proc RGFW_getProcAddress(const char* procname) {
-#ifdef RGFW_OPENGL
-    return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
-#else
-    return NULL
-#endif
-}
-
-void RGFW_sleep(u64 milisecond) {
-	emscripten_sleep(milisecond);
-}
-
-u64 RGFW_getTimerFreq(void) { return (u64)1000; }
-u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; }
-
-void RGFW_releaseCursor(RGFW_window* win) {
-	RGFW_UNUSED(win);
-	emscripten_exit_pointerlock();
-}
-
-void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
-	RGFW_UNUSED(win); RGFW_UNUSED(r);
-
-	emscripten_request_pointerlock("#canvas", 1);
-}
-
-
-void RGFW_window_setName(RGFW_window* win, const char* name) {
-	RGFW_UNUSED(win);
-	emscripten_set_window_title(name);
-}
-
-void RGFW_window_maximize(RGFW_window* win) {
-	RGFW_ASSERT(win != NULL);
-
-	RGFW_area screen = RGFW_getScreenSize();
-	RGFW_window_move(win, RGFW_POINT(0, 0));
-	RGFW_window_resize(win, screen);
-}
-
-void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
-	RGFW_ASSERT(win != NULL);
-	if (fullscreen) {
-		win->_flags |= RGFW_windowFullscreen;
-		EM_ASM( Module.requestFullscreen(false, true); );
-		return;
-	}
-	win->_flags &= ~(u32)RGFW_windowFullscreen;
-	EM_ASM( Module.exitFullscreen(false, true); );
-}
-
-void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
-	RGFW_UNUSED(win);
-	EM_ASM({
-		var element = document.getElementById("canvas");
-		if (element)
-		  element.style.opacity = $1;
-	  }, "elementId", opacity);
-}
-
-/* unsupported functions */
-void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
-void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
-RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; }
-RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; }
-RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
-void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
-void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
-void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a);  }
-void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a);  }
-void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
-void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
-void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
-void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border);  }
-RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE;  }
-void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
-void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
-RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
-RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
-RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
-RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
-RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; }
-#endif
-
-/* end of web asm defines */
-
-/* unix (macOS, linux, web asm) only stuff */
-#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM)  || defined(RGFW_WAYLAND)
-#ifndef RGFW_NO_THREADS
-#include <pthread.h>
-
-RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
-	RGFW_thread t;
-	pthread_create((pthread_t*) &t, NULL, *ptr, args);
-	return t;
-}
-void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
-void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
-
-#if defined(__linux__)
-void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
-#else
-void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); }
-#endif
-#endif
-
-#ifndef RGFW_WASM
-void RGFW_sleep(u64 ms) {
-	struct timespec time;
-	time.tv_sec = 0;
-	time.tv_nsec = (long int)((double)ms * 1e+6);
-
-	#ifndef RGFW_NO_UNIX_CLOCK
-	nanosleep(&time, NULL);
-	#endif
-}
-#endif
-
-#endif /* end of unix / mac stuff */
-#endif /* RGFW_IMPLEMENTATION */
-
-#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
-}
-#endif
-
-#if _MSC_VER
-	#pragma warning( pop )
-#endif
diff --git a/raylib/src/external/RGFW/RGFW.h b/raylib/src/external/RGFW/RGFW.h
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/RGFW/RGFW.h
@@ -0,0 +1,16103 @@
+/*
+*
+*	RGFW 2.0.0-dev
+
+* Copyright (C) 2022-26 Riley Mabb (@ColleagueRiley)
+*
+* libpng license
+*
+* 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.
+*
+*
+*/
+
+/*
+	(MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
+	#define RGFW_IMPLEMENTATION - makes it so source code is included with header
+*/
+
+/*
+	#define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
+	#define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
+	#define RGFW_EGL - (optional) compile with OpenGL functions, allowing you to use to use EGL instead of the native OpenGL functions
+	#define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
+	#define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
+	#define RGFW_WEBGPU - (optional) use WebGPU for rendering
+	#define RGFW_NATIVE - (optional) define native RGFW types that use native API structures
+
+	#define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
+	#define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
+	#define RGFW_NO_STATIC_CONTEXT - do not initalizize with a static variable, use the heap if RGFW is not manually initalized
+	#define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
+	#define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
+	#define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
+	#define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) use XCursor, but don't link it in code, (you'll have to link it with -lXcursor)
+	#define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use Xext, but don't link it in code, (you'll have to link it with -lXext)
+	#define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm (timeBeginPeriod), but don't link it in code, (you'll have to link it with -lwinmm)
+	#define RGFW_NO_WINMM (optional) (windows only) don't use winmm
+	#define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
+	#define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
+	#define RGFW_NO_DWM (windows only) - do not use or link dwmapi
+	#define RGFW_USE_XDL (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 dynamically during runtime (must include XDL.h along with RGFW)
+	#define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
+	#define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
+	#define RGFW_NO_DPI - do not calculate DPI and don't use libShcore (win32)
+	#define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue)
+	#define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION)
+	#define RGFW_NO_GLXWINDOW - do not use GLXWindow
+	#define RGFW_NO_ALLOCATE_MONITORS - do not allocate monitors on the heap at all (when there's no pre-allocated space left)
+	#define RGFW_NO_INCLUDE_VULKAN - do not include the Vulkan.h header, you have to include it yourself
+
+	#define RGFW_ALLOC x  - choose the default allocation function (defaults to standard malloc)
+	#define RGFW_FREE x  - choose the default deallocation function (defaults to standard free)
+	#define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
+
+	#define RGFW_EXPORT - use when building RGFW
+	#define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
+
+	#define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
+	#define RGFW_bool x - choose what type to use for bool, by default u32 is used
+
+	#define RGFW_PREALLOCATED_MONITORS x - choose the default amount of pre-allocated monitors (can be zero)
+*/
+
+/*
+Example to get you started :
+
+linux : gcc main.c -lX11 -lXrandr -lm
+windows : gcc main.c -lgdi32
+macos : gcc main.c -framework Cocoa -framework CoreVideo -framework IOKit
+
+#define RGFW_IMPLEMENTATION
+#include "RGFW.h"
+
+int main() {
+	RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, 0);
+
+	while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
+		RGFW_pollEvents();
+	}
+
+	RGFW_window_close(win);
+}
+
+	compiling :
+
+	if you wish to compile the library all you have to do is create a new file with this in it
+
+	rgfw.c
+	#define RGFW_IMPLEMENTATION
+	#include "RGFW.h"
+
+	You may also want to add
+	`#define RGFW_EXPORT` when compiling and
+	`#define RGFW_IMPORT`when linking RGFW on it's own:
+	this reduces inline functions and prevents bloat in the object file
+
+	then you can use gcc (or whatever compile you wish to use) to compile the library into object file
+
+	ex. gcc -c RGFW.c -fPIC
+
+	after you compile the library into an object file, you can also turn the object file into an static or shared library
+
+	(commands ar and gcc can be replaced with whatever equivalent your system uses)
+
+	static : ar rcs RGFW.a RGFW.o
+	shared :
+		windows:
+			gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
+		linux:
+			gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
+		macos:
+			gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
+*/
+
+
+
+/*
+	Credits :
+		EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing
+
+		contributors : (feel free to put yourself here if you contribute)
+		krisvers (@krisvers) -> code review
+		EimaMei (@SaCode) -> code review
+		Nycticebus (@Code-Nycticebus) -> bug fixes
+		Rob Rohan (@robrohan) -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
+		AICDG (@THISISAGOODNAME) -> vulkan support (example)
+		@Easymode -> support, testing/debugging, bug fixes and reviews
+		Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
+		@lesleyrs -> bug fix, review (OpenGL)
+		Nick Porcino (@meshula) - testing, organization, review (MacOS, examples)
+		@therealmarrakesh -> documentation
+		@DarekParodia -> code review (X11) (C++)
+		@NishiOwO -> fix BSD support, fix OSMesa example
+		@BaynariKattu -> code review and documentation
+		Miguel Pinto (@konopimi) -> code review, fix vulkan example
+		@m-doescode -> code review (wayland)
+		Robert Gonzalez (@uni-dos) -> code review (wayland)
+		@TheLastVoyager -> code review
+		@yehoravramenko -> code review (winapi)
+		@halocupcake -> code review (OpenGL)
+		@GideonSerf -> documentation
+		Alexandre Almeida (@M374LX) -> code review (keycodes)
+		Vũ Xuân Trường (@wanwanvxt) -> code review (winapi)
+		Lucas (@lightspeedlucas) -> code review (msvc++)
+		Jeffery Myers (@JeffM2501) -> code review (msvc)
+		Zeni (@zenitsuyo) -> documentation
+		TheYahton (@TheYahton) -> documentation
+		nonexistant_object (@DiarrheaMcgee)
+		AC Gaudette (@acgaudette)
+*/
+
+#if _MSC_VER
+	#pragma comment(lib, "gdi32")
+	#pragma comment(lib, "shell32")
+	#pragma comment(lib, "User32")
+	#pragma comment(lib, "Advapi32")
+    #pragma warning( push )
+	#pragma warning( disable : 4996 4191 4127)
+    #if _MSC_VER < 600
+        #define RGFW_C89
+    #endif
+#else
+    #if defined(__STDC__) && !defined(__STDC_VERSION__)
+        #define RGFW_C89
+    #endif
+#endif
+
+#if defined(RGFW_EGL) && !defined(RGFW_OPENGL)
+	#define RGFW_OPENGL
+#endif
+
+/* these OS macros look better & are standardized */
+/* plus it helps with cross-compiling */
+
+#ifdef __EMSCRIPTEN__
+	#define RGFW_WASM
+#endif
+
+#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
+	#define RGFW_MACOS_X11
+	#define RGFW_UNIX
+#endif
+
+#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */
+	#define RGFW_WINDOWS
+#endif
+#if defined(RGFW_WAYLAND)
+	#define RGFW_DEBUG /* wayland will be in debug mode by default for now */
+	#define RGFW_UNIX
+	#ifdef RGFW_OPENGL
+		#define RGFW_EGL
+	#endif
+	#ifdef RGFW_X11
+		#define RGFW_DYNAMIC
+	#endif
+#endif
+#if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11))  && !defined(RGFW_WASM)  && !defined(RGFW_CUSTOM_BACKEND)
+		#define RGFW_MACOS_X11
+		#define RGFW_X11
+		#define RGFW_UNIX
+#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11)  && !defined(RGFW_WASM)  && !defined(RGFW_CUSTOM_BACKEND)
+	#define RGFW_MACOS
+#endif
+
+#if defined(RGFW_X11) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
+	#ifndef _POSIX_C_SOURCE
+		#define _POSIX_C_SOURCE 199309L
+	#endif
+
+	/* __USE_POSIX199309 is part of glibc internals, and isn't intended to be used outside. */
+	/* However, existing RGFW code may depend on it implicitly. */
+	#ifndef __USE_POSIX199309
+		#define __USE_POSIX199309
+	#endif
+#endif
+
+#ifndef RGFW_ASSERT
+	#include <assert.h>
+	#define RGFW_ASSERT assert
+#endif
+
+#if !defined(__STDC_VERSION__)
+    #define RGFW_C89
+#endif
+
+#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND))
+	/* required for X11 errors */
+	#include <stdio.h>
+	#define RGFW_SNPRINTF snprintf
+#endif
+
+#ifndef RGFW_USERPTR
+	#define RGFW_USERPTR NULL
+#endif
+
+#ifndef RGFW_UNUSED
+	#define RGFW_UNUSED(x) (void)(x)
+#endif
+
+#ifndef RGFW_ROUND
+	#define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
+#endif
+
+#ifndef RGFW_ROUNDF
+	#define RGFW_ROUNDF(x) (float)((i32)((x) + ((x) < 0.0f ? -0.5f : 0.5f)))
+#endif
+
+#ifndef RGFW_MIN
+	#define RGFW_MIN(x, y) ((x < y) ? x : y)
+#endif
+
+#ifndef RGFW_ALLOC
+	#include <stdlib.h>
+	#define RGFW_ALLOC malloc
+	#define RGFW_FREE free
+#endif
+
+#if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMZERO)
+	#include <string.h>
+#endif
+
+#ifndef RGFW_MEMZERO
+	#define RGFW_MEMZERO(ptr, num) memset(ptr, 0, num)
+#endif
+
+#ifndef RGFW_MEMCPY
+	#define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
+#endif
+
+#ifndef RGFW_STRNCMP
+	#define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
+#endif
+
+#ifndef RGFW_STRNCPY
+	#define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
+#endif
+
+#ifndef RGFW_STRSTR
+	#define RGFW_STRSTR(str, substr) strstr(str, substr)
+#endif
+
+#ifndef RGFW_STRTOL
+	/* required for X11 XDnD and X11 Monitor DPI */
+	#include <stdlib.h>
+	#define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
+	#define RGFW_ATOF(num) atof(num)
+#endif
+
+#if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) )
+    /* required when using RGFW_DEBUG */
+    #include <stdio.h>
+    #define RGFW_PRINTF printf
+#endif
+
+#ifndef RGFW_MAX_EVENTS
+	#define RGFW_MAX_EVENTS 32
+#endif
+#ifndef RGFW_PREALLOCATED_MONITORS
+	#define RGFW_PREALLOCATED_MONITORS 6 /* the number of preallocated monitors */
+#elif defined(RGFW_NO_ALLOCATE_MONITORS) && (RGFW_PREALLOCATED_MONITORS == 0)
+	#warning RGFW monitors have no place to be allocated
+#endif
+
+#ifndef RGFW_COCOA_FRAME_NAME
+	#define RGFW_COCOA_FRAME_NAME NULL
+#endif
+
+#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
+	#define RGFW_NO_PASSTHROUGH
+#endif
+
+#if defined(RGFW_EXPORT) ||  defined(RGFW_IMPORT)
+	#if defined(_WIN32)
+		#if defined(__TINYC__) && (defined(RGFW_EXPORT) ||  defined(RGFW_IMPORT))
+			#define __declspec(x) __attribute__((x))
+		#endif
+
+		#if defined(RGFW_EXPORT)
+			#define RGFWDEF __declspec(dllexport)
+		#else
+			#define RGFWDEF __declspec(dllimport)
+		#endif
+	#else
+		#if defined(RGFW_EXPORT)
+			#define RGFWDEF __attribute__((visibility("default")))
+		#endif
+	#endif
+    #ifndef RGFWDEF
+        #define RGFWDEF
+    #endif
+#endif
+
+#ifndef RGFWDEF
+	#ifdef RGFW_C89
+		#define RGFWDEF __inline
+	#else
+		#define RGFWDEF inline
+	#endif
+#endif
+
+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
+	extern "C" {
+#endif
+
+/* makes sure the header file part is only defined once by default */
+#ifndef RGFW_HEADER
+
+#define RGFW_HEADER
+
+#include <stddef.h>
+#ifndef RGFW_INT_DEFINED
+	#ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
+		typedef unsigned char       u8;
+		typedef signed char         i8;
+		typedef unsigned short     u16;
+		typedef signed short 	   i16;
+		typedef unsigned long int  u32;
+		typedef signed long int    i32;
+		typedef unsigned long long u64;
+		typedef signed long long   i64;
+	#else /* use stdint standard types instead of c "standard" types */
+		#include <stdint.h>
+
+		typedef uint8_t     u8;
+		typedef int8_t      i8;
+		typedef uint16_t   u16;
+		typedef int16_t    i16;
+		typedef uint32_t   u32;
+		typedef int32_t    i32;
+		typedef uint64_t   u64;
+		typedef int64_t    i64;
+	#endif
+	#define RGFW_INT_DEFINED
+#endif
+
+typedef ptrdiff_t RGFW_ssize_t;
+
+#ifndef RGFW_BOOL_DEFINED
+    #define RGFW_BOOL_DEFINED
+    typedef u8 RGFW_bool;
+#endif
+
+#define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */
+#define RGFW_TRUE (RGFW_bool)1
+#define RGFW_FALSE (RGFW_bool)0
+
+#define RGFW_ENUM(type, name) type name; enum
+#define RGFW_BIT(x) (1 << (x))
+
+#ifdef RGFW_VULKAN
+
+	#if defined(RGFW_WAYLAND) && defined(RGFW_X11)
+		#define VK_USE_PLATFORM_WAYLAND_KHR
+		#define VK_USE_PLATFORM_XLIB_KHR
+		#define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
+	#elif defined(RGFW_WAYLAND)
+		#define VK_USE_PLATFORM_WAYLAND_KHR
+		#define VK_USE_PLATFORM_XLIB_KHR
+		#define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
+	#elif defined(RGFW_X11)
+		#define VK_USE_PLATFORM_XLIB_KHR
+		#define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
+	#elif defined(RGFW_WINDOWS)
+		#define VK_USE_PLATFORM_WIN32_KHR
+		#define OEMRESOURCE
+		#define RGFW_VK_SURFACE "VK_KHR_win32_surface"
+	#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
+		#define VK_USE_PLATFORM_MACOS_MVK
+		#define RGFW_VK_SURFACE "VK_MVK_macos_surface"
+	#else
+		#define RGFW_VK_SURFACE NULL
+	#endif
+
+#endif
+
+
+/*! @brief The stucture that contains information about the current RGFW instance */
+typedef struct RGFW_info RGFW_info;
+
+/*! @brief The window stucture for interfacing with the window */
+typedef struct RGFW_window RGFW_window;
+
+/*! @brief The source window stucture for interfacing with the underlying windowing API (e.g. winapi, wayland, cocoa, etc) */
+typedef struct RGFW_window_src RGFW_window_src;
+
+/*! @brief The color format for pixel data */
+typedef RGFW_ENUM(u8, RGFW_format) {
+	RGFW_formatRGB8 = 0,    /*!< 8-bit RGB (3 channels) */
+	RGFW_formatBGR8,    /*!< 8-bit BGR (3 channels) */
+	RGFW_formatRGBA8,   /*!< 8-bit RGBA (4 channels) */
+	RGFW_formatARGB8,   /*!< 8-bit RGBA (4 channels) */
+	RGFW_formatBGRA8,   /*!< 8-bit BGRA (4 channels) */
+	RGFW_formatABGR8,   /*!< 8-bit BGRA (4 channels) */
+	RGFW_formatCount
+};
+
+/*! @brief layout struct for mapping out format types */
+typedef struct RGFW_colorLayout {  i32 r, g, b, a; u32 channels;  } RGFW_colorLayout;
+
+/*! @brief function type converting raw image data between formats */
+typedef void (* RGFW_convertImageDataFunc)(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count);
+
+/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */
+typedef struct RGFW_nativeImage RGFW_nativeImage;
+
+/*! @brief a stucture for interfacing with pixel data as a renderable surface */
+typedef struct RGFW_surface RGFW_surface;
+
+/*! @brief gamma struct for monitors */
+typedef struct RGFW_gammaRamp {
+	u16* red; /*!< array for the red channel */
+	u16* green; /*!< array for the green channel */
+	u16* blue; /*!< array for the blue channel */
+	size_t count; /*! count of elements in each channel */
+} RGFW_gammaRamp;
+
+/*! @brief monitor mode data | can be changed by the user (with functions)*/
+typedef struct RGFW_monitorMode {
+	i32 w, h; /*!< monitor workarea size */
+	float refreshRate; /*!< monitor refresh rate */
+	u8 red, blue, green; /*!< sizeof rgb values */
+	void* src; /*!< source API mode */
+} RGFW_monitorMode;
+
+/*! @brief structure for monitor node and source monitor data */
+typedef struct RGFW_monitorNode RGFW_monitorNode;
+
+/*! @brief structure for monitor data */
+typedef struct RGFW_monitor {
+	i32 x, y; /*!< x - y of the monitor workarea */
+	char name[128]; /*!< monitor name */
+	float scaleX, scaleY; /*!< monitor content scale */
+	float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI)  */
+	float physW, physH; /*!< monitor physical size in inches */
+	RGFW_monitorMode mode; /*!< current mode of the monitor */
+	void* userPtr; /*!< pointer for user data */
+	RGFW_monitorNode* node; /*!< source node data of the monitor */
+} RGFW_monitor;
+
+/*! @brief what type of request you are making for the monitor */
+typedef RGFW_ENUM(u8, RGFW_modeRequest) {
+	RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
+	RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
+	RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
+	RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
+};
+
+/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */
+typedef void RGFW_mouse;
+
+/*! @brief RGFW's abstract keycodes */
+typedef RGFW_ENUM(u8, RGFW_key) {
+	RGFW_keyNULL = 0,
+	RGFW_keyEscape = '\033',
+	RGFW_keyBacktick = '`',
+	RGFW_key0 = '0',
+	RGFW_key1 = '1',
+	RGFW_key2 = '2',
+	RGFW_key3 = '3',
+	RGFW_key4 = '4',
+	RGFW_key5 = '5',
+	RGFW_key6 = '6',
+	RGFW_key7 = '7',
+	RGFW_key8 = '8',
+	RGFW_key9 = '9',
+	RGFW_keyMinus = '-',
+	RGFW_keyEqual = '=',
+	RGFW_keyEquals = RGFW_keyEqual,
+	RGFW_keyBackSpace = '\b',
+	RGFW_keyTab = '\t',
+	RGFW_keySpace = ' ',
+	RGFW_keyA = 'a',
+	RGFW_keyB = 'b',
+	RGFW_keyC = 'c',
+	RGFW_keyD = 'd',
+	RGFW_keyE = 'e',
+	RGFW_keyF = 'f',
+	RGFW_keyG = 'g',
+	RGFW_keyH = 'h',
+	RGFW_keyI = 'i',
+	RGFW_keyJ = 'j',
+	RGFW_keyK = 'k',
+	RGFW_keyL = 'l',
+	RGFW_keyM = 'm',
+	RGFW_keyN = 'n',
+	RGFW_keyO = 'o',
+	RGFW_keyP = 'p',
+	RGFW_keyQ = 'q',
+	RGFW_keyR = 'r',
+	RGFW_keyS = 's',
+	RGFW_keyT = 't',
+	RGFW_keyU = 'u',
+	RGFW_keyV = 'v',
+	RGFW_keyW = 'w',
+	RGFW_keyX = 'x',
+	RGFW_keyY = 'y',
+	RGFW_keyZ = 'z',
+	RGFW_keyPeriod = '.',
+	RGFW_keyComma = ',',
+	RGFW_keySlash = '/',
+	RGFW_keyBracket = '[',
+    RGFW_keyCloseBracket = ']',
+    RGFW_keySemicolon = ';',
+	RGFW_keyApostrophe = '\'',
+	RGFW_keyBackSlash = '\\',
+	RGFW_keyReturn = '\n',
+	RGFW_keyEnter = RGFW_keyReturn,
+	RGFW_keyDelete = '\177', /* 127 */
+	RGFW_keyF1,
+	RGFW_keyF2,
+	RGFW_keyF3,
+	RGFW_keyF4,
+	RGFW_keyF5,
+	RGFW_keyF6,
+	RGFW_keyF7,
+	RGFW_keyF8,
+	RGFW_keyF9,
+	RGFW_keyF10,
+	RGFW_keyF11,
+	RGFW_keyF12,
+    RGFW_keyF13,
+    RGFW_keyF14,
+    RGFW_keyF15,
+    RGFW_keyF16,
+    RGFW_keyF17,
+    RGFW_keyF18,
+    RGFW_keyF19,
+    RGFW_keyF20,
+    RGFW_keyF21,
+    RGFW_keyF22,
+    RGFW_keyF23,
+    RGFW_keyF24,
+    RGFW_keyF25,
+	RGFW_keyCapsLock,
+	RGFW_keyShiftL,
+	RGFW_keyControlL,
+	RGFW_keyAltL,
+	RGFW_keySuperL,
+	RGFW_keyShiftR,
+	RGFW_keyControlR,
+	RGFW_keyAltR,
+	RGFW_keySuperR,
+	RGFW_keyUp,
+	RGFW_keyDown,
+	RGFW_keyLeft,
+	RGFW_keyRight,
+	RGFW_keyInsert,
+	RGFW_keyMenu,
+	RGFW_keyEnd,
+	RGFW_keyHome,
+	RGFW_keyPageUp,
+	RGFW_keyPageDown,
+	RGFW_keyNumLock,
+	RGFW_keyPadSlash,
+	RGFW_keyPadMultiply,
+	RGFW_keyPadPlus,
+	RGFW_keyPadMinus,
+	RGFW_keyPadEqual,
+	RGFW_keyPadEquals = RGFW_keyPadEqual,
+	RGFW_keyPad1,
+	RGFW_keyPad2,
+	RGFW_keyPad3,
+	RGFW_keyPad4,
+	RGFW_keyPad5,
+	RGFW_keyPad6,
+	RGFW_keyPad7,
+	RGFW_keyPad8,
+	RGFW_keyPad9,
+	RGFW_keyPad0,
+	RGFW_keyPadPeriod,
+	RGFW_keyPadReturn,
+	RGFW_keyScrollLock,
+    RGFW_keyPrintScreen,
+    RGFW_keyPause,
+	RGFW_keyWorld1,
+    RGFW_keyWorld2,
+    RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
+};
+
+/*! @brief abstract mouse button codes */
+typedef RGFW_ENUM(u8, RGFW_mouseButton) {
+	RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
+	RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
+	RGFW_mouseRight, /*!< right mouse button is pressed */
+	RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
+	RGFW_mouseFinal
+};
+
+/*! abstract key modifier codes */
+typedef RGFW_ENUM(u8, RGFW_keymod) {
+	RGFW_modCapsLock = RGFW_BIT(0),
+	RGFW_modNumLock  = RGFW_BIT(1),
+	RGFW_modControl  = RGFW_BIT(2),
+	RGFW_modAlt = RGFW_BIT(3),
+	RGFW_modShift  = RGFW_BIT(4),
+	RGFW_modSuper = RGFW_BIT(5),
+	RGFW_modScrollLock = RGFW_BIT(6)
+};
+
+/*! types of dnd drag actions */
+typedef RGFW_ENUM(u8, RGFW_dndActionType) {
+	RGFW_dndActionNone = 0,
+	RGFW_dndActionEnter, /*!< data has been dragged into the window area */
+	RGFW_dndActionMove, /*!< the data that was dragged into the window area has moved inside the window */
+	RGFW_dndActionExit, /*!< the data that was dragged into the window area has left the window */
+};
+
+/*! types of transfered data (clipboard, dnd) */
+typedef RGFW_ENUM(u8, RGFW_dataTransferType) {
+	RGFW_dataNone = 0,
+	RGFW_dataText, /*!< plain text string */
+	RGFW_dataFile, /*!< file string */
+	RGFW_dataURL, /*!< URL string */
+	RGFW_dataImage, /*!< raw image data */
+	RGFW_dataUnknown /*!< unknown raw data */
+};
+
+/*! internal node for a individual data drop */
+typedef struct RGFW_dataDropNode {
+	const char* data; /*!< dropped data */
+	size_t size; /*!< the size of the data in bytes */
+	RGFW_dataTransferType type; /*!< the type of data being dropped */
+	struct RGFW_dataDropNode* next; /*!< the next drop data node if any [when handling callbacks, this will always be NULL because the linked list is built as events are processed] */
+} RGFW_dataDropNode;
+
+/*! @brief codes for the event types that can be sent */
+typedef RGFW_ENUM(u8, RGFW_eventType) {
+	RGFW_eventNone = 0, /*!< no event has been sent */
+ 	RGFW_keyPressed, /*!< a key has been pressed */
+	RGFW_keyReleased, /*!< a key has been released */
+	RGFW_keyChar, /*!< keyboard character input event specifically for utf8 input */
+	RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
+	RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
+	RGFW_mouseScroll, /*!< a mouse scroll event */
+	RGFW_mouseMotion, /*!< the position of the mouse has been changed / the mouse has moved */
+	RGFW_mouseRawMotion, /*!< raw mouse motion */
+	RGFW_mouseEnter, /*!< mouse entered the window */
+	RGFW_mouseLeave, /*!< mouse left the window */
+	RGFW_windowMoved, /*!< the window was moved (by the user) */
+	RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
+	RGFW_windowFocusIn, /*!< window is in focus now */
+	RGFW_windowFocusOut, /*!< window is out of focus now */
+	RGFW_windowRefresh, /*!< The window content needs to be refreshed */
+	RGFW_windowClose, /*!< the user attempts to close the window */
+	RGFW_windowMaximized, /*!< the window was maximized */
+	RGFW_windowMinimized, /*!< the window was minimized */
+	RGFW_windowRestored, /*!< the window was restored */
+	RGFW_dataDrop, /*!< data has been dropped into the window */
+	RGFW_dataDrag, /*!< the start of a drag and drop event, when data is being dragged */
+	RGFW_scaleUpdated, /*!< content scale factor changed */
+	RGFW_monitorConnected, /*!< a monitor has been connected */
+	RGFW_monitorDisconnected, /*!< a monitor has been disconnected */
+	RGFW_eventCount, /*!< the number of event types there are */
+	RGFW_mousePosChanged = RGFW_mouseMotion, /*!< alias for RGFW_mouseMotion (may be deleted at some point) */
+};
+
+/*! @brief flags for toggling whether or not an event should be processed */
+typedef RGFW_ENUM(u32, RGFW_eventFlag) {
+    RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed),
+    RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased),
+    RGFW_keyCharFlag = RGFW_BIT(RGFW_keyChar),
+    RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll),
+    RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed),
+    RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased),
+    RGFW_mouseMotionFlag = RGFW_BIT(RGFW_mouseMotion),
+    RGFW_mouseRawMotionFlag = RGFW_BIT(RGFW_mouseRawMotion),
+    RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter),
+    RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave),
+    RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved),
+    RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized),
+    RGFW_windowFocusInFlag = RGFW_BIT(RGFW_windowFocusIn),
+    RGFW_windowFocusOutFlag = RGFW_BIT(RGFW_windowFocusOut),
+    RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh),
+    RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized),
+    RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized),
+    RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored),
+    RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated),
+    RGFW_windowCloseFlag = RGFW_BIT(RGFW_windowClose),
+    RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop),
+    RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag),
+	RGFW_monitorConnectedFlag = RGFW_BIT(RGFW_monitorConnected),
+	RGFW_monitorDisconnectedFlag = RGFW_BIT(RGFW_monitorDisconnected),
+    RGFW_mousePosChangedFlag = RGFW_mouseMotionFlag, /* alias for RGFW_mouseMotionFlag (may be deleted at some point) */
+
+    RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag | RGFW_keyCharFlag,
+    RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mouseMotionFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag | RGFW_mouseRawMotionFlag,
+    RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag,
+    RGFW_windowFocusEventsFlag = RGFW_windowFocusInFlag | RGFW_windowFocusOutFlag,
+    RGFW_dataDragDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag,
+	RGFW_monitorEventsFlag = RGFW_monitorConnectedFlag | RGFW_monitorDisconnectedFlag,
+    RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_windowFocusEventsFlag | RGFW_dataDragDropEventsFlag | RGFW_windowCloseFlag | RGFW_monitorEventsFlag
+};
+
+/*! Event structure(s) and union for checking/getting events */
+
+/*! @brief common event data across all events */
+typedef struct RGFW_commonEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+} RGFW_commonEvent;
+
+/*! @brief event data for all focus events */
+typedef struct RGFW_windowFocusEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	RGFW_bool state; /*!< wether or not the window is in focus or not */
+} RGFW_windowFocusEvent;
+
+/*! @brief event data for any mouse button event (press/release) */
+typedef struct RGFW_mouseButtonEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	RGFW_mouseButton value; /* !< which mouse button was pressed */
+	RGFW_bool state; /*!< if the button was pressed or released */
+} RGFW_mouseButtonEvent;
+
+/*! @brief event data for any mouse scroll or raw motion event */
+typedef struct RGFW_mouseDeltaEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	float x, y; /*!< the raw mouse scroll or motion delta value */
+} RGFW_mouseDeltaEvent;
+
+/*! @brief event data for a mouse position event (RGFW_mouseMotion) */
+typedef struct RGFW_mouseMotionEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	i32 x, y; /*!< mouse x, y of event (or drop point) */
+	RGFW_bool inWindow; /*!< if the mouse is in the window or not */
+} RGFW_mouseMotionEvent;
+
+/*! @brief event data for a key press/release event */
+typedef struct RGFW_keyEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	RGFW_key value; /*!< the physical key of the event, refers to where key is physically */
+	RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
+	RGFW_keymod mod; /*!< state of the key modifier state */
+	RGFW_bool state; /*!< if the key was pressed or released */
+} RGFW_keyEvent;
+
+/*! @brief event data for a key character event */
+typedef struct RGFW_keyCharEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	u32 value; /*!< the unicode value of the key */
+} RGFW_keyCharEvent;
+
+/*! @brief event data for any data drop event */
+typedef struct RGFW_dataDropEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	const RGFW_dataDropNode* value;
+} RGFW_dataDropEvent;
+
+/*! @brief event data for any data drag event */
+typedef struct RGFW_dataDragEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	i32 x, y; /*!< mouse x, y of event (or drop point) */
+	RGFW_dndActionType action; /*!< the type of drag action, e.g. enter, leave, move */
+	RGFW_dataTransferType dataType; /*!< the type of data being dragged*/
+} RGFW_dataDragEvent;
+
+/*! @brief event data for when the window scale (DPI) is updated */
+typedef struct RGFW_scaleUpdatedEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	float x, y; /*!< DPI scaling */
+} RGFW_scaleUpdatedEvent;
+
+/*! @brief event data for when a monitor is connected, disconnected or updated */
+typedef struct RGFW_monitorEvent {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_window* win; /*!< the window this event applies to (for event queue events) */
+	const RGFW_monitor* monitor; /*!< the monitor that this event applies to */
+	RGFW_bool state; /*!< if the monitor is connected or disconnected */
+} RGFW_monitorEvent;
+
+/*! @breif event data for when the window is updated, moved, resized or refreshed */
+typedef struct RGFW_windowUpdateEvent {
+	RGFW_eventType type; /*!< the specific event type */
+	RGFW_window* win; /*!< the window that was updated */
+	i32 x; /*!< the new window x OR the x of the rectanglular refresh area */
+	i32 y; /*!< the new window y OR the y of the rectanglular refresh area */
+	i32 w; /*!< the new window width OR the width of the rectanglular refresh area */
+	i32 h; /*!< the new window height OR the height of the rectanglular refresh area */
+} RGFW_windowUpdateEvent;
+
+/*! @brief union for all of the event stucture types */
+typedef union RGFW_event {
+	RGFW_eventType type; /*!< which event has been sent?*/
+	RGFW_commonEvent common; /*!< common event data (e.g.) type and win */
+	RGFW_windowFocusEvent focus; /*!< event data  for focus in/out events */
+	RGFW_windowUpdateEvent update; /*!< data for window update/move/resize/refresh events */
+	RGFW_mouseButtonEvent button; /*!< data for a button press/release */
+	RGFW_mouseDeltaEvent delta; /*!< data for a mouse scroll or raw motion */
+	RGFW_mouseMotionEvent mouse; /*!< data for mouse motion events */
+	RGFW_keyEvent key; /*!< data for key press/release/hold events */
+	RGFW_keyCharEvent keyChar; /*!< data for key character events */
+	RGFW_dataDropEvent drop; /*!< data dropping events */
+	RGFW_dataDragEvent drag; /*!< data for data dragging events */
+	RGFW_scaleUpdatedEvent scale; /*!< data for dpi scaling update events */
+	RGFW_monitorEvent monitor; /*!< data for monitor events */
+} RGFW_event;
+
+/*!
+	@!brief codes for for RGFW_the code is stupid and C++ waitForEvent
+	waitMS -> Allows the function to keep checking for events even after there are no more events
+			  if waitMS == 0, the loop will not wait for events
+			  if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
+			  if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
+*/
+typedef RGFW_ENUM(i32, RGFW_eventWait) {
+	RGFW_eventNoWait = 0,
+	RGFW_eventWaitNext = -1
+};
+
+/*! @brief generic event callback function type */
+typedef void (*RGFW_genericFunc)(const RGFW_event* e);
+
+/*! brief structure that holds an array to callback data*/
+typedef struct RGFW_callbacks {
+	RGFW_genericFunc arr[RGFW_eventCount]; /*!< an array of all the callbacks */
+} RGFW_callbacks;
+
+/*! @brief optional bitwise arguments for making a windows, these can be OR'd together */
+typedef RGFW_ENUM(u32, RGFW_windowFlags) {
+	RGFW_windowNoBorder = RGFW_BIT(0), /*!< the window doesn't have a border / frame / decor */
+	RGFW_windowNoResize = RGFW_BIT(1), /*!< the window cannot be resized by the user */
+	RGFW_windowAllowDND = RGFW_BIT(2), /*!< the window supports drag and drop */
+	RGFW_windowHideMouse = RGFW_BIT(3), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_showMouse`) */
+	RGFW_windowFullscreen = RGFW_BIT(4), /*!< the window is fullscreen by default */
+	RGFW_windowTranslucent = RGFW_BIT(5), /*!< the window is translucent (only properly works on X11 and MacOS, although it's meant for for windows) */
+	RGFW_windowTransparent = RGFW_windowTranslucent,  /*!< the window is translucent (only properly works on X11 and MacOS, although it's meant for for windows) */
+	RGFW_windowCenter = RGFW_BIT(6), /*! center the window on the screen */
+	RGFW_windowRawMouse = RGFW_BIT(7), /*!< use raw mouse mouse on window creation */
+	RGFW_windowScaleToMonitor = RGFW_BIT(8), /*! scale the window to the screen */
+	RGFW_windowHide = RGFW_BIT(9), /*! the window is hidden */
+	RGFW_windowMaximize = RGFW_BIT(10), /*!< maximize the window on creation */
+	RGFW_windowCenterCursor = RGFW_BIT(11), /*!< center the cursor to the window on creation */
+	RGFW_windowFloating = RGFW_BIT(12), /*!< create a floating window */
+	RGFW_windowFocusOnShow = RGFW_BIT(13), /*!< focus the window when it's shown */
+	RGFW_windowMinimize = RGFW_BIT(14), /*!< focus the window when it's shown */
+	RGFW_windowFocus = RGFW_BIT(15), /*!< if the window is in focus */
+	RGFW_windowCaptureMouse = RGFW_BIT(16), /*!< capture the mouse mouse mouse on window creation */
+	RGFW_windowOpenGL = RGFW_BIT(17), /*!< create an OpenGL context (you can also do this manually with RGFW_window_createContext_OpenGL) */
+	RGFW_windowEGL = RGFW_BIT(18), /*!< create an EGL context (you can also do this manually with RGFW_window_createContext_EGL) */
+	RGFW_noDeinitOnClose = RGFW_BIT(19), /*!< do not auto deinit RGFW if the window closes and this is the last window open */
+	RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize,
+	RGFW_windowCaptureRawMouse = RGFW_windowCaptureMouse | RGFW_windowRawMouse
+};
+
+/*! @brief the types of icon to set */
+typedef RGFW_ENUM(u8, RGFW_icon) {
+	RGFW_iconTaskbar = RGFW_BIT(0),
+	RGFW_iconWindow = RGFW_BIT(1),
+	RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
+};
+
+/*! @brief standard mouse icons */
+typedef RGFW_ENUM(u8, RGFW_mouseIcon) {
+	RGFW_mouseNormal = 0,
+	RGFW_mouseArrow,
+	RGFW_mouseIbeam,
+	RGFW_mouseText = RGFW_mouseIbeam,
+	RGFW_mouseCrosshair,
+	RGFW_mousePointingHand,
+	RGFW_mouseResizeEW,
+	RGFW_mouseResizeNS,
+	RGFW_mouseResizeNWSE,
+	RGFW_mouseResizeNESW,
+	RGFW_mouseResizeNW,
+	RGFW_mouseResizeN,
+	RGFW_mouseResizeNE,
+	RGFW_mouseResizeE,
+	RGFW_mouseResizeSE,
+	RGFW_mouseResizeS,
+	RGFW_mouseResizeSW,
+	RGFW_mouseResizeW,
+	RGFW_mouseResizeAll,
+	RGFW_mouseNotAllowed,
+	RGFW_mouseWait,
+	RGFW_mouseProgress,
+	RGFW_mouseIconCount,
+    RGFW_mouseIconFinal = 16 /* padding for alignment */
+};
+
+/*! @breif flash request type */
+typedef RGFW_ENUM(u8, RGFW_flashRequest) {
+	RGFW_flashCancel = 0,
+	RGFW_flashBriefly,
+	RGFW_flashUntilFocused
+};
+
+/*! @brief the type of debug message */
+typedef RGFW_ENUM(u8, RGFW_debugType) {
+	RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
+};
+
+/*! @brief error codes for known failure types */
+typedef RGFW_ENUM(u8, RGFW_errorCode) {
+	RGFW_noError = 0, /*!< no error */
+	RGFW_errOutOfMemory,
+	RGFW_errOpenGLContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
+	RGFW_errWayland, RGFW_errX11,
+	RGFW_errDirectXContext,
+	RGFW_errIOKit,
+	RGFW_errClipboard,
+	RGFW_errFailedFuncLoad,
+	RGFW_errBuffer,
+	RGFW_errMetal,
+	RGFW_errPlatform,
+	RGFW_errEventQueue,
+	RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
+	RGFW_warningWayland, RGFW_warningOpenGL
+};
+
+/*! @brief data for debug messages */
+typedef struct RGFW_debugInfo {
+	RGFW_debugType type; /*!< the type of message */
+	RGFW_errorCode code; /*!< the code for the specific type of debug message */
+	const char* msg; /*!< string message */
+} RGFW_debugInfo;
+
+/*! @brief callback function type for debug messags */
+typedef void (* RGFW_debugFunc)(const RGFW_debugInfo* info);
+
+/*! @brief function pointer equivalent of void* */
+typedef void (*RGFW_proc)(void);
+
+#if defined(RGFW_OPENGL)
+
+/*! @brief abstract structure for interfacing with the underlying OpenGL API */
+typedef struct RGFW_glContext RGFW_glContext;
+
+/*! @brief abstract structure for interfacing with the underlying EGL API */
+typedef struct RGFW_eglContext RGFW_eglContext;
+
+/*! values for the releaseBehavior hint */
+typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior)   {
+	RGFW_glReleaseFlush = 0, /*!< flush the pipeline will be flushed when the context is release */
+	RGFW_glReleaseNone /*!< do nothing on release */
+};
+
+/*! values for the profile hint */
+typedef RGFW_ENUM(i32, RGFW_glProfile)  {
+	RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */
+	RGFW_glForwardCompatibility, /*!< only compatibility for newer versions of OpenGL as well as the requested version */
+	RGFW_glCompatibility, /*!< allow compatibility for older versions of OpenGL as well as the requested version */
+	RGFW_glES, /*!< use OpenGL ES */
+	RGFW_glWeb /*!< use WebGL version (otherwise the version is changed to match it's GLES equivalent) */
+};
+
+/*! values for the renderer hint */
+typedef RGFW_ENUM(i32, RGFW_glRenderer)  {
+	RGFW_glAccelerated = 0, /*!< hardware accelerated (GPU) */
+	RGFW_glSoftware /*!< software rendered (CPU) */
+};
+
+/*! OpenGL initalization hints */
+typedef struct RGFW_glHints {
+	i32 stencil;  /*!< set stencil buffer bit size (0 by default) */
+	i32 samples; /*!< set number of sample buffers (0 by default) */
+	i32 stereo; /*!< hint the context to use stereoscopic frame buffers for 3D (false by default) */
+	i32 auxBuffers; /*!< number of aux buffers (0 by default) */
+	i32 doubleBuffer; /*!< request double buffering (true by default) */
+	i32 red, green, blue, alpha; /*!< set color bit sizes (all 8 by default) */
+	i32 depth; /*!< set depth buffer bit size (24 by default) */
+	i32 accumRed, accumGreen, accumBlue, accumAlpha; /*!< set accumulated RGBA bit sizes (all 0 by default) */
+	RGFW_bool sRGB; /*!< request sRGA format (false by default) */
+	RGFW_bool robustness; /*!< request a "robust" (as in memory-safe) context (false by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt */
+	RGFW_bool debug; /*!< request OpenGL debugging (false by default). */
+	RGFW_bool noError; /*!< request no OpenGL errors (false by default). This causes OpenGL errors to be undefined behavior. For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_no_error.txt */
+	RGFW_glReleaseBehavior releaseBehavior; /*!< hint how the OpenGL driver should behave when changing contexts (RGFW_glReleaseNone by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_context_flush_control.txt */
+	RGFW_glProfile profile; /*!< set OpenGL API profile (RGFW_glCore by default) */
+	i32 major, minor;  /*!< set the OpenGL API profile version (by default RGFW_glMajor is 1, RGFW_glMinor is 0) */
+	RGFW_glContext* share; /*!< Share this OpenGL context with newly created OpenGL contexts; defaults to NULL. */
+	RGFW_eglContext* shareEGL; /*!< Share this EGL context with newly created OpenGL contexts; defaults to NULL. */
+	RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */
+} RGFW_glHints;
+
+#endif
+
+/**!
+ * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time.
+ * @param size The size (in bytes) of the memory block to allocate.
+ * @return A pointer to the allocated memory block.
+*/
+RGFWDEF void* RGFW_alloc(size_t size);
+
+/**!
+ * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time.
+ * @param ptr A pointer to the memory block to free.
+*/
+RGFWDEF void RGFW_free(void* ptr);
+
+/**!
+ * @brief Returns the size (in bytes) of the RGFW_window structure.
+ * @return The size of the RGFW_window structure.
+*/
+RGFWDEF size_t RGFW_sizeofWindow(void);
+
+/**!
+ * @brief Returns the size (in bytes) of the RGFW_window_src structure.
+ * @return The size of the RGFW_window_src structure.
+*/
+RGFWDEF size_t RGFW_sizeofWindowSrc(void);
+
+/**!
+ * @brief (Unix) Toggles the use of Wayland.
+ * This is enabled by default when compiled with `RGFW_WAYLAND`.
+ * If not using `RGFW_WAYLAND`, Wayland functions are not exposed.
+ * This function can be used to force the use of XWayland.
+ * @param wayland A boolean value indicating whether to use Wayland (true) or not (false).
+*/
+RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
+
+/**!
+ * @brief Checks if Wayland is currently being used.
+ * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_usingWayland(void);
+
+/**!
+ * @brief Retrieves the current Cocoa layer (macOS only).
+ * @return A pointer to the Cocoa layer, or NULL if the platform is not in use.
+*/
+RGFWDEF void* RGFW_getLayer_OSX(void);
+
+/**!
+ * @brief Retrieves the current X11 display connection.
+ * @return A pointer to the X11 display, or NULL if the platform is not in use.
+*/
+RGFWDEF void* RGFW_getDisplay_X11(void);
+
+/**!
+ * @brief Retrieves the current Wayland display connection.
+ * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use.
+*/
+RGFWDEF struct wl_display* RGFW_getDisplay_Wayland(void);
+
+/**!
+ * @brief Sets the class name for X11 and WinAPI windows.
+ * Windows with the same class name will be grouped by the window manager.
+ * By default, the class name matches the root window’s name.
+ * @param name The class name to assign.
+*/
+RGFWDEF void RGFW_setClassName(const char* name);
+
+/**!
+ * @brief Sets the X11 instance name.
+ * By default, the window name will be used as the instance name.
+ * @param name The X11 instance name to set.
+*/
+RGFWDEF void RGFW_setXInstName(const char* name);
+
+/**!
+ * @brief (macOS only) Changes the current working directory to the application’s resource folder.
+*/
+RGFWDEF void RGFW_moveToMacOSResourceDir(void);
+
+/*! copy image to another image, respecting each image's format */
+RGFWDEF void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func);
+
+/**!
+ * @brief Returns the size (in bytes) of the RGFW_nativeImage structure.
+ * @return The size of the RGFW_nativeImage structure.
+*/
+RGFWDEF size_t RGFW_sizeofNativeImage(void);
+
+/**!
+ * @brief Returns the size (in bytes) of the RGFW_surface structure.
+ * @return The size of the RGFW_surface structure.
+*/
+RGFWDEF size_t RGFW_sizeofSurface(void);
+
+/**!
+ * @brief Returns the native format type for the system
+ * @return the native format type for the system as a RGFW_format enum value
+*/
+RGFWDEF RGFW_format RGFW_nativeFormat(void);
+
+/**!
+ * @brief Creates a new surface from raw pixel data.
+ * @param data A pointer to the pixel data buffer.
+ * @param w The width of the surface in pixels.
+ * @param h The height of the surface in pixels.
+ * @param format The pixel format of the data.
+ * @return A pointer to the newly created RGFW_surface.
+ *
+ * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
+ * this means it may fail to render on any other window if the visual does not match
+ * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
+ * Of course, you can also manually set the root window with RGFW_setRootWindow
+*/
+RGFWDEF RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format);
+
+/**!
+ * @brief Creates a surface using a pre-allocated RGFW_surface structure.
+ * @param data A pointer to the pixel data buffer.
+ * @param w The width of the surface in pixels.
+ * @param h The height of the surface in pixels.
+ * @param format The pixel format of the data.
+ * @param surface A pointer to a pre-allocated RGFW_surface structure.
+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
+
+/**!
+ * @brief Retrieves the native image associated with a surface.
+ * @param surface A pointer to the RGFW_surface.
+ * @return A pointer to the native RGFW_nativeImage associated with the surface.
+*/
+RGFWDEF RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface);
+
+/**!
+ * @brief Frees the surface pointer and any buffers used for software rendering.
+ * @param surface A pointer to the RGFW_surface to free.
+*/
+RGFWDEF void RGFW_surface_free(RGFW_surface* surface);
+
+/**!
+ * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact.
+ * @param surface A pointer to the RGFW_surface whose buffers should be freed.
+*/
+RGFWDEF void RGFW_surface_freePtr(RGFW_surface* surface);
+
+
+/**!
+ * @brief create a mouse icon from bitmap data (similar to RGFW_window_setIcon).
+ * @param data A pointer to the bitmap pixel data.
+ * @param w The width of the mouse icon in pixels.
+ * @param h The height of the mouse icon in pixels.
+ * @param format The pixel format of the data.
+ * @return A pointer to the newly loaded RGFW_mouse structure.
+ *
+ * @note The icon is not resized by default.
+*/
+RGFWDEF RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format);
+
+/**!
+ * @brief create a standard mouse icon
+ * @param mouse The standard cursor type (see RGFW_MOUSE enum).
+ * @return A pointer to the newly loaded RGFW_mouse structure.
+*/
+RGFWDEF RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse);
+
+/**!
+ * @brief Frees the data associated with an RGFW_mouse structure.
+ * @param mouse A pointer to the RGFW_mouse to free.
+*/
+RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
+
+/**!
+ * @brief Get an allocated array of the supported modes of a monitor
+ * @param monitor the source monitor object
+ * @param count [OUTPUT] the count of the array
+ * @return the allocated array of supported modes
+*/
+RGFWDEF RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count);
+
+/**!
+ * @brief Free RGFW allocated modes array
+ * @param monitor the source monitor object
+ * @param modes a pointer to an allocated array of modes
+*/
+RGFWDEF void RGFW_freeModes(RGFW_monitorMode* modes);
+
+/**!
+ * @brief Get the supported modes of a monitor using a pre-allocated array
+ * @param monitor the source monitor object
+ * @param modes [OUTPUT] a pointer to an allocated array of modes
+ * @return the number of (possible) modes, if [modes == NULL] the possible nodes *may* be less than the actual modes
+*/
+RGFWDEF size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes);
+
+/**!
+ * @brief find the closest monitor mode based on the give mode with size being the highest priority, format being the second and refreshrate being the third.
+ * @param monitor the source monitor object
+ * @param mode user filled mode to use for comparison
+ * @param modes [OUTPUT] a pointer to be filled with the output closest monitor
+ * @return returns true if a suitable monitor was found and false if no suitable monitor was found at all
+*/
+
+RGFWDEF RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest);
+
+/**!
+ * @brief Get the allocated gamma ramp
+ * @param monitor the source monitor object
+*/
+RGFWDEF RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor);
+
+/**!
+ * @brief Free the gamma ramp allocated by RGFW
+ * @param allocated gamma ramp
+*/
+RGFWDEF void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp);
+
+/**!
+ * @brief Get the monitor's gamma ramp using a pre-allocated struct with allocated data
+ * @param monitor the source monitor object
+ * @param ramp [OUTPUT] a pointer to an allocated gamma ramp (can be NULL to just get the count)
+ * @return the count of the gamma ramp
+*/
+RGFWDEF size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
+
+/**!
+ * @brief Set the monitor's gamma ramp using a pre-allocated struct with allocated data
+ * @param monitor the source monitor object
+ * @param ramp a pointer to an allocated gamma ramp
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
+
+/**!
+ * @brief Create and set the monitor's gamma ramp with a base gamma exponent
+ * @param monitor the source monitor object
+ * @param the gamma exponent
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma);
+
+/**!
+ * @brief Create and set the monitor's gamma ramp with a base gamma exponent using a pre-allocated array
+ * @param monitor the source monitor object
+ * @param gamma the gamma exponent
+ * @param pre-allocated gammaramp channel
+ * @param count the length of the allocated channel array
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count);
+
+/**!
+ * @brief Get the workarea of a monitor, meaning the parts not occupied by OS graphics (i.e. the taskbar)
+ * @param monitor the source monitor object
+ * @param x [OUTPUT] the x pos of the workarea
+ * @param y [OUTPUT] the y pos of the workarea
+ * @param w [OUTPUT] the width of the workarea
+ * @param h [OUTPUT] the height of the workarea
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height);
+
+/**!
+ * @brief Get the position of a monitor (the same as monitor.x / monitor.y)
+ * @param x [OUTPUT] the x position of the monitor
+ * @param y [OUTPUT] the y position of the monitor
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y);
+
+/**!
+ * @brief Get the name of a monitor (the same as monitor.name)
+ * @return the cstring of the monitor's name
+*/
+RGFWDEF const char* RGFW_monitor_getName(RGFW_monitor* monitor);
+
+/**!
+ * @brief Get the scale of a monitor (the same as monitor.scaleX / monitor.scaleY)
+ * @param monitor the source monitor object
+ * @param x [OUTPUT] the x scale of the monitor
+ * @param y [OUTPUT] the y scale of the monitor
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y);
+
+/**!
+ * @brief Get the physical size of a monitor (the same as monitor.physW / monitor.physH)
+ * @param monitor the source monitor object
+ * @param w [OUTPUT] the physical width of the monitor
+ * @param h [OUTPUT] the physical height of the monitor
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h);
+
+/**!
+ * @brief Set the user pointer of a monitor (the same as monitor.userPtr = userPtr)
+ * @param monitor the source monitor object
+ * @param userPtr the new user pointer for the monitor
+*/
+RGFWDEF void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr);
+
+/**!
+ * @brief Get the user pointer of a monitor (the same as monitor.userPtr)
+ * @param monitor the source monitor object
+ * @return the user pointer of the monitor
+*/
+RGFWDEF void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor);
+
+/**!
+ * @brief Get the mode of a monitor (the same as monitor.mode)
+ * @param monitor the source monitor object
+ * @param mode [OUTPUT] current mode the monitor
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode);
+
+/**!
+ * @brief Poll and check for monitor updates (this is called internally on monitor update events and RGFW_init)
+*/
+RGFWDEF void RGFW_pollMonitors(void);
+
+/**!
+ * @brief Allocates and returns an array of all available monitors.
+ * @param len [OUTPUT] A pointer to store the number of monitors found.
+ * @return An allocated array of pointers to RGFW_monitor structures that must be freed.
+*/
+RGFWDEF RGFW_monitor** RGFW_getMonitors(size_t* len);
+
+/**!
+ * @brief fills a pre-allocated array with available monitors.
+ * @param maximum number of monitors that the passed [monitors] buffer supports, can be zero to get the length alone
+ * @param pre-allocated buffer of monitors, can be NULL to get the length alone
+ * @param len [OUTPUT] A pointer to store the number of monitors found, if max is not zero and monitors is not NULL, length will be set to max.
+ * @return An array of pointers to RGFW_monitor structures or NULL if the function failed.
+*/
+RGFWDEF RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len);
+
+/**!
+ * @brief Retrieves the primary monitor.
+ * @return A pointer to the RGFW_monitor structure representing the primary monitor.
+*/
+RGFWDEF RGFW_monitor* RGFW_getPrimaryMonitor(void);
+
+/**!
+ * @brief Requests the display mode for a monitor (based on what attributes are directly requested).
+ * @param mon The monitor to apply the mode change to.
+ * @param mode The desired RGFW_monitorMode.
+ * @param request The RGFW_modeRequest describing how to handle the mode change.
+ * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
+*/
+RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
+
+/**!
+ * @brief Sets a specific display mode for a monitor directly.
+ * @param mon The monitor to apply the mode change to.
+ * @param mode The desired RGFW_monitorMode.
+ * @param request The RGFW_modeRequest describing how to handle the mode change.
+ * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE.
+*/
+RGFWDEF RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode);
+
+/**!
+ * @brief Compares two monitor modes to check if they are equivalent.
+ * @param mon The first monitor mode.
+ * @param mon2 The second monitor mode.
+ * @param request The RGFW_modeRequest that defines the comparison parameters.
+ * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE.
+*/
+RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request);
+
+/**!
+ * @brief Scales a monitor’s mode to match a window’s size.
+ * @param mon The monitor to be scaled.
+ * @param win The window whose size should be used as a reference.
+ * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE.
+*/
+RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, struct RGFW_window* win);
+
+ /**!
+ * @brief set (enable or disable) raw mouse mode globally
+ * @param the boolean state of raw mouse mode
+ *
+*/
+RGFWDEF void RGFW_setRawMouseMode(RGFW_bool state);
+
+/**!
+ * @brief toggles building the drag-and-drop (DND) linked list
+ * @param allow RGFW_TRUE to allow DND building, RGFW_FALSE to disable
+ * @note this is for state checking, the list is created by default if you are using the event queue
+*/
+RGFWDEF void RGFW_setBuildDND(RGFW_bool allow);
+
+/**!
+* @brief sleep until RGFW gets an event or the timer ends (defined by OS)
+* @param waitMS how long to wait for the next event (in miliseconds)
+*/
+RGFWDEF void RGFW_waitForEvent(i32 waitMS);
+
+/**!
+* @brief Set if events should be queued or not (enabled by default if the event queue is checked)
+* @param queue boolean value if RGFW should queue events or not
+*/
+RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue);
+
+/**!
+ * @brief Sets the callback function for the event.
+ * @param the event type for the callback
+ * @param func The function to be called when the event is triggered.
+ * @return The previously set callback function, if any.
+*/
+RGFWDEF RGFW_genericFunc RGFW_setEventCallback(RGFW_eventType type, RGFW_genericFunc func);
+
+/**!
+ * @brief Sets the callback function for two continuous events.
+ * @param func The function to be called when the event is triggered.
+ * @param [OUTPUT] The previously set callback function for the first event, if any.
+ * @param [OUTPUT] The previously set callback function for the second event, if any.
+*/
+RGFWDEF void RGFW_setDualEventCallback(RGFW_eventType type, RGFW_genericFunc func, RGFW_genericFunc* first, RGFW_genericFunc* second);
+
+/**!
+ * @brief Sets the callback function for all events.
+ * @param func The function to be called when the event is triggered.
+ * @param [OUTPUT] a structure that holds an array of all the event callbacks
+*/
+RGFWDEF void RGFW_setAllEventCallbacks(RGFW_genericFunc func, RGFW_callbacks* callbacks);
+
+/**!
+* @brief check all the events until there are none left and updates window structure attributes
+*/
+RGFWDEF void RGFW_pollEvents(void);
+
+/**!
+* @brief check all the events until there are none left and updates window structure attributes
+* queues events if the queue is checked and/or requested
+*/
+RGFWDEF void RGFW_stopCheckEvents(void);
+
+/**!
+ * @brief polls and pops the next event
+ * @param event [OUTPUT] a pointer to store the retrieved event
+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
+ *
+ * NOTE: Using this function without a loop may cause event lag.
+ * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_checkQueuedEvent.
+ *
+ * Example:
+ * RGFW_event event;
+ * while (RGFW_checkEvent(win, &event)) {
+ *     // handle event
+ * }
+*/
+RGFWDEF RGFW_bool RGFW_checkEvent(RGFW_event* event);
+
+/**!
+ * @brief pops the first queued event
+ * @param event [OUTPUT] a pointer to store the retrieved event
+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event);
+
+/** * @defgroup Input
+* @{ */
+
+/**!
+ * @brief returns true if the key is pressed during the current frame
+ * @param key the key code of the key you want to check
+ * @return The boolean value if the key is pressed or not
+*/
+RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key);
+
+/**!
+ * @brief returns true if the key was released during the current frame
+ * @param key the key code of the key you want to check
+ * @return The boolean value if the key is released or not
+*/
+RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key);
+
+/**!
+ * @brief returns true if the key is down
+ * @param key the key code of the key you want to check
+ * @return The boolean value if the key is down or not
+*/
+RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key);
+
+/**!
+ * @brief returns true if the mouse button is pressed during the current frame
+ * @param button the mouse button code of the button you want to check
+ * @return The boolean value if the button is pressed or not
+*/
+RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button);
+
+/**!
+ * @brief returns true if the mouse button is released during the current frame
+ * @param button the mouse button code of the button you want to check
+ * @return The boolean value if the button is released or not
+*/
+RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button);
+
+/**!
+ * @brief returns true if the mouse button is down
+ * @param button the mouse button code of the button you want to check
+ * @return The boolean value if the button is down or not
+*/
+RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button);
+
+/**!
+ * @brief outputs the current x, y position of the mouse
+ * @param X [OUTPUT] a pointer for the output X value
+ * @param Y [OUTPUT] a pointer for the output Y value
+*/
+RGFWDEF void RGFW_getMouseScroll(float* x, float* y);
+
+/**!
+ * @brief outputs the current x, y movement vector of the mouse
+ * @param X [OUTPUT] a pointer for the output X vector value
+ * @param Y [OUTPUT] a pointer for the output Y vector value
+*/
+RGFWDEF void RGFW_getMouseVector(float* x, float* y);
+/** @} */
+
+/**!
+ * @brief creates a new window
+ * @param name the requested title of the window
+ * @param x the requested x position of the window
+ * @param y the requested y position of the window
+ * @param w the requested width of the window
+ * @param h the requested height of the window
+ * @param flags extra arguments ((u32)0 means no flags used)
+ * @return A pointer to the newly created window structure
+ *
+ * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window
+*/
+RGFWDEF RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h,  RGFW_windowFlags flags);
+
+/**!
+ * @brief creates a new window using a pre-allocated window structure
+ * @param name the requested title of the window
+ * @param x the requested x position of the window
+ * @param y the requested y position of the window
+ * @param w the requested width of the window
+ * @param h the requested height of the window
+ * @param flags extra arguments ((u32)0 means no flags used)
+ * @param win a pointer the pre-allocated window structure
+ * @return A pointer to the newly created window structure
+*/
+RGFWDEF RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win);
+
+/**!
+ * @brief creates a new surface structure
+ * @param win the source window of the surface
+ * @param data a pointer to the raw data of the structure (you allocate this)
+ * @param w the width the data
+ * @param h the height of the data
+ * @return A pointer to the newly created surface structure
+ *
+ * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual
+ * this means it may fail to render on any other window if the visual does not match
+ * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues
+ * Of course, you can also manually set the root window with RGFW_setRootWindow
+ */
+RGFWDEF RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
+
+/**!
+ * @brief creates a new surface structure using a pre-allocated surface structure
+ * @param win the source window of the surface
+ * @param data a pointer to the raw data of the structure (you allocate this)
+ * @param w the width the data
+ * @param h the height of the data
+ * @param a pointer to the pre-allocated surface structure
+ * @return a bool if the creation was successful or not
+*/
+RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
+
+/**!
+ * @brief set the function/callback used for converting surface data between formats
+ * @param surface a pointer to the surface
+ * @param a function pointer for the function to use [if NULL the default function is used]
+*/
+RGFWDEF void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func);
+
+/**!
+ * @brief blits a surface stucture to the window
+ * @param win a pointer the window to blit to
+ * @param surface a pointer to the surface
+*/
+RGFWDEF void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface);
+
+/**!
+ * @brief gets the position of the window | with RGFW_window.x and window.y
+ * @param x [OUTPUT] the x position of the window
+ * @param y [OUTPUT] the y position of the window
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y); /*!<  */
+
+/**!
+ * @brief gets the size of the window | with RGFW_window.w and window.h
+ * @param win a pointer to the window
+ * @param w [OUTPUT] the width of the window
+ * @param h [OUTPUT] the height of the window
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h);
+
+/**!
+ * @brief gets the size of the window in exact pixels
+ * @param win a pointer to the window
+ * @param w [OUTPUT] the width of the window
+ * @param h [OUTPUT] the height of the window
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h);
+
+/**!
+ * @brief gets the flags of the window | returns RGFW_window._flags
+ * @param win a pointer to the window
+ * @return the window flags
+*/
+RGFWDEF u32 RGFW_window_getFlags(RGFW_window* win);
+
+/**!
+ * @brief returns the exit key assigned to the window
+ * @param win a pointer to the target window
+ * @return The key code assigned as the exit key
+*/
+RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window* win);
+
+/**!
+ * @brief sets the exit key for the window
+ * @param win a pointer to the target window
+ * @param key the key code to assign as the exit key
+*/
+RGFWDEF void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key);
+
+/**!
+ * @brief sets the types of events you want the window to receive
+ * @param win a pointer to the target window
+ * @param events the event flags to enable (use RGFW_allEventFlags for all)
+*/
+RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events);
+
+/**!
+ * @brief gets the currently enabled events for the window
+ * @param win a pointer to the target window
+ * @return The enabled event flags for the window
+*/
+RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win);
+
+/**!
+ * @brief enables all events and disables selected ones
+ * @param win a pointer to the target window
+ * @param events the event flags to disable
+*/
+RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events);
+
+/**!
+ * @brief directly enables or disables a specific event or group of events
+ * @param win a pointer to the target window
+ * @param event the event flag or group of flags to modify
+ * @param state RGFW_TRUE to enable, RGFW_FALSE to disable
+*/
+RGFWDEF void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state);
+
+/**!
+ * @brief gets the user pointer associated with the window
+ * @param win a pointer to the target window
+ * @return The user-defined pointer stored in the window
+*/
+RGFWDEF void* RGFW_window_getUserPtr(RGFW_window* win);
+
+/**!
+ * @brief sets a user pointer for the window
+ * @param win a pointer to the target window
+ * @param ptr a pointer to associate with the window
+*/
+RGFWDEF void RGFW_window_setUserPtr(RGFW_window* win, void* ptr);
+
+/**!
+ * @brief retrieves the platform-specific window source pointer
+ * @param win a pointer to the target window
+ * @return A pointer to the internal RGFW_window_src structure
+*/
+RGFWDEF RGFW_window_src* RGFW_window_getSrc(RGFW_window* win);
+
+/**!
+ * @brief sets the macOS layer object associated with the window
+ * @param win a pointer to the target window
+ * @param layer a pointer to the macOS layer object
+ * @note Only available on macOS platforms
+*/
+RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer);
+
+/**!
+ * @brief retrieves the macOS view object associated with the window
+ * @param win a pointer to the target window
+ * @return A pointer to the macOS view object, or NULL if not on macOS
+*/
+RGFWDEF void* RGFW_window_getView_OSX(RGFW_window* win);
+
+/**!
+ * @brief retrieves the macOS window object
+ * @param win a pointer to the target window
+ * @return A pointer to the macOS window object, or NULL if not on macOS
+*/
+RGFWDEF void* RGFW_window_getWindow_OSX(RGFW_window* win);
+
+/**!
+ * @brief retrieves the HWND handle for the window
+ * @param win a pointer to the target window
+ * @return A pointer to the Windows HWND handle, or NULL if not on Windows
+*/
+RGFWDEF void* RGFW_window_getHWND(RGFW_window* win);
+
+/**!
+ * @brief retrieves the HDC handle for the window
+ * @param win a pointer to the target window
+ * @return A pointer to the Windows HDC handle, or NULL if not on Windows
+*/
+RGFWDEF void* RGFW_window_getHDC(RGFW_window* win);
+
+/**!
+ * @brief retrieves the X11 Window handle for the window
+ * @param win a pointer to the target window
+ * @return The X11 Window handle, or 0 if not on X11
+*/
+RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window* win);
+
+/**!
+ * @brief retrieves the Wayland surface handle for the window
+ * @param win a pointer to the target window
+ * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland
+*/
+RGFWDEF struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win);
+
+/** * @defgroup Window_management
+* @{ */
+
+/*! set the window flags (will undo flags if they don't match the old ones) */
+RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
+
+/**!
+ * @brief polls and pops the next event with the matching target window in event queue, pushes back events that don't match
+ * @param win a pointer to the target window
+ * @param event [OUTPUT] a pointer to store the retrieved event
+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
+ *
+ * NOTE: Using this function without a loop may cause event lag.
+ * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent.
+ *
+ * Example:
+ * RGFW_event event;
+ * while (RGFW_window_checkEvent(win, &event)) {
+ *     // handle event
+ * }
+*/
+RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event);
+
+/**!
+ * @brief pops the first queued event with the matching target window, pushes back events that don't match
+ * @param win a pointer to the target window
+ * @param event [OUTPUT] a pointer to store the retrieved event
+ * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event);
+
+/**!
+ * @brief checks if a key was pressed while the window is in focus
+ * @param win a pointer to the target window
+ * @param key the key code to check
+ * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key);
+
+/**!
+ * @brief checks if a key is currently being held down
+ * @param win a pointer to the target window
+ * @param key the key code to check
+ * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key);
+
+/**!
+ * @brief checks if a key was released
+ * @param win a pointer to the target window
+ * @param key the key code to check
+ * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key);
+
+/**!
+ * @brief checks if a mouse button was pressed
+ * @param win a pointer to the target window
+ * @param button the mouse button code to check
+ * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button);
+
+/**!
+ * @brief checks if a mouse button is currently held down
+ * @param win a pointer to the target window
+ * @param button the mouse button code to check
+ * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button);
+
+/**!
+ * @brief checks if a mouse button was released
+ * @param win a pointer to the target window
+ * @param button the mouse button code to check
+ * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button);
+
+/**!
+ * @brief checks if the mouse left the window (true only for the first frame)
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win);
+
+/**!
+ * @brief checks if the mouse entered the window (true only for the first frame)
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win);
+
+/**!
+ * @brief checks if the mouse is currently inside the window bounds
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window* win);
+
+/**!
+ * @brief checks if there is data being dragged into or within the window
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window* win);
+
+/**!
+ * @brief gets the position of a data drag
+ * @param win a pointer to the target window
+ * @param x [OUTPUT] pointer to store the x position
+ * @param y [OUTPUT] pointer to store the y position
+ * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y);
+
+/**!
+ * @brief checks if a data drop occurred in the window (first frame only)
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win);
+
+/**!
+ * @brief retrieves data from a data drop (drag and drop)
+ * @param win a pointer to the target window
+ * @return a valid pointer to the root drag node if a data drop occurred, NULL otherwise
+*/
+RGFWDEF RGFW_dataDropNode* RGFW_window_getDataDrop(RGFW_window* win);
+
+/**!
+ * @brief closes the window and frees its associated structure
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_close(RGFW_window* win);
+
+/**!
+ * @brief closes the window without freeing its structure
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_closePtr(RGFW_window* win);
+
+/**!
+ * @brief fetches the size of the window through the OS (and updates the internal values)
+ * @param win a pointer to the window
+ * @param w [OUTPUT] the width of the window
+ * @param h [OUTPUT] the height of the window
+ * @return a bool if the function was successful
+*/
+RGFWDEF RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h);
+
+/**!
+ * @brief moves the window to a new position on the screen
+ * @param win a pointer to the target window
+ * @param x the new x position
+ * @param y the new y position
+*/
+RGFWDEF void RGFW_window_move(RGFW_window* win, i32 x, i32 y);
+
+/**!
+ * @brief moves the window to a specific monitor
+ * @param win a pointer to the target window
+ * @param m the target monitor
+*/
+RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m);
+
+/**!
+ * @brief resizes the window to the given dimensions
+ * @param win a pointer to the target window
+ * @param w the new width
+ * @param h the new height
+*/
+RGFWDEF void RGFW_window_resize(RGFW_window* win, i32 w, i32 h);
+
+/**!
+ * @brief sets the aspect ratio of the window
+ * @param win a pointer to the target window
+ * @param w the width ratio
+ * @param h the height ratio
+*/
+RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h);
+
+/**!
+ * @brief sets the minimum size of the window
+ * @param win a pointer to the target window
+ * @param w the minimum width
+ * @param h the minimum height
+*/
+RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h);
+
+/**!
+ * @brief sets the maximum size of the window
+ * @param win a pointer to the target window
+ * @param w the maximum width
+ * @param h the maximum height
+*/
+RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h);
+
+/**!
+ * @brief sets focus to the window
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_focus(RGFW_window* win);
+
+/**!
+ * @brief checks if the window is currently in focus
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win);
+
+/**!
+ * @brief raises the window to the top of the stack
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_raise(RGFW_window* win);
+
+/**!
+ * @brief maximizes the window
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_maximize(RGFW_window* win);
+
+/**!
+ * @brief toggles fullscreen mode for the window
+ * @param win a pointer to the target window
+ * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable
+*/
+RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen);
+
+/**!
+ * @brief centers the window on the screen
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_center(RGFW_window* win);
+
+/**!
+ * @brief minimizes the window
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_minimize(RGFW_window* win);
+
+/**!
+ * @brief restores the window from minimized state
+ * @param win a pointer to the target window
+*/
+RGFWDEF void RGFW_window_restore(RGFW_window* win);
+
+/**!
+ * @brief makes the window a floating window
+ * @param win a pointer to the target window
+ * @param floating RGFW_TRUE to float, RGFW_FALSE to disable
+*/
+RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating);
+
+/**!
+ * @brief sets the opacity level of the window
+ * @param win a pointer to the target window
+ * @param opacity the opacity level (0–255)
+*/
+RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity);
+
+/**!
+ * @brief toggles window borders / frame / decor
+ * @param win a pointer to the target window
+ * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless
+*/
+RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
+
+/**!
+ * @brief checks if the window is borderless (has a border, frame or decor)
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
+
+/**!
+ * @brief toggles drag-and-drop (DND) support for the window
+ * @param win a pointer to the target window
+ * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable
+ * @note RGFW_windowAllowDND must still be passed when creating the window
+*/
+RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
+
+/**!
+ * @brief checks if drag-and-drop (DND) is allowed
+ * @param win a pointer to the target window
+ * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
+
+#ifndef RGFW_NO_PASSTHROUGH
+/**!
+ * @brief toggles mouse passthrough for the window
+ * @param win a pointer to the target window
+ * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable
+*/
+RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
+#endif
+
+/**!
+ * @brief renames the window
+ * @param win a pointer to the target window
+ * @param name the new title string for the window
+*/
+RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name);
+
+/**!
+ * @brief sets the icon for the window and taskbar
+ * @param win a pointer to the target window
+ * @param data the image data
+ * @param w the width of the icon
+ * @param h the height of the icon
+ * @param format the image format
+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
+ *
+ * NOTE: The image may be resized by default.
+*/
+RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format);
+
+/**!
+ * @brief sets the icon for the window and/or taskbar
+ * @param win a pointer to the target window
+ * @param data the image data
+ * @param w the width of the icon
+ * @param h the height of the icon
+ * @param format the image format
+ * @param type the target icon type (taskbar, window, or both)
+ * @return RGFW_TRUE if successful, RGFW_FALSE otherwise
+*/
+RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type);
+
+/**!
+ * @brief sets the mouse icon for the window using a loaded mouse icon
+ * @param win a pointer to the target window
+ * @param mouse a pointer to the RGFW_mouse struct containing the icon
+*/
+RGFWDEF RGFW_bool RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
+
+/**!
+ * @brief Sets the mouse to a preloaded [by RGFW] standard system cursor.
+ * @param win The target window.
+ * @param mouse The standardmouse icon (see RGFW_mouseIcon enum).
+ * @return True if the standard cursor was successfully applied.
+*/
+RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcon icon);
+
+/**!
+ * @brief Sets the mouse to the default cursor icon.
+ * @param win The target window.
+ * @return True if the default cursor was successfully set.
+*/
+RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win);
+
+/**!
+ * @brief set (enable or disable) raw mouse mode only for the select window
+ * @param win The target window.
+ * @param the boolean state of raw mouse mode
+ *
+*/
+RGFWDEF void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state);
+
+/**!
+ * @brief lock/unlock the cursor.
+ * @param win The target window.
+ * @param the boolean state of the mouse's capture state
+ *
+*/
+RGFWDEF void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state);
+
+/**!
+ * @brief lock/unlock the cursor and enable raw mpuise mode.
+ * @param win The target window.
+ * @param the boolean state of raw mouse mode
+ *
+*/
+RGFWDEF void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state);
+
+/**!
+ * @brief Returns true if the mouse is using raw mouse mode
+ * @param win The target window.
+ * @return True if the mouse is using raw mouse input mode.
+*/
+RGFWDEF RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win);
+
+
+/**!
+ * @brief Returns true if the mouse is captured
+ * @param win The target window.
+ * @return True if the mouse is being captured.
+*/
+RGFWDEF RGFW_bool RGFW_window_isCaptured(RGFW_window* win);
+
+/**!
+ * @brief Hides the window from view.
+ * @param win The target window.
+*/
+RGFWDEF void RGFW_window_hide(RGFW_window* win);
+
+/**!
+ * @brief Shows the window if it was hidden.
+ * @param win The target window.
+*/
+RGFWDEF void RGFW_window_show(RGFW_window* win);
+
+/**!
+ * @breif request a window flash to get attention from the user
+ * @param win the target window
+ * @param request the flash operation requested
+*/
+RGFWDEF void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request);
+
+/**!
+ * @brief Sets whether the window should close.
+ * @param win The target window.
+ * @param shouldClose True to signal the window should close, false to keep it open.
+ *
+ * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags.
+*/
+RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
+
+/**!
+ * @brief Retrieves the current global mouse position.
+ * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen.
+ * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen.
+ * @return True if the position was successfully retrieved.
+*/
+RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y);
+
+/**!
+ * @brief Retrieves the mouse position relative to the window.
+ * @param win The target window.
+ * @param x [OUTPUT] Pointer to store the X position within the window.
+ * @param y [OUTPUT] Pointer to store the Y position within the window.
+ * @return True if the position was successfully retrieved.
+*/
+RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y);
+
+/**!
+ * @brief Shows or hides the mouse cursor for the window.
+ * @param win The target window.
+ * @param show True to show the mouse, false to hide it.
+*/
+RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
+
+/**!
+ * @brief Checks if the mouse is currently hidden in the window.
+ * @param win The target window.
+ * @return True if the mouse is hidden.
+*/
+RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win);
+
+/**!
+ * @brief Moves the mouse to the specified position within the window.
+ * @param win The target window.
+ * @param x The new X position.
+ * @param y The new Y position.
+*/
+RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y);
+
+/**!
+ * @brief Checks if the window should close.
+ * @param win The target window.
+ * @return True if the window should close (for example, if ESC was pressed or a close event occurred).
+*/
+RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
+
+/**!
+ * @brief Checks if the window is currently fullscreen.
+ * @param win The target window.
+ * @return True if the window is fullscreen.
+*/
+RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
+
+/**!
+ * @brief Checks if the window is currently hidden.
+ * @param win The target window.
+ * @return True if the window is hidden.
+*/
+RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
+
+/**!
+ * @brief Checks if the window is minimized.
+ * @param win The target window.
+ * @return True if the window is minimized.
+*/
+RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
+
+/**!
+ * @brief Checks if the window is maximized.
+ * @param win The target window.
+ * @return True if the window is maximized.
+*/
+RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
+
+/**!
+ * @brief Checks if the window is floating.
+ * @param win The target window.
+ * @return True if the window is floating.
+*/
+RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
+/** @} */
+
+/** * @defgroup Monitor
+* @{ */
+
+/**!
+ * @brief Scales the window to match its monitor’s resolution.
+ * @param win The target window.
+ *
+ * This function is automatically called when the flag `RGFW_scaleToMonitor`
+ * is used during window creation.
+*/
+RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
+
+/**!
+ * @brief Retrieves the monitor structure associated with the window.
+ * @param win The target window.
+ * @return The monitor structure of the window.
+*/
+RGFWDEF RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win);
+
+/** @} */
+
+/** * @defgroup Clipboard
+* @{ */
+
+/**!
+ * @brief Reads clipboard data.
+ * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data.
+ * @return A pointer to the clipboard data as a string.
+*/
+RGFWDEF const char* RGFW_readClipboard(size_t* size);
+
+/**!
+ * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL.
+ * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size).
+ * @param strCapacity The capacity of the provided buffer.
+ * @return The number of bytes read or required length of clipboard data.
+*/
+RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
+
+/**!
+ * @brief Writes text to the clipboard.
+ * @param text The text to be written to the clipboard.
+ * @param textLen The length of the text being written.
+*/
+RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen);
+/** @} */
+
+
+
+/** * @defgroup error handling
+* @{ */
+/**!
+ * @brief Sets the callback function to handle debug messages from RGFW.
+ * @param func The function pointer to be used as the debug callback.
+ * @return The previously set debug callback function.
+*/
+RGFWDEF RGFW_debugFunc RGFW_setDebugCallback(RGFW_debugFunc func);
+
+/**!
+ * @brief Sends a debug message manually through the currently set debug callback.
+ * @param type The type of debug message being sent.
+ * @param err The associated error code.
+ * @param msg The debug message text.
+*/
+RGFWDEF void RGFW_debugCallback(RGFW_debugType type, RGFW_errorCode code, const char* msg);
+/** @} */
+
+/** * @defgroup graphics_API
+* @{ */
+
+/*! native rendering API functions */
+#if defined(RGFW_OPENGL)
+/* these are native opengl specific functions and will NOT work with EGL */
+
+/*!< make the window the current OpenGL drawing context
+
+	NOTE:
+ 	if you want to switch the graphics context's thread,
+	you have to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old thread
+	then RGFW_window_makeCurrentContext_OpenGL(valid_window) on the new thread
+*/
+
+/**!
+ * @brief Sets the global OpenGL hints to the specified pointer.
+ * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings.
+*/
+RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints);
+
+/**!
+ * @brief Resets the global OpenGL hints to their default values.
+*/
+RGFWDEF void RGFW_resetGlobalHints_OpenGL(void);
+
+/**!
+ * @brief Gets the current global OpenGL hints pointer.
+ * @return A pointer to the currently active RGFW_glHints structure.
+*/
+RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void);
+
+/**!
+ * @brief Creates and allocates an OpenGL context for the specified window.
+ * @param win A pointer to the target RGFW_window.
+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
+ * @return A pointer to the newly created RGFW_glContext.
+*/
+RGFWDEF RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints);
+
+/**!
+ * @brief Creates an OpenGL context for the specified window using a preallocated context structure.
+ * @param win A pointer to the target RGFW_window.
+ * @param ctx A pointer to an already allocated RGFW_glContext structure.
+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
+ * @return RGFW_TRUE on success, RGFW_FALSE on failure.
+*/
+RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
+
+/**!
+ * @brief Retrieves the OpenGL context associated with a window.
+ * @param win A pointer to the RGFW_window.
+ * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based.
+*/
+RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win);
+
+/**!
+ * @brief Deletes and frees the OpenGL context.
+ * @param win A pointer to the RGFW_window.
+ * @param ctx A pointer to the RGFW_glContext to delete.
+ *
+ * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
+*/
+RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
+
+/**!
+ * @brief Deletes the OpenGL context without freeing its memory.
+ * @param win A pointer to the RGFW_window.
+ * @param ctx A pointer to the RGFW_glContext to delete.
+ *
+ * @note This is automatically called by RGFW_window_close if the window’s context is not NULL.
+*/
+RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx);
+
+/**!
+ * @brief Retrieves the native source context from an RGFW_glContext.
+ * @param ctx A pointer to the RGFW_glContext.
+ * @return A pointer to the native OpenGL context handle.
+*/
+RGFWDEF void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx);
+
+/**!
+ * @brief Makes the specified window the current OpenGL rendering target.
+ * @param win A pointer to the RGFW_window to make current.
+ *
+ * @note This is typically called internally by RGFW_window_makeCurrent.
+*/
+RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win);
+
+/**!
+ * @brief Makes the OpenGL context of the specified window current.
+ * @param win A pointer to the RGFW_window whose context should be made current.
+ *
+ * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL)
+ *       on the old thread before making it current on the new one.
+*/
+RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win);
+
+/**!
+ * @brief Swaps the OpenGL buffers for the specified window.
+ * @param win A pointer to the RGFW_window whose buffers should be swapped.
+*/
+RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win);
+
+/**!
+ * @brief Retrieves the current OpenGL context.
+ * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend).
+*/
+RGFWDEF void* RGFW_getCurrentContext_OpenGL(void);
+
+/**!
+ * @brief Retrieves the current OpenGL window.
+ * @return A pointer to the RGFW_window currently bound as the OpenGL context target.
+*/
+RGFWDEF RGFW_window* RGFW_getCurrentWindow_OpenGL(void);
+
+/**!
+ * @brief Sets the OpenGL swap interval (vsync).
+ * @param win A pointer to the RGFW_window.
+ * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
+*/
+RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval);
+
+/**!
+ * @brief Retrieves the address of a native OpenGL procedure.
+ * @param procname The name of the OpenGL function to look up.
+ * @return A pointer to the function, or NULL if not found.
+*/
+RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname);
+
+/**!
+ * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported.
+ * @param extension The name of the extension to check.
+ * @param len The length of the extension string.
+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len);
+
+/**!
+ * @brief Checks whether a specific platform-dependent OpenGL extension is supported.
+ * @param extension The name of the extension to check.
+ * @param len The length of the extension string.
+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len);
+
+/* these are EGL specific functions, they may fallback to OpenGL */
+#ifdef RGFW_EGL
+/**!
+ * @brief Creates and allocates an OpenGL/EGL context for the specified window.
+ * @param win A pointer to the target RGFW_window.
+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
+ * @return A pointer to the newly created RGFW_eglContext.
+*/
+RGFWDEF RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints);
+
+/**!
+ * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure.
+ * @param win A pointer to the target RGFW_window.
+ * @param ctx A pointer to an already allocated RGFW_eglContext structure.
+ * @param hints A pointer to an RGFW_glHints structure defining context creation parameters.
+ * @return RGFW_TRUE on success, RGFW_FALSE on failure.
+*/
+RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints);
+
+/**!
+ * @brief Frees and deletes an OpenGL/EGL context.
+ * @param win A pointer to the RGFW_window.
+ * @param ctx A pointer to the RGFW_eglContext to delete.
+ *
+ * @note Automatically called by RGFW_window_close if RGFW owns the context.
+*/
+RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx);
+
+/**!
+ * @brief Deletes an OpenGL/EGL context without freeing its memory.
+ * @param win A pointer to the RGFW_window.
+ * @param ctx A pointer to the RGFW_eglContext to delete.
+ *
+ * @note Automatically called by RGFW_window_close if RGFW owns the context.
+*/
+RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx);
+
+/**!
+ * @brief Retrieves the OpenGL/EGL context associated with a window.
+ * @param win A pointer to the RGFW_window.
+ * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context.
+*/
+RGFWDEF RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win);
+
+/**!
+ * @brief Retrieves the EGL display handle.
+ * @return A pointer to the native EGLDisplay.
+*/
+RGFWDEF void* RGFW_getDisplay_EGL(void);
+
+/**!
+ * @brief Retrieves the native source context from an RGFW_eglContext.
+ * @param ctx A pointer to the RGFW_eglContext.
+ * @return A pointer to the native EGLContext handle.
+*/
+RGFWDEF void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx);
+
+/**!
+ * @brief Retrieves the EGL surface handle from an RGFW_eglContext.
+ * @param ctx A pointer to the RGFW_eglContext.
+ * @return A pointer to the EGLSurface associated with the context.
+*/
+RGFWDEF void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx);
+
+/**!
+ * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext.
+ * @param ctx A pointer to the RGFW_eglContext.
+ * @return A pointer to the wl_egl_window associated with the EGL context.
+*/
+RGFWDEF struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx);
+
+/**!
+ * @brief Swaps the EGL buffers for the specified window.
+ * @param win A pointer to the RGFW_window whose buffers should be swapped.
+ *
+ * @note Typically called by RGFW_window_swapInterval.
+*/
+RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window* win);
+
+/**!
+ * @brief Makes the specified window the current EGL rendering target.
+ * @param win A pointer to the RGFW_window to make current.
+ *
+ * @note This is typically called internally by RGFW_window_makeCurrent.
+*/
+RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win);
+
+/**!
+ * @brief Makes the EGL context of the specified window current.
+ * @param win A pointer to the RGFW_window whose context should be made current.
+ *
+ * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL)
+ *       on the old thread before making it current on the new one.
+*/
+RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win);
+
+/**!
+ * @brief Retrieves the current EGL context.
+ * @return A pointer to the currently active EGLContext.
+*/
+RGFWDEF void* RGFW_getCurrentContext_EGL(void);
+
+/**!
+ * @brief Retrieves the current EGL window.
+ * @return A pointer to the RGFW_window currently bound as the EGL context target.
+*/
+RGFWDEF RGFW_window* RGFW_getCurrentWindow_EGL(void);
+
+/**!
+ * @brief Sets the EGL swap interval (vsync).
+ * @param win A pointer to the RGFW_window.
+ * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable).
+*/
+RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval);
+
+/**!
+ * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context.
+ * @param procname The name of the OpenGL function to look up.
+ * @return A pointer to the function, or NULL if not found.
+*/
+RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char* procname);
+
+/**!
+ * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context.
+ * @param extension The name of the extension to check.
+ * @param len The length of the extension string.
+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len);
+
+/**!
+ * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context.
+ * @param extension The name of the extension to check.
+ * @param len The length of the extension string.
+ * @return RGFW_TRUE if supported, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len);
+#endif
+#endif
+
+#ifdef RGFW_VULKAN
+#ifndef RGFW_NO_INCLUDE_VULKAN
+	#include <vulkan/vulkan.h>
+#endif
+
+/* if you don't want to use the above macros */
+
+/**!
+ * @brief Retrieves the Vulkan instance extensions required by RGFW.
+ * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2).
+ * @return A pointer to a static array of required Vulkan instance extension names.
+*/
+RGFWDEF const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count);
+
+/**!
+ * @brief Creates a Vulkan surface for the specified window.
+ * @param win A pointer to the RGFW_window for which to create the Vulkan surface.
+ * @param instance The Vulkan instance used to create the surface.
+ * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface.
+ * @return A VkResult indicating success or failure.
+*/
+RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
+
+/**!
+ * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW.
+ * @param instance The Vulkan instance.
+ * @param physicalDevice The Vulkan physical device to check.
+ * @param queueFamilyIndex The index of the queue family to query for presentation support.
+ * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise.
+*/
+RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
+#endif
+
+#ifdef RGFW_DIRECTX
+#ifndef RGFW_WINDOWS
+	#undef RGFW_DIRECTX
+#else
+	#define OEMRESOURCE
+	#include <dxgi.h>
+
+	#ifndef __cplusplus
+		#define __uuidof(T) IID_##T
+	#endif
+/**!
+ * @brief Creates a DirectX swap chain for the specified RGFW window.
+ * @param win A pointer to the RGFW_window for which to create the swap chain.
+ * @param pFactory A pointer to the IDXGIFactory used to create the swap chain.
+ * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device).
+ * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain.
+ * @return An integer result code (0 on success, or a DirectX error code on failure).
+*/
+RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
+#endif
+#endif
+
+#ifdef RGFW_WEBGPU
+	#include <webgpu/webgpu.h>
+	/**!
+	 * @brief Creates a WebGPU surface for the specified RGFW window.
+	 * @param window A pointer to the RGFW_window for which to create the surface.
+	 * @param instance The WebGPU instance used to create the surface.
+	 * @return The created WGPUSurface handle.
+	*/
+	RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance);
+#endif
+
+/** @} */
+
+/** * @defgroup Supporting
+* @{ */
+
+/**!
+ * @brief Sets the root (main) RGFW window.
+ * @param win A pointer to the RGFW_window to set as the root window.
+*/
+RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
+
+/**!
+ * @brief Retrieves the current root RGFW window.
+ * @return A pointer to the current root RGFW_window.
+*/
+RGFWDEF RGFW_window* RGFW_getRootWindow(void);
+
+/**!
+ * @brief Pushes an event into the standard RGFW event queue.
+ * @param event A pointer to the RGFW_event to be added to the queue.
+*/
+RGFWDEF void RGFW_eventQueuePush(const RGFW_event* event);
+
+/**!
+ * @brief Pushes an event into the standard RGFW event queue and call the callback.
+ * @param event A pointer to the RGFW_event to be added to the queue.
+*/
+RGFWDEF void RGFW_eventQueuePushAndCall(const RGFW_event* event);
+
+/**!
+ * @brief Clears all events from the RGFW event queue without processing them.
+*/
+RGFWDEF void RGFW_eventQueueFlush(void);
+
+/**!
+ * @brief Pops the next event from the RGFW event queue.
+ * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
+*/
+RGFWDEF RGFW_event* RGFW_eventQueuePop(void);
+
+/**!
+ * @brief Pops the next event from the RGFW event queue that matches the target window, pushes back events that don't matchj.
+ * @param win A pointer to the target RGFW_window.
+ * @return A pointer to the popped RGFW_event, or NULL if the queue is empty.
+*/
+RGFWDEF RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win);
+
+/**!
+ * @brief Converts an API keycode to the RGFW unmapped (physical) key.
+ * @param keycode The platform-specific keycode.
+ * @return The corresponding RGFW keycode.
+*/
+RGFWDEF RGFW_key RGFW_apiKeyToRGFW(u32 keycode);
+
+/**!
+ * @brief Converts an RGFW keycode to the unmapped (physical) API key.
+ * @param keycode The RGFW keycode.
+ * @return The corresponding platform-specific keycode.
+*/
+RGFWDEF u32 RGFW_rgfwToApiKey(RGFW_key keycode);
+
+/**!
+ * @brief Converts an physical RGFW keycode to a mapped RGFW keycode.
+ * @param keycode the physical RGFW keycode.
+ * @return The corresponding mapped RGFW keycode.
+*/
+RGFWDEF RGFW_key RGFW_physicalToMappedKey(RGFW_key keycode);
+
+/**!
+ * @brief Retrieves the size of the RGFW_info structure.
+ * @return The size (in bytes) of RGFW_info.
+*/
+RGFWDEF size_t RGFW_sizeofInfo(void);
+
+/**!
+ * @brief Initializes the RGFW library internally.
+ * @return 0 on success, a negative number error error on failure.
+ * @note This is automatically called when the first window is created.
+*/
+RGFWDEF i32 RGFW_init(void);
+
+/**!
+ * @brief Deinitializes the current instance of the RGFW library.
+ * @note This is automatically called when the last open window is closed.
+*/
+RGFWDEF void RGFW_deinit(void);
+
+/**!
+ * @brief Initializes RGFW using a user-provided RGFW_info structure.
+ * @param info A pointer to an RGFW_info structure to be used for initialization.
+ * @return  0 on success, a negative number error error on failure and a positive number for a warning.
+*/
+RGFWDEF i32 RGFW_init_ptr(RGFW_info* info);
+
+/**!
+ * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer.
+ * @param info A pointer to the RGFW_info structure representing the instance to deinitialize.
+*/
+RGFWDEF void RGFW_deinit_ptr(RGFW_info* info);
+
+/**!
+ * @brief Sets the global RGFW_info structure pointer.
+ * @param info A pointer to the RGFW_info structure to set.
+*/
+RGFWDEF void RGFW_setInfo(RGFW_info* info);
+
+/**!
+ * @brief Retrieves the global RGFW_info structure pointer.
+ * @return A pointer to the current RGFW_info structure.
+*/
+RGFWDEF RGFW_info* RGFW_getInfo(void);
+
+/** @} */
+#endif /* RGFW_HEADER */
+
+#if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION))
+#define RGFW_NATIVE_HEADER
+	#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
+		#pragma comment(lib, "opengl32")
+	#endif
+
+	#ifdef RGFW_OPENGL
+		struct RGFW_eglContext {
+			void* ctx;
+			void* surface;
+			struct wl_egl_window* eglWindow;
+		};
+
+		typedef union RGFW_gfxContext {
+			RGFW_glContext* native;
+			RGFW_eglContext* egl;
+		} RGFW_gfxContext;
+
+		typedef RGFW_ENUM(u32, RGFW_gfxContextType) {
+			RGFW_gfxNativeOpenGL = RGFW_BIT(0),
+			RGFW_gfxEGL = RGFW_BIT(1),
+			RGFW_gfxOwnedByRGFW = RGFW_BIT(2)
+		};
+	#endif
+
+	/*! source data for the window (used by the APIs) */
+	#ifdef RGFW_WINDOWS
+
+	#ifndef WIN32_LEAN_AND_MEAN
+		#define WIN32_LEAN_AND_MEAN
+	#endif
+	#ifndef OEMRESOURCE
+		#define OEMRESOURCE
+	#endif
+
+	#include <windows.h>
+
+	struct RGFW_nativeImage {
+		HBITMAP bitmap;
+		u8* bitmapBits;
+		RGFW_format format;
+		HDC hdcMem;
+	};
+
+	#ifdef RGFW_OPENGL
+		struct RGFW_glContext {    HGLRC ctx;	};
+	#endif
+
+	struct RGFW_window_src {
+		HWND window; /*!< source window */
+		HDC hdc; /*!< source HDC */
+		HICON hIconSmall, hIconBig; /*!< source window icons */
+		i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */
+		RGFW_bool actionFrame; /* frame after a caption button was toggled (e.g. minimize, maximize or close) */
+		WCHAR highSurrogate;
+		#ifdef RGFW_OPENGL
+			RGFW_gfxContext ctx;
+			RGFW_gfxContextType gfxType;
+		#endif
+	};
+
+#elif defined(RGFW_UNIX)
+	#ifdef RGFW_X11
+		#include <X11/Xlib.h>
+		#include <X11/Xutil.h>
+
+		#include <X11/extensions/Xrandr.h>
+		#include <X11/Xresource.h>
+
+		#ifndef RGFW_XDND_VERSION
+			#define RGFW_XDND_VERSION 5
+		#endif
+	#endif
+
+	#ifdef RGFW_WAYLAND
+		#ifdef RGFW_LIBDECOR
+			#include <libdecor-0/libdecor.h>
+		#endif
+
+		#include <wayland-client.h>
+		#include <errno.h>
+	#endif
+
+	struct RGFW_nativeImage {
+		#ifdef RGFW_X11
+			XImage* bitmap;
+		#endif
+		#ifdef RGFW_WAYLAND
+			struct wl_buffer* wl_buffer;
+			i32 fd;
+			struct wl_shm_pool* pool;
+		#endif
+		u8* buffer;
+		RGFW_format format;
+	};
+
+	#ifdef RGFW_OPENGL
+		struct RGFW_glContext {
+			#ifdef RGFW_X11
+				struct __GLXcontextRec* ctx; /*!< source graphics context */
+				Window window;
+			#endif
+			#ifdef RGFW_WAYLAND
+				RGFW_eglContext egl;
+			#endif
+		};
+	#endif
+
+	struct RGFW_window_src {
+		i32 x, y, w, h;
+	#ifdef RGFW_OPENGL
+		RGFW_gfxContext ctx;
+		RGFW_gfxContextType gfxType;
+	#endif
+#ifdef RGFW_X11
+		Window window; /*!< source window */
+		Window parent; /*!< parent window */
+		GC gc;
+		XIC ic;
+		u64 flashEnd;
+		#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+			i64 counter_value;
+			XID counter;
+		#endif
+#endif /* RGFW_X11 */
+
+#if defined(RGFW_WAYLAND)
+		struct wl_surface* surface;
+		struct xdg_surface* xdg_surface;
+		struct xdg_toplevel* xdg_toplevel;
+		struct zxdg_toplevel_decoration_v1* decoration;
+		struct zwp_locked_pointer_v1 *locked_pointer;
+		struct xdg_toplevel_icon_v1 *icon;
+		u32 decoration_mode;
+		/* State flags to configure the window */
+		RGFW_bool pending_activated;
+		RGFW_bool activated;
+		RGFW_bool resizing;
+		RGFW_bool pending_maximized;
+		RGFW_bool maximized;
+		RGFW_bool minimized;
+		RGFW_bool configured;
+
+		RGFW_bool using_custom_cursor;
+		struct wl_surface* custom_cursor_surface;
+
+		RGFW_monitorNode* active_monitor;
+
+		struct wl_data_source *data_source; // offer data to other clients
+
+		#ifdef RGFW_LIBDECOR
+			struct libdecor* decorContext;
+		#endif
+#endif /* RGFW_WAYLAND */
+	};
+
+#elif defined(RGFW_MACOS)
+	#include <CoreVideo/CoreVideo.h>
+
+	struct RGFW_nativeImage {
+		RGFW_format format;
+		u8* buffer;
+		void* rep;
+	};
+
+	#ifdef RGFW_OPENGL
+		struct RGFW_glContext {
+			void* ctx;
+			void* format;
+		};
+	#endif
+
+	struct RGFW_window_src {
+		void* window;
+		void* view; /* apple viewpoint thingy */
+		void* mouse;
+		void* delegate;
+		#ifdef RGFW_OPENGL
+			RGFW_gfxContext ctx;
+			RGFW_gfxContextType gfxType;
+		#endif
+	};
+
+#elif defined(RGFW_WASM)
+
+	#include <emscripten/html5.h>
+	#include <emscripten/key_codes.h>
+
+	struct RGFW_nativeImage  {
+		RGFW_format format;
+	};
+
+	#ifdef RGFW_OPENGL
+		struct RGFW_glContext {
+			EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
+		};
+	#endif
+
+	struct RGFW_window_src {
+		#ifdef RGFW_OPENGL
+			RGFW_gfxContext ctx;
+			RGFW_gfxContextType gfxType;
+		#endif
+	};
+
+#endif
+
+struct RGFW_surface {
+	u8* data;
+	i32 w, h;
+	RGFW_format format;
+	RGFW_convertImageDataFunc convertFunc;
+	RGFW_nativeImage native;
+};
+
+/*! internal window data that is not specific to the OS */
+typedef struct RGFW_windowInternal {
+	/*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */
+	RGFW_key exitKey;
+	i32 lastMouseX, lastMouseY; /*!< last cusor point (for raw mouse data) */
+
+	RGFW_bool shouldClose;
+	RGFW_bool rawMouse;
+	RGFW_bool captureMouse;
+	RGFW_bool inFocus;
+	RGFW_bool mouseInside;
+	RGFW_keymod mod;
+	RGFW_eventFlag enabledEvents;
+	u32 flags; /*!< windows flags (for RGFW to check and modify) */
+	i32 oldX, oldY, oldW, oldH;
+	RGFW_monitorMode oldMode;
+	RGFW_mouse* mouse;
+} RGFW_windowInternal;
+
+struct RGFW_window {
+	RGFW_window_src src; /*!< src window data */
+	RGFW_windowInternal internal; /*!< internal window data that is not specific to the OS */
+	void* userPtr; /* ptr for user data */
+	i32 x, y, w, h; /*!< position and size of the window */
+}; /*!< window structure for the window */
+
+typedef struct RGFW_windowState {
+	RGFW_bool mouseEnter;
+	RGFW_bool dataDragging;
+	RGFW_bool dataDrop;
+	size_t dataSize;
+	i32 dropX, dropY;
+	RGFW_window* win; /*!< it's not possible for one of these events to happen in the frame that the other event happened */
+
+	RGFW_bool mouseLeave;
+	RGFW_window* winLeave; /*!< if a mouse leaves one window and enters the next */
+} RGFW_windowState;
+
+typedef struct {
+	RGFW_bool current;
+	RGFW_bool prev;
+} RGFW_keyState;
+
+struct RGFW_monitorNode {
+	RGFW_monitor mon;
+	RGFW_bool disconnected;
+	RGFW_monitorNode* next;
+#ifdef RGFW_WAYLAND
+	u32 id; /* Add id so wl_outputs can be removed */
+	struct wl_output *output;
+	struct zxdg_output_v1 *xdg_output;
+	RGFW_monitorMode* modes;
+	size_t modeCount;
+#endif
+#if defined(RGFW_X11)
+	i32 screen;
+	RROutput rrOutput;
+	RRCrtc crtc;
+#endif
+#ifdef RGFW_WINDOWS
+	HMONITOR hMonitor;
+	WCHAR adapterName[32];
+	WCHAR deviceName[32];
+#endif
+#ifdef RGFW_MACOS
+	void* screen;
+	CGDirectDisplayID display;
+	u32 uintNum;
+#endif
+};
+
+typedef struct RGFW_monitorList {
+	RGFW_monitorNode* head;
+	RGFW_monitorNode* cur;
+} RGFW_monitorList;
+
+typedef struct RGFW_monitors {
+	RGFW_monitorList list;
+	size_t count;
+
+	RGFW_monitorNode* primary;
+	#if (RGFW_PREALLOCATED_MONITORS)
+		RGFW_monitorList freeList;
+		RGFW_monitorNode data[RGFW_PREALLOCATED_MONITORS];
+	#endif
+} RGFW_monitors;
+
+struct RGFW_info {
+    RGFW_window* root;
+    i32 windowCount;
+
+	RGFW_mouse* hiddenMouse;
+	RGFW_mouse* standardMice[RGFW_mouseIconCount];
+
+	RGFW_debugFunc debugCallbackSrc;
+	RGFW_genericFunc callbacks[RGFW_eventCount];
+    RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len  */
+
+	i32 eventBottom;
+    i32 eventLen;
+	RGFW_bool queueEvents;
+	RGFW_bool polledEvents;
+
+    u32 apiKeycodes[RGFW_keyLast];
+	#if defined(RGFW_X11) || defined(RGFW_WAYLAND)
+		RGFW_key keycodes[256];
+	#elif defined(RGFW_WINDOWS)
+		RGFW_key keycodes[512];
+	#elif defined(RGFW_MACOS)
+		RGFW_key keycodes[128];
+	#elif defined(RGFW_WASM)
+		RGFW_key keycodes[256];
+	#endif
+
+    const char* className;
+    RGFW_bool useWaylandBool;
+    RGFW_bool stopCheckEvents_bool ;
+    u64 timerOffset;
+
+    char* clipboard_data;
+    char* clipboard; /* for writing to the clipboard selection */
+    size_t clipboard_len;
+
+	RGFW_bool dndBuild;
+	RGFW_dataDropNode* dndRoot;
+	RGFW_dataDropNode* dndCur;
+
+	#ifdef RGFW_X11
+        Display* display;
+		XContext context;
+        Window helperWindow;
+        const char* instName;
+        XErrorEvent* x11Error;
+		i32 xrandrEventBase;
+		XIM im;
+		Window x11Source;
+		long x11Version;
+		i32 x11Format;
+		RGFW_dataTransferType x11TransferType;
+    #endif
+    #ifdef RGFW_WAYLAND
+        struct wl_display* wl_display;
+        struct xkb_context *xkb_context;
+        struct xkb_keymap *keymap;
+        struct xkb_state *xkb_state;
+        struct zxdg_decoration_manager_v1 *decoration_manager;
+        struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
+        struct zwp_relative_pointer_v1 *relative_pointer;
+        struct zwp_pointer_constraints_v1 *constraint_manager;
+        struct xdg_toplevel_icon_manager_v1 *icon_manager;
+
+        struct zxdg_output_manager_v1 *xdg_output_manager;
+
+        struct wl_data_device_manager *data_device_manager;
+        struct wl_data_device *data_device; // supports clipboard and DND
+		struct wp_pointer_warp_v1* wp_pointer_warp;
+
+        struct wl_keyboard* wl_keyboard;
+        struct wl_pointer* wl_pointer;
+        struct wl_compositor* compositor;
+        struct xdg_wm_base* xdg_wm_base;
+        struct wl_shm* shm;
+        struct wl_seat *seat;
+        struct wl_registry *registry;
+        u32 mouse_enter_serial;
+        struct wl_cursor_theme* wl_cursor_theme;
+        struct wl_surface* cursor_surface;
+		struct xkb_compose_state* composeState;
+
+        RGFW_window* kbOwner;
+		RGFW_window* mouseOwner; /* what window has access to the mouse */
+
+		u32 last_key;  /* wayland key repeat data */
+		i32 wl_repeat_info_rate, wl_repeat_info_delay;
+		u32 last_key_time;
+    #endif
+
+    RGFW_monitors monitors;
+
+    #ifdef RGFW_UNIX
+	    int eventWait_forceStop[3];
+		i32 clock;
+    #endif
+
+    #ifdef RGFW_MACOS
+    void* NSApp;
+	i64 flash;
+	void* customViewClasses[2]; /* NSView and NSOpenGLView  */
+	void* customNSAppDelegateClass;
+	void* customWindowDelegateClass;
+	void* customNSAppDelegate;
+	void* tisBundle;
+    #endif
+
+	#ifdef RGFW_OPENGL
+		RGFW_window* current;
+	#endif
+	#ifdef RGFW_EGL
+		void* EGL_display;
+	#endif
+
+	RGFW_bool rawMouse; /* global raw mouse toggle */
+
+	RGFW_windowState windowState; /*! for checking window state events */
+
+	RGFW_keyState mouseButtons[RGFW_mouseFinal];
+	RGFW_keyState keyboard[RGFW_keyLast];
+	float scrollX, scrollY;
+	float vectorX, vectorY;
+};
+#endif /* RGFW_NATIVE_HEADER */
+
+#ifdef RGFW_IMPLEMENTATION
+
+#ifndef RGFW_NO_MATH
+#include <math.h>
+#endif
+
+/* global private API */
+
+/* for C++ / C89 */
+RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win);
+RGFWDEF void RGFW_window_closePlatform(RGFW_window* win);
+RGFWDEF RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse);
+
+RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags);
+
+RGFWDEF void RGFW_initKeycodes(void);
+RGFWDEF void RGFW_initKeycodesPlatform(void);
+RGFWDEF void RGFW_resetPrevState(void);
+RGFWDEF void RGFW_resetKey(void);
+RGFWDEF void RGFW_unloadEGL(void);
+RGFWDEF void RGFW_keyUpdateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
+RGFWDEF void RGFW_keyUpdateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
+RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
+RGFWDEF void RGFW_keyUpdateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
+
+RGFWDEF void RGFW_monitors_refresh(void);
+RGFWDEF RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon);
+RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev);
+
+RGFWDEF void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
+RGFWDEF void RGFW_windowMinimizedCallback(RGFW_window* win);
+RGFWDEF void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
+RGFWDEF void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y);
+RGFWDEF void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h);
+RGFWDEF void RGFW_windowCloseCallback(RGFW_window* win);
+RGFWDEF void RGFW_mouseMotionCallback(RGFW_window* win, i32 x, i32 y);
+RGFWDEF void RGFW_rawMotionCallback(RGFW_window* win, float x, float y);
+RGFWDEF void RGFW_windowRefreshCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h);
+RGFWDEF void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus);
+RGFWDEF void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status);
+RGFWDEF void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t count, RGFW_dataTransferType dataType);
+RGFWDEF void RGFW_dataDragCallback(RGFW_window* win, RGFW_dataTransferType dataType, RGFW_dndActionType action, i32 x, i32 y);
+RGFWDEF void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint);
+RGFWDEF void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press);
+RGFWDEF void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press);
+RGFWDEF void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y);
+RGFWDEF void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY);
+RGFWDEF void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected);
+
+RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set);
+RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
+
+RGFWDEF void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state);
+RGFWDEF void RGFW_window_setRawMouseModePlatform(RGFW_window *win, RGFW_bool state);
+
+RGFWDEF void RGFW_copyImageData64(u8* dest_data, i32 w, i32 h, RGFW_format dest_format,
+							u8* src_data, RGFW_format src_format, RGFW_bool is64bit, RGFW_convertImageDataFunc func);
+
+RGFWDEF RGFW_bool RGFW_loadEGL(void);
+
+#ifdef RGFW_OPENGL
+typedef struct RGFW_attribStack {
+	i32* attribs;
+	size_t count;
+	size_t max;
+} RGFW_attribStack;
+RGFWDEF void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max);
+RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib);
+RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2);
+
+RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len);
+#endif
+
+#ifdef RGFW_X11
+RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win);
+#endif
+#ifdef RGFW_MACOS
+RGFWDEF void RGFW_osx_initView(RGFW_window* win);
+#endif
+/* end of global private API defs */
+
+RGFW_info* _RGFW = NULL;
+void RGFW_setInfo(RGFW_info* info) { _RGFW = info; }
+RGFW_info* RGFW_getInfo(void) { return _RGFW; }
+
+
+void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); }
+void RGFW_free(void* ptr) { RGFW_FREE(ptr); }
+
+void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland);  }
+RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; }
+
+void RGFW_setRawMouseMode(RGFW_bool state) {
+	_RGFW->rawMouse = state;
+	RGFW_window_setRawMouseModePlatform(_RGFW->root, state);
+}
+
+void RGFW_clipboard_switch(char* newstr);
+void RGFW_clipboard_switch(char* newstr) {
+	if (_RGFW->clipboard_data != NULL)
+		RGFW_FREE(_RGFW->clipboard_data);
+	_RGFW->clipboard_data =  newstr;
+}
+
+#define RGFW_CHECK_CLIPBOARD() \
+	if (size <= 0 && _RGFW->clipboard_data != NULL) \
+		return (const char*)_RGFW->clipboard_data; \
+	else if (size <= 0) \
+		return "\0";
+
+const char* RGFW_readClipboard(size_t* len) {
+	RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
+    RGFW_CHECK_CLIPBOARD();
+    char* str = (char*)RGFW_ALLOC((size_t)size);
+    RGFW_ASSERT(str != NULL);
+    str[0] = '\0';
+
+    size = RGFW_readClipboardPtr(str, (size_t)size);
+
+    RGFW_CHECK_CLIPBOARD();
+
+	if (len != NULL) *len = (size_t)size;
+
+	RGFW_clipboard_switch(str);
+	return (const char*)str;
+}
+
+/* generic RGFW defines */
+
+void RGFW_initKeycodes(void) {
+	RGFW_MEMZERO(_RGFW->keycodes, sizeof(_RGFW->keycodes));
+	RGFW_initKeycodesPlatform();
+	size_t i, y;
+    for (i = 0; i < RGFW_keyLast; i++) {
+        for (y = 0; y < (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)); y++) {
+            if (_RGFW->keycodes[y] == i) {
+                _RGFW->apiKeycodes[i] = (RGFW_key)y;
+                break;
+            }
+        }
+    }
+
+
+    RGFW_resetKey();
+}
+
+RGFW_key RGFW_apiKeyToRGFW(u32 keycode) {
+    /* make sure the key isn't out of bounds */
+	if (keycode > (sizeof(_RGFW->keycodes) / sizeof(RGFW_key)))
+		return 0;
+
+	return _RGFW->keycodes[keycode];
+}
+
+u32 RGFW_rgfwToApiKey(RGFW_key keycode) {
+	/* make sure the key isn't out of bounds */
+	return _RGFW->apiKeycodes[keycode];
+}
+
+void RGFW_resetKey(void) { RGFW_MEMZERO(_RGFW->keyboard, sizeof(_RGFW->keyboard)); }
+/*
+	this is the end of keycode data
+*/
+
+RGFW_genericFunc RGFW_setEventCallback(RGFW_eventType type, RGFW_genericFunc func) {
+	RGFW_ASSERT(type > RGFW_eventNone && type < RGFW_eventCount);
+	RGFW_init();
+
+	RGFW_genericFunc old = _RGFW->callbacks[type];
+	_RGFW->callbacks[type] = func;
+
+	return old;
+}
+
+void RGFW_setDualEventCallback(RGFW_eventType type, RGFW_genericFunc func, RGFW_genericFunc* first, RGFW_genericFunc* second) {
+	RGFW_genericFunc func1 = RGFW_setEventCallback(type, func);
+	RGFW_genericFunc func2 = RGFW_setEventCallback(type + 1, func);
+
+	if (first) *first = func1;
+	if (second) *second = func2;
+}
+
+void RGFW_setAllEventCallbacks(RGFW_genericFunc func, RGFW_callbacks* callbacks) {
+	for (RGFW_eventType i = RGFW_eventNone + 1; i < RGFW_eventCount; i++) {
+		if (callbacks) callbacks->arr[i] = _RGFW->callbacks[i];
+		RGFW_setEventCallback(i, func);
+	}
+}
+
+RGFW_debugFunc RGFW_setDebugCallback(RGFW_debugFunc func) {
+	RGFW_init();
+	RGFW_debugFunc prev = _RGFW->debugCallbackSrc;
+	_RGFW->debugCallbackSrc = func;
+	return prev;
+}
+
+void RGFW_eventQueuePushAndCall(const RGFW_event* event) {
+	RGFW_ASSERT(event->type > RGFW_eventNone && event->type < RGFW_eventCount);
+	if (_RGFW->callbacks[event->type]) (_RGFW->callbacks[event->type])(event);
+	RGFW_eventQueuePush(event);
+}
+
+void RGFW_windowMaximizedCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
+	win->internal.flags |= RGFW_windowMaximize;
+	win->x = x;
+	win->y = y;
+	win->w = w;
+	win->h = h;
+
+	if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_windowMaximized;
+	event.update.x = x;
+	event.update.y = y;
+	event.update.w = w;
+	event.update.h = h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowMinimizedCallback(RGFW_window* win) {
+	win->internal.flags |= RGFW_windowMinimize;
+
+	if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_windowMinimized;
+	event.update.x = win->x;
+	event.update.y = win->y;
+	event.update.w = win->w;
+	event.update.h = win->h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowRestoredCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
+	win->internal.flags &= ~(u32)RGFW_windowMinimize;
+	win->x = x;
+	win->y = y;
+	win->w = w;
+	win->h = h;
+
+	if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32)RGFW_windowMaximize;
+
+	if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_windowRestored;
+	event.update.x = x;
+	event.update.y = y;
+	event.update.w = w;
+	event.update.h = h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowMovedCallback(RGFW_window* win, i32 x, i32 y) {
+	win->x = x;
+	win->y = y;
+	if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_windowMoved;
+	event.update.x = x;
+	event.update.y = y;
+	event.update.w = win->w;
+	event.update.h = win->h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowResizedCallback(RGFW_window* win, i32 w, i32 h) {
+	win->w = w;
+	win->h = h;
+
+	if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return;
+	RGFW_event event;
+	event.type = RGFW_windowResized;
+	event.update.x = win->x;
+	event.update.y = win->y;
+	event.update.w = w;
+	event.update.h = h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowCloseCallback(RGFW_window* win) {
+	win->internal.shouldClose = RGFW_TRUE;
+
+	RGFW_event event;
+	event.type = RGFW_windowClose;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_mouseMotionCallback(RGFW_window* win, i32 x, i32 y) {
+	win->internal.lastMouseX = x;
+	win->internal.lastMouseY = y;
+
+	if (!(win->internal.enabledEvents & RGFW_mouseMotionFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_mouseMotion;
+	event.mouse.x = x;
+	event.mouse.y = y;
+	event.mouse.inWindow = win->internal.mouseInside;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_rawMotionCallback(RGFW_window* win, float x, float y) {
+	_RGFW->vectorX = x;
+	_RGFW->vectorY = y;
+	if (!(win->internal.enabledEvents & RGFW_mouseRawMotionFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_mouseRawMotion;
+	event.delta.x = x;
+	event.delta.y = y;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowRefreshCallback(RGFW_window* win, i32 x, i32 y, i32 w, i32 h) {
+	if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return;
+	RGFW_event event;
+	event.type = RGFW_windowRefresh;
+	event.update.x = x;
+	event.update.y = y;
+	event.update.w = w;
+	event.update.h = h;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_windowFocusCallback(RGFW_window* win, RGFW_bool inFocus) {
+	win->internal.inFocus = inFocus;
+
+	if (win->internal.captureMouse) {
+		RGFW_window_captureMousePlatform(win, inFocus);
+	}
+
+	RGFW_event event;
+	event.common.win = win;
+	event.focus.state = inFocus;
+
+	if (inFocus == RGFW_TRUE) {
+		if ((win->internal.flags & RGFW_windowFullscreen))
+			RGFW_window_raise(win);
+
+		event.type = RGFW_windowFocusIn;
+	} else if (inFocus == RGFW_FALSE) {
+		if ((win->internal.flags & RGFW_windowFullscreen))
+			RGFW_window_minimize(win);
+
+		size_t key;
+		for (key = 0; key < RGFW_keyLast; key++) {
+			if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue;
+
+			_RGFW->keyboard[key].current = RGFW_FALSE;
+			if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) {
+				RGFW_keyCallback(win, (u8)key, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
+			}
+		}
+
+		RGFW_resetKey();
+		event.type = RGFW_windowFocusOut;
+	}
+
+	event.common.win = win;
+
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_mouseNotifyCallback(RGFW_window* win, i32 x, i32 y, RGFW_bool status) {
+	win->internal.mouseInside = status;
+	_RGFW->windowState.win = win;
+
+	win->internal.lastMouseX = x;
+	win->internal.lastMouseY = y;
+
+	RGFW_event event;
+	event.common.win = win;
+	event.mouse.x = x;
+	event.mouse.y = y;
+	event.mouse.inWindow = win->internal.mouseInside;
+
+	if (status) {
+		if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return;
+		_RGFW->windowState.mouseEnter =  RGFW_TRUE;
+		_RGFW->windowState.win = win;
+		event.type = RGFW_mouseEnter;
+	} else {
+		if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return;
+		_RGFW->windowState.winLeave = win;
+		_RGFW->windowState.mouseLeave =  RGFW_TRUE;
+		event.type = RGFW_mouseLeave;
+	}
+
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_dataDropCallback(RGFW_window* win, const char* data, size_t size, RGFW_dataTransferType dataType) {
+	if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || !(win->internal.flags & RGFW_windowAllowDND))
+		return;
+
+	_RGFW->windowState.win = win;
+	_RGFW->windowState.dataDrop = RGFW_TRUE;
+	_RGFW->windowState.dataSize = size;
+
+	RGFW_dataDropNode node;
+	RGFW_MEMZERO(&node, sizeof(node));
+	node.data = data;
+	node.size = size;
+	node.type = dataType;
+	node.next = NULL;
+
+	RGFW_event event;
+	event.type = RGFW_dataDrop;
+	event.drop.value = &node;
+	event.drop.win = win;
+
+	if (_RGFW->callbacks[event.type]) (_RGFW->callbacks[event.type])(&event);
+
+	if (_RGFW->queueEvents == RGFW_TRUE || _RGFW->dndBuild) {
+		if (_RGFW->dndRoot == NULL) {
+			_RGFW->dndRoot = (RGFW_dataDropNode*)RGFW_ALLOC(sizeof(RGFW_dataDropNode));
+			_RGFW->dndCur =	_RGFW->dndRoot;
+		} else if (_RGFW->dndCur) {
+			_RGFW->dndCur->next = (RGFW_dataDropNode*)RGFW_ALLOC(sizeof(RGFW_dataDropNode));
+			_RGFW->dndCur = _RGFW->dndCur->next;
+		} else { RGFW_ASSERT(0); }
+
+		char* dataCopy = (char*)RGFW_ALLOC(size);
+		RGFW_MEMCPY(dataCopy, data, size);
+		node.data = dataCopy;
+
+		RGFW_MEMCPY(_RGFW->dndCur, &node, sizeof(node));
+
+		event.drop.value = _RGFW->dndCur;
+		RGFW_eventQueuePush(&event);
+	}
+}
+
+void RGFW_dataDragCallback(RGFW_window* win, RGFW_dataTransferType dataType, RGFW_dndActionType action, i32 x, i32 y) {
+	if (!(win->internal.enabledEvents & RGFW_dataDragFlag) || !(win->internal.flags & RGFW_windowAllowDND)) return;
+
+	_RGFW->windowState.win = win;
+	_RGFW->windowState.dataDragging = RGFW_TRUE;
+	_RGFW->windowState.dropX = x;
+	_RGFW->windowState.dropY = y;
+
+	RGFW_event event;
+	event.type = RGFW_dataDrag;
+	event.drag.x = x;
+	event.drag.y = y;
+	event.drag.action = action;
+	event.drag.dataType = dataType;
+	event.common.win = win;
+
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_keyCharCallback(RGFW_window* win, u32 codepoint) {
+	if (!(win->internal.enabledEvents & RGFW_keyCharFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_keyChar;
+	event.keyChar.value = codepoint;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_keyCallback(RGFW_window* win, RGFW_key key, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool press) {
+	RGFW_event event;
+
+	if (press) {
+		if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
+		event.type = RGFW_keyPressed;
+	} else {
+		if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
+		event.type = RGFW_keyReleased;
+	}
+
+	_RGFW->keyboard[key].prev = _RGFW->keyboard[key].current;
+	_RGFW->keyboard[key].current = press;
+
+	event.key.value = key;
+	event.key.repeat = repeat;
+	event.key.mod = mod;
+	event.key.state = press;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_mouseButtonCallback(RGFW_window* win, RGFW_mouseButton button, RGFW_bool press) {
+	RGFW_event event;
+
+	if (press) {
+		if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return;
+		event.type = RGFW_mouseButtonPressed;
+	} else {
+		if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return;
+		event.type = RGFW_mouseButtonReleased;
+	}
+
+	_RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current;
+	_RGFW->mouseButtons[button].current = press;
+
+	event.button.value = button;
+	event.button.state = press;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_mouseScrollCallback(RGFW_window* win, float x, float y) {
+	if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return;
+	_RGFW->scrollX = x;
+	_RGFW->scrollY = y;
+
+	RGFW_event event;
+	event.type = RGFW_mouseScroll;
+	event.delta.x = x;
+	event.delta.y = y;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_scaleUpdatedCallback(RGFW_window* win, float scaleX, float scaleY) {
+	if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return;
+
+	RGFW_event event;
+	event.type = RGFW_scaleUpdated;
+	event.scale.x = scaleX;
+	event.scale.y = scaleY;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+void RGFW_monitorCallback(RGFW_window* win, const RGFW_monitor* monitor, RGFW_bool connected) {
+	if (win) {
+		if (connected && !(win->internal.enabledEvents & RGFW_monitorConnectedFlag)) return;
+		if (!connected && !(win->internal.enabledEvents & RGFW_monitorDisconnectedFlag)) return;
+	}
+
+	RGFW_event event;
+	event.type = (connected) ? (RGFW_eventType)(RGFW_monitorConnected) : (RGFW_eventType)(RGFW_monitorDisconnected);
+	event.monitor.monitor = monitor;
+	event.monitor.state = connected;
+	event.common.win = win;
+	RGFW_eventQueuePushAndCall(&event);
+}
+
+#ifdef RGFW_DEBUG
+#include <stdio.h>
+#endif
+
+void RGFW_debugCallback(RGFW_debugType type, RGFW_errorCode code, const char* msg) {
+	RGFW_debugInfo info;
+	info.type = type;
+	info.code = code;
+	info.msg = msg;
+
+	if (_RGFW && _RGFW->debugCallbackSrc) _RGFW->debugCallbackSrc(&info);
+
+    #ifdef RGFW_DEBUG
+	switch (type) {
+		case RGFW_typeInfo: RGFW_PRINTF("RGFW INFO (%i %i): %s", type, code, msg); break;
+		case RGFW_typeError: RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, code, msg); break;
+		case RGFW_typeWarning: RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, code, msg); break;
+		default: break;
+	}
+
+	RGFW_PRINTF("\n");
+	#endif
+}
+
+void RGFW_window_checkMode(RGFW_window* win);
+void RGFW_window_checkMode(RGFW_window* win) {
+	if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) {
+		RGFW_windowMinimizedCallback(win);
+	} else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) {
+		RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
+	} else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
+				(win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) {
+		RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
+	}
+}
+
+/*
+no more event call back defines
+*/
+
+size_t RGFW_sizeofInfo(void) { return sizeof(RGFW_info); }
+size_t RGFW_sizeofNativeImage(void) { return sizeof(RGFW_nativeImage); }
+size_t RGFW_sizeofSurface(void) { return sizeof(RGFW_surface); }
+size_t RGFW_sizeofWindow(void) { return sizeof(RGFW_window); }
+size_t RGFW_sizeofWindowSrc(void) { return sizeof(RGFW_window_src); }
+
+RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { return &win->src; }
+RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; }
+RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; }
+u32 RGFW_window_getFlags(RGFW_window* win) { return win->internal.flags; }
+RGFW_key RGFW_window_getExitKey(RGFW_window* win) { return win->internal.exitKey; }
+void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { win->internal.exitKey = key; }
+void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { win->internal.enabledEvents = events; }
+RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { return win->internal.enabledEvents; }
+void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) {   RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events);  }
+void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); }
+void* RGFW_window_getUserPtr(RGFW_window* win) { return win->userPtr; }
+void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { win->userPtr = ptr; }
+
+RGFW_bool RGFW_window_getSizeInPixels(RGFW_window* win, i32* w, i32* h) {
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon == NULL) return RGFW_FALSE;
+
+	if (w) *w = (i32)((float)win->w * mon->pixelRatio);
+	if (h) *h = (i32)((float)win->h * mon->pixelRatio);
+
+	return RGFW_TRUE;
+}
+
+
+#if defined(RGFW_USE_XDL) && defined(RGFW_X11)
+	#define XDL_IMPLEMENTATION
+	#include "XDL.h"
+#endif
+
+#ifndef RGFW_NO_STATIC_CONTEXT
+
+i32 RGFW_init(void) {
+	static RGFW_info _rgfwGlobal;
+	return RGFW_init_ptr(&_rgfwGlobal);
+}
+
+
+void RGFW_deinit(void) { RGFW_deinit_ptr(_RGFW); }
+
+#else
+
+RGFW_info* _rgfwGlobal;
+
+i32 RGFW_init(void) {
+	if (_rgfwGlobal != NULL) {
+		RGFW_FREE(_rgfwGlobal);
+	}
+
+	_rgfwGlobal = (RGFW_info*)RGFW_ALLOC(sizeof(RGFW_info));
+
+	return RGFW_init_ptr(&_rgfwGlobal);
+}
+
+void RGFW_deinit(void) {
+	if (_RGFW == _rgfwGlobal) {
+		RGFW_FREE(_rgfwGlobal);
+		_rgfwGlobal = NULL;
+	}
+	RGFW_deinit_ptr(_RGFW);
+}
+
+#endif
+
+i32 RGFW_initPlatform(void);
+void RGFW_deinitPlatform(void);
+
+i32 RGFW_init_ptr(RGFW_info* info) {
+    if (info == _RGFW || info == NULL) return 1;
+
+    RGFW_setInfo(info);
+    RGFW_MEMZERO(_RGFW, sizeof(RGFW_info));
+	_RGFW->queueEvents = RGFW_FALSE;
+	_RGFW->polledEvents = RGFW_FALSE;
+#ifdef RGFW_WAYLAND
+	_RGFW->useWaylandBool = RGFW_TRUE;
+#endif
+
+	#if (RGFW_PREALLOCATED_MONITORS)
+		_RGFW->monitors.freeList.head = &_RGFW->monitors.data[0];
+		_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head;
+
+		for (size_t i = 1; i < RGFW_PREALLOCATED_MONITORS; i++) {
+			RGFW_monitorNode* newNode = &_RGFW->monitors.data[i];
+			_RGFW->monitors.freeList.cur->next = newNode;
+			_RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next;
+		}
+	#endif
+
+	_RGFW->monitors.list.head = NULL;
+	_RGFW->monitors.list.head = NULL;
+    RGFW_initKeycodes();
+    i32 out = RGFW_initPlatform();
+
+	for (size_t i = 0; i < RGFW_mouseIconCount; i++) {
+        _RGFW->standardMice[i] = RGFW_createMouseStandard((RGFW_mouseIcon)i);
+	}
+
+	RGFW_pollMonitors();
+
+    RGFW_debugCallback(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized");
+
+	return out;
+}
+
+#ifndef RGFW_EGL
+void RGFW_unloadEGL(void) { }
+#endif
+
+void RGFW_deinit_ptr(RGFW_info* info) {
+    if (info == NULL) return;
+
+    RGFW_setInfo(info);
+	RGFW_unloadEGL();
+
+	for (RGFW_mouseIcon i = 0; i < RGFW_mouseIconCount; i++) {
+		if (_RGFW->standardMice[i]) RGFW_freeMouse(_RGFW->standardMice[i]);
+	}
+
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized");
+	RGFW_deinitPlatform();
+
+    _RGFW->root = NULL;
+    _RGFW->windowCount = 0;
+    RGFW_setInfo(NULL);
+}
+
+RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
+	RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
+	RGFW_ASSERT(win != NULL);
+    return RGFW_createWindowPtr(name, x, y, w, h, flags, win);
+}
+
+void RGFW_window_close(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_window_closePtr(win);
+	RGFW_FREE(win);
+}
+
+RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	if (name == NULL) name = "\0";
+
+	RGFW_MEMZERO(win, sizeof(RGFW_window));
+
+	if (_RGFW == NULL) RGFW_init();
+	_RGFW->windowCount++;
+
+	/* rect based the requested flags */
+	if (_RGFW->root == NULL) {
+		RGFW_setRootWindow(win);
+	}
+
+	/* set and init the new window's data */
+	win->x = x;
+	win->y = y;
+	win->w = w;
+	win->h = h;
+	win->internal.mouse = _RGFW->standardMice[RGFW_mouseNormal];
+	win->internal.flags = flags;
+	win->internal.enabledEvents = RGFW_allEventFlags;
+
+	RGFW_windowFlags reservedFlags = flags & (RGFW_windowScaleToMonitor);
+	flags &= ~reservedFlags;
+
+	RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win);
+
+	flags |= reservedFlags;
+
+#ifndef RGFW_X11
+	RGFW_window_setFlagsInternal(win, flags, 0);
+#endif
+
+#ifdef RGFW_OPENGL
+	win->src.gfxType = 0;
+	if (flags & RGFW_windowOpenGL)
+		RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL());
+#endif
+
+#ifdef RGFW_EGL
+	if (flags & RGFW_windowEGL)
+		RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL());
+#endif
+
+	/* X11 creates the window after the OpenGL context is created (because of visual garbage),
+		 * so we have to wait to set the flags
+		 * This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used
+		 * if a window is created, CreateContext will delete the window and create a new one
+		 * */
+#ifdef RGFW_X11
+	RGFW_window_setFlagsInternal(win, flags, 0);
+#endif
+
+#ifdef RGFW_MACOS
+	/*NOTE: another OpenGL/setFlags related hack, this because OSX the 'view' class must be setup after the NSOpenGL view is made AND after setFlags happens */
+	RGFW_osx_initView(win);
+#endif
+
+#ifdef RGFW_WAYLAND
+	/* recieve all events needed to configure the surface */
+	/* also gets the wl_outputs */
+	if (RGFW_usingWayland()) {
+		wl_display_roundtrip(_RGFW->wl_display);
+		/* NOTE: this is a hack so that way wayland spawns a window, even if nothing is drawn */
+		if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) {
+			u8* data = (u8*)RGFW_ALLOC((u32)(win->w * win->h * 3));
+			RGFW_MEMZERO(data, (u32)(win->w * win->h * 3) * sizeof(u8));
+			RGFW_surface* surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8);
+			RGFW_window_blitSurface(win, surface);
+			RGFW_FREE(data);
+			RGFW_surface_free(surface);
+		}
+	}
+#endif
+
+	if (!(flags & RGFW_windowHideMouse)) {
+		RGFW_window_setMouseDefault(win);
+	}
+
+	RGFW_window_setName(win, name);
+	if (!(flags & RGFW_windowHide)) {
+		flags |= RGFW_windowHide;
+		RGFW_window_show(win);
+	}
+
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a new window was created");
+
+	return ret;
+}
+
+void RGFW_window_closePtr(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	if (win->internal.captureMouse) {
+		RGFW_window_captureMouse(win, RGFW_FALSE);
+	}
+
+	#ifdef RGFW_EGL
+	if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) {
+		RGFW_window_deleteContext_EGL(win, win->src.ctx.egl);
+		win->src.ctx.egl = NULL;
+	}
+	#endif
+
+	#ifdef RGFW_OPENGL
+	if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) {
+		RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native);
+		win->src.ctx.native = NULL;
+	}
+	#endif
+
+	RGFW_window_closePlatform(win);
+
+	RGFW_clipboard_switch(NULL);
+
+	_RGFW->windowCount--;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
+
+	if (_RGFW->windowCount == 0 && !(win->internal.flags & RGFW_noDeinitOnClose)) RGFW_deinit();
+}
+
+void RGFW_setQueueEvents(RGFW_bool queue) {  _RGFW->queueEvents = RGFW_BOOL(queue); }
+
+void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; }
+
+void RGFW_eventQueuePush(const RGFW_event* event) {
+	if (_RGFW->queueEvents == RGFW_FALSE) return;
+	RGFW_ASSERT(_RGFW->eventLen >= 0);
+
+	if (_RGFW->eventLen >= RGFW_MAX_EVENTS) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue.");
+		RGFW_eventQueueFlush();
+		return;
+	}
+
+	i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS;
+	_RGFW->eventLen += 1;
+	_RGFW->events[eventTop] = *event;
+}
+
+RGFW_event* RGFW_eventQueuePop(void) {
+	RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS);
+	RGFW_event* ev;
+
+	if (_RGFW->eventLen == 0) {
+		return NULL;
+	}
+
+	ev = &_RGFW->events[_RGFW->eventBottom];
+	_RGFW->eventLen -= 1;
+    _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS;
+
+	return ev;
+}
+
+RGFW_bool RGFW_checkEvent(RGFW_event* event) {
+	if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
+		_RGFW->queueEvents = RGFW_TRUE;
+		RGFW_pollEvents();
+		_RGFW->polledEvents = RGFW_TRUE;
+	}
+
+	if (RGFW_checkQueuedEvent(event) == RGFW_FALSE) {
+		_RGFW->polledEvents = RGFW_FALSE;
+		return RGFW_FALSE;
+	}
+
+	return RGFW_TRUE;
+}
+
+RGFW_bool RGFW_checkQueuedEvent(RGFW_event* event) {
+	RGFW_event* ev;
+	_RGFW->queueEvents = RGFW_TRUE;
+	/* check queued events */
+	ev = RGFW_eventQueuePop();
+	if (ev != NULL) {
+		*event = *ev;
+		return RGFW_TRUE;
+    }
+
+	return RGFW_FALSE;
+}
+
+void RGFW_resetPrevState(void) {
+	size_t i; /*!< reset each previous state  */
+    for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current;
+    for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current;
+	_RGFW->scrollX = 0.0f;
+	_RGFW->scrollY = 0.0f;
+	_RGFW->vectorX = (float)0.0f;
+	_RGFW->vectorY = (float)0.0f;
+	RGFW_MEMZERO(&_RGFW->windowState, sizeof(_RGFW->windowState));
+
+	for (RGFW_dataDropNode* node = _RGFW->dndRoot; node; ) {
+		RGFW_dataDropNode* next = node->next;
+		RGFW_FREE(node);
+		node = next;
+	}
+
+	_RGFW->dndRoot = NULL;
+	_RGFW->dndCur = NULL;
+}
+
+RGFW_bool RGFW_isKeyPressed(RGFW_key key) {
+	RGFW_ASSERT(_RGFW != NULL);
+    return _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev;
+}
+RGFW_bool RGFW_isKeyDown(RGFW_key key) {
+	RGFW_ASSERT(_RGFW != NULL);
+	return _RGFW->keyboard[key].current;
+}
+RGFW_bool RGFW_isKeyReleased(RGFW_key key) {
+	RGFW_ASSERT(_RGFW != NULL);
+	return !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev;
+}
+
+
+RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) {
+	RGFW_ASSERT(_RGFW != NULL);
+	return _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev;
+}
+RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) {
+	RGFW_ASSERT(_RGFW != NULL);
+	return _RGFW->mouseButtons[button].current;
+}
+RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) {
+	RGFW_ASSERT(_RGFW != NULL);
+	return !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev;
+}
+
+void RGFW_getMouseScroll(float* x, float* y) {
+	RGFW_ASSERT(_RGFW != NULL);
+	if (x) *x = _RGFW->scrollX;
+	if (y) *y = _RGFW->scrollY;
+}
+
+void RGFW_getMouseVector(float* x, float* y) {
+	RGFW_ASSERT(_RGFW != NULL);
+	if (x) *x = _RGFW->vectorX;
+	if (y) *y = _RGFW->vectorY;
+}
+
+RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; }
+RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; }
+RGFW_bool RGFW_window_isMouseInside(RGFW_window* win) { return win->internal.mouseInside;  }
+
+RGFW_bool RGFW_window_isDataDragging(RGFW_window* win) { return RGFW_window_getDataDrag(win, (i32*)NULL, (i32*)NULL); }
+RGFW_bool RGFW_window_didDataDrop(RGFW_window* win) { return RGFW_window_getDataDrop(win) != NULL;}
+
+
+RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y) {
+	if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE;
+	if (x) *x = _RGFW->windowState.dropX;
+	if (y) *y =  _RGFW->windowState.dropY;
+	return RGFW_TRUE;
+}
+RGFW_dataDropNode* RGFW_window_getDataDrop(RGFW_window* win) {
+	if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return NULL;
+	return _RGFW->dndRoot;
+}
+
+RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event) {
+	if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) {
+		_RGFW->queueEvents = RGFW_TRUE;
+		RGFW_pollEvents();
+		_RGFW->polledEvents = RGFW_TRUE;
+	}
+
+	if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) {
+		_RGFW->polledEvents = RGFW_FALSE;
+		return RGFW_FALSE;
+	}
+
+	return RGFW_TRUE;
+}
+
+RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event) {
+	RGFW_event* ev;
+	RGFW_ASSERT(win != NULL);
+	_RGFW->queueEvents = RGFW_TRUE;
+	/* check queued events */
+	ev = RGFW_window_eventQueuePop(win);
+	if (ev == NULL) return RGFW_FALSE;
+
+	*event = *ev;
+	return RGFW_TRUE;
+}
+
+RGFW_event* RGFW_window_eventQueuePop(RGFW_window* win) {
+	RGFW_event* ev = RGFW_eventQueuePop();
+	if (ev == NULL) return ev;
+
+	for (i32 i = 1; i < _RGFW->eventLen && ev->common.win != win && ev->common.win != NULL; i++) {
+		RGFW_eventQueuePush(ev);
+		ev = RGFW_eventQueuePop();
+	}
+
+	if (ev->common.win != win && ev->common.win != NULL) {
+		return NULL;
+	}
+
+	return ev;
+}
+
+void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; }
+RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; }
+
+#ifndef RGFW_EGL
+RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; }
+#endif
+
+void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) {
+	if (flags & RGFW_windowNoBorder)            RGFW_window_setBorder(win, 0);
+	else if (cmpFlags & RGFW_windowNoBorder)    RGFW_window_setBorder(win, 1);
+	if (flags & RGFW_windowMaximize)            RGFW_window_maximize(win);
+	else if (cmpFlags & RGFW_windowMaximize)    RGFW_window_restore(win);
+	if (flags & RGFW_windowMinimize)            RGFW_window_minimize(win);
+	else if (cmpFlags & RGFW_windowMinimize)    RGFW_window_restore(win);
+	if (flags & RGFW_windowCenter)              RGFW_window_center(win);
+	if (flags & RGFW_windowCenterCursor)        RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2));
+	if (flags & RGFW_windowFullscreen)          RGFW_window_setFullscreen(win, RGFW_TRUE);
+	else if (cmpFlags & RGFW_windowFullscreen)  RGFW_window_setFullscreen(win, 0);
+	if (flags & RGFW_windowHideMouse)           RGFW_window_showMouse(win, 0);
+	else if (cmpFlags & RGFW_windowHideMouse)   RGFW_window_showMouse(win, 1);
+	if (flags & RGFW_windowHide)                RGFW_window_hide(win);
+	else if (cmpFlags & RGFW_windowHide)        RGFW_window_show(win);
+	if (flags & RGFW_windowFloating)            RGFW_window_setFloating(win, 1);
+	else if (cmpFlags & RGFW_windowFloating)    RGFW_window_setFloating(win, 0);
+	if (flags & RGFW_windowRawMouse)			RGFW_window_setRawMouseMode(win, RGFW_TRUE);
+	else if (cmpFlags & RGFW_windowRawMouse)	RGFW_window_setRawMouseMode(win, RGFW_FALSE);
+	if (flags & RGFW_windowCaptureMouse)			RGFW_window_captureRawMouse(win, RGFW_TRUE);
+	else if (cmpFlags & RGFW_windowCaptureMouse)	RGFW_window_captureMouse(win, RGFW_FALSE);
+	if (flags & RGFW_windowFocus)               RGFW_window_focus(win);
+	if (flags & RGFW_windowScaleToMonitor)      RGFW_window_scaleToMonitor(win);
+
+	if (flags & RGFW_windowNoResize) {
+	    RGFW_window_setMaxSize(win, win->w, win->h);
+	    RGFW_window_setMinSize(win, win->w, win->h);
+	} else if (cmpFlags & RGFW_windowNoResize) {
+		RGFW_window_setMaxSize(win, 0, 0);
+		RGFW_window_setMinSize(win, 0, 0);
+	}
+
+	win->internal.flags = flags;
+}
+
+
+void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); }
+
+RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
+#ifdef RGFW_WASM
+    return RGFW_TRUE;
+#else
+    return RGFW_BOOL(win->internal.inFocus);
+#endif
+}
+
+void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; }
+void RGFW_setBuildDND(RGFW_bool state) { _RGFW->dndBuild = state; }
+
+#ifndef RGFW_X11
+void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
+#endif
+
+RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y) {
+	RGFW_ASSERT(win != NULL);
+	if (x) *x = win->internal.lastMouseX;
+	if (y) *y = win->internal.lastMouseY;
+	return RGFW_TRUE;
+}
+
+RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key) { return RGFW_isKeyPressed(key)  && RGFW_window_isInFocus(win); }
+RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); }
+RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); }
+
+RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); }
+RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); }
+RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); }
+
+
+
+#ifndef RGFW_X11
+void* RGFW_getDisplay_X11(void) { return NULL; }
+u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; }
+#endif
+
+#ifndef RGFW_WAYLAND
+struct wl_display* RGFW_getDisplay_Wayland(void) { return NULL; }
+struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
+#endif
+
+#ifndef RGFW_WINDOWS
+void* RGFW_window_getHWND(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
+void* RGFW_window_getHDC(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
+#endif
+
+#ifndef RGFW_MACOS
+void* RGFW_window_getView_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
+void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { RGFW_UNUSED(win); RGFW_UNUSED(layer); }
+void* RGFW_getLayer_OSX(void) { return NULL; }
+void* RGFW_window_getWindow_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; }
+#endif
+
+void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) {
+	if (set) *var |=  mask;
+	else     *var &= ~mask;
+}
+
+void RGFW_window_center(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon == NULL) return;
+
+	RGFW_window_move(win, mon->x + ((i32)(mon->mode.w - win->w) / 2), mon->y + ((mon->mode.h - win->h) / 2));
+}
+
+RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor* mon, RGFW_window* win) {
+	RGFW_monitorMode mode;
+    RGFW_ASSERT(win != NULL);
+
+	mode.w = win->w;
+	mode.h = win->h;
+	RGFW_bool ret = RGFW_monitor_requestMode(mon, &mode, RGFW_monitorScale);
+
+	/* move window to monitor origin so it doesn't move to the next monitor */
+	RGFW_window_move(win, mon->x, mon->y);
+
+	return ret;
+}
+
+void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
+    if (bpp == 32) bpp = 24;
+    mode->red = mode->green = mode->blue = (u8)(bpp / 3);
+
+    u32 delta = bpp - (mode->red * 3); /* handle leftovers */
+    if (delta >= 1) mode->green = mode->green + 1;
+    if (delta == 2) mode->red = mode->red + 1;
+}
+
+RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode* mon, RGFW_monitorMode* mon2, RGFW_modeRequest request) {
+	RGFW_ASSERT(mon);
+	RGFW_ASSERT(mon2);
+
+	return (((mon->w == mon2->w && mon->h == mon2->h) || !(request & RGFW_monitorScale)) &&
+			((mon->refreshRate == mon2->refreshRate) || !(request & RGFW_monitorRefresh)) &&
+			((mon->red == mon2->red && mon->green == mon2->green && mon->blue == mon2->blue) || !(request & RGFW_monitorRGB)));
+}
+
+RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
+	return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_isKeyDown(win->internal.exitKey)));
+}
+
+void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
+	if (shouldClose)  {
+		RGFW_windowCloseCallback(win);
+	} else {
+		win->internal.shouldClose = RGFW_FALSE;
+	}
+}
+
+void RGFW_window_scaleToMonitor(RGFW_window* win) {
+	RGFW_monitor* monitor = RGFW_window_getMonitor(win);
+	if (monitor->scaleX == 0 && monitor->scaleY == 0)
+		return;
+
+	RGFW_window_resize(win, (i32)(monitor->scaleX * (float)win->w), (i32)(monitor->scaleY * (float)win->h));
+}
+
+void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor* m) {
+	RGFW_window_move(win, m->x + win->x, m->y + win->y);
+}
+
+RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format) {
+	RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
+	RGFW_MEMZERO(surface, sizeof(RGFW_surface));
+	RGFW_createSurfacePtr(data, w, h, format, surface);
+	return surface;
+}
+
+void RGFW_surface_setConvertFunc(RGFW_surface* surface, RGFW_convertImageDataFunc func) {
+	surface->convertFunc = func;
+}
+
+void RGFW_surface_free(RGFW_surface* surface) {
+	RGFW_surface_freePtr(surface);
+	RGFW_FREE(surface);
+}
+
+RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) {
+	return &surface->native;
+}
+
+RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
+	RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface));
+	RGFW_MEMZERO(surface, sizeof(RGFW_surface));
+	RGFW_window_createSurfacePtr(win, data, w, h, format, surface);
+	return surface;
+}
+
+#ifndef RGFW_X11
+RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	RGFW_UNUSED(win);
+	return RGFW_createSurfacePtr(data, w, h, format, surface);
+}
+#endif
+
+const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = {
+	{ 0, 1, 2, 3, 3 }, /* RGFW_formatRGB8 */
+	{ 2, 1, 0, 3, 3 }, /* RGFW_formatBGR8 */
+	{ 0, 1, 2, 3, 4 }, /* RGFW_formatRGBA8 */
+	{ 1, 2, 3, 0, 4 }, /* RGFW_formatARGB8 */
+	{ 2, 1, 0, 3, 4 }, /* RGFW_formatBGRA8 */
+	{ 3, 2, 1, 0, 4 }, /* RGFW_formatABGR8 */
+};
+
+
+void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_convertImageDataFunc func) {
+	RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE, func);
+}
+
+RGFWDEF void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit);
+void RGFW_convertImageData64(u8* dest_data, u8* src_data, const RGFW_colorLayout* srcLayout, const RGFW_colorLayout* destLayout, size_t count, RGFW_bool is64bit) {
+	u32 i, i2 = 0;
+	u8 rgba[4] = {0};
+
+	for (i = 0; i < count; i++) {
+		const u8* src_px = &src_data[i * srcLayout->channels];
+		u8* dst_px = &dest_data[i2 * destLayout->channels];
+        rgba[0] = src_px[srcLayout->r];
+        rgba[1] = src_px[srcLayout->g];
+        rgba[2] = src_px[srcLayout->b];
+        rgba[3] = (srcLayout->channels == 4) ? src_px[srcLayout->a] : 255;
+
+        dst_px[destLayout->r] = rgba[0];
+        dst_px[destLayout->g] = rgba[1];
+        dst_px[destLayout->b] = rgba[2];
+		if (destLayout->channels == 4)
+			dst_px[destLayout->a] = rgba[3];
+
+		i2 += 1 + is64bit;
+	}
+}
+
+void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_bool is64bit, RGFW_convertImageDataFunc func) {
+	RGFW_ASSERT(dest_data && src_data);
+
+    u32 count = (u32)(dest_w * dest_h);
+
+	if (src_format == dest_format) {
+		u32 channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3;
+        RGFW_MEMCPY(dest_data, src_data, count * channels);
+        return;
+    }
+
+    const RGFW_colorLayout* srcLayout  = &RGFW_layouts[src_format];
+    const RGFW_colorLayout* destLayout = &RGFW_layouts[dest_format];
+
+	if (is64bit || func == NULL) {
+		RGFW_convertImageData64(dest_data, src_data, srcLayout, destLayout, count, is64bit);
+	} else {
+		func(dest_data, src_data, srcLayout, destLayout, count);
+	}
+}
+
+RGFW_monitorNode* RGFW_monitors_add(const RGFW_monitor* mon) {
+	RGFW_monitorNode* node = NULL;
+
+	#if (RGFW_PREALLOCATED_MONITORS)
+		node = _RGFW->monitors.freeList.head;
+		if (node) {
+			_RGFW->monitors.freeList.head = node->next;
+			if (_RGFW->monitors.freeList.head == NULL) {
+				_RGFW->monitors.freeList.cur = NULL;
+			}
+		} else
+	#elif !defined(RGFW_NO_ALLOCATE_MONITORS)
+	{
+		node = (RGFW_monitorNode*)RGFW_ALLOC(sizeof(RGFW_monitorNode));
+	}
+	#endif
+
+	if (node == NULL) return NULL;
+
+	node->next = NULL;
+
+	if (_RGFW->monitors.list.head == NULL) {
+		_RGFW->monitors.list.head = node;
+	} else {
+		_RGFW->monitors.list.cur->next = node;
+	}
+
+	_RGFW->monitors.list.cur = node;
+
+	if (mon) node->mon = *mon;
+	node->mon.node = node;
+	node->disconnected = RGFW_FALSE;
+
+	_RGFW->monitors.count += 1;
+	return node;
+}
+
+void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) {
+	_RGFW->monitors.count -= 1;
+
+	/* remove node from the list */
+	if (prev != node) {
+		prev->next = node->next;
+	} else { /* node is the head */
+		_RGFW->monitors.list.head = NULL;
+	}
+
+	node->next = NULL;
+
+	#if (RGFW_PREALLOCATED_MONITORS)
+	/* check if the monitor was allocated in the heap or not */
+	if (node >= _RGFW->monitors.data && node <= &_RGFW->monitors.data[RGFW_PREALLOCATED_MONITORS - 1]) {
+		/* move node to the free list */
+		if (_RGFW->monitors.freeList.head == NULL) {
+			_RGFW->monitors.freeList.head = node;
+		} else {
+			_RGFW->monitors.freeList.cur->next = node;
+		}
+
+		_RGFW->monitors.freeList.cur = node;
+	} else
+	{
+	#elif !defined(RGFW_NO_ALLOCATE_MONITORS)
+		RGFW_FREE(node);
+	#endif
+	}
+}
+
+void RGFW_monitors_refresh(void) {
+	RGFW_monitorNode* prev = _RGFW->monitors.list.head;
+	for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
+		if (node->disconnected == RGFW_FALSE) continue;
+
+		RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
+		RGFW_monitors_remove(node, prev);
+		prev = node;
+	}
+}
+
+RGFW_monitorMode* RGFW_monitor_getModes(RGFW_monitor* monitor, size_t* count) {
+	size_t num = RGFW_monitor_getModesPtr(monitor, NULL);
+	RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(num * sizeof(RGFW_monitorNode));
+	num = RGFW_monitor_getModesPtr(monitor, &modes);
+
+	if (count) *count = num;
+	return modes;
+}
+
+void RGFW_freeModes(RGFW_monitorMode* modes) {
+	RGFW_FREE(modes);
+}
+
+RGFW_bool RGFW_monitor_findClosestMode(RGFW_monitor* monitor, RGFW_monitorMode* mode, RGFW_monitorMode* closest) {
+	size_t count = RGFW_monitor_getModesPtr(monitor, NULL);
+	RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(count * sizeof(RGFW_monitorNode));
+	count = RGFW_monitor_getModesPtr(monitor, &modes);
+
+	RGFW_monitorMode* chosen = NULL;
+
+	u32 topScore = 1;
+	for (size_t i = 0; i < count; i++) {
+		RGFW_monitorMode* mode2 = &modes[i];
+
+		u32 score = 0;
+		if (mode->w == mode2->w && mode->h == mode2->h) score += 1000;
+		if (mode->red == mode2->red && mode->green == mode2->green && mode->blue == mode2->blue) score += 100;
+		if (mode->refreshRate == mode->refreshRate) score += 10;
+
+		if (score > topScore) {
+			topScore = score;
+			chosen = mode2;
+		}
+	}
+
+	if (chosen && closest) *closest = *chosen;
+
+
+	RGFW_FREE(modes);
+
+	return (chosen == NULL) ? RGFW_FALSE : RGFW_TRUE;
+}
+
+RGFW_bool RGFW_monitor_getPosition(RGFW_monitor* monitor, i32* x, i32* y) {
+	if (x) *x = monitor->x;
+	if (y) *y = monitor->y;
+	return RGFW_TRUE;
+}
+
+const char* RGFW_monitor_getName(RGFW_monitor* monitor) {
+	return monitor->name;
+}
+
+RGFW_bool RGFW_monitor_getScale(RGFW_monitor* monitor, float* x, float* y) {
+	if (x) *x = monitor->scaleX;
+	if (y) *y = monitor->scaleY;
+	return RGFW_TRUE;
+}
+
+RGFW_bool RGFW_monitor_getPhysicalSize(RGFW_monitor* monitor, float* w, float* h) {
+	if (w) *w = monitor->physW;
+	if (h) *h = monitor->physH;
+	return RGFW_TRUE;
+}
+
+void RGFW_monitor_setUserPtr(RGFW_monitor* monitor, void* userPtr) {
+	monitor->userPtr = userPtr;
+}
+
+void* RGFW_monitor_getUserPtr(RGFW_monitor* monitor) {
+	return monitor->userPtr;
+}
+
+RGFW_bool RGFW_monitor_getMode(RGFW_monitor* monitor, RGFW_monitorMode* mode) {
+	if (mode) *mode = monitor->mode;
+	return RGFW_TRUE;
+}
+
+RGFW_gammaRamp* RGFW_monitor_getGammaRamp(RGFW_monitor* monitor) {
+	RGFW_gammaRamp* ramp = (RGFW_gammaRamp*)RGFW_ALLOC(sizeof(RGFW_gammaRamp));
+	ramp->count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
+	ramp->red = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
+	ramp->green = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
+	ramp->blue = (u16*)RGFW_ALLOC(sizeof(u16) * ramp->count);
+	ramp->count = RGFW_monitor_getGammaRampPtr(monitor, ramp);
+
+	return ramp;
+}
+
+void RGFW_freeGammaRamp(RGFW_gammaRamp* ramp) {
+	RGFW_FREE(ramp->red);
+	RGFW_FREE(ramp->green);
+	RGFW_FREE(ramp->blue);
+	RGFW_FREE(ramp);
+}
+
+RGFW_bool RGFW_monitor_setGammaPtr(RGFW_monitor* monitor, float gamma, u16* ptr, size_t count) {
+	RGFW_ASSERT(monitor);
+    RGFW_ASSERT(gamma > 0.0f);
+
+	size_t i;
+    for (i = 0;  i < count;  i++) {
+        float value = (float)i / (float) (count - 1);
+		#ifndef RGFW_NO_MATH
+			value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
+		#endif
+        value = RGFW_MIN(value, 65535.f);
+
+        ptr[i] = (u16)value;
+    }
+
+    RGFW_gammaRamp ramp;
+    ramp.red = ptr;
+    ramp.green = ptr;
+    ramp.blue = ptr;
+    ramp.count = count;
+
+    return RGFW_monitor_setGammaRamp(monitor, &ramp);
+}
+
+RGFW_bool RGFW_monitor_setGamma(RGFW_monitor* monitor, float gamma) {
+	size_t count = RGFW_monitor_getGammaRampPtr(monitor, NULL);
+	u16* ptr = (u16*)RGFW_ALLOC(count * sizeof(u16));
+
+	RGFW_bool ret = RGFW_monitor_setGammaPtr(monitor, gamma, ptr, count);
+	RGFW_FREE(ptr);
+
+	return ret;
+}
+
+RGFW_monitor** RGFW_getMonitors(size_t* len) {
+	if (len != NULL) *len = 0;
+
+	size_t count = 0;
+	if (RGFW_getMonitorsPtr(0, NULL, &count) == RGFW_FALSE || count == 0) return NULL;
+
+	RGFW_monitor** monitors = (RGFW_monitor**)RGFW_ALLOC(sizeof(RGFW_monitor*) * count);
+
+	if (RGFW_getMonitorsPtr(count, monitors, &count) == RGFW_FALSE) {
+		RGFW_FREE(monitors);
+		return NULL;
+	}
+
+	if (len != NULL) *len = count;
+
+	return monitors;
+}
+
+RGFW_bool RGFW_getMonitorsPtr(size_t max, RGFW_monitor** monitors, size_t* len) {
+	RGFW_init();
+	if (len != NULL) {
+		*len = _RGFW->monitors.count;
+	}
+
+	if (monitors == NULL || max == 0) return RGFW_TRUE;
+
+
+	if (len != NULL) {
+		*len = max;
+	}
+
+	size_t i = 0;
+	RGFW_monitorNode* cur_node = _RGFW->monitors.list.head;
+	while (cur_node != NULL && i < max) {
+		monitors[i] = &cur_node->mon;
+		i++;
+		cur_node = cur_node->next;
+	}
+
+	return RGFW_TRUE;
+}
+
+RGFW_monitor* RGFW_getPrimaryMonitor(void) {
+	RGFW_init();
+	if (_RGFW->monitors.primary == NULL) {
+		_RGFW->monitors.primary = _RGFW->monitors.list.head;
+	}
+
+	return &_RGFW->monitors.primary->mon;
+}
+
+RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) {
+	return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth);
+}
+
+void RGFW_window_captureMouse(RGFW_window* win, RGFW_bool state) {
+	win->internal.captureMouse = state;
+	RGFW_window_captureMousePlatform(win, state);
+}
+
+void RGFW_window_setRawMouseMode(RGFW_window* win, RGFW_bool state) {
+	win->internal.rawMouse = state;
+	RGFW_window_setRawMouseModePlatform(win, state);
+}
+
+void RGFW_window_captureRawMouse(RGFW_window* win, RGFW_bool state) {
+	RGFW_window_captureMouse(win, state);
+	RGFW_window_setRawMouseMode(win, state);
+}
+
+RGFW_bool RGFW_window_isRawMouseMode(RGFW_window* win) { return RGFW_BOOL(win->internal.rawMouse); }
+RGFW_bool RGFW_window_isCaptured(RGFW_window* win) { return RGFW_BOOL(win->internal.captureMouse);  }
+
+void RGFW_keyUpdateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
+	if (value) win->internal.mod |= mod;
+	else win->internal.mod &= ~mod;
+}
+
+void RGFW_keyUpdateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
+	RGFW_keyUpdateKeyMod(win, RGFW_modCapsLock, capital);
+	RGFW_keyUpdateKeyMod(win, RGFW_modNumLock, numlock);
+	RGFW_keyUpdateKeyMod(win, RGFW_modControl, control);
+	RGFW_keyUpdateKeyMod(win, RGFW_modAlt, alt);
+	RGFW_keyUpdateKeyMod(win, RGFW_modShift, shift);
+	RGFW_keyUpdateKeyMod(win, RGFW_modSuper, super);
+	RGFW_keyUpdateKeyMod(win, RGFW_modScrollLock, scroll);
+}
+
+void RGFW_keyUpdateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
+	RGFW_keyUpdateKeyModsEx(win, capital, numlock,
+					RGFW_isKeyDown(RGFW_keyControlL) || RGFW_isKeyDown(RGFW_keyControlR),
+					RGFW_isKeyDown(RGFW_keyAltL) || RGFW_isKeyDown(RGFW_keyAltR),
+					RGFW_isKeyDown(RGFW_keyShiftL) || RGFW_isKeyDown(RGFW_keyShiftR),
+					RGFW_isKeyDown(RGFW_keySuperL) || RGFW_isKeyDown(RGFW_keySuperR),
+					scroll);
+}
+
+void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
+	if (show && (win->internal.flags & RGFW_windowHideMouse))
+		win->internal.flags ^= RGFW_windowHideMouse;
+	else if (!show && !(win->internal.flags & RGFW_windowHideMouse))
+		win->internal.flags |= RGFW_windowHideMouse;
+}
+
+RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) {
+	return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse);
+}
+
+RGFW_bool RGFW_window_borderless(RGFW_window* win) {
+	return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder);
+}
+
+RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); }
+RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); }
+
+RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
+	return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
+}
+
+RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcon icon) {
+	RGFW_ASSERT(win);
+	RGFW_ASSERT(icon < RGFW_mouseIconCount);
+	return RGFW_window_setMouse(win, _RGFW->standardMice[icon]);
+}
+
+RGFW_bool RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win && mouse);
+	if (mouse != _RGFW->hiddenMouse) {
+		win->internal.mouse = mouse;
+	}
+
+	return RGFW_window_setMousePlatform(win, mouse);
+}
+
+#ifndef RGFW_WINDOWS
+void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
+	RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
+}
+#endif
+
+#if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS)
+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
+	RGFW_window_showMouseFlags(win, show);
+	if (show == RGFW_FALSE) {
+		RGFW_window_setMouse(win, _RGFW->hiddenMouse);
+	} else {
+		RGFW_window_setMouse(win, win->internal.mouse);
+	}
+}
+#endif
+
+#ifndef RGFW_MACOS
+void RGFW_moveToMacOSResourceDir(void) { }
+#endif
+
+RGFWDEF RGFW_bool RGFW_isLatin(const char *string, size_t length);
+RGFW_bool RGFW_isLatin(const char *string, size_t length) {
+	for (size_t i = 0; i < length; i++) {
+        if ((u8)string[i] >= 0x80) {
+            return RGFW_TRUE;
+        }
+    }
+    return RGFW_FALSE;
+}
+
+RGFWDEF u32 RGFW_decodeUTF8(const char* string, size_t* starting_index);
+u32 RGFW_decodeUTF8(const char* string, size_t* starting_index) {
+    static const u32 offsets[] = {
+        0x00000000u, 0x00003080u, 0x000e2080u,
+        0x03c82080u, 0xfa082080u, 0x82082080u
+    };
+
+    u32 codepoint = (u8)string[(*starting_index)];
+	size_t count;
+	for (count = 1; (string[count + (*starting_index)] & 0xc0) == 0x80; count++) {
+        codepoint = (codepoint << 6) + (u8)string[count + (*starting_index)];
+	}
+
+	*starting_index += count;
+
+    RGFW_ASSERT(count <= 6);
+    return codepoint - offsets[count - 1];
+}
+
+/*
+	graphics API specific code (end of generic code)
+	starts here
+*/
+
+
+/*
+	OpenGL defines start here   (Normal, EGL, OSMesa)
+*/
+
+#if defined(RGFW_OPENGL)
+/* EGL, OpenGL */
+#define RGFW_DEFAULT_GL_HINTS { \
+	/* Stencil         */ 0, \
+	/* Samples         */ 0, \
+	/* Stereo          */ RGFW_FALSE, \
+	/* AuxBuffers      */ 0, \
+	/* DoubleBuffer    */ RGFW_TRUE, \
+	/* Red             */ 8, \
+	/* Green           */ 8, \
+	/* Blue            */ 8, \
+	/* Alpha           */ 8, \
+	/* Depth           */ 24, \
+	/* AccumRed        */ 0, \
+	/* AccumGreen      */ 0, \
+	/* AccumBlue       */ 0, \
+	/* AccumAlpha      */ 0, \
+	/* SRGB            */ RGFW_FALSE, \
+	/* Robustness      */ RGFW_FALSE, \
+	/* Debug           */ RGFW_FALSE, \
+	/* NoError         */ RGFW_FALSE, \
+	/* ReleaseBehavior */ RGFW_glReleaseNone, \
+	/* Profile         */ RGFW_glCore, \
+	/* Major           */ 1, \
+	/* Minor           */ 0, \
+	/* Share */ NULL, \
+	/* Share_EGL */ NULL, \
+	/* renderer */ RGFW_glAccelerated \
+}
+
+RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
+RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC;
+
+void RGFW_resetGlobalHints_OpenGL(void) {
+#if !defined(__cplusplus) || defined(RGFW_MACOS)
+	RGFW_globalHints_OpenGL_SRC = (RGFW_glHints)RGFW_DEFAULT_GL_HINTS;
+#else
+	RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS;
+#endif
+}
+void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints;  }
+RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; }
+
+
+void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) {
+	RGFW_UNUSED(ctx);
+
+#ifdef RGFW_WAYLAND
+	if (RGFW_usingWayland()) return (void*)ctx->egl.ctx;
+#endif
+
+#if defined(RGFW_X11)
+	return (void*)ctx->ctx;
+#else
+	return NULL;
+#endif
+}
+
+RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
+	#ifdef RGFW_WAYLAND
+	if (RGFW_usingWayland()) {
+		return (RGFW_glContext*)RGFW_window_createContext_EGL(win, hints);
+	}
+	#endif
+	RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
+	if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) {
+		RGFW_FREE(ctx);
+		win->src.ctx.native = NULL;
+		return NULL;
+	}
+	win->src.gfxType |= RGFW_gfxOwnedByRGFW;
+	return ctx;
+}
+
+RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win) {
+	if (win->src.gfxType & RGFW_windowEGL) return NULL;
+	return win->src.ctx.native;
+}
+
+void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
+	RGFW_window_deleteContextPtr_OpenGL(win, ctx);
+	if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
+}
+
+RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) {
+    const char *start = extensions;
+    const char *where;
+    const char* terminator;
+
+    if (extensions == NULL || ext == NULL) {
+        return RGFW_FALSE;
+	}
+
+	while (ext[len - 1] == '\0' && len > 3) {
+		len--;
+	}
+
+    where = RGFW_STRSTR(extensions, ext);
+    while (where) {
+		terminator = where + len;
+        if ((where == start || *(where - 1) == ' ') &&
+            (*terminator == ' ' || *terminator == '\0')) {
+			return RGFW_TRUE;
+        }
+        where = RGFW_STRSTR(terminator, ext);
+    }
+
+    return RGFW_FALSE;
+}
+
+RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len);
+RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) {
+    #ifdef GL_NUM_EXTENSIONS
+    if (RGFW_globalHints_OpenGL->major >= 3) {
+        i32 i;
+
+        GLint count = 0;
+
+        RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi");
+        RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv");
+		if (RGFW_glGetIntegerv)
+            ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count);
+
+        for (i = 0; RGFW_glGetStringi && i < count;  i++) {
+            const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i);
+            if (en && RGFW_STRNCMP(en, extension, len) == 0) {
+				return RGFW_TRUE;
+			}
+        }
+    } else
+#endif
+    {
+        RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString");
+		#define RGFW_GL_EXTENSIONS 0x1F03
+        if (RGFW_glGetString) {
+            const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS);
+
+            if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) {
+				return RGFW_TRUE;
+			}
+        }
+    }
+	return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) {
+	if (RGFW_extensionSupported_base(extension, len))  return RGFW_TRUE;
+    return RGFW_extensionSupportedPlatform_OpenGL(extension, len);
+}
+
+void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) {
+	if (win) {
+		_RGFW->current = win;
+	}
+
+    RGFW_window_makeCurrentContext_OpenGL(win);
+}
+
+RGFW_window* RGFW_getCurrentWindow_OpenGL(void) { return _RGFW->current; }
+void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; }
+void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib) {
+	RGFW_ASSERT(stack->count < stack->max);
+	stack->attribs[stack->count] = attrib;
+	stack->count += 1;
+}
+void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) {
+	RGFW_attribStack_pushAttrib(stack, attrib1);
+	RGFW_attribStack_pushAttrib(stack, attrib2);
+}
+
+/* EGL */
+#ifdef RGFW_EGL
+#include <EGL/egl.h>
+
+PFNEGLINITIALIZEPROC RGFW_eglInitialize;
+PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs;
+PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig;
+PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface;
+PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext;
+PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent;
+PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay;
+PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers;
+PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval;
+PFNEGLBINDAPIPROC RGFW_eglBindAPI;
+PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext;
+PFNEGLTERMINATEPROC RGFW_eglTerminate;
+PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface;
+PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext;
+PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL;
+PFNEGLQUERYSTRINGPROC RGFW_eglQueryString;
+PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib;
+
+#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
+#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
+
+#ifdef RGFW_WINDOWS
+    #include <windows.h>
+#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
+    #include <dlfcn.h>
+#endif
+
+#ifdef RGFW_WAYLAND
+#include <wayland-egl.h>
+#endif
+
+void* RGFW_eglLibHandle = NULL;
+
+void* RGFW_getDisplay_EGL(void) { return _RGFW->EGL_display; }
+void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx) { return ctx->ctx; }
+void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx) { return ctx->surface; }
+struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx) { return ctx->eglWindow; }
+
+RGFW_bool RGFW_loadEGL(void) {
+	RGFW_init();
+	if (RGFW_eglGetProcAddress != NULL) {
+		return RGFW_TRUE;
+	}
+
+#ifndef RGFW_WASM
+	#ifdef RGFW_WINDOWS
+		const char* libNames[] = { "libEGL.dll", "EGL.dll" };
+	#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
+		/* Linux and macOS */
+		const char* libNames[] = {
+			"libEGL.so.1",  /* most common */
+			"libEGL.so",    /* fallback */
+			"/System/Library/Frameworks/OpenGL.framework/OpenGL"  /* fallback for older macOS EGL-like systems */
+		};
+	#endif
+
+	for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); i++) {
+		#ifdef RGFW_WINDOWS
+			RGFW_eglLibHandle = (void*)LoadLibraryA(libNames[i]);
+			if (RGFW_eglLibHandle) {
+				RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)RGFW_eglLibHandle, "eglGetProcAddress");
+				break;
+			}
+		#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
+			RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL);
+			if (RGFW_eglLibHandle) {
+				void* lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress");
+				if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC));
+				break;
+			}
+		#endif
+	}
+
+	if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) {
+		return RGFW_FALSE;
+	}
+
+	RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize");
+	RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs");
+	RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig");
+	RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface");
+	RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext");
+	RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent");
+	RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay");
+	RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers");
+	RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval");
+	RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI");
+	RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext");
+	RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate");
+	RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface");
+	RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString");
+	RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext");
+	RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib");
+
+#else
+	RGFW_eglGetProcAddress = eglGetProcAddress;
+	RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize;
+	RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs;
+	RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig;
+	RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface;
+	RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext;
+	RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent;
+	RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay;
+	RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers;
+	RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval;
+	RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI;
+	RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext;
+	RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate;
+	RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface;
+	RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString;
+	RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext;
+	RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib;
+#endif
+
+	RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize!= NULL &&
+	            RGFW_eglGetConfigs!= NULL &&
+	            RGFW_eglChooseConfig!= NULL &&
+	            RGFW_eglCreateWindowSurface!= NULL &&
+	            RGFW_eglCreateContext!= NULL &&
+	            RGFW_eglMakeCurrent!= NULL &&
+	            RGFW_eglGetDisplay!= NULL &&
+	            RGFW_eglSwapBuffers!= NULL &&
+	            RGFW_eglSwapInterval != NULL &&
+	            RGFW_eglBindAPI!= NULL &&
+	            RGFW_eglDestroyContext!= NULL &&
+	            RGFW_eglTerminate!= NULL &&
+	            RGFW_eglDestroySurface!= NULL &&
+				RGFW_eglQueryString != NULL &&
+				RGFW_eglGetCurrentContext != NULL &&
+				RGFW_eglGetConfigAttrib != NULL);
+
+	if (out) {
+		#ifdef RGFW_WINDOWS
+		HDC dc = GetDC(NULL);
+		_RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc);
+		ReleaseDC(NULL, dc);
+		#elif defined(RGFW_WAYLAND)
+		if (_RGFW->useWaylandBool)
+			_RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display);
+		else
+		#endif
+		#ifdef RGFW_X11
+			_RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display);
+		#else
+		{}
+		#endif
+		#if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11)
+		_RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY);
+		#endif
+	}
+
+	RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL);
+	return out;
+}
+
+
+void RGFW_unloadEGL(void) {
+	if (!RGFW_eglLibHandle) return;
+	RGFW_eglTerminate(_RGFW->EGL_display);
+	#ifdef RGFW_WINDOWS
+	    FreeLibrary((HMODULE)RGFW_eglLibHandle);
+	#elif defined(RGFW_MACOS) || defined(RGFW_UNIX)
+	    dlclose(RGFW_eglLibHandle);
+	#endif
+
+    RGFW_eglLibHandle = NULL;
+    RGFW_eglGetProcAddress = NULL;
+}
+
+RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints) {
+	if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
+	win->src.ctx.egl = ctx;
+	win->src.gfxType = RGFW_gfxEGL;
+
+#ifdef RGFW_WAYLAND
+    if (_RGFW->useWaylandBool)
+        win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h);
+#endif
+
+	#ifndef EGL_OPENGL_ES1_BIT
+	#define EGL_OPENGL_ES1_BIT 0x1
+	#endif
+
+	EGLint egl_config[24];
+
+	{
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, egl_config, 24);
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
+		RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE);
+
+		if (hints->profile == RGFW_glES) {
+			switch (hints->major) {
+				case 1: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break;
+				case 2: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break;
+				case 3: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break;
+				default: break;
+			}
+		} else {
+			RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT);
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red);
+		RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green);
+		RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue);
+		RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha);
+		RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth);
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil);
+		if (hints->samples) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1);
+			RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples);
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
+	}
+
+	EGLint numConfigs, best_config = -1, best_samples = 0;
+
+	RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs);
+	EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs);
+
+	RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs);
+
+#ifdef RGFW_X11
+	RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
+	EGLint best_depth = 0;
+#endif
+
+	for (EGLint i = 0; i < numConfigs; i++) {
+		EGLint visual_id = 0;
+		EGLint samples = 0;
+
+		RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id);
+		RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples);
+
+		if (best_config  == -1) best_config = i;
+
+#ifdef RGFW_X11
+		if (_RGFW->useWaylandBool == RGFW_FALSE) {
+			XVisualInfo vinfo_template;
+			vinfo_template.visualid = (VisualID)visual_id;
+
+			int num_visuals = 0;
+			XVisualInfo* vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals);
+			if (!vi) continue;
+			if ((!transparent || vi->depth == 32) && best_depth == 0) {
+				best_config = i;
+				best_depth = vi->depth;
+			}
+
+			if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) {
+				best_depth = vi->depth;
+				best_config = i;
+				best_samples = samples;
+				XFree(vi);
+				continue;
+			}
+		}
+#endif
+
+		if (samples <= hints->samples && samples > best_samples) {
+			best_config = i;
+			best_samples = samples;
+		}
+	}
+
+	EGLConfig config = configs[best_config];
+	RGFW_FREE(configs);
+#ifdef RGFW_X11
+    if (_RGFW->useWaylandBool == RGFW_FALSE) {
+		/*  This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
+		XVisualInfo* result;
+		XVisualInfo desired;
+		EGLint visualID = 0, count = 0;
+
+		RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID);
+		if (visualID) {
+			desired.visualid = (VisualID)visualID;
+			result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count);
+		} else  RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext,  "Failed to fetch a valid EGL VisualID");
+
+		if (result == NULL || count == 0) {
+			if (win->src.window == 0) {
+				/* try to create a EGL context anyway (this will work if you're not using a NVidia driver) */
+				win->internal.flags &= ~(u32)RGFW_windowEGL;
+				RGFW_createWindowPlatform("", win->internal.flags, win);
+			}
+			RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext,  "Failed to find a valid visual for the EGL config");
+		} else {
+			RGFW_bool showWindow = RGFW_FALSE;
+			if (win->src.window) {
+				showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
+				RGFW_window_closePlatform(win);
+			}
+
+			RGFW_XCreateWindow(*result, "", win->internal.flags, win);
+
+			if (showWindow) {
+				RGFW_window_show(win);
+			}
+			XFree(result);
+		}
+	}
+#endif
+
+	EGLint surf_attribs[9];
+
+	{
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, surf_attribs, 9);
+
+		const char present_opaque_str[] = "EGL_EXT_present_opaque";
+		RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str));
+
+		#ifndef EGL_PRESENT_OPAQUE_EXT
+		#define EGL_PRESENT_OPAQUE_EXT 0x31df
+		#endif
+
+		#ifndef EGL_GL_COLORSPACE_KHR
+		#define EGL_GL_COLORSPACE_KHR 0x309D
+		#ifndef EGL_GL_COLORSPACE_SRGB_KHR
+		#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
+		#endif
+		#endif
+
+		const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace";
+		RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str));
+
+		if (hints->sRGB && gl_colorspace_Found) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
+		}
+
+		if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found)
+			RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE);
+
+		if (hints->doubleBuffer == 0) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
+	}
+	#if defined(RGFW_MACOS)
+		void* layer = RGFW_getLayer_OSX();
+
+		RGFW_window_setLayer_OSX(win, layer);
+
+		win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs);
+	#elif defined(RGFW_WINDOWS)
+		win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
+	#elif defined(RGFW_WAYLAND)
+		if (_RGFW->useWaylandBool)
+			win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs);
+		else
+    #endif
+    #ifdef RGFW_X11
+        win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs);
+    #else
+    {}
+    #endif
+	#ifdef RGFW_WASM
+		win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0);
+	#endif
+
+	if (win->src.ctx.egl->surface == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface.");
+		return RGFW_FALSE;
+	}
+
+	EGLint attribs[20];
+	{
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, attribs, 20);
+
+		if (hints->major || hints->minor) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major);
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor);
+		}
+
+		if (hints->profile == RGFW_glCore) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
+		} else if (hints->profile == RGFW_glCompatibility) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
+		} else if (hints->profile == RGFW_glForwardCompatibility) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE, EGL_TRUE);
+		}
+
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness);
+		RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug);
+
+		#ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR
+			#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
+		#endif
+
+		#ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR
+			#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
+		#endif
+
+		if (hints->releaseBehavior == RGFW_glReleaseFlush) {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
+		} else {
+			RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000);
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE);
+	}
+
+	if (hints->profile == RGFW_glES)
+		RGFW_eglBindAPI(EGL_OPENGL_ES_API);
+	else
+		RGFW_eglBindAPI(EGL_OPENGL_API);
+
+	win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs);
+
+	if (win->src.ctx.egl->ctx == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errEGLContext,  "Failed to create an EGL context.");
+		return RGFW_FALSE;
+	}
+
+	RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
+	RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized.");
+	return RGFW_TRUE;
+}
+
+RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) {
+	if (win->src.gfxType == RGFW_windowOpenGL) return NULL;
+	return win->src.ctx.egl;
+}
+
+void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
+	if (_RGFW->EGL_display == NULL) return;
+
+	RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface);
+	RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx);
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed");
+	#ifdef RGFW_WAYLAND
+		if (_RGFW->useWaylandBool == RGFW_FALSE) return;
+		wl_egl_window_destroy(win->src.ctx.egl->eglWindow);
+		RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed");
+	#endif
+	win->src.ctx.egl = NULL;
+}
+
+void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.egl);
+	if (win == NULL)
+        RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    else {
+        RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx);
+    }
+}
+
+void RGFW_window_swapBuffers_EGL(RGFW_window* win) {
+	if (RGFW_eglSwapBuffers)
+		RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface);
+	else RGFW_window_swapBuffers_OpenGL(win);
+}
+
+void* RGFW_getCurrentContext_EGL(void) {
+	return RGFW_eglGetCurrentContext();
+}
+
+RGFW_proc RGFW_getProcAddress_EGL(const char* procname) {
+	#if defined(RGFW_WINDOWS)
+	RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
+
+		if (proc)
+			return proc;
+	#endif
+
+	return (RGFW_proc) RGFW_eglGetProcAddress(procname);
+}
+
+RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len) {
+	if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE;
+	const char* extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS);
+	return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
+}
+
+void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval);
+}
+
+RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) {
+	if (RGFW_extensionSupported_base(extension, len))  return RGFW_TRUE;
+    return RGFW_extensionSupportedPlatform_EGL(extension, len);
+}
+
+void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) {
+    _RGFW->current = win;
+    RGFW_window_makeCurrentContext_EGL(win);
+}
+
+RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; }
+
+RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) {
+	RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext));
+	if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) {
+		RGFW_FREE(ctx);
+		win->src.ctx.egl = NULL;
+		return NULL;
+	}
+	win->src.gfxType |= RGFW_gfxOwnedByRGFW;
+	return ctx;
+}
+
+void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) {
+	RGFW_window_deleteContextPtr_EGL(win, ctx);
+	if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx);
+}
+
+#endif /* RGFW_EGL */
+
+/*
+	end of RGFW_EGL defines
+*/
+#endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
+
+/*
+	RGFW_VULKAN defines
+*/
+#ifdef RGFW_VULKAN
+#ifdef RGFW_MACOS
+#include <objc/message.h>
+#endif
+
+const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) {
+    static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
+    arr[1] = RGFW_VK_SURFACE;
+    if (count != NULL) *count = 2;
+
+    return (const char**)arr;
+}
+
+#ifndef RGFW_MACOS
+VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
+    RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
+	RGFW_ASSERT(surface != NULL);
+
+    *surface = VK_NULL_HANDLE;
+
+#ifdef RGFW_X11
+
+    VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) _RGFW->display, (Window) win->src.window };
+    return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
+#endif
+#if defined(RGFW_WAYLAND)
+
+    VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) _RGFW->wl_display, (struct wl_surface*) win->src.surface };
+    return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
+#elif defined(RGFW_WINDOWS)
+    VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
+
+    return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
+#endif
+}
+#endif
+
+RGFW_bool RGFW_getPresentationSupport_Vulkan(VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
+	if (_RGFW == NULL) RGFW_init();
+#ifdef RGFW_X11
+
+	Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
+    RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual));
+    return out;
+#endif
+#if defined(RGFW_WAYLAND)
+
+    RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display);
+    return wlout;
+#elif defined(RGFW_WINDOWS)
+	RGFW_bool out = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
+	return out;
+#elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
+	RGFW_UNUSED(physicalDevice);
+	RGFW_UNUSED(queueFamilyIndex);
+    return RGFW_FALSE; /* TODO */
+#endif
+}
+#endif /* end of RGFW_vulkan */
+
+/*
+This is where OS specific stuff starts
+*/
+
+/* start of unix (wayland or X11 (unix) ) defines */
+
+#ifdef RGFW_UNIX
+
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+#include <time.h>
+
+void RGFW_stopCheckEvents(void) {
+
+	_RGFW->eventWait_forceStop[2] = 1;
+	while (1) {
+		const char byte = 0;
+		const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1);
+		if (result == 1 || result == -1)
+			break;
+	}
+}
+
+RGFWDEF u64 RGFW_linux_getTimeNS(void);
+u64 RGFW_linux_getTimeNS(void) {
+    struct timespec ts;
+    const u64 scale_factor = 1000000000;
+    clock_gettime(_RGFW->clock, &ts);
+    return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec;
+}
+
+void RGFW_waitForEvent(i32 waitMS) {
+	if (waitMS == 0) return;
+
+	if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) {
+		if (pipe(_RGFW->eventWait_forceStop) != -1) {
+			fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0);
+			fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0);
+			fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0);
+			fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0);
+		}
+	}
+
+	struct pollfd fds[2];
+    fds[0].fd = 0;
+    fds[0].events = POLLIN;
+    fds[0].revents = 0;
+    fds[1].fd = _RGFW->eventWait_forceStop[0];
+    fds[1].events = POLLIN;
+    fds[1].revents = 0;
+
+
+	if (RGFW_usingWayland()) {
+		#ifdef RGFW_WAYLAND
+		fds[0].fd = wl_display_get_fd(_RGFW->wl_display);
+
+		/* empty the queue */
+		while (wl_display_prepare_read(_RGFW->wl_display) != 0) {
+			/* error occured when dispatching the queue */
+			if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
+				return;
+			}
+		}
+
+		/* send any pending requests to the compositor */
+		while (wl_display_flush(_RGFW->wl_display) == -1) {
+
+			/* queue is full dispatch them */
+			if (errno == EAGAIN) {
+				if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
+					return;
+				}
+			} else {
+				return;
+			}
+		}
+		#endif
+	} else {
+		#ifdef RGFW_X11
+		fds[0].fd = ConnectionNumber(_RGFW->display);
+		#endif
+	}
+
+
+	u64 start = RGFW_linux_getTimeNS();
+	if (RGFW_usingWayland()) {
+		#ifdef RGFW_WAYLAND
+		while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) {
+			if (poll(fds, 1, waitMS) <= 0) {
+				wl_display_cancel_read(_RGFW->wl_display);
+				break;
+			} else {
+				if (wl_display_read_events(_RGFW->wl_display) == -1)
+					return;
+			}
+
+			if (waitMS != RGFW_eventWaitNext) {
+				waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
+			}
+		}
+
+		/* queue contains events from read, dispatch them */
+		if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
+			return;
+		}
+		#endif
+	} else {
+		#ifdef RGFW_X11
+		while (XPending(_RGFW->display) == 0) {
+			if (poll(fds, 1, waitMS) <= 0)
+				break;
+
+			if (waitMS != RGFW_eventWaitNext) {
+				waitMS -= (i32)(RGFW_linux_getTimeNS() - start) / (i32)1e+6;
+			}
+		}
+		#endif
+	}
+
+	/* drain any data in the stop request */
+	if (_RGFW->eventWait_forceStop[2]) {
+		char data[64];
+        RGFW_MEMZERO(data, sizeof(data));
+        (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data));
+
+		_RGFW->eventWait_forceStop[2] = 0;
+	}
+}
+
+char* RGFW_strtok(char* str, const char* delimStr);
+char* RGFW_strtok(char* str, const char* delimStr) {
+    static char* static_str = NULL;
+
+    if (str != NULL)
+        static_str = str;
+
+    if (static_str == NULL) {
+        return NULL;
+    }
+
+    while (*static_str != '\0') {
+        RGFW_bool delim = 0;
+        const char* d;
+        for (d = delimStr; *d != '\0'; d++) {
+            if (*static_str == *d) {
+                delim = 1;
+                break;
+            }
+        }
+        if (!delim)
+            break;
+        static_str++;
+    }
+
+    if (*static_str == '\0')
+        return NULL;
+
+    char* token_start = static_str;
+    while (*static_str != '\0') {
+        int delim = 0;
+        const char* d;
+        for (d = delimStr; *d != '\0'; d++) {
+            if (*static_str == *d) {
+                delim = 1;
+                break;
+            }
+        }
+
+        if (delim) {
+            *static_str = '\0';
+            static_str++;
+            break;
+        }
+        static_str++;
+    }
+
+    return token_start;
+}
+
+#ifdef RGFW_X11
+RGFWDEF i32 RGFW_initPlatform_X11(void);
+RGFWDEF void RGFW_deinitPlatform_X11(void);
+#endif
+#ifdef RGFW_WAYLAND
+RGFWDEF i32 RGFW_initPlatform_Wayland(void);
+RGFWDEF void RGFW_deinitPlatform_Wayland(void);
+#endif
+
+RGFWDEF void RGFW_load_X11(void);
+RGFWDEF void RGFW_load_Wayland(void);
+
+#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND)
+void RGFW_load_X11(void) { }
+void RGFW_load_Wayland(void) { }
+#endif
+
+/*
+ * Sadly we have to use magic linux keycodes
+ * We can't use X11 functions, because that breaks Wayland, but they use the same keycodes so there's no use redeffing them
+ * We can't use linux enums, because the headers don't exist on BSD
+ */
+void RGFW_initKeycodesPlatform(void) {
+	_RGFW->keycodes[49] = RGFW_keyBacktick;
+	_RGFW->keycodes[19] = RGFW_key0;
+	_RGFW->keycodes[10] = RGFW_key1;
+	_RGFW->keycodes[11] = RGFW_key2;
+	_RGFW->keycodes[12] = RGFW_key3;
+	_RGFW->keycodes[13] = RGFW_key4;
+	_RGFW->keycodes[14] = RGFW_key5;
+	_RGFW->keycodes[15] = RGFW_key6;
+	_RGFW->keycodes[16] = RGFW_key7;
+	_RGFW->keycodes[17] = RGFW_key8;
+	_RGFW->keycodes[18] = RGFW_key9;
+	_RGFW->keycodes[65] = RGFW_keySpace;
+	_RGFW->keycodes[38] = RGFW_keyA;
+	_RGFW->keycodes[56] = RGFW_keyB;
+	_RGFW->keycodes[54] = RGFW_keyC;
+	_RGFW->keycodes[40] = RGFW_keyD;
+	_RGFW->keycodes[26] = RGFW_keyE;
+	_RGFW->keycodes[41] = RGFW_keyF;
+	_RGFW->keycodes[42] = RGFW_keyG;
+	_RGFW->keycodes[43] = RGFW_keyH;
+	_RGFW->keycodes[31] = RGFW_keyI;
+	_RGFW->keycodes[44] = RGFW_keyJ;
+	_RGFW->keycodes[45] = RGFW_keyK;
+	_RGFW->keycodes[46] = RGFW_keyL;
+	_RGFW->keycodes[58] = RGFW_keyM;
+	_RGFW->keycodes[57] = RGFW_keyN;
+	_RGFW->keycodes[32] = RGFW_keyO;
+	_RGFW->keycodes[33] = RGFW_keyP;
+	_RGFW->keycodes[24] = RGFW_keyQ;
+	_RGFW->keycodes[27] = RGFW_keyR;
+	_RGFW->keycodes[39] = RGFW_keyS;
+	_RGFW->keycodes[28] = RGFW_keyT;
+	_RGFW->keycodes[30] = RGFW_keyU;
+	_RGFW->keycodes[55] = RGFW_keyV;
+	_RGFW->keycodes[25] = RGFW_keyW;
+	_RGFW->keycodes[53] = RGFW_keyX;
+	_RGFW->keycodes[29] = RGFW_keyY;
+	_RGFW->keycodes[52] = RGFW_keyZ;
+	_RGFW->keycodes[60] = RGFW_keyPeriod;
+	_RGFW->keycodes[59] = RGFW_keyComma;
+	_RGFW->keycodes[61] = RGFW_keySlash;
+	_RGFW->keycodes[34] = RGFW_keyBracket;
+	_RGFW->keycodes[35] = RGFW_keyCloseBracket;
+	_RGFW->keycodes[47] = RGFW_keySemicolon;
+	_RGFW->keycodes[48] = RGFW_keyApostrophe;
+	_RGFW->keycodes[51] = RGFW_keyBackSlash;
+	_RGFW->keycodes[36] = RGFW_keyReturn;
+	_RGFW->keycodes[119] = RGFW_keyDelete;
+	_RGFW->keycodes[77] = RGFW_keyNumLock;
+	_RGFW->keycodes[106] = RGFW_keyPadSlash;
+	_RGFW->keycodes[63] = RGFW_keyPadMultiply;
+	_RGFW->keycodes[86] = RGFW_keyPadPlus;
+	_RGFW->keycodes[82] = RGFW_keyPadMinus;
+	_RGFW->keycodes[87] = RGFW_keyPad1;
+	_RGFW->keycodes[88] = RGFW_keyPad2;
+	_RGFW->keycodes[89] = RGFW_keyPad3;
+	_RGFW->keycodes[83] = RGFW_keyPad4;
+	_RGFW->keycodes[84] = RGFW_keyPad5;
+	_RGFW->keycodes[85] = RGFW_keyPad6;
+	_RGFW->keycodes[81] = RGFW_keyPad9;
+	_RGFW->keycodes[90] = RGFW_keyPad0;
+	_RGFW->keycodes[91] = RGFW_keyPadPeriod;
+	_RGFW->keycodes[104] = RGFW_keyPadReturn;
+	_RGFW->keycodes[20] = RGFW_keyMinus;
+	_RGFW->keycodes[21] = RGFW_keyEquals;
+	_RGFW->keycodes[22] = RGFW_keyBackSpace;
+	_RGFW->keycodes[23] = RGFW_keyTab;
+	_RGFW->keycodes[66] = RGFW_keyCapsLock;
+	_RGFW->keycodes[50] = RGFW_keyShiftL;
+	_RGFW->keycodes[37] = RGFW_keyControlL;
+	_RGFW->keycodes[64] = RGFW_keyAltL;
+	_RGFW->keycodes[133] = RGFW_keySuperL;
+	_RGFW->keycodes[105] = RGFW_keyControlR;
+	_RGFW->keycodes[134] = RGFW_keySuperR;
+	_RGFW->keycodes[62] = RGFW_keyShiftR;
+	_RGFW->keycodes[108] = RGFW_keyAltR;
+	_RGFW->keycodes[67] = RGFW_keyF1;
+	_RGFW->keycodes[68] = RGFW_keyF2;
+	_RGFW->keycodes[69] = RGFW_keyF3;
+	_RGFW->keycodes[70] = RGFW_keyF4;
+	_RGFW->keycodes[71] = RGFW_keyF5;
+	_RGFW->keycodes[72] = RGFW_keyF6;
+	_RGFW->keycodes[73] = RGFW_keyF7;
+	_RGFW->keycodes[74] = RGFW_keyF8;
+	_RGFW->keycodes[75] = RGFW_keyF9;
+	_RGFW->keycodes[76] = RGFW_keyF10;
+	_RGFW->keycodes[95] = RGFW_keyF11;
+	_RGFW->keycodes[96] = RGFW_keyF12;
+	_RGFW->keycodes[111] = RGFW_keyUp;
+	_RGFW->keycodes[116] = RGFW_keyDown;
+	_RGFW->keycodes[113] = RGFW_keyLeft;
+	_RGFW->keycodes[114] = RGFW_keyRight;
+	_RGFW->keycodes[118] = RGFW_keyInsert;
+	_RGFW->keycodes[115] = RGFW_keyEnd;
+	_RGFW->keycodes[112] = RGFW_keyPageUp;
+	_RGFW->keycodes[117] = RGFW_keyPageDown;
+	_RGFW->keycodes[9] = RGFW_keyEscape;
+	_RGFW->keycodes[110] = RGFW_keyHome;
+	_RGFW->keycodes[78] = RGFW_keyScrollLock;
+	_RGFW->keycodes[107] = RGFW_keyPrintScreen;
+	_RGFW->keycodes[128] = RGFW_keyPause;
+    _RGFW->keycodes[191] = RGFW_keyF13;
+    _RGFW->keycodes[192] = RGFW_keyF14;
+    _RGFW->keycodes[193] = RGFW_keyF15;
+    _RGFW->keycodes[194] = RGFW_keyF16;
+    _RGFW->keycodes[195] = RGFW_keyF17;
+    _RGFW->keycodes[196] = RGFW_keyF18;
+    _RGFW->keycodes[197] = RGFW_keyF19;
+    _RGFW->keycodes[198] = RGFW_keyF20;
+    _RGFW->keycodes[199] = RGFW_keyF21;
+    _RGFW->keycodes[200] = RGFW_keyF22;
+    _RGFW->keycodes[201] = RGFW_keyF23;
+    _RGFW->keycodes[202] = RGFW_keyF24;
+    _RGFW->keycodes[203] = RGFW_keyF25;
+	_RGFW->keycodes[142] = RGFW_keyPadEqual;
+	_RGFW->keycodes[161] = RGFW_keyWorld1; /* non-US key #1 */
+    _RGFW->keycodes[162] = RGFW_keyWorld2; /* non-US key #2 */
+}
+
+i32 RGFW_initPlatform(void) {
+	#if defined(_POSIX_MONOTONIC_CLOCK)
+	struct timespec ts;
+	RGFW_MEMZERO(&ts, sizeof(struct timespec));
+
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+		_RGFW->clock = CLOCK_MONOTONIC;
+	#else
+		_RGFW->clock = CLOCK_REALTIME;
+	#endif
+
+#ifdef RGFW_WAYLAND
+	RGFW_load_Wayland();
+	i32 ret = RGFW_initPlatform_Wayland();
+	if (ret == 0) {
+		return 0;
+	} else {
+		#ifdef RGFW_X11
+			RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland,  "Falling back to X11");
+			RGFW_useWayland(0);
+		#else
+			return ret;
+		#endif
+	}
+#endif
+#ifdef RGFW_X11
+	RGFW_load_X11();
+	return RGFW_initPlatform_X11();
+#else
+	return 0;
+#endif
+}
+
+
+void RGFW_deinitPlatform(void) {
+    if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]){
+        close(_RGFW->eventWait_forceStop[0]);
+        close(_RGFW->eventWait_forceStop[1]);
+    }
+#ifdef RGFW_WAYLAND
+	if (_RGFW->useWaylandBool) {
+		RGFW_deinitPlatform_Wayland();
+		return;
+	}
+#endif
+#ifdef RGFW_X11
+	RGFW_deinitPlatform_X11();
+#endif
+}
+
+RGFWDEF size_t RGFW_unix_stringlen(const char* name);
+size_t RGFW_unix_stringlen(const char* name) {
+	size_t i = 0;
+    while (name[i]) { i++; }
+	return i;
+}
+
+RGFWDEF void RGFW_unix_parseURI(RGFW_window* win, char* data);
+void RGFW_unix_parseURI(RGFW_window* win, char* data) {
+	const char* prefix = (const char*)"file://";
+	char* line;
+	while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
+		data = NULL;
+
+		if (line[0] == '#')
+			continue;
+
+		char* l;
+		for (l = line; 1; l++) {
+			if ((l - line) > 7)
+				break;
+			else if (*l != prefix[(l - line)])
+				break;
+			else if (*l == '\0' && prefix[(l - line)] == '\0') {
+				line += 7;
+				while (*line != '/')
+					line++;
+				break;
+			} else if (*l == '\0')
+				break;
+		}
+
+		size_t len = RGFW_unix_stringlen(line);
+		char* path = (char*)RGFW_ALLOC(len + 1);
+
+		size_t index = 0;
+		while (*line) {
+			if (line[0] == '%' && line[1] && line[2]) {
+				char digits[3] = {0};
+				digits[0] = line[1];
+				digits[1] = line[2];
+				digits[2] = '\0';
+				path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
+				line += 2;
+			} else {
+				if (index >= len) {
+					break;
+				}
+
+				path[index] = *line;
+			}
+
+			index++;
+			line++;
+		}
+
+		path[len] = '\0';
+		RGFW_dataDropCallback(win, (const char*)path, len + 1, RGFW_dataFile);
+		RGFW_FREE(path);
+	}
+}
+
+
+#endif /* end of wayland or X11 defines */
+
+
+/*
+
+
+Start of Linux / Unix defines
+
+
+*/
+
+#ifdef RGFW_X11
+#ifdef RGFW_WAYLAND
+#define RGFW_FUNC(func) func##_X11
+#else
+#define RGFW_FUNC(func) func
+#endif
+
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
+#include <poll.h>
+
+void RGFW_setXInstName(const char* name) { _RGFW->instName = name; }
+#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
+	#include <X11/Xcursor/Xcursor.h>
+#endif
+
+#include <X11/Xatom.h>
+#include <X11/keysymdef.h>
+#include <X11/extensions/sync.h>
+
+#include <X11/XKBlib.h> /* for converting keycode to string */
+#include <X11/cursorfont.h> /* for hiding */
+#include <X11/extensions/shapeconst.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/XInput2.h>
+
+#ifdef RGFW_OPENGL
+	#ifndef __gl_h_
+		#define __gl_h_
+		#define RGFW_gl_ndef
+		#define GLubyte     unsigned char
+		#define GLenum      unsigned int
+		#define GLint       int
+		#define GLuint      unsigned int
+		#define GLsizei     int
+		#define GLfloat     float
+		#define GLvoid      void
+		#define GLbitfield  unsigned int
+		#define GLintptr    ptrdiff_t
+		#define GLsizeiptr  ptrdiff_t
+		#define GLboolean   unsigned char
+	#endif
+
+	#include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
+	#ifndef GLX_MESA_swap_control
+		#define  GLX_MESA_swap_control
+	#endif
+
+	#ifdef RGFW_gl_ndef
+		#undef __gl_h_
+		#undef GLubyte
+		#undef GLenum
+		#undef GLint
+		#undef GLuint
+		#undef GLsizei
+		#undef GLfloat
+		#undef GLvoid
+		#undef GLbitfield
+		#undef GLintptr
+		#undef GLsizeiptr
+		#undef GLboolean
+	#endif
+	typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+#endif
+
+/* atoms needed for drag and drop */
+#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
+		typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
+		typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
+		typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
+#endif
+
+#if !defined(RGFW_NO_X11_XI_PRELOAD)
+		typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
+		PFN_XISelectEvents XISelectEventsSRC = NULL;
+		#define XISelectEvents XISelectEventsSRC
+
+		void* X11Xihandle = NULL;
+#endif
+
+#if !defined(RGFW_NO_X11_EXT_PRELOAD)
+		typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
+		PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
+		#define XSyncIntToValue XSyncIntToValueSRC
+
+		typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
+		PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
+		#define XSyncSetCounter XSyncSetCounterSRC
+
+		typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
+		PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
+		#define XSyncCreateCounter XSyncCreateCounterSRC
+
+		typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
+		PFN_XShapeCombineMask XShapeCombineMaskSRC;
+		#define XShapeCombineMask XShapeCombineMaskSRC
+
+		typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
+		PFN_XShapeCombineRegion XShapeCombineRegionSRC;
+		#define XShapeCombineRegion XShapeCombineRegionSRC
+		void* X11XEXThandle = NULL;
+#endif
+
+#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
+		PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
+		PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
+		PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
+
+		#define XcursorImageLoadCursor XcursorImageLoadCursorSRC
+		#define XcursorImageCreate XcursorImageCreateSRC
+		#define XcursorImageDestroy XcursorImageDestroySRC
+
+		void* X11Cursorhandle = NULL;
+#endif
+
+RGFWDEF RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win);
+RGFW_bool RGFW_waitForShowEvent_X11(RGFW_window* win) {
+    XEvent dummy;
+    while (!XCheckTypedWindowEvent(_RGFW->display, win->src.window, VisibilityNotify, &dummy)) {
+		RGFW_waitForEvent(100);
+    }
+
+	return RGFW_TRUE;
+}
+
+RGFWDEF void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData);
+void RGFW_x11_icCallback(XIC ic, char* clientData, char* callData) {
+	RGFW_UNUSED(ic); RGFW_UNUSED(callData);
+    RGFW_window* win = (RGFW_window*)(void*)clientData;
+    win->src.ic = NULL;
+}
+
+RGFWDEF void RGFW_x11_imCallback(XIM im, char* clientData, char* callData);
+void RGFW_x11_imCallback(XIM im, char* clientData, char* callData) {
+	RGFW_UNUSED(im); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
+	_RGFW->im = NULL;
+}
+
+RGFWDEF void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData);
+void RGFW_x11_imInitCallback(Display* display, XPointer clientData, XPointer callData) {
+	RGFW_UNUSED(display); RGFW_UNUSED(clientData); RGFW_UNUSED(callData);
+
+	if (_RGFW->im) {
+		return;
+	}
+
+	_RGFW->im = XOpenIM(_RGFW->display, 0, NULL, NULL);
+	if (_RGFW->im == NULL) {
+		return;
+	}
+
+    RGFW_bool found = RGFW_FALSE;
+    XIMStyles* styles = NULL;
+
+    if (XGetIMValues(_RGFW->im, XNQueryInputStyle, &styles, NULL) != NULL) {
+        found = RGFW_FALSE;
+	} else {
+		for (unsigned int i = 0;  i < styles->count_styles;  i++) {
+			if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
+				found = RGFW_TRUE;
+				break;
+			}
+		}
+
+	    XFree(styles);
+	}
+
+	if (found == RGFW_FALSE) {
+		XCloseIM(_RGFW->im);
+		_RGFW->im = NULL;
+	}
+
+	XIMCallback callback;
+	callback.callback = (XIMProc) RGFW_x11_imCallback;
+	callback.client_data = NULL;
+	XSetIMValues(_RGFW->im, XNDestroyCallback, &callback, NULL);
+}
+
+void* RGFW_getDisplay_X11(void) { return _RGFW->display; }
+u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; }
+
+RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage* image);
+RGFW_format RGFW_XImage_getFormat(XImage* image) {
+    switch (image->bits_per_pixel) {
+        case 24:
+            if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF)
+                return RGFW_formatRGB8;
+            if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000)
+                return RGFW_formatBGR8;
+            break;
+        case 32:
+            if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
+                return RGFW_formatBGRA8;
+            if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000)
+                return RGFW_formatRGBA8;
+            if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000)
+                return RGFW_formatABGR8;
+            if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF)
+                return RGFW_formatARGB8;  /* ambiguous without alpha */
+            break;
+    }
+	return RGFW_formatARGB8;
+}
+
+
+RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+	surface->data = data;
+	surface->w = w;
+	surface->h = h;
+	surface->format = format;
+
+	XWindowAttributes attrs;
+	if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes.");
+		return RGFW_FALSE;
+	}
+
+	surface->native.bitmap = XCreateImage(_RGFW->display,  attrs.visual,  (u32)attrs.depth,
+										ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0);
+
+	surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
+	surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap);
+
+	if (surface->native.bitmap == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer,  "Failed to create XImage.");
+		return RGFW_FALSE;
+	}
+
+	surface->native.format = RGFW_formatBGRA8;
+	return RGFW_TRUE;
+}
+
+RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
+
+RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface);
+}
+
+void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+	surface->native.bitmap->data = (char*)surface->native.buffer;
+	RGFW_copyImageData((u8*)surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
+
+	XPutImage(_RGFW->display, win->src.window, win->src.gc, surface->native.bitmap, 0, 0, 0, 0, (u32)RGFW_MIN(win->w, surface->w), (u32)RGFW_MIN(win->h, surface->h));
+	surface->native.bitmap->data = NULL;
+	return;
+}
+
+void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+	RGFW_FREE(surface->native.buffer);
+	XDestroyImage(surface->native.bitmap);
+	return;
+}
+
+#define RGFW_LOAD_ATOM(name) \
+	static Atom name = 0; \
+	if (name == 0) name = XInternAtom(_RGFW->display, #name, False);
+
+void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
+	RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
+	RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
+
+	struct __x11WindowHints {
+		unsigned long flags, functions, decorations, status;
+		long input_mode;
+	} hints;
+	hints.flags = 2;
+	hints.decorations = border;
+
+	XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5);
+
+	if (RGFW_window_isHidden(win) == 0) {
+		RGFW_window_hide(win);
+		RGFW_window_show(win);
+	}
+}
+
+void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win);
+	unsigned char mask[XIMaskLen(XI_RawMotion)];
+	RGFW_MEMZERO(mask, sizeof(mask));
+	if (state) XISetMask(mask, XI_RawMotion);
+
+	XIEventMask em;
+	em.deviceid = XIAllMasterDevices;
+	em.mask_len = sizeof(mask);
+	em.mask = mask;
+
+	XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1);
+}
+
+void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
+	if (state) {
+		unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
+		XGrabPointer(_RGFW->display, win->src.window, True, event_mask, GrabModeAsync, GrabModeAsync, win->src.window, None, CurrentTime);
+	} else {
+		XUngrabPointer(_RGFW->display, CurrentTime);
+	}
+}
+
+#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
+#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
+	void* ptr = dlsym(proc, #name); \
+	if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \
+}
+
+RGFWDEF void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent);
+void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent) {
+	visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display));
+	visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
+	if (transparent) {
+		XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /*!< for RGBA backgrounds */
+		if (visual->depth != 32)
+			RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth.");
+	}
+}
+
+RGFWDEF int RGFW_XErrorHandler(Display* display, XErrorEvent* ev);
+int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) {
+    char errorText[512];
+    XGetErrorText(display, ev->error_code, errorText, sizeof(errorText));
+
+    char buf[1024];
+    RGFW_SNPRINTF(buf, sizeof(buf),  "[X Error] %s\n  Error code: %d\n  Request code: %d\n  Minor code: %d\n  Serial: %lu\n",
+             errorText,
+             ev->error_code, ev->request_code, ev->minor_code, ev->serial);
+
+    RGFW_debugCallback(RGFW_typeError, RGFW_errX11, buf);
+    _RGFW->x11Error = ev;
+    return 0;
+}
+
+void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask |
+						LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask;
+
+	/* make X window attrubutes */
+	XSetWindowAttributes swa;
+    RGFW_MEMZERO(&swa, sizeof(swa));
+
+	win->src.parent = DefaultRootWindow(_RGFW->display);
+
+	Colormap cmap;
+	swa.colormap = cmap = XCreateColormap(_RGFW->display,
+		win->src.parent,
+		visual.visual, AllocNone);
+	swa.event_mask = event_mask;
+    swa.background_pixmap = None;
+
+	/* create the window */
+	win->src.window = XCreateWindow(_RGFW->display, win->src.parent, win->x, win->y, (u32)win->w, (u32)win->h,
+		0, visual.depth, InputOutput, visual.visual,
+		CWBorderPixel | CWColormap | CWEventMask, &swa);
+
+	win->src.flashEnd = 0;
+
+	XFreeColors(_RGFW->display, cmap, NULL, 0, 0);
+
+	XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win);
+
+	win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL);
+
+	if (_RGFW->im) {
+		XIMCallback callback;
+		callback.callback = (XIMProc) RGFW_x11_icCallback;
+		callback.client_data = (XPointer) win;
+
+		win->src.ic = XCreateIC(_RGFW->im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win->src.window, XNFocusWindow, win->src.window, XNDestroyCallback, &callback, NULL);
+	}
+
+
+	/* In your .desktop app, if you set the property
+	    StartupWMClass=RGFW that will assoicate the launcher icon
+	     with your application - robrohan */
+	if (_RGFW->className == NULL)
+		_RGFW->className = (char*)name;
+
+	XClassHint hint;
+	hint.res_class = (char*)_RGFW->className;
+
+	if (_RGFW->instName == NULL)	hint.res_name = (char*)name;
+	else 						hint.res_name = (char*)_RGFW->instName;
+
+	XSetClassHint(_RGFW->display, win->src.window, &hint);
+
+	XWMHints hints;
+	hints.flags = StateHint;
+	hints.initial_state = NormalState;
+
+	XSetWMHints(_RGFW->display, win->src.window, &hints);
+
+	XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
+
+	/* make it so the user can't close the window until the program does */
+    RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
+	XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1);
+	/* set the background */
+	RGFW_window_setName(win, name);
+
+	XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */
+
+	if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
+		win->internal.flags |= RGFW_windowAllowDND;
+
+		/* actions */
+		Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False);
+		const u8 version = 5;
+
+		XChangeProperty(_RGFW->display, win->src.window,
+			XdndAware, 4, 32,
+			PropModeReplace, &version, 1); /*!< turns on drag and drop */
+	}
+
+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+    RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
+    RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
+
+    Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW};
+    XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2);
+
+    XSyncValue initial_value;
+    XSyncIntToValue(&initial_value, 0);
+    win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value);
+
+    XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (u8*)&win->src.counter, 1);
+#endif
+
+	win->src.x = win->x;
+	win->src.y = win->y;
+	win->src.w = win->w;
+	win->src.h = win->h;
+
+	XSetWindowBackground(_RGFW->display, win->src.window, None);
+    XClearWindow(_RGFW->display, win->src.window);
+
+	/* stupid hack to make resizing the window less bad */
+	XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None);
+}
+
+RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) {
+		win->src.window = 0;
+		return win;
+	}
+
+	XVisualInfo visual;
+	RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent));
+	RGFW_XCreateWindow(visual, name, flags, win);
+	return win; /*return newly created window */
+}
+
+RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) {
+	RGFW_init();
+	i32 x, y;
+	u32 z;
+	Window window1, window2;
+	XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z);
+	return RGFW_TRUE;
+}
+
+RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
+void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event);
+    RGFW_LOAD_ATOM(ATOM_PAIR);
+	RGFW_LOAD_ATOM(MULTIPLE);
+	RGFW_LOAD_ATOM(TARGETS);
+	RGFW_LOAD_ATOM(SAVE_TARGETS);
+	RGFW_LOAD_ATOM(UTF8_STRING);
+
+    const XSelectionRequestEvent* request = &event->xselectionrequest;
+    Atom formats[2] = {0};
+    formats[0] = UTF8_STRING;
+    formats[1] = XA_STRING;
+    const int formatCount = sizeof(formats) / sizeof(formats[0]);
+
+    if (request->target == TARGETS) {
+        Atom targets[4] = {0};
+        targets[0] = TARGETS;
+        targets[1] = MULTIPLE;
+        targets[2] = UTF8_STRING;
+        targets[3] = XA_STRING;
+
+        XChangeProperty(_RGFW->display, request->requestor, request->property,
+                        XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
+    }  else if (request->target == MULTIPLE) {
+		Atom* targets = NULL;
+
+		Atom actualType = 0;
+		int actualFormat = 0;
+		unsigned long count = 0, bytesAfter = 0;
+
+		XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX,
+							False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
+
+		unsigned long i;
+		for (i = 0; i < (u32)count; i += 2) {
+			if (targets[i] == UTF8_STRING || targets[i] == XA_STRING)
+				XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i],
+					8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32)_RGFW->clipboard_len);
+			else
+				targets[i + 1] = None;
+		}
+
+		XChangeProperty(_RGFW->display,
+			request->requestor, request->property, ATOM_PAIR, 32,
+			PropModeReplace, (u8*) targets, (i32)count);
+
+		XFlush(_RGFW->display);
+		XFree(targets);
+	} else if (request->target == SAVE_TARGETS)
+        XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
+    else {
+        int i;
+        for (i = 0;  i < formatCount;  i++) {
+			if (request->target != formats[i])
+				continue;
+			XChangeProperty(_RGFW->display, request->requestor, request->property, request->target,
+								8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len);
+		}
+	}
+
+    XEvent reply = { SelectionNotify };
+    reply.xselection.property = request->property;
+    reply.xselection.display = request->display;
+    reply.xselection.requestor = request->requestor;
+    reply.xselection.selection = request->selection;
+    reply.xselection.target = request->target;
+    reply.xselection.time = request->time;
+
+    XSendEvent(_RGFW->display, request->requestor, False, 0, &reply);
+	XFlush(_RGFW->display);
+}
+
+i32 RGFW_XHandleClipboardSelectionHelper(void);
+
+RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey) (RGFW_key key) {
+    KeyCode keycode = (KeyCode)RGFW_rgfwToApiKey(key);
+    KeySym sym = XkbKeycodeToKeysym(_RGFW->display, keycode, 0, 0);
+
+    if (sym < 256) {
+        return (RGFW_key)sym;
+    }
+
+    switch (sym) {
+        case XK_F1:  return RGFW_keyF1;
+        case XK_F2:  return RGFW_keyF2;
+        case XK_F3:  return RGFW_keyF3;
+        case XK_F4:  return RGFW_keyF4;
+        case XK_F5:  return RGFW_keyF5;
+        case XK_F6:  return RGFW_keyF6;
+        case XK_F7:  return RGFW_keyF7;
+        case XK_F8:  return RGFW_keyF8;
+        case XK_F9:  return RGFW_keyF9;
+        case XK_F10: return RGFW_keyF10;
+        case XK_F11: return RGFW_keyF11;
+        case XK_F12: return RGFW_keyF12;
+        case XK_F13: return RGFW_keyF13;
+        case XK_F14: return RGFW_keyF14;
+        case XK_F15: return RGFW_keyF15;
+        case XK_F16: return RGFW_keyF16;
+        case XK_F17: return RGFW_keyF17;
+        case XK_F18: return RGFW_keyF18;
+        case XK_F19: return RGFW_keyF19;
+        case XK_F20: return RGFW_keyF20;
+        case XK_F21: return RGFW_keyF21;
+        case XK_F22: return RGFW_keyF22;
+        case XK_F23: return RGFW_keyF23;
+        case XK_F24: return RGFW_keyF24;
+        case XK_F25: return RGFW_keyF25;
+        case XK_Shift_L:   return RGFW_keyShiftL;
+        case XK_Shift_R:   return RGFW_keyShiftR;
+        case XK_Control_L: return RGFW_keyControlL;
+        case XK_Control_R: return RGFW_keyControlR;
+        case XK_Alt_L:     return RGFW_keyAltL;
+        case XK_Alt_R:     return RGFW_keyAltR;
+        case XK_Super_L:   return RGFW_keySuperL;
+        case XK_Super_R:   return RGFW_keySuperR;
+        case XK_Caps_Lock: return RGFW_keyCapsLock;
+        case XK_Num_Lock:  return RGFW_keyNumLock;
+        case XK_Scroll_Lock:return RGFW_keyScrollLock;
+        case XK_Up:        return RGFW_keyUp;
+        case XK_Down:      return RGFW_keyDown;
+        case XK_Left:      return RGFW_keyLeft;
+        case XK_Right:     return RGFW_keyRight;
+        case XK_Home:      return RGFW_keyHome;
+        case XK_End:       return RGFW_keyEnd;
+        case XK_Page_Up:   return RGFW_keyPageUp;
+        case XK_Page_Down: return RGFW_keyPageDown;
+        case XK_Insert:    return RGFW_keyInsert;
+        case XK_Menu:      return RGFW_keyMenu;
+        case XK_KP_Add:      return RGFW_keyPadPlus;
+        case XK_KP_Subtract: return RGFW_keyPadMinus;
+        case XK_KP_Multiply: return RGFW_keyPadMultiply;
+        case XK_KP_Divide:   return RGFW_keyPadSlash;
+        case XK_KP_Equal:    return RGFW_keyPadEqual;
+        case XK_KP_Enter:    return RGFW_keyPadReturn;
+        case XK_KP_Decimal:  return RGFW_keyPadPeriod;
+        case XK_KP_0: return RGFW_keyPad0;
+        case XK_KP_1: return RGFW_keyPad1;
+        case XK_KP_2: return RGFW_keyPad2;
+        case XK_KP_3: return RGFW_keyPad3;
+        case XK_KP_4: return RGFW_keyPad4;
+        case XK_KP_5: return RGFW_keyPad5;
+        case XK_KP_6: return RGFW_keyPad6;
+        case XK_KP_7: return RGFW_keyPad7;
+        case XK_KP_8: return RGFW_keyPad8;
+        case XK_KP_9: return RGFW_keyPad9;
+        case XK_Print: return RGFW_keyPrintScreen;
+        case XK_Pause: return RGFW_keyPause;
+        default: break;
+    }
+
+    return RGFW_keyNULL;
+}
+
+RGFWDEF void RGFW_XHandleEvent(void);
+void RGFW_XHandleEvent(void) {
+	RGFW_LOAD_ATOM(XdndTypeList);
+	RGFW_LOAD_ATOM(XdndSelection);
+	RGFW_LOAD_ATOM(XdndEnter);
+	RGFW_LOAD_ATOM(XdndPosition);
+	RGFW_LOAD_ATOM(XdndStatus);
+	RGFW_LOAD_ATOM(XdndLeave);
+	RGFW_LOAD_ATOM(XdndDrop);
+	RGFW_LOAD_ATOM(XdndFinished);
+	RGFW_LOAD_ATOM(XdndActionCopy);
+	RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
+	RGFW_LOAD_ATOM(WM_PROTOCOLS);
+	RGFW_LOAD_ATOM(WM_STATE);
+	RGFW_LOAD_ATOM(_NET_WM_STATE);
+
+	static float deltaX = 0.0f;
+	static float deltaY = 0.0f;
+
+	XEvent E;
+
+	XNextEvent(_RGFW->display, &E);
+
+	if (E.type != GenericEvent) {
+		deltaX = 0.0f;
+		deltaY = 0.0f;
+	}
+
+	if (E.type == _RGFW->xrandrEventBase + RRNotify) {
+		RGFW_pollMonitors();
+		return;
+	}
+
+	switch (E.type) {
+		case SelectionRequest:
+			RGFW_XHandleClipboardSelection(&E);
+			return;
+		case GenericEvent: {
+			XGetEventData(_RGFW->display, &E.xcookie);
+			switch (E.xcookie.evtype) {
+				case XI_RawMotion: {
+					XIRawEvent* raw = (XIRawEvent *)E.xcookie.data;
+					if (raw->valuators.mask_len == 0) {
+						XFreeEventData(_RGFW->display, &E.xcookie);
+						return;
+					}
+
+					i32 index = 0;
+					if (XIMaskIsSet(raw->valuators.mask, 0) != 0) {
+						deltaX += (float)raw->raw_values[index];
+						index += 1;
+					}
+
+					if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
+						deltaY += (float)raw->raw_values[index];
+
+					_RGFW->vectorX = (float)deltaX;
+					_RGFW->vectorY = (float)deltaY;
+					RGFW_rawMotionCallback(_RGFW->root, _RGFW->vectorX, _RGFW->vectorY);
+				}
+				default: break;
+			}
+
+			XFreeEventData(_RGFW->display, &E.xcookie);
+			return;
+		}
+	}
+
+	RGFW_window* win = NULL;
+	if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) {
+		return;
+	}
+
+	if (win->src.flashEnd) {
+		if ((win->src.flashEnd <= RGFW_linux_getTimeNS()) || RGFW_window_isInFocus(win)) {
+			RGFW_window_flash(win, RGFW_flashCancel);
+		}
+	}
+
+
+	/*
+		Repeated key presses are sent as a release followed by another press at the same time.
+		We want to convert that into a single key press event with the repeat flag set
+	*/
+
+	RGFW_bool keyRepeat = RGFW_FALSE;
+
+	if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) {
+		XEvent NE;
+		XPeekEvent(_RGFW->display, &NE);
+		if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) {
+			/* Use the next KeyPress event */
+			XNextEvent(_RGFW->display, &E);
+			keyRepeat = RGFW_TRUE;
+		}
+	}
+
+	switch (E.type) {
+		case KeyPress: {
+			if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
+			RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
+
+			XkbStateRec state;
+			XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
+			RGFW_keyUpdateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
+
+			if (win->src.ic && XFilterEvent(&E, None) == False) {
+				char buffer[100];
+				char* chars = buffer;
+
+				Status status;
+				size_t count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, buffer, sizeof(buffer) - 1, NULL, &status);
+
+				if (status == XBufferOverflow) {
+					chars = (char*)RGFW_ALLOC(count + 1);
+					count = (size_t)Xutf8LookupString(win->src.ic, &E.xkey, chars, (int)count, NULL, &status);
+				}
+
+				if (status == XLookupChars || status == XLookupBoth) {
+					chars[count] = '\0';
+					for (size_t index = 0; index < count;
+						RGFW_keyCharCallback(win, RGFW_decodeUTF8(&chars[index], &index))
+					);
+				}
+
+				if (chars != buffer)
+					RGFW_FREE(chars);
+			} else {
+				Window root = DefaultRootWindow(_RGFW->display);
+				Window ret_root, ret_child;
+				int root_x, root_y, win_x, win_y;
+				unsigned int mask;
+				XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask);
+				KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW->display, (KeyCode)E.xkey.keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0);
+
+				if ((mask & LockMask) && sym >= XK_a && sym <= XK_z)
+					sym = (mask & ShiftMask) ? sym + 32 : sym - 32;
+				if ((u8)sym != (u32)sym)
+					sym = 0;
+
+				RGFW_keyCharCallback(win, (u8)sym);
+			}
+
+			RGFW_keyCallback(win, value, win->internal.mod, keyRepeat, RGFW_TRUE);
+			break;
+		}
+		case KeyRelease: {
+			if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
+
+			RGFW_key value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
+
+			XkbStateRec state;
+			XkbGetState(_RGFW->display, XkbUseCoreKbd, &state);
+			RGFW_keyUpdateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
+
+			RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
+			break;
+		}
+		case ButtonPress: {
+			RGFW_bool scroll = RGFW_FALSE;
+			if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) {
+				scroll = RGFW_TRUE;
+			}
+
+			float scrollX = 0.0f;
+			float scrollY = 0.0f;
+			RGFW_mouseButton value = 0;
+
+			switch (E.xbutton.button) {
+				case Button1: value = RGFW_mouseLeft; break;
+				case Button2: value = RGFW_mouseMiddle; break;
+				case Button3: value = RGFW_mouseRight; break;
+				case Button4: scrollY = 1.0; break;
+				case Button5: scrollY = -1.0; break;
+				case 6: scrollX = 1.0f; break;
+				case 7: scrollX = -1.0f; break;
+				default:
+					value = (u8)E.xbutton.button - Button1 - 4;
+					break;
+			}
+
+			if (scroll) {
+				RGFW_mouseScrollCallback(win, scrollX, scrollY);
+				break;
+			}
+
+			RGFW_mouseButtonCallback(win, value, RGFW_TRUE);
+			break;
+		}
+		case ButtonRelease: {
+			if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break;
+
+			RGFW_mouseButton value = 0;
+			switch(E.xbutton.button) {
+				case Button1: value = RGFW_mouseLeft; break;
+				case Button2: value = RGFW_mouseMiddle; break;
+				case Button3: value = RGFW_mouseRight; break;
+				default:
+					value = (u8)E.xbutton.button - Button1 - 4;
+					break;
+			}
+
+			RGFW_mouseButtonCallback(win, value, RGFW_FALSE);
+			break;
+		}
+		case MotionNotify:
+			RGFW_mouseMotionCallback(win, E.xmotion.x, E.xmotion.y);
+			break;
+
+		case Expose: {
+			RGFW_windowRefreshCallback(win, E.xexpose.x, E.xexpose.y, E.xexpose.width, E.xexpose.height);
+
+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+			XSyncValue value;
+			XSyncIntToValue(&value, (i32)win->src.counter_value);
+			XSyncSetCounter(_RGFW->display, win->src.counter, value);
+#endif
+			break;
+		}
+
+		case PropertyNotify:
+			if (E.xproperty.state != PropertyNewValue) break;
+
+			if (E.xproperty.atom == WM_STATE) {
+				if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) {
+					RGFW_windowMinimizedCallback(win);
+					break;
+				}
+			} else if (E.xproperty.atom == _NET_WM_STATE) {
+				if (RGFW_window_isMaximized(win) && !(win->internal.flags & RGFW_windowMaximize)) {
+					RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h);
+					break;
+				}
+			}
+
+			RGFW_window_checkMode(win);
+			break;
+		case MapNotify: case UnmapNotify: 		RGFW_window_checkMode(win); break;
+		case ClientMessage: {
+			RGFW_LOAD_ATOM(WM_DELETE_WINDOW);
+			/* if the client closed the window */
+			if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) {
+				RGFW_windowCloseCallback(win);
+				break;
+			}
+#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+			if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
+				RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
+				win->src.counter_value = 0;
+				win->src.counter_value |= E.xclient.data.l[2];
+				win->src.counter_value |= (E.xclient.data.l[3] << 32);
+
+				XSyncValue value;
+				XSyncIntToValue(&value, (i32)win->src.counter_value);
+				XSyncSetCounter(_RGFW->display, win->src.counter, value);
+				break;
+			}
+#endif
+			if ((win->internal.flags & RGFW_windowAllowDND) == 0 || _RGFW->x11Version > RGFW_XDND_VERSION) {
+				return;
+			}
+
+			i32 dragX = 0;
+			i32 dragY = 0;
+
+			if (E.xclient.message_type == XdndEnter) {
+				unsigned long count;
+				Atom* formats;
+				Atom real_formats[3];
+				Bool list = E.xclient.data.l[1] & 1;
+
+				_RGFW->x11Source = (Window)E.xclient.data.l[0];
+				_RGFW->x11Version = E.xclient.data.l[1] >> 24;
+				_RGFW->x11Format = None;
+				if (list) {
+					Atom actualType;
+					i32 actualFormat;
+					unsigned long bytesAfter;
+
+					XGetWindowProperty(
+						_RGFW->display, _RGFW->x11Source, XdndTypeList,
+						0, LONG_MAX, False, 4,
+						&actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
+					);
+				} else {
+					count = 0;
+
+					size_t i;
+					for (i = 2; i < (2 + 3); i++) {
+						if (E.xclient.data.l[i] != None) {
+							real_formats[count] = (unsigned long int)E.xclient.data.l[i];
+							count += 1;
+						}
+					}
+
+					formats = real_formats;
+				}
+
+				Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False);
+				Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False);
+
+				size_t i;
+				for (i = 0; i < count; i++) {
+					if (formats[i] == XtextUriList)  _RGFW->x11TransferType  = RGFW_dataFile;
+					else if (formats[i] == XtextPlain) _RGFW->x11TransferType  = RGFW_dataText;
+					else continue;
+
+					_RGFW->x11Format = (int)formats[i];
+					break;
+				}
+
+				if (list && formats) {
+					XFree(formats);
+				}
+
+
+				RGFW_dataDragCallback(win, _RGFW->x11TransferType , RGFW_dndActionEnter, dragX, dragY);
+			} else if (E.xclient.message_type == XdndPosition) {
+				const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
+				const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
+				Window dummy;
+				i32 xpos, ypos;
+
+				XTranslateCoordinates(
+					_RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window,
+					xabs, yabs, &xpos, &ypos, &dummy
+				);
+
+				dragX = xpos;
+				dragY = ypos;
+
+				RGFW_mouseMotionCallback(win, xpos, ypos);
+                XEvent reply = { ClientMessage };
+				reply.xclient.window = _RGFW->x11Source;
+                reply.xclient.message_type = XdndStatus;
+                reply.xclient.format = 32;
+				reply.xclient.data.l[0] = (long)win->src.window;
+                reply.xclient.data.l[2] = 0;
+                reply.xclient.data.l[3] = 0;
+
+				if (_RGFW->x11Format) {
+					reply.xclient.data.l[1] = 1;
+					if (_RGFW->x11Version >= 2)
+						reply.xclient.data.l[4] = (long)XdndActionCopy;
+				}
+
+				XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
+				XFlush(_RGFW->display);
+
+
+				RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionMove, dragX, dragY);
+			} else if (E.xclient.message_type == XdndLeave) {
+				RGFW_dataDragCallback(win, _RGFW->x11TransferType, RGFW_dndActionExit, dragX, dragY);
+			} else if (E.xclient.message_type == XdndDrop) {
+				if (_RGFW->x11Format) {
+					Time time = (_RGFW->x11Version >= 1)
+						? (Time)E.xclient.data.l[2]
+						: CurrentTime;
+					XConvertSelection(
+						_RGFW->display, XdndSelection, (Atom)_RGFW->x11Format,
+						XdndSelection, win->src.window, time
+					);
+				} else if (_RGFW->x11Version >= 2) {
+                    XEvent reply = { ClientMessage };
+                    reply.xclient.window = _RGFW->x11Source;
+                    reply.xclient.message_type = XdndFinished;
+                    reply.xclient.format = 32;
+                    reply.xclient.data.l[0] = (long)win->src.window;
+                    reply.xclient.data.l[1] = 0;
+                    reply.xclient.data.l[2] = None;
+
+					XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
+					XFlush(_RGFW->display);
+				}
+			}
+		} break;
+		case SelectionNotify: {
+			/* this is only for checking for xdnd drops */
+			if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND))
+				return;
+			char* data;
+			unsigned long result;
+
+			Atom actualType;
+			i32 actualFormat;
+			unsigned long bytesAfter;
+
+			XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
+
+			if (result != 0) {
+				RGFW_unix_parseURI(win, data);
+
+				if (data)
+					XFree(data);
+			}
+
+			if (_RGFW->x11Version >= 2) {
+				XEvent reply = { ClientMessage };
+				reply.xclient.window = _RGFW->x11Source;
+				reply.xclient.message_type = XdndFinished;
+				reply.xclient.format = 32;
+				reply.xclient.data.l[0] = (long)win->src.window;
+				reply.xclient.data.l[1] = (long int)result;
+				reply.xclient.data.l[2] = (long int)XdndActionCopy;
+				XSendEvent(_RGFW->display, _RGFW->x11Source, False, NoEventMask, &reply);
+				XFlush(_RGFW->display);
+			}
+			break;
+		}
+		case FocusIn:
+            if (win->src.ic) XSetICFocus(win->src.ic);
+			RGFW_windowFocusCallback(win, 1);
+			break;
+		case FocusOut:
+            if (win->src.ic) XUnsetICFocus(win->src.ic);
+			RGFW_windowFocusCallback(win, 0);
+			break;
+		case EnterNotify: {
+			RGFW_mouseNotifyCallback(win, E.xcrossing.x, E.xcrossing.y, RGFW_TRUE);
+			break;
+		}
+
+		case LeaveNotify: {
+			RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
+			break;
+		}
+        case ReparentNotify:
+            win->src.parent = E.xreparent.parent;
+			break;
+		case ConfigureNotify: {
+			/* detect resize */
+			if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) {
+				RGFW_window_checkMode(win);
+				win->src.w = E.xconfigure.width;
+				win->src.h = E.xconfigure.height;
+				RGFW_windowResizedCallback(win, E.xconfigure.width, E.xconfigure.height);
+			}
+
+			i32 x = E.xconfigure.x;
+			i32 y = E.xconfigure.y;
+
+			/*
+			 if the event came from the server and we're not a direct child of the root window then
+			 we're using local coords which need to be translated into screen coords
+			*/
+			Window root = DefaultRootWindow(_RGFW->display);
+			if (E.xany.send_event == 0 && win->src.parent != root) {
+				Window dummy = 0;
+				XTranslateCoordinates(_RGFW->display, win->src.parent, root, x, y, &x, &y, &dummy);
+			}
+
+			/* detect move */
+			if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) {
+				win->src.x = E.xconfigure.x;
+				win->src.y = E.xconfigure.y;
+				RGFW_windowMovedCallback(win, E.xconfigure.x, E.xconfigure.y);
+			}
+			return;
+		}
+		default:
+			break;
+	}
+
+	XFlush(_RGFW->display);
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_fetchSize) (RGFW_window* win, i32* w, i32* h) {
+    XWindowAttributes attribs;
+    XGetWindowAttributes(_RGFW->display, win->src.window, &attribs);
+
+    win->w = attribs.width;
+    win->h = attribs.height;
+
+	return RGFW_window_getSize(win, w, h);
+}
+
+void RGFW_FUNC(RGFW_pollEvents) (void) {
+	RGFW_resetPrevState();
+
+	XPending(_RGFW->display);
+    /* if there is no unread queued events, get a new one */
+	while (QLength(_RGFW->display)) {
+		RGFW_XHandleEvent();
+	}
+}
+
+void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+	win->x = x;
+	win->y = y;
+
+	XMoveWindow(_RGFW->display, win->src.window, x, y);
+	return;
+}
+
+
+void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+	win->w = (i32)w;
+	win->h = (i32)h;
+
+	XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h);
+
+	if ((win->internal.flags & RGFW_windowNoResize)) {
+		XSizeHints sh;
+		sh.flags = (1L << 4) | (1L << 5);
+		sh.min_width = sh.max_width = (i32)w;
+		sh.min_height = sh.max_height = (i32)h;
+
+		XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
+	}
+	return;
+}
+
+void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+
+	if (w == 0 && h == 0)
+		return;
+	XSizeHints hints;
+	long flags;
+
+	XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
+
+	hints.flags |= PAspect;
+
+	hints.min_aspect.x = hints.max_aspect.x = (i32)w;
+	hints.min_aspect.y = hints.max_aspect.y = (i32)h;
+
+	XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
+    return;
+}
+
+void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+    long flags;
+	XSizeHints hints;
+    RGFW_MEMZERO(&hints, sizeof(XSizeHints));
+
+	XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
+
+	hints.flags |= PMinSize;
+
+	hints.min_width = (i32)w;
+	hints.min_height = (i32)h;
+
+	XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
+    return;
+}
+
+void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+    long flags;
+	XSizeHints hints;
+    RGFW_MEMZERO(&hints, sizeof(XSizeHints));
+
+	XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags);
+
+	hints.flags |= PMaxSize;
+
+	hints.max_width = (i32)w;
+	hints.max_height = (i32)h;
+
+	XSetWMNormalHints(_RGFW->display, win->src.window, &hints);
+	return;
+}
+
+void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
+void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_LOAD_ATOM(_NET_WM_STATE);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
+
+	XEvent xev = {0};
+	xev.type = ClientMessage;
+	xev.xclient.window = win->src.window;
+	xev.xclient.message_type = _NET_WM_STATE;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = maximized;
+	xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
+	xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
+	xev.xclient.data.l[3] = 0;
+	xev.xclient.data.l[4] = 0;
+
+	XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
+	win->internal.oldX = win->x;
+	win->internal.oldY = win->y;
+	win->internal.oldW = win->w;
+	win->internal.oldH = win->h;
+
+    RGFW_toggleXMaximized(win, 1);
+	RGFW_window_fetchSize(win, NULL, NULL);
+    return;
+}
+
+void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) {
+	RGFW_ASSERT(win);
+
+	XWindowAttributes attr;
+	XGetWindowAttributes(_RGFW->display, win->src.window, &attr);
+	if (attr.map_state != IsViewable) return;
+
+	XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime);
+	XFlush(_RGFW->display);
+}
+
+void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) {
+	RGFW_ASSERT(win);
+	XMapRaised(_RGFW->display, win->src.window);
+	RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
+}
+
+void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
+void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_LOAD_ATOM(_NET_WM_STATE);
+
+	XEvent xev = {0};
+	xev.xclient.type = ClientMessage;
+	xev.xclient.serial = 0;
+	xev.xclient.send_event = True;
+	xev.xclient.message_type = _NET_WM_STATE;
+	xev.xclient.window = win->src.window;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = fullscreen;
+	xev.xclient.data.l[1] = (long int)netAtom;
+	xev.xclient.data.l[2] = 0;
+
+	XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+}
+
+void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+
+	if (fullscreen) {
+		win->internal.flags |= RGFW_windowFullscreen;
+		win->internal.oldX = win->x;
+		win->internal.oldY = win->y;
+		win->internal.oldW = win->w;
+		win->internal.oldH = win->h;
+	}
+	else win->internal.flags &= ~(u32)RGFW_windowFullscreen;
+
+	XRaiseWindow(_RGFW->display, win->src.window);
+
+	RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
+	RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
+
+	if (!(win->internal.flags & RGFW_windowTransparent)) {
+		const unsigned char value = fullscreen;
+		RGFW_LOAD_ATOM(_NET_WM_BYPASS_COMPOSITOR);
+		XChangeProperty(
+			_RGFW->display, win->src.window,
+			_NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
+			PropModeReplace, &value, 1);
+	}
+}
+
+void RGFW_FUNC(RGFW_window_setFloating)(RGFW_window* win, RGFW_bool floating) {
+    RGFW_ASSERT(win != NULL);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
+	RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
+}
+
+void RGFW_FUNC(RGFW_window_setOpacity)(RGFW_window* win, u8 opacity) {
+	RGFW_ASSERT(win != NULL);
+    const u32 value = (u32) (0xffffffffu * (double) opacity);
+	RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
+    XChangeProperty(_RGFW->display, win->src.window,
+					NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
+}
+
+void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	if (RGFW_window_isMaximized(win)) return;
+
+	win->internal.oldX = win->x;
+	win->internal.oldY = win->y;
+	win->internal.oldW = win->w;
+	win->internal.oldH = win->h;
+    XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display));
+	XFlush(_RGFW->display);
+}
+
+void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_toggleXMaximized(win, RGFW_FALSE);
+	RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
+	RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
+
+    RGFW_window_show(win);
+    XFlush(_RGFW->display);
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
+    RGFW_LOAD_ATOM(_NET_WM_STATE);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
+
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems, bytes_after;
+	Atom* prop_return = NULL;
+
+	int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
+									&actual_type, &actual_format, &nitems, &bytes_after,
+									(unsigned char **)&prop_return);
+
+	if (status != Success || actual_type != XA_ATOM)
+		return RGFW_FALSE;
+
+    unsigned long i;
+	for (i = 0; i < nitems; i++)
+		if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
+
+	if (prop_return)
+		XFree(prop_return);
+	return RGFW_FALSE;
+}
+
+void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) {
+	RGFW_ASSERT(win != NULL);
+	if (name == NULL) name = "\0";
+
+	Xutf8SetWMProperties(_RGFW->display, win->src.window, name, name, NULL, 0, NULL, NULL, NULL);
+	XStoreName(_RGFW->display, win->src.window, name);
+
+	RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING);
+
+    XChangeProperty(
+		_RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING,
+		8, PropModeReplace, (u8*)name, (int)RGFW_unix_stringlen(name)
+	);
+}
+
+#ifndef RGFW_NO_PASSTHROUGH
+void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
+	RGFW_ASSERT(win != NULL);
+    if (passthrough) {
+		Region region = XCreateRegion();
+		XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
+		XDestroyRegion(region);
+
+		return;
+	}
+
+	XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
+}
+#endif /* RGFW_NO_PASSTHROUGH */
+
+RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
+	Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False);
+	RGFW_ASSERT(win != NULL);
+	if (data_src == NULL) {
+		RGFW_bool res = (RGFW_bool)XChangeProperty(
+			_RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
+			PropModeReplace, (u8*)NULL, 0
+		);
+		return res;
+	}
+
+	i32 count = (i32)(2 + (w * h));
+
+	unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
+    RGFW_ASSERT(data != NULL);
+
+	RGFW_MEMZERO(data, (u32)count * sizeof(unsigned long));
+    data[0] = (unsigned long)w;
+	data[1] = (unsigned long)h;
+
+	RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE, NULL);
+	RGFW_bool res = RGFW_TRUE;
+	if (type & RGFW_iconTaskbar) {
+		res = (RGFW_bool)XChangeProperty(
+			_RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
+			PropModeReplace, (u8*)data, count
+		);
+	}
+
+	RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE, NULL);
+
+	if (type & RGFW_iconWindow) {
+		XWMHints wm_hints;
+		wm_hints.flags = IconPixmapHint;
+
+		i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display));
+		XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)),
+									(u32)depth, ZPixmap, 0, (char *)&data[2], (u32)w, (u32)h, 32, 0);
+
+		wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32)w, (u32)h, (u32)depth);
+		XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32)w, (u32)h);
+		image->data = NULL;
+		XDestroyImage(image);
+
+		XSetWMHints(_RGFW->display, win->src.window, &wm_hints);
+	}
+
+	RGFW_FREE(data);
+	XFlush(_RGFW->display);
+	return RGFW_BOOL(res);
+}
+
+RGFW_mouse* RGFW_FUNC(RGFW_createMouseStandard) (RGFW_mouseIcon mouse) {
+	u32 mouseIcon = 0;
+
+    switch (mouse) {
+        case RGFW_mouseNormal: mouseIcon = XC_left_ptr; break;
+        case RGFW_mouseArrow: mouseIcon = XC_left_ptr; break;
+        case RGFW_mouseIbeam: mouseIcon = XC_xterm; break;
+        case RGFW_mouseWait: mouseIcon = XC_watch; break;
+        case RGFW_mouseCrosshair: mouseIcon = XC_tcross; break;
+        case RGFW_mouseProgress: mouseIcon = XC_watch; break;
+        case RGFW_mouseResizeNWSE: mouseIcon = XC_top_left_corner; break;
+        case RGFW_mouseResizeNESW: mouseIcon = XC_top_right_corner; break;
+        case RGFW_mouseResizeEW: mouseIcon = XC_sb_h_double_arrow; break;
+        case RGFW_mouseResizeNS: mouseIcon = XC_sb_v_double_arrow; break;
+        case RGFW_mouseResizeNW: mouseIcon = XC_top_left_corner; break;
+        case RGFW_mouseResizeN: mouseIcon = XC_top_side; break;
+        case RGFW_mouseResizeNE: mouseIcon = XC_top_right_corner; break;
+        case RGFW_mouseResizeE: mouseIcon = XC_right_side; break;
+        case RGFW_mouseResizeSE: mouseIcon = XC_bottom_right_corner; break;
+        case RGFW_mouseResizeS: mouseIcon = XC_bottom_side; break;
+        case RGFW_mouseResizeSW: mouseIcon = XC_bottom_left_corner; break;
+        case RGFW_mouseResizeW: mouseIcon = XC_left_side; break;
+		case RGFW_mouseResizeAll: mouseIcon = XC_fleur; break;
+        case RGFW_mouseNotAllowed: mouseIcon = XC_pirate; break;
+        case RGFW_mousePointingHand: mouseIcon = XC_hand2; break;
+		default: return NULL;
+	}
+
+	Cursor cursor = XCreateFontCursor(_RGFW->display, mouseIcon);
+	return (RGFW_mouse*)cursor;
+}
+
+RGFW_mouse* RGFW_FUNC(RGFW_createMouse) (u8* data, i32 w, i32 h, RGFW_format format) {
+    RGFW_ASSERT(data);
+#ifndef RGFW_NO_X11_CURSOR
+	RGFW_init();
+    XcursorImage* native = XcursorImageCreate((i32)w, (i32)h);
+	native->xhot = 0;
+	native->yhot = 0;
+	RGFW_MEMZERO(native->pixels, (u32)(w * h * 4));
+	RGFW_copyImageData((u8*)native->pixels, w, h, RGFW_formatBGRA8, data, format, NULL);
+
+	Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native);
+	XcursorImageDestroy(native);
+
+	return (void*)cursor;
+#else
+	RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format);
+	return NULL;
+#endif
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_setMousePlatform)(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win && mouse);
+	XDefineCursor(_RGFW->display, win->src.window, (Cursor)mouse);
+	return RGFW_TRUE;
+}
+
+void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
+	RGFW_ASSERT(mouse);
+	XFreeCursor(_RGFW->display, (Cursor)mouse);
+}
+
+void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+
+	XEvent event;
+	XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display),
+		&event.xbutton.root, &event.xbutton.window,
+		&event.xbutton.x_root, &event.xbutton.y_root,
+		&event.xbutton.x, &event.xbutton.y,
+		&event.xbutton.state);
+
+	win->internal.lastMouseX = x - win->x;
+	win->internal.lastMouseY = y - win->y;
+	if (event.xbutton.x == x && event.xbutton.y == y)
+		return;
+
+	XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->y);
+}
+
+void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) {
+	win->internal.flags |= (u32)RGFW_windowHide;
+	XUnmapWindow(_RGFW->display, win->src.window);
+
+	XFlush(_RGFW->display);
+}
+
+void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
+	win->internal.flags &= ~(u32)RGFW_windowHide;
+	if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
+
+	if (RGFW_window_isHidden(win) == RGFW_FALSE) {
+		return;
+	}
+
+	XMapWindow(_RGFW->display, win->src.window);
+	RGFW_window_move(win, win->x, win->y);
+
+	RGFW_waitForShowEvent_X11(win);
+	RGFW_window_setFullscreen(win, RGFW_window_isFullscreen(win));
+	return;
+}
+
+void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
+	if (RGFW_window_isInFocus(win) && request) {
+		return;
+	}
+
+	XWMHints* wmhints = XGetWMHints(_RGFW->display, win->src.window);
+	if (wmhints == NULL) return;
+
+	if (request) {
+		wmhints->flags |= XUrgencyHint;
+		if (request == RGFW_flashBriefly)
+			win->src.flashEnd = RGFW_linux_getTimeNS() + (u64)1e+9;
+		if (request == RGFW_flashUntilFocused)
+			win->src.flashEnd = (u64)-1;
+	} else {
+		win->src.flashEnd = 0;
+		wmhints->flags &= ~XUrgencyHint;
+	}
+
+    XSetWMHints(_RGFW->display, win->src.window, wmhints);
+    XFree(wmhints);
+}
+
+RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) {
+	RGFW_init();
+	RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD);
+	if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
+		if (str != NULL)
+			RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
+		_RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
+		return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
+	}
+
+	XEvent event;
+	int format;
+	unsigned long N, sizeN;
+	char* data;
+	Atom target;
+
+	XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime);
+	XSync(_RGFW->display, 0);
+	while (1) {
+		XNextEvent(_RGFW->display, &event);
+		if (event.type != SelectionNotify) continue;
+
+		if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
+			return -1;
+		break;
+	}
+
+	XGetWindowProperty(event.xselection.display, event.xselection.requestor,
+			event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
+			&format, &sizeN, &N, (u8**) &data);
+
+	RGFW_ssize_t size;
+	if (sizeN > strCapacity && str != NULL)
+		size = -1;
+
+	if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) {
+		RGFW_MEMCPY(str, data, sizeN);
+		str[sizeN] = '\0';
+		XFree(data);
+	} else if (str != NULL) size = -1;
+
+	XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
+	size = (RGFW_ssize_t)sizeN;
+
+    return size;
+}
+
+i32 RGFW_XHandleClipboardSelectionHelper(void) {
+    RGFW_LOAD_ATOM(SAVE_TARGETS);
+
+    XEvent event;
+    XPending(_RGFW->display);
+
+    if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))
+        XNextEvent(_RGFW->display, &event);
+    else
+        return 0;
+
+    switch (event.type) {
+        case SelectionRequest:
+            RGFW_XHandleClipboardSelection(&event);
+            return 0;
+        case SelectionNotify:
+            if (event.xselection.target == SAVE_TARGETS)
+                return 0;
+            break;
+        default: break;
+    }
+
+    return 0;
+}
+
+void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) {
+	RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD);
+    RGFW_init();
+
+    /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
+	XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime);
+	if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) {
+    	RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard,  "X11 failed to become owner of clipboard selection");
+		return;
+	}
+
+	if (_RGFW->clipboard)
+		RGFW_FREE(_RGFW->clipboard);
+
+	_RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
+	RGFW_ASSERT(_RGFW->clipboard != NULL);
+
+	RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
+	_RGFW->clipboard[textLen - 1] = '\0';
+	_RGFW->clipboard_len = textLen;
+	return;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	XWindowAttributes windowAttributes;
+	XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
+
+	return (windowAttributes.map_state != IsViewable);
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+    RGFW_LOAD_ATOM(WM_STATE);
+
+	Atom actual_type;
+	i32 actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char* prop_data;
+
+	i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False,
+		AnyPropertyType, &actual_type, &actual_format,
+		&nitems, &bytes_after, &prop_data);
+
+	if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
+		XFree(prop_data);
+		return RGFW_TRUE;
+	}
+
+	if (prop_data != NULL)
+		XFree(prop_data);
+
+	XWindowAttributes windowAttributes;
+	XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes);
+    return windowAttributes.map_state != IsViewable;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+    RGFW_LOAD_ATOM(_NET_WM_STATE);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
+	RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
+
+	Atom actual_type;
+	i32 actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char* prop_data;
+
+	i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False,
+		XA_ATOM, &actual_type, &actual_format,
+		&nitems, &bytes_after, &prop_data);
+
+	if (status != Success) {
+		if (prop_data != NULL)
+			XFree(prop_data);
+
+		return RGFW_FALSE;
+	}
+
+	u64 i;
+	for (i = 0; i < nitems; i++) {
+		if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
+			prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
+			XFree(prop_data);
+			return RGFW_TRUE;
+		}
+	}
+
+	if (prop_data != NULL)
+		XFree(prop_data);
+
+	return RGFW_FALSE;
+}
+
+RGFWDEF void RGFW_XGetSystemContentDPI(float* dpi);
+void RGFW_XGetSystemContentDPI(float* dpi) {
+	if (dpi == NULL) return;
+	float dpiOutput = 96.0f;
+
+	char* rms = XResourceManagerString(_RGFW->display);
+	if (rms == NULL) return;
+
+	XrmDatabase db = XrmGetStringDatabase(rms);
+	if (db == NULL) return;
+
+	XrmValue value;
+	char* type = NULL;
+
+	if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
+		dpiOutput = (float)RGFW_ATOF(value.addr);
+	XrmDestroyDatabase(db);
+
+	if (dpi) *dpi = dpiOutput;
+}
+
+RGFWDEF XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode);
+XRRModeInfo* RGFW_XGetMode(XRRCrtcInfo* ci, XRRScreenResources* res, RRMode mode, RGFW_monitorMode* foundMode) {
+	XRRModeInfo* mi = None;
+	for (i32 j = 0; j < res->nmode; j++) {
+		if (res->modes[j].id ==  mode)
+			mi = &res->modes[j];
+	}
+
+	if (mi == None) return NULL;
+
+	if ((mi->modeFlags & RR_Interlace) != 0) return NULL;
+
+	foundMode->w = (i32)mi->width;
+	foundMode->h = (i32)mi->height;
+	if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) {
+		foundMode->w = (i32)mi->height;
+		foundMode->h = (i32)mi->width;
+	} else {
+		foundMode->w = (i32)mi->width;
+		foundMode->h = (i32)mi->height;
+	}
+
+	RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), foundMode);
+
+	foundMode->src = (void*)mode;
+
+	foundMode->refreshRate = 0;
+	if (mi->hTotal == 0 || mi->vTotal == 0)
+		return mi;
+
+    u32 vTotal = mi->vTotal;
+
+    if (mi->modeFlags & RR_DoubleScan) {
+        vTotal *= 2;
+    }
+
+    if (mi->modeFlags & RR_Interlace) {
+        vTotal /= 2;
+    }
+
+	i32 numerator = (i32)mi->dotClock;
+	i32 denominator = (i32)(mi->hTotal * vTotal);
+	float refreshRate = 0;
+
+	if (denominator <= 0) {
+		denominator = 1;
+	}
+
+	refreshRate = ((float)numerator / (float)denominator);
+
+	foundMode->refreshRate = RGFW_ROUNDF((refreshRate * 100)) / 100.0f;
+	return mi;
+}
+
+void RGFW_FUNC(RGFW_pollMonitors) (void) {
+    RGFW_init();
+
+	Window root = XDefaultRootWindow(_RGFW->display);
+	XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, root);
+	if (res == 0) {
+		return;
+	}
+
+	RROutput primary = XRRGetOutputPrimary(_RGFW->display, root);
+
+	for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
+		node->disconnected = RGFW_TRUE;
+	}
+
+	for (i32 i = 0; i < res->noutput; i++) {
+		RGFW_monitorNode* node = NULL;
+		for (node = _RGFW->monitors.list.head; node; node = node->next) {
+			if (node->rrOutput == res->outputs[i]) {
+				break;
+			}
+		}
+
+		if (node) {
+			node->disconnected = RGFW_FALSE;
+			if (node->rrOutput == primary) {
+				_RGFW->monitors.primary = node;
+			}
+			continue;
+		}
+
+		RGFW_monitor monitor;
+
+		XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, res, res->outputs[i]);
+		if (info == NULL) continue;
+		if (info->connection != RR_Connected || info->crtc == None) {
+			XRRFreeOutputInfo(info);
+			continue;
+		}
+
+		XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, info->crtc);
+
+		if (ci == NULL) {
+			continue;
+		}
+
+		float physW = (float)info->mm_width / 25.4f;
+		float physH = (float)info->mm_height / 25.4f;
+
+		RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1);
+		monitor.name[sizeof(monitor.name) - 1] = '\0';
+
+		if (physW > 0.0f && physH > 0.0f) {
+			monitor.physW = physW;
+			monitor.physH = physH;
+		} else {
+			monitor.physW = (float) ((float)ci->width / 96.f);
+			monitor.physH = (float) ((float)ci->height / 96.f);
+		}
+
+		monitor.x = ci->x;
+		monitor.y = ci->y;
+
+		float dpi = 96.0f;
+		RGFW_XGetSystemContentDPI(&dpi);
+
+		monitor.scaleX = dpi / 96.0f;
+		monitor.scaleY = dpi / 96.0f;
+
+		monitor.pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
+
+		XRRModeInfo* mi = RGFW_XGetMode(ci, res, ci->mode, &monitor.mode);
+
+		if (mi == NULL) {
+			break;
+		}
+
+		XRRFreeCrtcInfo(ci);
+
+		node = RGFW_monitors_add(&monitor);
+		if (node == NULL) break;
+
+		node->rrOutput = res->outputs[i];
+		node->crtc = info->crtc;
+
+		if (node->rrOutput == primary) {
+			_RGFW->monitors.primary = node;
+		}
+
+		XRRFreeOutputInfo(info);
+		info = NULL;
+
+		RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
+	}
+
+	XRRFreeScreenResources(res);
+
+	RGFW_monitors_refresh();
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
+    RGFW_LOAD_ATOM(_NET_WORKAREA);
+    RGFW_LOAD_ATOM(_NET_CURRENT_DESKTOP);
+
+	Window root = DefaultRootWindow(_RGFW->display);
+
+	i32 areaX = monitor->x;
+	i32 areaY = monitor->y;
+	i32 areaW = monitor->mode.w;
+	i32 areaH  = monitor->mode.h;
+
+    if (_NET_WORKAREA && _NET_CURRENT_DESKTOP) {
+        Atom* extents = NULL;
+        Atom* desktop = NULL;
+
+		Atom actualType = 0;
+		int actualFormat = 0;
+		unsigned long extentCount = 0, bytesAfter = 0;
+		XGetWindowProperty(_RGFW->display, root, _NET_WORKAREA, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &extentCount, &bytesAfter, (u8**) &extents);
+
+		unsigned long count;
+		XGetWindowProperty(_RGFW->display, root, _NET_CURRENT_DESKTOP, 0, LONG_MAX, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &desktop);
+
+        if (count) {
+			if (extentCount >= 4 && *desktop < extentCount / 4) {
+                i32 globalX = (i32)extents[*desktop * 4 + 0];
+                i32 globalY = (i32)extents[*desktop * 4 + 1];
+                i32 globalW = (i32)extents[*desktop * 4 + 2];
+                i32 globalH = (i32)extents[*desktop * 4 + 3];
+
+                if (areaX < globalX) {
+                    areaW -= globalX - areaX;
+                    areaX = globalX;
+                }
+
+                if (areaY < globalY) {
+                    areaH -= globalY - areaY;
+                    areaY = globalY;
+                }
+
+                if (areaX + areaW > globalX + globalW)
+                    areaW = globalX - areaX + globalW;
+                if (areaY + areaH > globalY + globalH)
+                    areaH = globalY - areaY + globalH;
+            }
+        }
+
+        if (extents)
+            XFree(extents);
+        if (desktop)
+            XFree(desktop);
+    }
+
+    if (x) *x = areaX;
+    if (y) *y = areaY;
+    if (width) *width = areaW;
+    if (height) *height = areaH;
+
+	return RGFW_TRUE;
+}
+
+size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
+	size_t count = 0;
+
+	XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
+	if (res == NULL) return 0;
+
+	XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, monitor->node->crtc);
+	XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, monitor->node->rrOutput);
+	count = (size_t)oi->nmode;
+
+	int i;
+	for (i = 0; modes && i < oi->nmode; i++) {
+		XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &((*modes)[i]));
+		RGFW_UNUSED(mi);
+	}
+
+    XRRFreeOutputInfo(oi);
+	XRRFreeCrtcInfo(ci);
+    XRRFreeScreenResources(res);
+
+	return count;
+}
+
+size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
+	size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
+	XRRCrtcGamma* gamma = XRRGetCrtcGamma(_RGFW->display, monitor->node->crtc);
+
+	if (ramp) {
+		RGFW_MEMCPY(ramp->red,   gamma->red,   size * sizeof(unsigned short));
+		RGFW_MEMCPY(ramp->green, gamma->green, size * sizeof(unsigned short));
+		RGFW_MEMCPY(ramp->blue,  gamma->blue,  size * sizeof(unsigned short));
+	}
+
+	XRRFreeGamma(gamma);
+	return size;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
+
+	size_t size = (size_t)XRRGetCrtcGammaSize(_RGFW->display, monitor->node->crtc);
+	if (size != ramp->count) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "X11: Gamma ramp size must match current ramp size");
+		return RGFW_FALSE;
+	}
+
+	XRRCrtcGamma* gamma = XRRAllocGamma((int)ramp->count);
+
+	memcpy(gamma->red,   ramp->red,   ramp->count * sizeof(unsigned short));
+	memcpy(gamma->green, ramp->green, ramp->count * sizeof(unsigned short));
+	memcpy(gamma->blue,  ramp->blue,  ramp->count * sizeof(unsigned short));
+
+	XRRSetCrtcGamma(_RGFW->display, monitor->node->crtc, gamma);
+	XRRFreeGamma(gamma);
+
+	return RGFW_TRUE;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_setMode)(RGFW_monitor* mon, RGFW_monitorMode* mode) {
+	RGFW_bool out = RGFW_FALSE;
+
+	XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
+	XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
+
+	if (XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, (RRMode)mode->src, ci->rotation, ci->outputs, ci->noutput) == True) {
+		out = RGFW_TRUE;
+	}
+
+	XRRFreeCrtcInfo(ci);
+    XRRFreeScreenResources(res);
+	return out;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
+    RGFW_init();
+
+	RGFW_bool output = RGFW_FALSE;
+
+	XRRScreenResources* res = XRRGetScreenResourcesCurrent(_RGFW->display, DefaultRootWindow(_RGFW->display));
+	if (res == NULL) return RGFW_FALSE;
+
+	XRRCrtcInfo* ci = XRRGetCrtcInfo(_RGFW->display, res, mon->node->crtc);
+	XRROutputInfo* oi = XRRGetOutputInfo(_RGFW->display, res, mon->node->rrOutput);
+
+	RRMode native = None;
+
+    int i;
+    for (i = 0; i < oi->nmode; i++) {
+		RGFW_monitorMode foundMode;
+		XRRModeInfo* mi = RGFW_XGetMode(ci, res, oi->modes[i], &foundMode);
+		if (mi == NULL) {
+			continue;
+		}
+
+		if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
+			native = mi->id;
+			output = RGFW_TRUE;
+			mon->mode = foundMode;
+			break;
+		}
+	}
+
+	if (native) {
+		XRRSetCrtcConfig(_RGFW->display, res, mon->node->crtc, CurrentTime, ci->x, ci->y, native, ci->rotation, ci->outputs, ci->noutput);
+	}
+
+    XRRFreeOutputInfo(oi);
+	XRRFreeCrtcInfo(ci);
+    XRRFreeScreenResources(res);
+	return output;
+}
+
+RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
+    RGFW_ASSERT(win != NULL);
+
+	XWindowAttributes attrs;
+    if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) {
+		return NULL;
+	}
+
+	for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
+		if ((attrs.x < node->mon.x + node->mon.mode.w) && (attrs.x + attrs.width > node->mon.x) && (attrs.y < node->mon.y + node->mon.mode.h) && (attrs.y + attrs.height > node->mon.y))
+			return &node->mon;
+	}
+
+
+	return &_RGFW->monitors.list.head->mon;
+}
+
+#ifdef RGFW_OPENGL
+RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) {
+	/* for checking extensions later */
+	const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB";
+	const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB";
+	const char noErorrStr[]  = "GLX_ARB_create_context_no_error";
+	const char flushStr[] = "GLX_ARB_context_flush_control";
+	const char robustStr[]	= "GLX_ARB_create_context_robustness";
+
+	/* basic RGFW int */
+	win->src.ctx.native = context;
+	win->src.gfxType = RGFW_gfxNativeOpenGL;
+
+	/*  This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */
+	RGFW_bool showWindow = RGFW_FALSE;
+	if (win->src.window) {
+		showWindow = (RGFW_window_isMinimized(win) == RGFW_FALSE);
+		RGFW_window_closePlatform(win);
+	}
+
+	RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent);
+
+	/* start by creating a GLX config / X11 Viusal */
+	XVisualInfo visual;
+	GLXFBConfig bestFbc;
+
+	i32 visual_attribs[40];
+	RGFW_attribStack stack;
+	RGFW_attribStack_init(&stack, visual_attribs, 40);
+	RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR);
+	RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1);
+	RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT);
+	RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
+	RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1);
+	RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha);
+	RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth);
+	RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil);
+	RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo);
+	RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers);
+	RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red);
+	RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green);
+	RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue);
+	RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed);
+	RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen);
+	RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue);
+	RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha);
+
+	if (hints->sRGB) {
+		if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr)))
+			RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB);
+		if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr)))
+			RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB);
+	}
+
+	RGFW_attribStack_pushAttribs(&stack, 0, 0);
+
+	/* find the configs */
+	i32 fbcount;
+	GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount);
+
+	i32 best_fbc = -1;
+	i32 best_depth = 0;
+	i32 best_samples = 0;
+
+	if (fbcount == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs.");
+		return 0;
+	}
+
+	/* search through all found configs to find the best match */
+	i32 i;
+	for (i = 0; i < fbcount; i++) {
+		XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]);
+		if (vi == NULL)
+			continue;
+
+		i32 samp_buf, samples;
+		glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
+		glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples);
+
+		if (best_fbc == -1) best_fbc = i;
+		if ((!(transparent) || vi->depth == 32)  && best_depth == 0) {
+			best_fbc = i;
+			best_depth = vi->depth;
+		}
+		if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) {
+			best_fbc = i;
+			best_depth = vi->depth;
+			best_samples = samples;
+		}
+		XFree(vi);
+	}
+
+	if (best_fbc == -1) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual.");
+		return 0;
+	}
+
+	/* we found a config */
+	bestFbc = fbc[best_fbc];
+	XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc);
+	if (vi->depth != 32 && transparent)
+		RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL,  "Failed to to find a matching visual with a 32-bit depth.");
+
+	if (best_samples < hints->samples)
+		RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count.");
+
+	XFree(fbc);
+	visual = *vi;
+	XFree(vi);
+
+	/* use the visual to create a new window */
+	RGFW_XCreateWindow(visual, "", win->internal.flags, win);
+
+	if (showWindow) {
+		RGFW_window_show(win);
+	}
+
+	/* create the actual OpenGL context  */
+	i32 context_attribs[40];
+	RGFW_attribStack_init(&stack, context_attribs, 40);
+
+	i32 mask = 0;
+	switch (hints->profile) {
+		case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break;
+		case RGFW_glForwardCompatibility: mask |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
+		case RGFW_glCompatibility: mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
+		case RGFW_glCore: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
+		default: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break;
+	}
+
+	RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask);
+
+	if (hints->minor || hints->major) {
+		RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major);
+		RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor);
+	}
+
+
+	if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) {
+		if (hints->releaseBehavior == RGFW_glReleaseFlush) {
+			RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
+		} else if (hints->releaseBehavior == RGFW_glReleaseNone) {
+			RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
+		}
+	}
+
+	i32 flags = 0;
+	if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+	if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
+	if (flags) {
+		RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags);
+	}
+
+	if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) {
+		RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
+	}
+
+	RGFW_attribStack_pushAttribs(&stack, 0, 0);
+
+	/*  create the context */
+	glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
+	char str[] = "glXCreateContextAttribsARB";
+	glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str);
+
+	GLXContext ctx = NULL;
+	if (hints->share) {
+		ctx = hints->share->ctx;
+	}
+
+	if (glXCreateContextAttribsARB == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context.");
+			win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
+	} else {
+		_RGFW->x11Error = NULL;
+		win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs);
+		if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) {
+			RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context.");
+			win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True);
+		}
+	}
+
+	#ifndef RGFW_NO_GLXWINDOW
+		win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL);
+	#else
+		win->src.ctx.native->window = win->src.window;
+	#endif
+
+	glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx);
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
+
+	RGFW_window_swapInterval_OpenGL(win, 0);
+
+	return RGFW_TRUE;
+}
+
+void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) {
+	#ifndef RGFW_NO_GLXWINDOW
+	if (win->src.ctx.native->window != win->src.window) {
+		glXDestroyWindow(_RGFW->display, win->src.ctx.native->window);
+	}
+	#endif
+
+	glXDestroyContext(_RGFW->display, ctx->ctx);
+	win->src.ctx.native = NULL;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL,  "OpenGL context freed.");
+}
+
+RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL)(const char * extension, size_t len) {
+	RGFW_init();
+	const char* extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display));
+	return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len);
+}
+
+RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); }
+
+void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.native);
+	if (win == NULL)
+		glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
+	else
+		glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx);
+	return;
+}
+void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return glXGetCurrentContext(); }
+void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); }
+
+void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) {
+	RGFW_ASSERT(win != NULL);
+	/* cached pfn to avoid calling glXGetProcAddress more than once */
+	static PFNGLXSWAPINTERVALEXTPROC pfn = NULL;
+	static int (*pfn2)(int) = NULL;
+
+	if (pfn == NULL) {
+		u8 str[] = "glXSwapIntervalEXT";
+		pfn = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(str);
+		if (pfn == NULL)  {
+			pfn = (PFNGLXSWAPINTERVALEXTPROC)1;
+			const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
+
+			size_t i;
+			for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) {
+				pfn2 = (int(*)(int))glXGetProcAddress((u8*)array[i]);
+			}
+
+			if (pfn2 != NULL) {
+				RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext,  "Failed to load swap interval function, fallingback to the native swapinterval function");
+			} else {
+				RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext,  "Failed to load swap interval function");
+			}
+		}
+	}
+
+	if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) {
+		pfn(_RGFW->display, win->src.ctx.native->window, swapInterval);
+	}
+	else if (pfn2 != NULL) {
+		pfn2(swapInterval);
+	}
+}
+#endif /* RGFW_OPENGL */
+
+i32 RGFW_initPlatform_X11(void) {
+    #ifdef RGFW_USE_XDL
+		XDL_init();
+	#endif
+
+	#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
+	#if defined(__CYGWIN__)
+				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
+	#elif defined(__OpenBSD__) || defined(__NetBSD__)
+				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
+	#else
+				RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
+	#endif
+		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
+		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
+		RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
+	#endif
+
+	#if !defined(RGFW_NO_X11_XI_PRELOAD)
+	#if defined(__CYGWIN__)
+			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
+	#elif defined(__OpenBSD__) || defined(__NetBSD__)
+			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
+	#else
+			RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
+	#endif
+			RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
+	#endif
+
+	#if !defined(RGFW_NO_X11_EXT_PRELOAD)
+	#if defined(__CYGWIN__)
+			RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
+	#elif defined(__OpenBSD__) || defined(__NetBSD__)
+	        RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
+	#else
+			RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
+	#endif
+			RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
+			RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
+			RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
+    	    RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
+	        RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
+    #endif
+
+    XInitThreads(); /*!< init X11 threading */
+    _RGFW->display = XOpenDisplay(0);
+	_RGFW->context = XUniqueContext();
+
+	XSetWindowAttributes wa;
+    RGFW_MEMZERO(&wa, sizeof(wa));
+    wa.event_mask = PropertyChangeMask;
+    _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0,
+                                        InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa);
+
+    u8 RGFW_blk[] = { 0, 0, 0, 0 };
+	_RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
+
+	_RGFW->clipboard = NULL;
+
+    XkbComponentNamesRec rec;
+    XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd);
+    XkbDescPtr evdesc;
+    XSetErrorHandler(RGFW_XErrorHandler);
+	u8 old[256];
+
+    XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc);
+
+    RGFW_MEMZERO(&rec, sizeof(rec));
+    char evdev[] = "evdev";
+    rec.keycodes = evdev;
+    evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
+    /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
+    if(evdesc != NULL && desc != NULL) {
+        int i, j;
+        for(i = 0; i < (int)sizeof(old); i++){
+    	    old[i] = _RGFW->keycodes[i];
+    	    _RGFW->keycodes[i] = 0;
+        }
+        for(i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
+    	    for(j = desc->min_key_code; j <= desc->max_key_code; j++){
+                if(RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
+                    _RGFW->keycodes[j] = old[i];
+                    break;
+                }
+    	    }
+        }
+		XkbFreeKeyboard(desc, 0, True);
+		XkbFreeKeyboard(evdesc, 0, True);
+    }
+
+	XSetLocaleModifiers("");
+	XRegisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
+
+	i32 errorBase;
+	if (XRRQueryExtension(_RGFW->display, &_RGFW->xrandrEventBase, &errorBase)) {
+        XRRSelectInput(_RGFW->display, RootWindow(_RGFW->display, DefaultScreen(_RGFW->display)), RROutputChangeNotifyMask);
+	}
+
+	return 0;
+}
+
+void RGFW_deinitPlatform_X11(void) {
+    #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
+	/* to save the clipboard on the x server after the window is closed */
+	RGFW_LOAD_ATOM(CLIPBOARD_MANAGER);  RGFW_LOAD_ATOM(CLIPBOARD);
+	RGFW_LOAD_ATOM(SAVE_TARGETS);
+	if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) {
+		XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime);
+        while (RGFW_XHandleClipboardSelectionHelper());
+	}
+
+	XUnregisterIMInstantiateCallback(_RGFW->display, NULL, NULL, NULL, RGFW_x11_imInitCallback, NULL);
+
+    if (_RGFW->im) {
+        XCloseIM(_RGFW->im);
+        _RGFW->im = NULL;
+    }
+
+	if (_RGFW->clipboard) {
+		RGFW_FREE(_RGFW->clipboard);
+		_RGFW->clipboard = NULL;
+	}
+
+	if (_RGFW->hiddenMouse) {
+		RGFW_freeMouse(_RGFW->hiddenMouse);
+		_RGFW->hiddenMouse = NULL;
+	}
+
+    XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */
+    XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */
+
+    #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
+        RGFW_FREE_LIBRARY(X11Cursorhandle);
+    #endif
+    #if !defined(RGFW_NO_X11_XI_PRELOAD)
+        RGFW_FREE_LIBRARY(X11Xihandle);
+    #endif
+
+    #ifdef RGFW_USE_XDL
+        XDL_close();
+    #endif
+
+    #if !defined(RGFW_NO_X11_EXT_PRELOAD)
+        RGFW_FREE_LIBRARY(X11XEXThandle);
+    #endif
+}
+
+void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
+    if (win->src.ic) {
+        XDestroyIC(win->src.ic);
+        win->src.ic = NULL;
+    }
+
+	XFreeGC(_RGFW->display, win->src.gc);
+	XDeleteContext(_RGFW->display, win->src.window, _RGFW->context);
+	XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /*!< close the window */
+	return;
+}
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
+	WGPUSurfaceDescriptor surfaceDesc = {0};
+	WGPUSurfaceSourceXlibWindow fromXlib = {0};
+	fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
+	fromXlib.display = _RGFW->display;
+	fromXlib.window = window->src.window;
+
+	surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain;
+	return wgpuInstanceCreateSurface(instance, &surfaceDesc);
+}
+#endif
+
+#endif
+/*
+	End of X11 linux / wayland / unix defines
+*/
+
+/*
+
+	Start of Wayland defayland
+*/
+
+#ifdef RGFW_WAYLAND
+#ifdef RGFW_X11
+#undef RGFW_FUNC /* remove previous define */
+#define RGFW_FUNC(func) func##_Wayland
+#else
+#define RGFW_FUNC(func) func
+#endif
+
+/*
+Wayland TODO: (out of date)
+- fix RGFW_keyPressed lock state
+
+	RGFW_windowMoved, 		the window was moved (by the user)
+	RGFW_windowRefresh	 	The window content needs to be refreshed
+
+	RGFW_dataDrop 				a file has been dropped into the window
+	RGFW_dataDrag
+
+- window args:
+	#define RGFW_windowNoResize	 			the window cannot be resized  by the user
+	#define RGFW_windowAllowDND     			the window supports drag and drop
+	#define RGFW_scaleToMonitor 			scale the window to the screen
+
+- other missing functions functions ("TODO wayland") (~30 functions)
+- fix buffer rendering weird behavior
+*/
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-keysyms.h>
+#include <xkbcommon/xkbcommon-compose.h>
+#include <dirent.h>
+#include <linux/kd.h>
+#include <wayland-cursor.h>
+#include <fcntl.h>
+
+struct wl_display* RGFW_getDisplay_Wayland(void) { return _RGFW->wl_display; }
+struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { return win->src.surface; }
+
+
+/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
+#include "xdg-shell.h"
+#include "xdg-toplevel-icon-v1.h"
+#include "xdg-decoration-unstable-v1.h"
+#include "relative-pointer-unstable-v1.h"
+#include "pointer-constraints-unstable-v1.h"
+#include "xdg-output-unstable-v1.h"
+#include "pointer-warp-v1.h"
+
+void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized);
+
+static void RGFW_wl_setOpaque(RGFW_window* win) {
+	struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor);
+
+	if (!wl_region) return; /* return if no region was created */
+
+	wl_region_add(wl_region, 0, 0, win->w, win->h);
+	wl_surface_set_opaque_region(win->src.surface, wl_region);
+	wl_region_destroy(wl_region);
+
+}
+
+static void RGFW_wl_xdg_wm_base_ping_handler(void* data, struct xdg_wm_base* wm_base,
+		u32 serial) {
+	RGFW_UNUSED(data);
+    xdg_wm_base_pong(wm_base, serial);
+}
+static void RGFW_wl_xdg_surface_configure_handler(void* data, struct xdg_surface* xdg_surface,
+		u32 serial) {
+
+    xdg_surface_ack_configure(xdg_surface, serial);
+
+    RGFW_window* win = (RGFW_window*)data;
+
+    if (win == NULL) {
+		win = _RGFW->kbOwner;
+		if (win == NULL)
+			return;
+	}
+
+	/* useful for libdecor */
+	if (win->src.activated != win->src.pending_activated) {
+		win->src.activated = win->src.pending_activated;
+	}
+
+	if (win->src.maximized != win->src.pending_maximized) {
+		RGFW_toggleWaylandMaximized(win, win->src.pending_maximized);
+
+		RGFW_window_checkMode(win);
+	}
+
+
+	if (win->src.resizing) {
+
+		RGFW_windowResizedCallback(win, win->w, win->h);
+		RGFW_window_resize(win, win->w, win->h);
+		if (!(win->internal.flags & RGFW_windowTransparent)) {
+			RGFW_wl_setOpaque(win);
+		}
+	}
+
+	win->src.configured = RGFW_TRUE;
+}
+
+static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel,
+		i32 width, i32 height, struct wl_array* states) {
+
+    RGFW_UNUSED(toplevel);
+    RGFW_window* win = (RGFW_window*)data;
+
+
+    win->src.pending_activated = RGFW_FALSE;
+    win->src.pending_maximized = RGFW_FALSE;
+    win->src.resizing = RGFW_FALSE;
+
+
+	enum xdg_toplevel_state* state;
+	wl_array_for_each(state, states) {
+		switch (*state) {
+			case XDG_TOPLEVEL_STATE_ACTIVATED:
+				 win->src.pending_activated = RGFW_TRUE;
+				break;
+			case XDG_TOPLEVEL_STATE_MAXIMIZED:
+				win->src.pending_maximized = RGFW_TRUE;
+				break;
+			default:
+				break;
+		}
+
+	}
+	/* if width and height are not zero and are not the same as the window */
+    /* the window is resizing so update the values */
+	if ((width && height) && (win->w != width ||  win->h != height)) {
+		win->src.resizing = RGFW_TRUE;
+		win->src.w = win->w = width;
+		win->src.h = win->h = height;
+	}
+}
+
+static void RGFW_wl_xdg_toplevel_close_handler(void* data, struct xdg_toplevel *toplevel) {
+	RGFW_UNUSED(toplevel);
+	RGFW_window* win = (RGFW_window*)data;
+
+	if (!win->internal.shouldClose) {
+		RGFW_windowCloseCallback(win);
+	}
+}
+
+static void RGFW_wl_xdg_decoration_configure_handler(void* data,
+		struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, u32 mode) {
+	RGFW_window* win = (RGFW_window*)data; RGFW_UNUSED(zxdg_toplevel_decoration_v1);
+
+	/* this is expected to run once */
+    /* set the decoration mode set by earlier request */
+	if (mode != win->src.decoration_mode) {
+		win->src.decoration_mode = mode;
+	}
+}
+
+static void RGFW_wl_shm_format_handler(void* data, struct wl_shm *shm, u32 format) {
+	RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
+}
+
+static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
+	u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) {
+
+	RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo);
+	RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel);
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+
+	RGFW_ASSERT(RGFW->mouseOwner != NULL);
+	RGFW_window* win = RGFW->mouseOwner;
+
+	RGFW_ASSERT(win);
+
+	float vecX =  (float)wl_fixed_to_double(dx);
+	float vecY = (float)wl_fixed_to_double(dy);
+	RGFW_rawMotionCallback(win, vecX, vecY);
+}
+
+static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) {
+	RGFW_UNUSED(zwp_locked_pointer_v1);
+	RGFW_info* RGFW = (RGFW_info*)data;
+	wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); /* draw no cursor */
+}
+
+static void RGFW_wl_pointer_enter(void* data, struct wl_pointer* pointer, u32 serial,
+		struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
+
+	/* save when the pointer is locked or using default cursor */
+	RGFW->mouse_enter_serial = serial;
+	win->internal.mouseInside = RGFW_TRUE;
+	RGFW->windowState.mouseEnter = RGFW_TRUE;
+
+	RGFW->mouseOwner = win;
+
+	/* set the cursor */
+	if (win->src.using_custom_cursor) {
+		wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0);
+	}
+	else {
+		RGFW_window_setMouseDefault(win);
+	}
+
+	i32 x = (i32)wl_fixed_to_double(surface_x);
+	i32 y = (i32)wl_fixed_to_double(surface_y);
+	RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE);
+}
+
+static void RGFW_wl_pointer_leave(void* data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) {
+	RGFW_UNUSED(pointer); RGFW_UNUSED(serial);
+	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
+	RGFW_info* RGFW = (RGFW_info*)data;
+	if (RGFW->mouseOwner == win)
+		RGFW->mouseOwner = NULL;
+
+	RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
+}
+
+static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) {
+	RGFW_UNUSED(pointer); RGFW_UNUSED(time);
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_ASSERT(RGFW->mouseOwner != NULL);
+
+	RGFW_window* win = RGFW->mouseOwner;
+
+	i32 convertedX = (i32)wl_fixed_to_double(x);
+	i32 convertedY = (i32)wl_fixed_to_double(y);
+
+	RGFW_mouseMotionCallback(win, convertedX, convertedY);
+}
+
+static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) {
+	RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
+	RGFW_info* RGFW = (RGFW_info*)data;
+
+	RGFW_ASSERT(RGFW->mouseOwner != NULL);
+	RGFW_window* win = RGFW->mouseOwner;
+
+	u32 b = (button - 0x110);
+
+	/* flip right and middle button codes */
+	if (b == 1) b = 2;
+	else if (b == 2) b = 1;
+
+	RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state));
+}
+
+static void RGFW_wl_pointer_axis(void* data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) {
+	RGFW_UNUSED(pointer); RGFW_UNUSED(time);  RGFW_UNUSED(axis);
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_ASSERT(RGFW->mouseOwner != NULL);
+	RGFW_window* win = RGFW->mouseOwner;
+
+	float scrollX = 0.0;
+	float scrollY = 0.0;
+
+	if (!(win->internal.enabledEvents  & (RGFW_BIT(RGFW_mouseScroll)))) return;
+
+	if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
+		scrollX = (float)(-wl_fixed_to_double(value) / 10.0);
+	else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+		scrollY = (float)(-wl_fixed_to_double(value) / 10.0);
+
+	RGFW_mouseScrollCallback(win, scrollX, scrollY);
+}
+
+
+static void RGFW_doNothing(void) { }
+
+static void RGFW_wl_keyboard_keymap(void* data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size) {
+	RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
+	RGFW_info* RGFW = (RGFW_info*)data;
+
+	char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+	xkb_keymap_unref(RGFW->keymap);
+	RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+	munmap(keymap_string, size);
+	close(fd);
+	xkb_state_unref(RGFW->xkb_state);
+	RGFW->xkb_state = xkb_state_new(RGFW->keymap);
+
+	const char* locale = getenv("LC_ALL");
+	if (!locale)
+		locale = getenv("LC_CTYPE");
+	if (!locale)
+		locale = getenv("LANG");
+	if (!locale)
+		locale = "C";
+
+	struct xkb_compose_table* composeTable = xkb_compose_table_new_from_locale(RGFW->xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
+	if (composeTable) {
+		RGFW->composeState = xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
+		xkb_compose_table_unref(composeTable);
+	}
+}
+
+static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) {
+	RGFW_UNUSED(keyboard); RGFW_UNUSED(keys);
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
+	RGFW->kbOwner = win;
+
+
+	// this is to prevent race conditions
+	if (RGFW->data_device != NULL && win->src.data_source != NULL) {
+		wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial);
+	}
+	/* is set when RGFW_window_minimize is called; if the minimize button is */
+	/* pressed this flag is not set since there is no event to listen for */
+	if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE;
+
+	RGFW_windowFocusCallback(win, RGFW_TRUE);
+}
+
+static void RGFW_wl_keyboard_leave(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) {
+	RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
+	if (RGFW->kbOwner == win)
+		RGFW->kbOwner = NULL;
+
+	RGFW_windowFocusCallback(win, RGFW_FALSE);
+}
+
+static xkb_keysym_t RGFW_wl_composeSymbol(RGFW_info* RGFW, xkb_keysym_t sym) {
+    if (sym == XKB_KEY_NoSymbol || !RGFW->composeState)
+        return sym;
+    if (xkb_compose_state_feed(RGFW->composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED)
+        return sym;
+    switch (xkb_compose_state_get_status(RGFW->composeState)) {
+        case XKB_COMPOSE_COMPOSED:
+            return xkb_compose_state_get_one_sym(RGFW->composeState);
+        case XKB_COMPOSE_COMPOSING:
+        case XKB_COMPOSE_CANCELLED:
+            return XKB_KEY_NoSymbol;
+        case XKB_COMPOSE_NOTHING:
+        default:
+            return sym;
+    }
+}
+
+static void RGFW_wl_send_key_event(u32 key) {
+	const xkb_keysym_t* keysyms;
+	if (xkb_state_key_get_syms(_RGFW->xkb_state, key + 8, &keysyms) == 1) {
+		xkb_keysym_t keysym = RGFW_wl_composeSymbol(_RGFW, keysyms[0]);
+		u32 codepoint = xkb_keysym_to_utf32(keysym);
+		if (codepoint != 0) {
+			RGFW_keyCharCallback(_RGFW->kbOwner, codepoint);
+		}
+	}
+}
+
+static void RGFW_wl_keyboard_key(void* data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) {
+	RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+	if (RGFW->kbOwner == NULL) return;
+
+	RGFW_window *RGFW_key_win = RGFW->kbOwner;
+	RGFW_key RGFWkey = RGFW_apiKeyToRGFW(key + 8);
+
+	RGFW_keyUpdateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "ScrollLock")));
+	RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, RGFW_key_win->internal.mod, RGFW_isKeyDown((u8)RGFWkey) && RGFW_BOOL(state), RGFW_BOOL(state));
+
+	/* [comment by Kala Telo (@kala-telo) and edited by Riley Mabb (@ColleagueRiley)]
+		we send the event at the moment we receive it, and
+		repeated key presses will be handled by RGFW_pollEvents
+		if the compositor doesn't support proxy (seat?) version
+		of at least 4, it won't initialize wl_repeat_info_rate,
+		and by spec, rate of 0 means disabled, thus repeating
+		keys are disabled by being zero-initialized
+	*/
+	RGFW->last_key = state ? key : 0;
+	RGFW->last_key_time = time + (u32)_RGFW->wl_repeat_info_delay;
+	if (state) {
+		RGFW_wl_send_key_event(_RGFW->last_key);
+	}
+}
+
+static void RGFW_wl_keyboard_modifiers(void* data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) {
+	RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
+	RGFW_info* RGFW = (RGFW_info*)data;
+	xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
+}
+
+static void RGFW_wl_keyboard_repeat_info(void* data, struct wl_keyboard *keyboard, i32 rate, i32 delay) {
+	RGFW_UNUSED(data);
+	RGFW_UNUSED(keyboard);
+	_RGFW->wl_repeat_info_rate = rate;
+	_RGFW->wl_repeat_info_delay = delay;
+}
+
+static void RGFW_wl_seat_capabilities(void* data, struct wl_seat *seat, u32 capabilities) {
+	RGFW_info* RGFW = (RGFW_info*)data;
+    static struct wl_pointer_listener pointer_listener;
+	RGFW_MEMZERO(&pointer_listener, sizeof(pointer_listener));
+	pointer_listener.enter = &RGFW_wl_pointer_enter;
+	pointer_listener.leave = &RGFW_wl_pointer_leave;
+	pointer_listener.motion = &RGFW_wl_pointer_motion;
+	pointer_listener.button = &RGFW_wl_pointer_button;
+	pointer_listener.axis = &RGFW_wl_pointer_axis;
+
+	static struct wl_keyboard_listener keyboard_listener;
+	RGFW_MEMZERO(&keyboard_listener, sizeof(keyboard_listener));
+	keyboard_listener.keymap = &RGFW_wl_keyboard_keymap;
+	keyboard_listener.enter = &RGFW_wl_keyboard_enter;
+	keyboard_listener.leave = &RGFW_wl_keyboard_leave;
+	keyboard_listener.key = &RGFW_wl_keyboard_key;
+	keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers;
+	keyboard_listener.repeat_info = &RGFW_wl_keyboard_repeat_info;
+
+    if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) {
+		RGFW->wl_pointer = wl_seat_get_pointer(seat);
+		wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW);
+	}
+	if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) {
+		RGFW->wl_keyboard = wl_seat_get_keyboard(seat);
+		wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW);
+	}
+
+    if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) {
+		wl_pointer_destroy(RGFW->wl_pointer);
+	}
+	if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) {
+		wl_keyboard_destroy(RGFW->wl_keyboard);
+	}
+}
+
+static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output,
+			 i32 x, i32 y, i32 physical_width, i32 physical_height,
+			 i32 subpixel, const char *make, const char *model, i32 transform) {
+
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+	monitor->x = x;
+	monitor->y = y;
+
+	monitor->physW = (float)physical_width / 25.4f;
+	monitor->physH = (float)physical_height / 25.4f;
+
+	RGFW_UNUSED(wl_output);
+	RGFW_UNUSED(subpixel);
+	RGFW_UNUSED(make);
+	RGFW_UNUSED(model);
+	RGFW_UNUSED(transform);
+}
+
+static void RGFW_wl_output_handle_mode(void *data, struct wl_output *wl_output, u32 flags,
+		     i32 width, i32 height, i32 refresh) {
+
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+
+	RGFW_monitorMode mode;
+	mode.w = width;
+	mode.h = height;
+	mode.refreshRate = (float)refresh / 1000.0f;
+	mode.src = wl_output;
+
+	monitor->node->modeCount += 1;
+
+	RGFW_monitorMode* modes = (RGFW_monitorMode*)RGFW_ALLOC(monitor->node->modeCount * sizeof(RGFW_monitorMode));
+
+	if (monitor->node->modeCount > 1) {
+		RGFW_monitor_getModesPtr(monitor, &modes);
+		RGFW_FREE(monitor->node->modes);
+	}
+
+	modes[monitor->node->modeCount - 1] = mode;
+	monitor->node->modes = modes;
+
+	if (flags & WL_OUTPUT_MODE_CURRENT) {
+		monitor->mode = mode;
+	} else {
+	}
+}
+
+static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, i32 factor) {
+	RGFW_UNUSED(wl_output);
+	RGFW_monitor* mon = &((RGFW_monitorNode*)data)->mon;
+
+	mon->scaleX = (float)factor;
+	mon->scaleY = (float)factor;
+}
+
+static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name) {
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+
+	RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1);
+	monitor->name[sizeof(monitor->name) - 1] = '\0';
+
+	RGFW_UNUSED(wl_output);
+
+}
+
+static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 x, i32 y) {
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+	monitor->x = x;
+	monitor->y = y;
+	RGFW_UNUSED(zxdg_output_v1);
+}
+
+static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, i32 width, i32 height) {
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+
+	float mon_float_width = (float) monitor->mode.w;
+	float mon_float_height = (float) monitor->mode.h;
+
+	float scaleX = (mon_float_width / (float) width);
+	float scaleY = (mon_float_height / (float) height);
+	RGFW_UNUSED(scaleY);
+
+	float dpi = scaleX * 96.0f;
+
+	monitor->pixelRatio = dpi >= 192.0f ? 2.0f : 1.0f;
+
+	/* under xwayland the monitor changes w & h when compositor scales it */
+	monitor->mode.w = width;
+	monitor->mode.h = height;
+	RGFW_UNUSED(zxdg_output_v1);
+}
+
+
+static void RGFW_wl_output_handle_done(void* data, struct wl_output* output) {
+	RGFW_UNUSED(output);
+
+	RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon;
+
+    if (monitor->physW <= 0 || monitor->physH <= 0) {
+		monitor->physW = (i32) ((float)monitor->mode.w / 96.0f);
+		monitor->physH = (i32) ((float)monitor->mode.h / 96.0f);
+    }
+
+	if (((RGFW_monitorNode*)data)->disconnected == RGFW_FALSE) {
+		return;
+	}
+
+	((RGFW_monitorNode*)data)->disconnected = RGFW_TRUE;
+
+	RGFW_monitorCallback(_RGFW->root, monitor, RGFW_TRUE);
+}
+
+static void RGFW_wl_create_outputs(struct wl_registry *const registry, u32 id) {
+	struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_proxy_get_version((struct wl_proxy*)_RGFW->seat));
+	RGFW_monitorNode* node;
+	RGFW_monitor mon;
+
+	if (!output) return;
+
+	char RGFW_mon_default_name[10];
+
+	RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%zu", _RGFW->monitors.count);
+	RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1);
+	mon.name[sizeof(mon.name) - 1] = '\0';
+
+	/* set in case compositor does not send one */
+    /* or no xdg_output support */
+	mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f;
+
+	node = RGFW_monitors_add(&mon);
+	if (node == NULL) return;
+
+	node->modeCount = 0;
+	node->disconnected = RGFW_TRUE;
+	node->id = id;
+	node->output = output;
+
+	static const struct wl_output_listener wl_output_listener = {
+			.geometry = RGFW_wl_output_set_geometry,
+			.mode = RGFW_wl_output_handle_mode,
+			.done = RGFW_wl_output_handle_done,
+			.scale = RGFW_wl_output_set_scale,
+			.name = RGFW_wl_output_set_name,
+			.description = (void (*)(void *, struct wl_output *, const char *))&RGFW_doNothing
+	};
+
+	/* the wl_output will have a reference to the node */
+	wl_output_set_user_data(output, node);
+
+	/* pass the monitor so we can access it in the callback functions */
+	wl_output_add_listener(output, &wl_output_listener, node);
+
+	if (!_RGFW->xdg_output_manager)
+		return; /* compositor does not support it */
+
+	static const struct zxdg_output_v1_listener xdg_output_listener = {
+		.name = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
+		.done = (void (*)(void *,struct zxdg_output_v1 *))&RGFW_doNothing,
+		.description = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing,
+		.logical_position = RGFW_xdg_output_logical_pos,
+		.logical_size = RGFW_xdg_output_logical_size
+	};
+
+	node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output);
+	zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
+}
+
+static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) {
+	RGFW_UNUSED(wl_surface);
+
+	RGFW_window* win = (RGFW_window*)data;
+	RGFW_monitorNode* node = wl_output_get_user_data(output);
+	if (node == NULL) return;
+
+	win->src.active_monitor = node;
+}
+
+static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, i32 fd) {
+	RGFW_UNUSED(data); RGFW_UNUSED(wl_data_source);
+
+	// a client can accept our clipboard
+	if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) {
+		// do not write \0
+		write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1);
+	}
+
+	close(fd);
+}
+
+static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) {
+
+	RGFW_info* RGFW = (RGFW_info*)data;
+
+	if (RGFW->kbOwner->src.data_source == wl_data_source) {
+		RGFW->kbOwner->src.data_source = NULL;
+	}
+
+	wl_data_source_destroy(wl_data_source);
+
+}
+
+static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
+
+	RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
+	static const struct wl_data_offer_listener wl_data_offer_listener = {
+		.offer = (void (*)(void *data, struct wl_data_offer *wl_data_offer, const char *))RGFW_doNothing,
+		.source_actions = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing,
+		.action = (void (*)(void *data, struct wl_data_offer *wl_data_offer, u32 dnd_action))RGFW_doNothing
+	};
+	wl_data_offer_add_listener(wl_data_offer, &wl_data_offer_listener, NULL);
+}
+
+static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) {
+	RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device);
+	/* Clipboard is empty */
+	if (wl_data_offer == NULL) {
+		return;
+	}
+
+	int pfds[2];
+	pipe(pfds);
+
+	wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]);
+	close(pfds[1]);
+
+	wl_display_roundtrip(_RGFW->wl_display);
+
+	char buf[1024];
+
+	ssize_t n = read(pfds[0], buf, sizeof(buf));
+
+	if (_RGFW->clipboard) {
+		RGFW_FREE(_RGFW->clipboard);
+	}
+	_RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n);
+	RGFW_ASSERT(_RGFW->clipboard != NULL);
+	RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n);
+
+	_RGFW->clipboard_len = (size_t)n + 1;
+
+	close(pfds[0]);
+
+	wl_data_offer_destroy(wl_data_offer);
+
+}
+
+static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) {
+
+    static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
+    static const struct wl_shm_listener shm_listener = { .format = RGFW_wl_shm_format_handler };
+
+    RGFW_info* RGFW = (RGFW_info*)data;
+    RGFW_UNUSED(version);
+
+    if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
+		RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4);
+	} else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
+		RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
+	} else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
+		RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
+    } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) {
+		RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1);
+    } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) {
+		RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
+	} else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) {
+		RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1);
+    } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
+        RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+        wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW);
+	} else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
+		RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, version < 4 ? 3 : 4);
+		wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW);
+	} else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) {
+		RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1);
+	} else if (RGFW_STRNCMP(interface,"wl_output", 10) == 0) {
+		RGFW_wl_create_outputs(registry, id);
+	} else if (RGFW_STRNCMP(interface, wp_pointer_warp_v1_interface.name, 255) == 0) {
+		RGFW->wp_pointer_warp = wl_registry_bind(registry, id, &wp_pointer_warp_v1_interface, 1);
+	} else if (RGFW_STRNCMP(interface,"wl_data_device_manager", 23) == 0) {
+		RGFW->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1);
+	}
+}
+
+static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *registry, u32 id) {
+	RGFW_UNUSED(data); RGFW_UNUSED(registry);
+	RGFW_info* RGFW = (RGFW_info*)data;
+	RGFW_monitorNode* prev = RGFW->monitors.list.head;
+	RGFW_monitorNode* node = NULL;
+	if (prev == NULL) return;
+
+	if (prev->id != id) {
+		/* find the first node that has a matching id */
+		while(prev->next != NULL && prev->next->id != id) {
+			prev = prev->next;
+		}
+
+		if (prev->next == NULL) return;
+		node = prev->next;
+	} else {
+		node = prev;
+	}
+
+	if (node->output) {
+		wl_output_destroy(node->output);
+	}
+
+	if (node->xdg_output) {
+		zxdg_output_v1_destroy(node->xdg_output);
+	}
+
+	if (node->modeCount) {
+		RGFW_FREE(node->modes);
+		node->modeCount = 0;
+	}
+
+	RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_FALSE);
+	RGFW_monitors_remove(node, prev);
+}
+
+static void RGFW_wl_randname(char *buf) {
+	struct timespec ts;
+	clock_gettime(CLOCK_REALTIME, &ts);
+	long r = ts.tv_nsec;
+
+    int i;
+    for (i = 0; i < 6; i++) {
+		buf[i] = (char)('A'+(r&15)+(r&16)*2);
+		r >>= 5;
+	}
+}
+
+static int RGFW_wl_anonymous_shm_open(void) {
+	char name[] = "/RGFW-wayland-XXXXXX";
+	int retries = 100;
+
+	do {
+		RGFW_wl_randname(name + RGFW_unix_stringlen(name) - 6);
+
+		--retries;
+		/* shm_open guarantees that O_CLOEXEC is set */
+		int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
+		if (fd >= 0) {
+			shm_unlink(name);
+			return fd;
+		}
+	} while (retries > 0 && errno == EEXIST);
+
+	return -1;
+}
+
+static int RGFW_wl_create_shm_file(off_t size) {
+	int fd = RGFW_wl_anonymous_shm_open();
+	if (fd < 0) {
+		return fd;
+	}
+
+	if (ftruncate(fd, size) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+i32 RGFW_initPlatform_Wayland(void) {
+	_RGFW->wl_display = wl_display_connect(NULL);
+	if (_RGFW->wl_display == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errWayland,  "Failed to load Wayland display");
+		return -1;
+	}
+
+	_RGFW->compositor = NULL;
+	static const struct wl_registry_listener registry_listener = {
+		.global = RGFW_wl_global_registry_handler,
+		.global_remove = RGFW_wl_global_registry_remove,
+	};
+
+	_RGFW->registry = wl_display_get_registry(_RGFW->wl_display);
+	wl_registry_add_listener(_RGFW->registry, &registry_listener, _RGFW);
+
+	wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */
+
+	if (_RGFW->compositor == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errWayland, "Can't find compositor.");
+		return -1;
+	}
+
+	if (_RGFW->wl_cursor_theme == NULL) {
+		_RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm);
+		_RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
+	}
+
+	 u8 RGFW_blk[] = { 0, 0, 0, 0 };
+	_RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
+
+	static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+		.ping = RGFW_wl_xdg_wm_base_ping_handler,
+	};
+
+	xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL);
+
+	_RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+
+	static const struct wl_data_device_listener wl_data_device_listener = {
+		.data_offer = RGFW_wl_data_device_data_offer,
+		.enter = (void (*)(void *, struct wl_data_device *, u32, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer *))&RGFW_doNothing,
+		.leave = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
+		.motion = (void (*)(void *, struct wl_data_device *, u32, wl_fixed_t, wl_fixed_t))&RGFW_doNothing,
+		.drop = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing,
+		.selection = RGFW_wl_data_device_selection
+	};
+
+	if (_RGFW->seat && _RGFW->data_device_manager) {
+		_RGFW->data_device = wl_data_device_manager_get_data_device(_RGFW->data_device_manager, _RGFW->seat);
+		wl_data_device_add_listener(_RGFW->data_device, &wl_data_device_listener, NULL);
+	}
+
+	return 0;
+}
+
+void RGFW_deinitPlatform_Wayland(void) {
+	if (_RGFW->clipboard) {
+		RGFW_FREE(_RGFW->clipboard);
+		_RGFW->clipboard = NULL;
+	}
+
+    if (_RGFW->wl_pointer) {
+		wl_pointer_destroy(_RGFW->wl_pointer);
+	}
+	if (_RGFW->wl_keyboard) {
+		wl_keyboard_destroy(_RGFW->wl_keyboard);
+	}
+
+	wl_registry_destroy(_RGFW->registry);
+	if (_RGFW->decoration_manager != NULL)
+		zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager);
+	if (_RGFW->relative_pointer_manager != NULL) {
+		zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager);
+	}
+
+	if (_RGFW->relative_pointer) {
+		zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
+	}
+
+	if (_RGFW->constraint_manager != NULL) {
+		zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager);
+	}
+
+	if (_RGFW->xdg_output_manager != NULL)
+	if (_RGFW->icon_manager != NULL) {
+		xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager);
+	}
+
+	if (_RGFW->xdg_output_manager) {
+		zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager);
+	}
+
+	if (_RGFW->data_device_manager) {
+		wl_data_device_manager_destroy(_RGFW->data_device_manager);
+	}
+
+	if (_RGFW->data_device) {
+		wl_data_device_destroy(_RGFW->data_device);
+	}
+
+	if (_RGFW->wl_cursor_theme != NULL) {
+		wl_cursor_theme_destroy(_RGFW->wl_cursor_theme);
+	}
+
+	if (_RGFW->wp_pointer_warp != NULL) {
+		wp_pointer_warp_v1_destroy(_RGFW->wp_pointer_warp);
+	}
+
+	RGFW_freeMouse(_RGFW->hiddenMouse);
+
+	RGFW_monitorNode* node = _RGFW->monitors.list.head;
+
+	while (node != NULL) {
+		if (node->output) {
+			wl_output_destroy(node->output);
+		}
+
+		if (node->xdg_output) {
+			zxdg_output_v1_destroy(node->xdg_output);
+		}
+
+		_RGFW->monitors.count -= 1;
+		node = node->next;
+
+	}
+
+	wl_surface_destroy(_RGFW->cursor_surface);
+	wl_shm_destroy(_RGFW->shm);
+	wl_seat_release(_RGFW->seat);
+	xdg_wm_base_destroy(_RGFW->xdg_wm_base);
+	wl_compositor_destroy(_RGFW->compositor);
+	wl_display_disconnect(_RGFW->wl_display);
+}
+
+RGFW_format RGFW_FUNC(RGFW_nativeFormat)(void) { return RGFW_formatBGRA8; }
+
+RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+	surface->data = data;
+	surface->w = w;
+	surface->h = h;
+	surface->format = format;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoBuffer,  "Creating a 4 channel buffer");
+
+	u32 size = (u32)(surface->w * surface->h * 4);
+	int fd = RGFW_wl_create_shm_file(size);
+	if (fd < 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer.");
+		return RGFW_FALSE;
+	}
+
+	surface->native.pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size);
+
+	surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (surface->native.buffer == MAP_FAILED) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer, "mmap failed.");
+		return RGFW_FALSE;
+	}
+
+	surface->native.fd = fd;
+	surface->native.format = RGFW_formatBGRA8;
+	return RGFW_TRUE;
+}
+
+void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+
+	surface->native.wl_buffer = wl_shm_pool_create_buffer(surface->native.pool, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888);
+	RGFW_copyImageData(surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
+
+	wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0);
+	wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h));
+	wl_surface_commit(win->src.surface);
+
+	wl_buffer_destroy(surface->native.wl_buffer);
+
+	surface->native.wl_buffer = NULL;
+}
+
+void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+
+	if (surface->native.pool) wl_shm_pool_destroy(surface->native.pool);
+	if (surface->native.fd) close(surface->native.fd);
+	if (surface->native.buffer) munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4));
+}
+
+void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) {
+	RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
+
+	/* for now just toggle between SSD & CSD depending on the bool */
+	if (_RGFW->decoration_manager != NULL) {
+		zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE));
+	}
+}
+
+void RGFW_FUNC(RGFW_window_setRawMouseModePlatform) (RGFW_window* win, RGFW_bool state) {
+	RGFW_ASSERT(win);
+	if (_RGFW->relative_pointer_manager == NULL) return;
+
+	if (state == RGFW_FALSE) {
+		if (_RGFW->relative_pointer != NULL)
+			zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer);
+		_RGFW->relative_pointer = NULL;
+		return;
+	}
+
+	if (_RGFW->relative_pointer != NULL) return;
+
+	_RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer);
+
+	static const struct zwp_relative_pointer_v1_listener relative_motion_listener = {
+		.relative_motion = RGFW_wl_relative_pointer_motion
+	};
+
+	zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW);
+}
+
+void RGFW_FUNC(RGFW_window_captureMousePlatform) (RGFW_window* win, RGFW_bool state) {
+	RGFW_ASSERT(win);
+
+	/* compositor has no support or window already is locked do nothing */
+	if (_RGFW->constraint_manager == NULL) return;
+
+	if (state == RGFW_FALSE) {
+		if (win->src.locked_pointer != NULL)
+			zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
+		win->src.locked_pointer = NULL;
+		return;
+	}
+
+
+	if (win->src.locked_pointer != NULL) return;
+	win->src.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(_RGFW->constraint_manager, win->src.surface, _RGFW->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+
+	static const struct zwp_locked_pointer_v1_listener locked_listener = {
+		.locked = RGFW_wl_pointer_locked,
+		.unlocked = (void (*)(void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing
+	};
+
+	zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW);
+}
+
+RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	RGFW_debugCallback(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental");
+
+	static const struct xdg_surface_listener xdg_surface_listener = {
+		.configure = RGFW_wl_xdg_surface_configure_handler,
+	};
+
+	static const struct wl_surface_listener wl_surface_listener = {
+		.enter = RGFW_wl_surface_enter,
+		.leave = (void (*)(void *, struct wl_surface *, struct wl_output *))&RGFW_doNothing,
+		.preferred_buffer_scale = (void (*)(void *, struct wl_surface *, i32))&RGFW_doNothing,
+		.preferred_buffer_transform = (void (*)(void *, struct wl_surface *, u32))&RGFW_doNothing
+	};
+
+	win->src.surface = wl_compositor_create_surface(_RGFW->compositor);
+	wl_surface_add_listener(win->src.surface, &wl_surface_listener, win);
+
+	/* create a surface for a custom cursor */
+	win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor);
+
+	win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface);
+	xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win);
+
+	xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win);
+
+	win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
+
+	if (_RGFW->className == NULL)
+		_RGFW->className = (char*)name;
+
+	xdg_toplevel_set_app_id(win->src.xdg_toplevel, name);
+
+	xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
+
+	if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */
+		RGFW_wl_setOpaque(win);
+	}
+
+	static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+		.configure = RGFW_wl_xdg_toplevel_configure_handler,
+		.close = RGFW_wl_xdg_toplevel_close_handler,
+	};
+
+	xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win);
+
+	/* compositor supports both SSD & CSD
+	   So choose accordingly
+	 */
+	if (_RGFW->decoration_manager) {
+		u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
+		win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
+			_RGFW->decoration_manager, win->src.xdg_toplevel);
+
+		static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = {
+			.configure = RGFW_wl_xdg_decoration_configure_handler
+		};
+
+		zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win);
+
+		/* we want no decorations */
+		if ((flags & RGFW_windowNoBorder)) {
+			decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
+		}
+
+		zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode);
+
+        /* no xdg_decoration support */
+	} else if (!(flags & RGFW_windowNoBorder)) {
+		/* TODO, some fallback */
+		#ifdef RGFW_LIBDECOR
+			static struct libdecor_interface interface = {
+				.error = NULL,
+			};
+
+			static struct libdecor_frame_interface frameInterface = {0}; /*= {
+				RGFW_wl_handle_configure,
+				RGFW_wl_handle_close,
+				RGFW_wl_handle_commit,
+				RGFW_wl_handle_dismiss_popup,
+			};*/
+
+			win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface);
+			if (win->src.decorContext) {
+				struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win);
+				if (!frame) {
+					libdecor_unref(win->src.decorContext);
+					win->src.decorContext = NULL;
+				} else {
+					libdecor_frame_set_app_id(frame, "my-libdecor-app");
+					libdecor_frame_set_title(frame, "My Libdecor Window");
+				}
+			}
+		#endif
+	}
+
+	if (_RGFW->icon_manager != NULL) {
+		/* set the default wayland icon */
+		xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL);
+	}
+
+	wl_surface_commit(win->src.surface);
+
+	while (win->src.configured == RGFW_FALSE) {
+		wl_display_dispatch(_RGFW->wl_display);
+	}
+
+	RGFW_UNUSED(name);
+
+	return win;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) {
+	RGFW_init();
+	if (x) *x = 0;
+	if (y) *y = 0;
+	return RGFW_FALSE;
+}
+
+RGFW_key RGFW_FUNC(RGFW_physicalToMappedKey)(RGFW_key key) {
+    u32 keycode = RGFW_rgfwToApiKey(key);
+	xkb_keycode_t kc = keycode + 8;
+    xkb_keysym_t sym = xkb_state_key_get_one_sym(_RGFW->xkb_state, kc);
+    if (sym < 256) {
+        return (RGFW_key)sym;
+    }
+
+    switch (sym) {
+        case XKB_KEY_F1:  return RGFW_keyF1;
+        case XKB_KEY_F2:  return RGFW_keyF2;
+        case XKB_KEY_F3:  return RGFW_keyF3;
+        case XKB_KEY_F4:  return RGFW_keyF4;
+        case XKB_KEY_F5:  return RGFW_keyF5;
+        case XKB_KEY_F6:  return RGFW_keyF6;
+        case XKB_KEY_F7:  return RGFW_keyF7;
+        case XKB_KEY_F8:  return RGFW_keyF8;
+        case XKB_KEY_F9:  return RGFW_keyF9;
+        case XKB_KEY_F10: return RGFW_keyF10;
+        case XKB_KEY_F11: return RGFW_keyF11;
+        case XKB_KEY_F12: return RGFW_keyF12;
+        case XKB_KEY_F13: return RGFW_keyF13;
+        case XKB_KEY_F14: return RGFW_keyF14;
+        case XKB_KEY_F15: return RGFW_keyF15;
+        case XKB_KEY_F16: return RGFW_keyF16;
+        case XKB_KEY_F17: return RGFW_keyF17;
+        case XKB_KEY_F18: return RGFW_keyF18;
+        case XKB_KEY_F19: return RGFW_keyF19;
+        case XKB_KEY_F20: return RGFW_keyF20;
+        case XKB_KEY_F21: return RGFW_keyF21;
+        case XKB_KEY_F22: return RGFW_keyF22;
+        case XKB_KEY_F23: return RGFW_keyF23;
+        case XKB_KEY_F24: return RGFW_keyF24;
+        case XKB_KEY_F25: return RGFW_keyF25;
+        case XKB_KEY_Shift_L:   return RGFW_keyShiftL;
+        case XKB_KEY_Shift_R:   return RGFW_keyShiftR;
+        case XKB_KEY_Control_L: return RGFW_keyControlL;
+        case XKB_KEY_Control_R: return RGFW_keyControlR;
+        case XKB_KEY_Alt_L:     return RGFW_keyAltL;
+        case XKB_KEY_Alt_R:     return RGFW_keyAltR;
+        case XKB_KEY_Super_L:   return RGFW_keySuperL;
+        case XKB_KEY_Super_R:   return RGFW_keySuperR;
+        case XKB_KEY_Caps_Lock: return RGFW_keyCapsLock;
+        case XKB_KEY_Num_Lock:  return RGFW_keyNumLock;
+        case XKB_KEY_Scroll_Lock:return RGFW_keyScrollLock;
+        case XKB_KEY_Up:        return RGFW_keyUp;
+        case XKB_KEY_Down:      return RGFW_keyDown;
+        case XKB_KEY_Left:      return RGFW_keyLeft;
+        case XKB_KEY_Right:     return RGFW_keyRight;
+        case XKB_KEY_Home:      return RGFW_keyHome;
+        case XKB_KEY_End:       return RGFW_keyEnd;
+        case XKB_KEY_Page_Up:   return RGFW_keyPageUp;
+        case XKB_KEY_Page_Down: return RGFW_keyPageDown;
+        case XKB_KEY_Insert:    return RGFW_keyInsert;
+        case XKB_KEY_Menu:      return RGFW_keyMenu;
+        case XKB_KEY_KP_Add:      return RGFW_keyPadPlus;
+        case XKB_KEY_KP_Subtract: return RGFW_keyPadMinus;
+        case XKB_KEY_KP_Multiply: return RGFW_keyPadMultiply;
+        case XKB_KEY_KP_Divide:   return RGFW_keyPadSlash;
+        case XKB_KEY_KP_Equal:    return RGFW_keyPadEqual;
+        case XKB_KEY_KP_Enter:    return RGFW_keyPadReturn;
+        case XKB_KEY_KP_Decimal:  return RGFW_keyPadPeriod;
+        case XKB_KEY_KP_0: return RGFW_keyPad0;
+        case XKB_KEY_KP_1: return RGFW_keyPad1;
+        case XKB_KEY_KP_2: return RGFW_keyPad2;
+        case XKB_KEY_KP_3: return RGFW_keyPad3;
+        case XKB_KEY_KP_4: return RGFW_keyPad4;
+        case XKB_KEY_KP_5: return RGFW_keyPad5;
+        case XKB_KEY_KP_6: return RGFW_keyPad6;
+        case XKB_KEY_KP_7: return RGFW_keyPad7;
+        case XKB_KEY_KP_8: return RGFW_keyPad8;
+        case XKB_KEY_KP_9: return RGFW_keyPad9;
+        case XKB_KEY_Print: return RGFW_keyPrintScreen;
+        case XKB_KEY_Pause: return RGFW_keyPause;
+        default: break;
+    }
+
+    return RGFW_keyNULL;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_fetchSize) (RGFW_window* win, i32* w, i32* h) {
+	return RGFW_window_getSize(win, w, h);
+}
+
+void RGFW_FUNC(RGFW_pollEvents) (void) {
+	RGFW_resetPrevState();
+
+	/* send buffered requests to compositor */
+	while (wl_display_flush(_RGFW->wl_display) == -1) {
+		/* compositor not responding to new requests */
+		/* so let's dispatch some events so the compositor responds */
+		if (errno == EAGAIN) {
+			if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) {
+				return;
+			}
+		} else {
+			return;
+		}
+	}
+	if (_RGFW->wl_repeat_info_rate != 0 && _RGFW->last_key) {
+		u32 now = (u32)(RGFW_linux_getTimeNS() / 1000000);
+		if (now > _RGFW->last_key_time) {
+			RGFW_wl_send_key_event(_RGFW->last_key);
+			_RGFW->last_key_time = now + 1000 / (u32)_RGFW->wl_repeat_info_rate;
+		}
+	}
+
+	/* read the events; if empty this reads from the */
+	/* wayland file descriptor */
+	struct pollfd fds;
+	memset(&fds, 0, sizeof(fds));
+    fds.fd = wl_display_get_fd(_RGFW->wl_display);
+    fds.events = POLLIN;
+    fds.revents = 0;
+
+    while (1) {
+        while (wl_display_prepare_read(_RGFW->wl_display) != 0) {
+            if (wl_display_dispatch_pending(_RGFW->wl_display) > 0)
+                return;
+        }
+
+        if (poll(&fds, 1, 0) == 0) {
+            wl_display_cancel_read(_RGFW->wl_display);
+            return;
+        }
+
+        if (fds.revents & POLLIN) {
+            wl_display_read_events(_RGFW->wl_display);
+            if (wl_display_dispatch_pending(_RGFW->wl_display) > 0) {
+				return;
+			}
+		} else {
+            wl_display_cancel_read(_RGFW->wl_display);
+		}
+	}
+}
+
+void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+	win->x = x;
+	win->y = y;
+}
+
+
+void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+	win->w = w;
+	win->h = h;
+	if (_RGFW->compositor) {
+		xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h);
+		#ifdef RGFW_OPENGL
+		if (win->src.ctx.egl)
+			wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0);
+		#endif
+	}
+}
+
+void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+	if (w == 0 && h == 0)
+		return;
+    xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h);
+}
+
+void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+    xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h);
+}
+
+void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+    xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h);
+}
+
+void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) {
+    win->src.maximized = maximized;
+    if (maximized) {
+		xdg_toplevel_set_maximized(win->src.xdg_toplevel);
+    } else {
+		xdg_toplevel_unset_maximized(win->src.xdg_toplevel);
+    }
+}
+
+void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) {
+	win->internal.oldX = win->x;
+	win->internal.oldY = win->y;
+	win->internal.oldW = win->w;
+	win->internal.oldH = win->h;
+    RGFW_toggleWaylandMaximized(win, 1);
+	RGFW_window_fetchSize(win, NULL, NULL);
+    return;
+}
+
+void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) {
+	RGFW_ASSERT(win);
+}
+
+void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) {
+	RGFW_ASSERT(win);
+}
+
+void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+    if (fullscreen) {
+
+		win->internal.flags |= RGFW_windowFullscreen;
+		win->internal.oldX = win->x;
+		win->internal.oldY = win->y;
+		win->internal.oldW = win->w;
+		win->internal.oldH = win->h;
+		xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); /* let the compositor decide */
+	} else {
+		win->internal.flags &= ~(u32)RGFW_windowFullscreen;
+		xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel);
+	}
+
+}
+
+void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) {
+    RGFW_ASSERT(win != NULL);
+	RGFW_UNUSED(floating);
+}
+
+void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_UNUSED(opacity);
+}
+
+void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	if (RGFW_window_isMaximized(win)) return;
+	win->internal.oldX = win->x;
+	win->internal.oldY = win->y;
+	win->internal.oldW = win->w;
+	win->internal.oldH = win->h;
+	win->src.minimized = RGFW_TRUE;
+	xdg_toplevel_set_minimized(win->src.xdg_toplevel);
+}
+
+void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_toggleWaylandMaximized(win, RGFW_FALSE);
+
+	RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
+	RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
+
+	RGFW_window_show(win);
+	RGFW_window_move(win, win->internal.oldX, win->internal.oldY);
+	RGFW_window_resize(win, win->internal.oldW, win->internal.oldH);
+
+    RGFW_window_show(win);
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) {
+	return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win));
+}
+
+void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) {
+	RGFW_ASSERT(win != NULL);
+	if (name == NULL) name = "\0";
+
+	if (_RGFW->compositor)
+		xdg_toplevel_set_title(win->src.xdg_toplevel, name);
+}
+
+#ifndef RGFW_NO_PASSTHROUGH
+void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) {
+	RGFW_ASSERT(win != NULL);
+    RGFW_UNUSED(passthrough);
+}
+#endif /* RGFW_NO_PASSTHROUGH */
+
+RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_UNUSED(type);
+
+	if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE;
+
+	if (win->src.icon) {
+		xdg_toplevel_icon_v1_destroy(win->src.icon);
+		win->src.icon= NULL;
+	}
+
+	RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
+
+	if (surface == NULL) return RGFW_FALSE;
+
+	RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
+
+	win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager);
+	xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1);
+	xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon);
+
+	RGFW_surface_free(surface);
+	return RGFW_TRUE;
+}
+
+RGFW_mouse* RGFW_FUNC(RGFW_createMouseStandard) (RGFW_mouseIcon mouse) {
+	char* cursorName = NULL;
+	switch (mouse) {
+		case RGFW_mouseNormal:       cursorName = (char*)"left_ptr"; break;
+		case RGFW_mouseArrow:       cursorName = (char*)"left_ptr"; break;
+		case RGFW_mouseIbeam:       cursorName = (char*)"xterm"; break;
+		case RGFW_mouseCrosshair:    cursorName = (char*)"crosshair"; break;
+		case RGFW_mousePointingHand: cursorName = (char*)"hand2"; break;
+		case RGFW_mouseResizeEW:     cursorName = (char*)"sb_h_double_arrow"; break;
+		case RGFW_mouseResizeNS:     cursorName = (char*)"sb_v_double_arrow"; break;
+		case RGFW_mouseResizeNWSE:   cursorName = (char*)"top_left_corner"; break;   /* or fd_double_arrow */
+		case RGFW_mouseResizeNESW:   cursorName = (char*)"top_right_corner"; break;  /* or bd_double_arrow */
+		case RGFW_mouseResizeNW:     cursorName = (char*)"top_left_corner"; break;
+		case RGFW_mouseResizeN:      cursorName = (char*)"top_side"; break;
+		case RGFW_mouseResizeNE:     cursorName = (char*)"top_right_corner"; break;
+		case RGFW_mouseResizeE:      cursorName = (char*)"right_side"; break;
+		case RGFW_mouseResizeSE:     cursorName = (char*)"bottom_right_corner"; break;
+		case RGFW_mouseResizeS:      cursorName = (char*)"bottom_side"; break;
+		case RGFW_mouseResizeSW:     cursorName = (char*)"bottom_left_corner"; break;
+		case RGFW_mouseResizeW:      cursorName = (char*)"left_side"; break;
+		case RGFW_mouseResizeAll:    cursorName = (char*)"fleur"; break;
+		case RGFW_mouseNotAllowed:   cursorName = (char*)"not-allowed"; break;
+		case RGFW_mouseWait:         cursorName = (char*)"watch"; break;
+		case RGFW_mouseProgress:     cursorName = (char*)"watch"; break;
+		default:                     return NULL;
+	}
+
+	struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, cursorName);
+	if (wlcursor == NULL)
+		return NULL;
+	struct wl_cursor_image* cursor_image = wlcursor->images[0];
+	struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
+
+	RGFW_surface* surface = RGFW_ALLOC(sizeof(RGFW_surface));
+	RGFW_MEMZERO(surface, sizeof(RGFW_surface));
+	surface->w = (i32)cursor_image->width;
+	surface->h = (i32)cursor_image->height;
+	surface->native.wl_buffer = cursor_buffer;
+
+	return (RGFW_mouse*)surface;
+}
+
+RGFW_mouse* RGFW_FUNC(RGFW_createMouse)(u8* data, i32 w, i32 h, RGFW_format format) {
+    RGFW_surface* surface = RGFW_createSurface(data, w, h, format);
+	if (surface == NULL) return NULL;
+
+	surface->native.wl_buffer = wl_shm_pool_create_buffer(surface->native.pool, 0, surface->w, surface->h, (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888);
+
+	RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format, NULL);
+
+	return (RGFW_mouse*)surface;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_setMousePlatform)(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win); RGFW_ASSERT(mouse);
+	RGFW_surface* surface = (RGFW_surface*)mouse;
+
+	win->src.using_custom_cursor = RGFW_TRUE;
+
+	wl_surface_attach(win->src.custom_cursor_surface, surface->native.wl_buffer, 0, 0);
+	wl_surface_damage(win->src.custom_cursor_surface, 0, 0, surface->w, surface->h);
+	wl_surface_commit(win->src.custom_cursor_surface);
+
+	return RGFW_TRUE;
+}
+
+void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) {
+	if (mouse != NULL) {
+		RGFW_surface* surface = (RGFW_surface*)mouse;
+
+		if (surface->native.buffer && surface->native.wl_buffer) {
+			wl_buffer_destroy(surface->native.wl_buffer);
+		}
+
+		RGFW_surface_free(surface);
+	}
+}
+
+void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) {
+	if (_RGFW->wp_pointer_warp != NULL) {
+		wp_pointer_warp_v1_warp_pointer(_RGFW->wp_pointer_warp, win->src.surface, _RGFW->wl_pointer, wl_fixed_from_int(x), wl_fixed_from_int(y), _RGFW->mouse_enter_serial);
+	}
+}
+
+void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) {
+	wl_surface_attach(win->src.surface, NULL, 0, 0);
+	wl_surface_commit(win->src.surface);
+	win->internal.flags |= RGFW_windowHide;
+}
+
+void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) {
+	win->internal.flags &= ~(u32)RGFW_windowHide;
+	if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
+	/* wl_surface_attach(win->src.surface, win->x, win->y, win->w, win->h, 0, 0); */
+	wl_surface_commit(win->src.surface);
+}
+
+void RGFW_FUNC(RGFW_window_flash) (RGFW_window* win, RGFW_flashRequest request) {
+	if (RGFW_window_isInFocus(win) && request) {
+		return;
+	}
+}
+
+RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) {
+
+	RGFW_UNUSED(strCapacity);
+
+	if (str != NULL)
+		RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1);
+	_RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0';
+	return (RGFW_ssize_t)_RGFW->clipboard_len - 1;
+}
+
+void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) {
+
+	// compositor does not support wl_data_device_manager
+	// clients cannot read rgfw's clipboard
+	if (_RGFW->data_device_manager == NULL) return;
+	// clear the clipboard
+	if (_RGFW->clipboard)
+		RGFW_FREE(_RGFW->clipboard);
+
+	// set the contents
+	_RGFW->clipboard = (char*)RGFW_ALLOC(textLen);
+	RGFW_ASSERT(_RGFW->clipboard != NULL);
+	RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1);
+	_RGFW->clipboard[textLen - 1] = '\0';
+	_RGFW->clipboard_len = textLen;
+
+	// means we already wrote to the clipboard
+	// so destroy it to create a new one
+	RGFW_window* win = _RGFW->kbOwner;
+
+	if (win->src.data_source != NULL) {
+		wl_data_source_destroy(win->src.data_source);
+		win->src.data_source = NULL;
+	}
+
+	// advertise to other clients that we offer text
+	win->src.data_source = wl_data_device_manager_create_data_source(_RGFW->data_device_manager);
+
+	// basic error checking
+	if (win->src.data_source == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source");
+		return;
+	}
+	wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8");
+
+	// needed RGFW_doNothing because wayland will call the functions
+	// if not set they are random data that lead to a crash
+	static const struct wl_data_source_listener data_source_listener = {
+		.target = (void (*)(void *, struct wl_data_source *, const char *))&RGFW_doNothing,
+		.action = (void (*)(void *, struct wl_data_source *, u32))&RGFW_doNothing,
+		.dnd_drop_performed = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
+		.dnd_finished = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing,
+		.send = RGFW_wl_data_source_send,
+		.cancelled = RGFW_wl_data_source_cancelled
+	};
+
+	wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW);
+
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+    return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+    return win->src.minimized;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	return win->src.maximized;
+}
+
+void RGFW_FUNC(RGFW_pollMonitors) (void) {
+	_RGFW->monitors.primary = _RGFW->monitors.list.head;
+}
+
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_getWorkarea) (RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
+	/* NOTE: Wayland has no way to get the actual workarea as far as I'm aware :( */
+	if (x) *x = monitor->x;
+	if (y) *y = monitor->y;
+	if (width) *width = monitor->mode.w;
+	if (height) *height = monitor->mode.h;
+	return RGFW_TRUE;
+}
+
+size_t RGFW_FUNC(RGFW_monitor_getModesPtr) (RGFW_monitor* monitor, RGFW_monitorMode** modes) {
+	if (modes) {
+		RGFW_MEMCPY((*modes), monitor->node->modes, monitor->node->modeCount * sizeof(RGFW_monitorMode));
+	}
+
+	return monitor->node->modeCount;
+}
+
+size_t RGFW_FUNC(RGFW_monitor_getGammaRampPtr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
+	return 0;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_setGammaRamp) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	RGFW_UNUSED(monitor); RGFW_UNUSED(ramp);
+	return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
+	for (size_t i = 0; i < mon->node->modeCount; i++) {
+		if (RGFW_monitorModeCompare(mode, &mon->node->modes[i], request) == RGFW_FALSE) {
+			continue;
+		}
+
+		RGFW_monitor_setMode(mon, &mon->node->modes[i]);
+		return RGFW_TRUE;
+	}
+
+	return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_FUNC(RGFW_monitor_setMode) (RGFW_monitor* mon, RGFW_monitorMode* mode) {
+	RGFW_UNUSED(mon); RGFW_UNUSED(mode);
+	return RGFW_FALSE;
+}
+
+RGFW_monitor* RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) {
+	RGFW_ASSERT(win);
+	if (win->src.active_monitor == NULL) {
+		/* TODO: fix race condition [probably a problem with wayland] */
+		return RGFW_getPrimaryMonitor();
+	}
+
+	return &win->src.active_monitor->mon;
+}
+
+#ifdef RGFW_OPENGL
+RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extension, size_t len) { return RGFW_extensionSupportedPlatform_EGL(extension, len); }
+RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char* procname) { return RGFW_getProcAddress_EGL(procname); }
+
+
+RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
+	RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints);
+	win->src.gfxType = RGFW_gfxNativeOpenGL;
+
+	RGFW_window_swapInterval_OpenGL(win, 0);
+	return out;
+}
+void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; }
+
+void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { RGFW_window_makeCurrentContext_EGL(win); }
+void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return RGFW_getCurrentContext_EGL(); }
+void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_window_swapBuffers_EGL(win); }
+void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); }
+#endif /* RGFW_OPENGL */
+
+void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoWindow, "a window was freed");
+	#ifdef RGFW_LIBDECOR
+		if (win->src.decorContext)
+			libdecor_unref(win->src.decorContext);
+	#endif
+
+	if (win->src.decoration) {
+		zxdg_toplevel_decoration_v1_destroy(win->src.decoration);
+	}
+
+	if (win->src.xdg_toplevel) {
+		xdg_toplevel_destroy(win->src.xdg_toplevel);
+	}
+
+	wl_surface_destroy(win->src.custom_cursor_surface);
+
+	if (win->src.locked_pointer) {
+		zwp_locked_pointer_v1_destroy(win->src.locked_pointer);
+	}
+
+	if (win->src.icon) {
+		xdg_toplevel_icon_v1_destroy(win->src.icon);
+	}
+
+	xdg_surface_destroy(win->src.xdg_surface);
+	wl_surface_destroy(win->src.surface);
+}
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) {
+	WGPUSurfaceDescriptor surfaceDesc = {0};
+	WGPUSurfaceSourceWaylandSurface fromWl = {0};
+	fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
+	fromWl.display = _RGFW->wl_display;
+	fromWl.surface = window->src.surface;
+
+	surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain;
+	return wgpuInstanceCreateSurface(instance, &surfaceDesc);
+}
+#endif
+
+
+
+#endif /* RGFW_WAYLAND */
+/*
+	End of Wayland defines
+*/
+
+/*
+
+	Start of Windows defines
+
+
+*/
+
+#ifdef RGFW_WINDOWS
+#ifndef WIN32_LEAN_AND_MEAN
+	#define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef OEMRESOURCE
+	#define OEMRESOURCE
+#endif
+
+#include <windows.h>
+
+#ifndef OCR_NORMAL
+#define OCR_NORMAL 32512
+#define OCR_IBEAM 32513
+#define OCR_WAIT 32514
+#define OCR_CROSS 32515
+#define OCR_UP 32516
+#define OCR_SIZENWSE 32642
+#define OCR_SIZENESW 32643
+#define OCR_SIZEWE 32644
+#define OCR_SIZENS 32645
+#define OCR_SIZEALL 32646
+#define OCR_NO 32648
+#define OCR_HAND 32649
+#define OCR_APPSTARTING 32650
+#endif
+
+#include <windowsx.h>
+#include <shellapi.h>
+#include <shellscalingapi.h>
+#include <wchar.h>
+#include <locale.h>
+#include <winuser.h>
+
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED       0x02E0
+#endif
+
+RGFWDEF DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags);
+DWORD RGFW_winapi_window_getStyle(RGFW_window* win, RGFW_windowFlags flags) {
+	RGFW_UNUSED(win);
+    DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+
+    if ((flags & RGFW_windowFullscreen)) {
+        style |= WS_POPUP;
+    } else {
+        style |= WS_SYSMENU | WS_MINIMIZEBOX;
+
+        if (!(flags & RGFW_windowNoBorder)) {
+            style |= WS_CAPTION;
+
+            if (!(flags & RGFW_windowNoResize))
+                style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
+        }
+        else
+            style |= WS_POPUP;
+    }
+
+    return style;
+}
+
+RGFWDEF DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags);
+DWORD RGFW_winapi_window_getExStyle(RGFW_window* win, RGFW_windowFlags flags) {
+    DWORD style = WS_EX_APPWINDOW;
+    if (flags & RGFW_windowFullscreen || (flags & RGFW_windowFloating || RGFW_window_isFloating(win))) {
+        style |= WS_EX_TOPMOST;
+	}
+
+    return style;
+}
+
+RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max);
+
+#define GL_FRONT				0x0404
+#define GL_BACK					0x0405
+#define GL_LEFT					0x0406
+#define GL_RIGHT				0x0407
+
+typedef int (*PFN_wglGetSwapIntervalEXT)(void);
+PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
+#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
+
+/* these two wgl functions need to be preloaded */
+typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
+PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
+
+HMODULE RGFW_wgl_dll = NULL;
+
+#ifndef RGFW_NO_LOAD_WGL
+	typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
+	typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
+	typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
+	typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
+	typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
+	typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
+	typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
+
+	PFN_wglCreateContext wglCreateContextSRC;
+	PFN_wglDeleteContext wglDeleteContextSRC;
+	PFN_wglGetProcAddress wglGetProcAddressSRC;
+	PFN_wglMakeCurrent wglMakeCurrentSRC;
+	PFN_wglGetCurrentDC wglGetCurrentDCSRC;
+	PFN_wglGetCurrentContext wglGetCurrentContextSRC;
+	PFN_wglShareLists wglShareListsSRC;
+
+	#define wglCreateContext wglCreateContextSRC
+	#define wglDeleteContext wglDeleteContextSRC
+	#define wglGetProcAddress wglGetProcAddressSRC
+	#define wglMakeCurrent wglMakeCurrentSRC
+	#define wglGetCurrentDC wglGetCurrentDCSRC
+	#define wglGetCurrentContext wglGetCurrentContextSRC
+	#define wglShareLists wglShareListsSRC
+#endif
+
+void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; }
+void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; }
+
+#ifdef RGFW_OPENGL
+RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
+
+typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
+PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
+
+typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
+PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
+#endif
+
+#ifndef RGFW_NO_DWM
+HMODULE RGFW_dwm_dll = NULL;
+#ifndef _DWMAPI_H_
+typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
+#endif
+typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
+PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
+
+typedef HRESULT (WINAPI * PFN_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
+PFN_DwmSetWindowAttribute DwmSetWindowAttributeSRC = NULL;
+#endif
+void RGFW_win32_makeWindowTransparent(RGFW_window* win);
+void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
+	if (!(win->internal.flags & RGFW_windowTransparent)) return;
+
+	#ifndef RGFW_NO_DWM
+	if (DwmEnableBlurBehindWindowSRC != NULL) {
+			DWM_BLURBEHIND bb = {0, 0, 0, 0};
+			bb.dwFlags = 0x1;
+			bb.fEnable = TRUE;
+			bb.hRgnBlur = NULL;
+			DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
+
+	} else
+	#endif
+	{
+		SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
+		SetLayeredWindowAttributes(win->src.window, 0, 128,  LWA_ALPHA);
+	}
+}
+
+RGFWDEF RGFW_bool RGFW_win32_getDarkModeState(void);
+RGFW_bool RGFW_win32_getDarkModeState(void) {
+	u32 lightMode = 1;
+#if (_WIN32_WINNT >= 0x0600)
+	DWORD len = sizeof(lightMode);
+
+	RegGetValueW(
+		HKEY_CURRENT_USER,
+		L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
+		L"AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, &lightMode, &len
+	);
+#endif
+
+	return (lightMode == 0);
+}
+
+RGFWDEF void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state);
+void RGFW_win32_makeWindowDarkMode(RGFW_window* win, RGFW_bool state) {
+	BOOL value = (state == RGFW_TRUE) ? TRUE : FALSE;
+	DwmSetWindowAttributeSRC(win->src.window, 20 /* DWMWA_USE_IMMERSIVE_DARK_MODE */, &value, sizeof(value));
+}
+
+LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+    RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
+	if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
+
+	static BYTE keyboardState[256];
+	GetKeyboardState(keyboardState);
+
+	RECT frame;
+	ZeroMemory(&frame, sizeof(frame));
+	DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
+	DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
+	AdjustWindowRectEx(&frame, style, FALSE, exStyle);
+
+	switch (message) {
+        case WM_DISPLAYCHANGE:
+            RGFW_pollMonitors();
+            break;
+		case WM_CLOSE:
+		case WM_QUIT:
+			RGFW_windowCloseCallback(win);
+			return 0;
+		case WM_ACTIVATE: {
+			RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
+			RGFW_windowFocusCallback(win, inFocus);
+
+			return DefWindowProcW(hWnd, message, wParam, lParam);
+		}
+		case WM_MOVE:
+			if (win->internal.captureMouse) {
+				RGFW_window_captureMousePlatform(win, RGFW_TRUE);
+			}
+
+			RGFW_windowMovedCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+			return DefWindowProcW(hWnd, message, wParam, lParam);
+		case WM_SIZE: {
+			if (win->internal.captureMouse) {
+				RGFW_window_captureMousePlatform(win, RGFW_TRUE);
+			}
+
+			RGFW_windowResizedCallback(win, LOWORD(lParam), HIWORD(lParam));
+			RGFW_window_checkMode(win);
+			return DefWindowProcW(hWnd, message, wParam, lParam);
+		}
+        case WM_MOUSEACTIVATE:         {
+            if (HIWORD(lParam) == WM_LBUTTONDOWN) {
+                if (LOWORD(lParam) != HTCLIENT)
+                    win->src.actionFrame = RGFW_TRUE;
+            }
+
+            break;
+        }
+		case WM_CAPTURECHANGED:         {
+            if (lParam == 0 && win->src.actionFrame) {
+				RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
+                win->src.actionFrame = RGFW_FALSE;
+            }
+
+            break;
+        }
+		#ifndef RGFW_NO_DPI
+		case WM_DPICHANGED: {
+			const float scaleX = HIWORD(wParam) / (float) 96;
+            const float scaleY = LOWORD(wParam) / (float) 96;
+
+			RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
+			return DefWindowProcW(hWnd, message, wParam, lParam);
+		}
+		#endif
+		case WM_SIZING: {
+			if (win->src.aspectRatioW == 0 && win->src.aspectRatioH == 0) {
+				break;
+			}
+
+			RECT* area = (RECT*)lParam;
+			i32 edge = (i32)wParam;
+
+			double ratio = (double)win->src.aspectRatioW / (double) win->src.aspectRatioH;
+
+			if (edge == WMSZ_LEFT  || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) {
+				area->bottom = area->top + (frame.bottom - frame.top) + (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
+			} else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) {
+				area->top = area->bottom - (frame.bottom - frame.top) - (i32) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
+			} else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) {
+				area->right = area->left + (frame.right - frame.left) + (i32) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio);
+			}
+
+			return TRUE;
+		}
+		case WM_GETMINMAXINFO: {
+			MINMAXINFO* mmi = (MINMAXINFO*) lParam;
+			RGFW_bool resize = ((win->src.minSizeW == win->src.maxSizeW) && (win->src.minSizeH == win->src.maxSizeH));
+			RGFW_setBit(&win->internal.flags, RGFW_windowNoResize, resize);
+
+			mmi->ptMinTrackSize.x = (LONG)(win->src.minSizeW + (frame.right - frame.left));
+			mmi->ptMinTrackSize.y = (LONG)(win->src.minSizeH + (frame.bottom - frame.top));
+			if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0)
+				return DefWindowProcW(hWnd, message, wParam, lParam);
+
+			mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSizeW + (frame.right - frame.left));
+			mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSizeH + (frame.bottom - frame.top));
+			return DefWindowProcW(hWnd, message, wParam, lParam);
+		}
+		case WM_PAINT: {
+			RECT rect;
+			if (GetUpdateRect(hWnd, &rect, FALSE)) {
+				RGFW_windowRefreshCallback(win, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+			} else {
+				PAINTSTRUCT ps;
+				BeginPaint(hWnd, &ps);
+				RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
+				EndPaint(hWnd, &ps);
+			}
+
+            return DefWindowProcW(hWnd, message, wParam, lParam);
+		}
+		#if(_WIN32_WINNT >= 0x0600)
+		case WM_DWMCOMPOSITIONCHANGED:
+		case WM_DWMCOLORIZATIONCOLORCHANGED:
+			RGFW_win32_makeWindowTransparent(win);
+			break;
+		#endif
+
+		case WM_ENTERSIZEMOVE: {
+			if (win->src.actionFrame)
+				RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
+
+			#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+				SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
+			#endif
+			break;
+		}
+        case WM_EXITSIZEMOVE: {
+			if (win->src.actionFrame)
+				RGFW_window_captureMousePlatform(win, win->internal.captureMouse);
+
+			#ifdef RGFW_ADVANCED_SMOOTH_RESIZE
+				KillTimer(win->src.window, 1); break;
+			#endif
+			break;
+		}
+        case WM_TIMER:
+			RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
+			break;
+
+		case WM_NCLBUTTONDOWN: {
+            /* workaround for half-second pause when starting to move window
+                see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
+            */
+            POINT point = { 0, 0 };
+            if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
+                break;
+
+            ScreenToClient(win->src.window, &point);
+            PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32)(point.x)|((u32)(point.y) << 16));
+            break;
+        }
+		case WM_MOUSELEAVE:
+			RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
+			break;
+
+        case WM_CHAR:
+        case WM_SYSCHAR: {
+            if (wParam >= 0xd800 && wParam <= 0xdbff)
+                win->src.highSurrogate = (WCHAR) wParam;
+            else {
+                u32 codepoint = 0;
+
+                if (wParam >= 0xdc00 && wParam <= 0xdfff) {
+                    if (win->src.highSurrogate) {
+                        codepoint += (u32)((win->src.highSurrogate - 0xd800) << 10);
+                        codepoint += (u32)((WCHAR) wParam - 0xdc00);
+                        codepoint += 0x10000;
+                    }
+                }
+                else
+                    codepoint = (WCHAR) wParam;
+
+                win->src.highSurrogate = 0;
+				RGFW_keyCharCallback(win, (u32)codepoint);
+            }
+
+            return 0;
+        }
+
+        case WM_UNICHAR: {
+            if (wParam == UNICODE_NOCHAR) {
+                return TRUE;
+            }
+
+			RGFW_keyCharCallback(win, (u32)wParam);
+            return 0;
+        }
+		case WM_SYSKEYUP: case WM_KEYUP: {
+			if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
+			i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
+			if (scancode == 0)
+				scancode = (i32)MapVirtualKeyW((UINT)wParam, MAPVK_VK_TO_VSC);
+
+			switch (scancode) {
+				case 0x54: scancode = 0x137; break; /*  Alt+PrtS */
+				case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
+				case 0x136: scancode = 0x36; break; /*  CJK IME sets the extended bit for right Shift */
+				default: break;
+			}
+
+			RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
+
+			if (wParam == VK_CONTROL) {
+				if (HIWORD(lParam) & KF_EXTENDED)
+					value = RGFW_keyControlR;
+				else value = RGFW_keyControlL;
+			}
+
+			RGFW_keyUpdateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
+			RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, RGFW_FALSE);
+			break;
+		}
+		case WM_SYSKEYDOWN: case WM_KEYDOWN: {
+			if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);
+            i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
+			if (scancode == 0)
+				scancode = (i32)MapVirtualKeyW((u32)wParam, MAPVK_VK_TO_VSC);
+
+			switch (scancode) {
+				case 0x54: scancode = 0x137; break; /*  Alt+PrtS */
+				case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
+				case 0x136: scancode = 0x36; break; /*  CJK IME sets the extended bit for right Shift */
+				default: break;
+			}
+
+			RGFW_key value = (u8)RGFW_apiKeyToRGFW((u32) scancode);
+			if (wParam == VK_CONTROL) {
+				if (HIWORD(lParam) & KF_EXTENDED)
+					value = RGFW_keyControlR;
+				else value = RGFW_keyControlL;
+			}
+
+			RGFW_bool repeat = RGFW_isKeyDown(value);
+
+			RGFW_keyUpdateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
+			RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
+			break;
+		}
+		case WM_MOUSEMOVE: {
+			if (win->internal.mouseInside == RGFW_FALSE) {
+				RGFW_mouseNotifyCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RGFW_TRUE);
+			}
+
+			RGFW_mouseMotionCallback(win, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+			break;
+		}
+		case WM_INPUT: {
+			if (!(win->internal.rawMouse || _RGFW->rawMouse)) return DefWindowProcW(hWnd, message, wParam, lParam);
+			unsigned size = sizeof(RAWINPUT);
+			static RAWINPUT raw;
+
+			GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
+
+			if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
+				break;
+
+			float vecX = 0.0f;
+			float vecY = 0.0f;
+
+			if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
+				POINT pos = {0, 0};
+				int width, height;
+
+				if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
+					pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
+					pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
+					width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+					height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+				}
+				else {
+					width = GetSystemMetrics(SM_CXSCREEN);
+					height = GetSystemMetrics(SM_CYSCREEN);
+				}
+
+				pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
+				pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
+				ScreenToClient(win->src.window, &pos);
+
+				vecX = (float)(pos.x - win->internal.lastMouseX);
+				vecY = (float)(pos.y - win->internal.lastMouseY);
+			} else {
+				vecX = (float)(raw.data.mouse.lLastX);
+				vecY = (float)(raw.data.mouse.lLastY);
+			}
+
+			RGFW_rawMotionCallback(win, vecX, vecY);
+			break;
+		}
+		case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: {
+			RGFW_mouseButton value = 0;
+			if (message == WM_XBUTTONDOWN)
+				value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
+			else value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft :
+									 (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
+
+			RGFW_mouseButtonCallback(win, value, 1);
+			break;
+		}
+		case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: {
+			RGFW_mouseButton value = 0;
+			if (message == WM_XBUTTONUP)
+				value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2);
+			else value = (message == WM_LBUTTONUP) ? (u8)RGFW_mouseLeft :
+									 (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle;
+
+			RGFW_mouseButtonCallback(win, value, 0);
+			break;
+		}
+		case WM_MOUSEWHEEL: {
+			float scrollY = (float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
+			RGFW_mouseScrollCallback(win, 0.0f, scrollY);
+			break;
+		}
+		case 0x020E: {/* WM_MOUSEHWHEEL */
+			float scrollX = -(float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA);
+			RGFW_mouseScrollCallback(win, scrollX, 0.0f);
+			break;
+		}
+		case WM_DROPFILES: {
+			HDROP drop = (HDROP) wParam;
+			POINT pt;
+
+			/* Move the mouse to the position of the drop */
+			DragQueryPoint(drop, &pt);
+			RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionMove, pt.x, pt.y);
+
+			if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam);
+			size_t count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
+
+			u32 i;
+			for (i = 0; i < count; i++) {
+				UINT length = DragQueryFileW(drop, i, NULL, 0);
+				if (length == 0)
+					continue;
+
+				WCHAR* buffer = (WCHAR*)RGFW_ALLOC(sizeof(WCHAR) * (length + 1));
+				char* cbuffer = (char*)RGFW_ALLOC(length + 1);
+
+				DragQueryFileW(drop, i, buffer, length + 1);
+
+				RGFW_createUTF8FromWideStringWin32(buffer, cbuffer, length);
+
+				RGFW_dataDropCallback(win, cbuffer, length + 1, RGFW_dataFile);
+				RGFW_FREE(buffer);
+				RGFW_FREE(cbuffer);
+			}
+
+			DragFinish(drop);
+
+			break;
+		}
+		default: break;
+	}
+
+	return DefWindowProcW(hWnd, message, wParam, lParam);
+}
+
+#ifndef RGFW_NO_DPI
+	HMODULE RGFW_Shcore_dll = NULL;
+	typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
+	PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
+	#define GetDpiForMonitor GetDpiForMonitorSRC
+#endif
+
+#if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
+	HMODULE RGFW_winmm_dll = NULL;
+	typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
+	typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
+	PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
+	#define timeBeginPeriod timeBeginPeriodSRC
+	#define timeEndPeriod timeEndPeriodSRC
+#elif !defined(RGFW_NO_WINMM)
+	__declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
+	__declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
+#endif
+#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
+                                        name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name)); \
+                                        RGFW_ASSERT(name##SRC != NULL); \
+                                    }
+
+RGFW_format RGFW_nativeFormat(void) { return RGFW_formatBGRA8; }
+
+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+	surface->data = data;
+	surface->w = w;
+	surface->h = h;
+	surface->format = format;
+
+	BITMAPV5HEADER bi;
+	ZeroMemory(&bi, sizeof(bi));
+	bi.bV5Size = sizeof(bi);
+	bi.bV5Width = (i32)w;
+	bi.bV5Height = -((LONG) h);
+	bi.bV5Planes = 1;
+	bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24;
+	bi.bV5Compression = BI_RGB;
+
+	surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc,
+		(BITMAPINFO*) &bi, DIB_RGB_COLORS,
+		(void**) &surface->native.bitmapBits,
+		NULL, (DWORD) 0);
+
+	surface->native.format = (format >= RGFW_formatRGBA8) ? (RGFW_format) RGFW_formatBGRA8 : (RGFW_format) RGFW_formatBGR8;
+
+	if (surface->native.bitmap == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errBuffer,  "Failed to create DIB section.");
+		return RGFW_FALSE;
+	}
+
+	surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc);
+	SelectObject(surface->native.hdcMem, surface->native.bitmap);
+
+	return RGFW_TRUE;
+}
+
+void RGFW_surface_freePtr(RGFW_surface* surface) {
+	RGFW_ASSERT(surface != NULL);
+
+	DeleteDC(surface->native.hdcMem);
+	DeleteObject(surface->native.bitmap);
+}
+
+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
+	RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format, surface->convertFunc);
+	BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY);
+}
+
+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win);
+	RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
+	id.dwFlags = (state == RGFW_TRUE) ? 0 : RIDEV_REMOVE;
+
+	RegisterRawInputDevices(&id, 1, sizeof(id));
+}
+
+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
+	if (state == RGFW_FALSE) {
+		ClipCursor(NULL);
+		return;
+	}
+
+	RECT clipRect;
+	GetClientRect(win->src.window, &clipRect);
+	ClientToScreen(win->src.window, (POINT*) &clipRect.left);
+	ClientToScreen(win->src.window, (POINT*) &clipRect.right);
+	ClipCursor(&clipRect);
+}
+
+#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); }
+
+#ifdef RGFW_DIRECTX
+int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
+    RGFW_ASSERT(win && pFactory && pDevice && swapchain);
+
+    static DXGI_SWAP_CHAIN_DESC swapChainDesc;
+	RGFW_MEMZERO(&swapChainDesc, sizeof(swapChainDesc));
+    swapChainDesc.BufferCount = 2;
+    swapChainDesc.BufferDesc.Width = win->w;
+    swapChainDesc.BufferDesc.Height = win->h;
+    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    swapChainDesc.OutputWindow = (HWND)win->src.window;
+    swapChainDesc.SampleDesc.Count = 1;
+    swapChainDesc.SampleDesc.Quality = 0;
+    swapChainDesc.Windowed = TRUE;
+    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+    HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
+    if (FAILED(hr)) {
+        RGFW_debugCallback(RGFW_typeError, RGFW_errDirectXContext,  "Failed to create DirectX swap chain!");
+        return -2;
+    }
+
+    return 0;
+}
+#endif
+
+/* we're doing it with magic numbers because some keys are missing  */
+void RGFW_initKeycodesPlatform(void) {
+	_RGFW->keycodes[0x00B] = RGFW_key0;
+	_RGFW->keycodes[0x002] = RGFW_key1;
+	_RGFW->keycodes[0x003] = RGFW_key2;
+	_RGFW->keycodes[0x004] = RGFW_key3;
+	_RGFW->keycodes[0x005] = RGFW_key4;
+	_RGFW->keycodes[0x006] = RGFW_key5;
+	_RGFW->keycodes[0x007] = RGFW_key6;
+	_RGFW->keycodes[0x008] = RGFW_key7;
+	_RGFW->keycodes[0x009] = RGFW_key8;
+	_RGFW->keycodes[0x00A] = RGFW_key9;
+	_RGFW->keycodes[0x01E] = RGFW_keyA;
+	_RGFW->keycodes[0x030] = RGFW_keyB;
+	_RGFW->keycodes[0x02E] = RGFW_keyC;
+	_RGFW->keycodes[0x020] = RGFW_keyD;
+	_RGFW->keycodes[0x012] = RGFW_keyE;
+	_RGFW->keycodes[0x021] = RGFW_keyF;
+	_RGFW->keycodes[0x022] = RGFW_keyG;
+	_RGFW->keycodes[0x023] = RGFW_keyH;
+	_RGFW->keycodes[0x017] = RGFW_keyI;
+	_RGFW->keycodes[0x024] = RGFW_keyJ;
+	_RGFW->keycodes[0x025] = RGFW_keyK;
+	_RGFW->keycodes[0x026] = RGFW_keyL;
+	_RGFW->keycodes[0x032] = RGFW_keyM;
+	_RGFW->keycodes[0x031] = RGFW_keyN;
+	_RGFW->keycodes[0x018] = RGFW_keyO;
+	_RGFW->keycodes[0x019] = RGFW_keyP;
+	_RGFW->keycodes[0x010] = RGFW_keyQ;
+	_RGFW->keycodes[0x013] = RGFW_keyR;
+	_RGFW->keycodes[0x01F] = RGFW_keyS;
+	_RGFW->keycodes[0x014] = RGFW_keyT;
+	_RGFW->keycodes[0x016] = RGFW_keyU;
+	_RGFW->keycodes[0x02F] = RGFW_keyV;
+	_RGFW->keycodes[0x011] = RGFW_keyW;
+	_RGFW->keycodes[0x02D] = RGFW_keyX;
+	_RGFW->keycodes[0x015] = RGFW_keyY;
+	_RGFW->keycodes[0x02C] = RGFW_keyZ;
+	_RGFW->keycodes[0x028] = RGFW_keyApostrophe;
+	_RGFW->keycodes[0x02B] = RGFW_keyBackSlash;
+	_RGFW->keycodes[0x033] = RGFW_keyComma;
+	_RGFW->keycodes[0x00D] = RGFW_keyEquals;
+	_RGFW->keycodes[0x029] = RGFW_keyBacktick;
+	_RGFW->keycodes[0x01A] = RGFW_keyBracket;
+	_RGFW->keycodes[0x00C] = RGFW_keyMinus;
+	_RGFW->keycodes[0x034] = RGFW_keyPeriod;
+	_RGFW->keycodes[0x01B] = RGFW_keyCloseBracket;
+	_RGFW->keycodes[0x027] = RGFW_keySemicolon;
+	_RGFW->keycodes[0x035] = RGFW_keySlash;
+	_RGFW->keycodes[0x056] = RGFW_keyWorld2;
+	_RGFW->keycodes[0x00E] = RGFW_keyBackSpace;
+	_RGFW->keycodes[0x153] = RGFW_keyDelete;
+	_RGFW->keycodes[0x14F] = RGFW_keyEnd;
+	_RGFW->keycodes[0x01C] = RGFW_keyEnter;
+	_RGFW->keycodes[0x001] = RGFW_keyEscape;
+	_RGFW->keycodes[0x147] = RGFW_keyHome;
+	_RGFW->keycodes[0x152] = RGFW_keyInsert;
+	_RGFW->keycodes[0x15D] = RGFW_keyMenu;
+	_RGFW->keycodes[0x151] = RGFW_keyPageDown;
+	_RGFW->keycodes[0x149] = RGFW_keyPageUp;
+	_RGFW->keycodes[0x045] = RGFW_keyPause;
+	_RGFW->keycodes[0x039] = RGFW_keySpace;
+	_RGFW->keycodes[0x00F] = RGFW_keyTab;
+	_RGFW->keycodes[0x03A] = RGFW_keyCapsLock;
+	_RGFW->keycodes[0x145] = RGFW_keyNumLock;
+	_RGFW->keycodes[0x046] = RGFW_keyScrollLock;
+	_RGFW->keycodes[0x03B] = RGFW_keyF1;
+	_RGFW->keycodes[0x03C] = RGFW_keyF2;
+	_RGFW->keycodes[0x03D] = RGFW_keyF3;
+	_RGFW->keycodes[0x03E] = RGFW_keyF4;
+	_RGFW->keycodes[0x03F] = RGFW_keyF5;
+	_RGFW->keycodes[0x040] = RGFW_keyF6;
+	_RGFW->keycodes[0x041] = RGFW_keyF7;
+	_RGFW->keycodes[0x042] = RGFW_keyF8;
+	_RGFW->keycodes[0x043] = RGFW_keyF9;
+	_RGFW->keycodes[0x044] = RGFW_keyF10;
+	_RGFW->keycodes[0x057] = RGFW_keyF11;
+	_RGFW->keycodes[0x058] = RGFW_keyF12;
+	_RGFW->keycodes[0x064] = RGFW_keyF13;
+	_RGFW->keycodes[0x065] = RGFW_keyF14;
+	_RGFW->keycodes[0x066] = RGFW_keyF15;
+	_RGFW->keycodes[0x067] = RGFW_keyF16;
+	_RGFW->keycodes[0x068] = RGFW_keyF17;
+	_RGFW->keycodes[0x069] = RGFW_keyF18;
+	_RGFW->keycodes[0x06A] = RGFW_keyF19;
+	_RGFW->keycodes[0x06B] = RGFW_keyF20;
+	_RGFW->keycodes[0x06C] = RGFW_keyF21;
+	_RGFW->keycodes[0x06D] = RGFW_keyF22;
+	_RGFW->keycodes[0x06E] = RGFW_keyF23;
+	_RGFW->keycodes[0x076] = RGFW_keyF24;
+	_RGFW->keycodes[0x038] = RGFW_keyAltL;
+	_RGFW->keycodes[0x01D] = RGFW_keyControlL;
+	_RGFW->keycodes[0x02A] = RGFW_keyShiftL;
+	_RGFW->keycodes[0x15B] = RGFW_keySuperL;
+	_RGFW->keycodes[0x137] = RGFW_keyPrintScreen;
+	_RGFW->keycodes[0x138] = RGFW_keyAltR;
+	_RGFW->keycodes[0x11D] = RGFW_keyControlR;
+	_RGFW->keycodes[0x036] = RGFW_keyShiftR;
+	_RGFW->keycodes[0x15C] = RGFW_keySuperR;
+	_RGFW->keycodes[0x150] = RGFW_keyDown;
+	_RGFW->keycodes[0x14B] = RGFW_keyLeft;
+	_RGFW->keycodes[0x14D] = RGFW_keyRight;
+	_RGFW->keycodes[0x148] = RGFW_keyUp;
+	_RGFW->keycodes[0x052] = RGFW_keyPad0;
+	_RGFW->keycodes[0x04F] = RGFW_keyPad1;
+	_RGFW->keycodes[0x050] = RGFW_keyPad2;
+	_RGFW->keycodes[0x051] = RGFW_keyPad3;
+	_RGFW->keycodes[0x04B] = RGFW_keyPad4;
+	_RGFW->keycodes[0x04C] = RGFW_keyPad5;
+	_RGFW->keycodes[0x04D] = RGFW_keyPad6;
+	_RGFW->keycodes[0x047] = RGFW_keyPad7;
+	_RGFW->keycodes[0x048] = RGFW_keyPad8;
+	_RGFW->keycodes[0x049] = RGFW_keyPad9;
+	_RGFW->keycodes[0x04E] = RGFW_keyPadPlus;
+	_RGFW->keycodes[0x053] = RGFW_keyPadPeriod;
+	_RGFW->keycodes[0x135] = RGFW_keyPadSlash;
+	_RGFW->keycodes[0x11C] = RGFW_keyPadReturn;
+	_RGFW->keycodes[0x059] = RGFW_keyPadEqual;
+	_RGFW->keycodes[0x037] = RGFW_keyPadMultiply;
+	_RGFW->keycodes[0x04A] = RGFW_keyPadMinus;
+}
+
+
+i32 RGFW_initPlatform(void) {
+#ifndef RGFW_NO_DPI
+	#if (_WIN32_WINNT >= 0x0600)
+		SetProcessDPIAware();
+	#endif
+#endif
+
+	#ifndef RGFW_NO_WINMM
+		#ifndef RGFW_NO_LOAD_WINMM
+			RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
+			RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
+			RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
+		#endif
+		timeBeginPeriod(1);
+	#endif
+
+	#ifndef RGFW_NO_DWM
+	RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
+	RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
+	RGFW_PROC_DEF(RGFW_dwm_dll, DwmSetWindowAttribute);
+	#endif
+
+	RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
+	#ifndef RGFW_NO_LOAD_WGL
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
+		RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
+	#endif
+
+	u8 RGFW_blk[] = { 0, 0, 0, 0 };
+	_RGFW->hiddenMouse = RGFW_createMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8);
+    return 0;
+}
+
+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	if (name[0] == 0) name = (char*) " ";
+	win->src.hIconSmall = win->src.hIconBig = NULL;
+	win->src.maxSizeW = 0;
+	win->src.maxSizeH = 0;
+	win->src.minSizeW = 0;
+	win->src.minSizeH = 0;
+	win->src.aspectRatioW = 0;
+	win->src.aspectRatioH = 0;
+
+	HINSTANCE inh = GetModuleHandleA(NULL);
+
+	#ifndef __cplusplus
+	WNDCLASSW Class = {0}; /*!< Setup the Window class. */
+	#else
+	WNDCLASSW Class = {};
+	#endif
+
+	if (_RGFW->className == NULL)
+		_RGFW->className = (char*)name;
+
+	wchar_t wide_class[256];
+	MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255);
+
+	Class.lpszClassName = wide_class;
+	Class.hInstance = inh;
+	Class.hCursor = LoadCursor(NULL, IDC_ARROW);
+	Class.lpfnWndProc = WndProcW;
+	Class.cbClsExtra = sizeof(RGFW_window*);
+
+	Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+	if (Class.hIcon == NULL)
+		Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+
+	RegisterClassW(&Class);
+
+	DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+
+	if (!(flags & RGFW_windowNoBorder)) {
+		window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
+
+		if (!(flags & RGFW_windowNoResize))
+			window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
+	} else
+		window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
+
+	wchar_t wide_name[256];
+	MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
+	HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0);
+
+#ifdef RGFW_OPENGL
+	RGFW_win32_loadOpenGLFuncs(dummyWin);
+#endif
+
+	DestroyWindow(dummyWin);
+
+	RECT rect = { 0, 0, win->w, win->h};
+	DWORD style = RGFW_winapi_window_getStyle(win, flags);
+	DWORD exStyle = RGFW_winapi_window_getExStyle(win, flags);
+	AdjustWindowRectEx(&rect, style, FALSE, exStyle);
+
+	win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x + rect.left, win->y + rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, inh, 0);
+	SetPropW(win->src.window, L"RGFW", win);
+	RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */
+
+	if (flags & RGFW_windowAllowDND) {
+		win->internal.flags |= RGFW_windowAllowDND;
+		RGFW_window_setDND(win, 1);
+	}
+	win->src.hdc = GetDC(win->src.window);
+
+	RGFW_win32_makeWindowDarkMode(win, RGFW_win32_getDarkModeState());
+	RGFW_win32_makeWindowTransparent(win);
+	return win;
+}
+
+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
+	RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
+
+	RECT rect;
+    GetClientRect(win->src.window, &rect);
+
+	LONG style = GetWindowLong(win->src.window, GWL_STYLE);
+	style |= (LONG)RGFW_winapi_window_getStyle(win, win->internal.flags);
+
+	if (border == 0) {
+		style &= ~WS_OVERLAPPEDWINDOW;
+	} else {
+		if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
+		style |= WS_OVERLAPPEDWINDOW;
+	}
+
+	DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
+	ClientToScreen(win->src.window, (POINT*) &rect.left);
+    ClientToScreen(win->src.window, (POINT*) &rect.right);
+
+	AdjustWindowRectEx(&rect, (DWORD)style, FALSE, exStyle);
+	SetWindowLong(win->src.window, GWL_STYLE, style);
+
+    SetWindowLongW(win->src.window, GWL_STYLE, style);
+    SetWindowPos(win->src.window, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
+	RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow);
+	DragAcceptFiles(win->src.window, allow);
+}
+
+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
+	POINT p;
+	GetCursorPos(&p);
+	if (x) *x = p.x;
+	if (y) *y = p.y;
+	return RGFW_TRUE;
+}
+
+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+	win->src.aspectRatioW = w;
+	win->src.aspectRatioH = h;
+}
+
+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+	win->src.minSizeW = w;
+	win->src.minSizeH = h;
+}
+
+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+	win->src.maxSizeW = w;
+	win->src.maxSizeH = h;
+}
+
+void RGFW_window_focus(RGFW_window* win) {
+	RGFW_ASSERT(win);
+	SetForegroundWindow(win->src.window);
+	SetFocus(win->src.window);
+}
+
+void RGFW_window_raise(RGFW_window* win) {
+	RGFW_ASSERT(win);
+	BringWindowToTop(win->src.window);
+	SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
+}
+
+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+
+	RGFW_monitor* mon  = RGFW_window_getMonitor(win);
+
+	if (fullscreen == RGFW_FALSE) {
+		RGFW_monitor_setMode(mon, &win->internal.oldMode);
+
+		RGFW_window_setBorder(win, 1);
+
+		RECT rect = { 0, 0, win->internal.oldW, win->internal.oldH};
+		DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
+		DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
+		AdjustWindowRectEx(&rect, style, FALSE, exStyle);
+		SetWindowPos(win->src.window, HWND_TOP, win->internal.oldX, win->internal.oldY, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
+
+		win->internal.flags &= ~(u32)RGFW_windowFullscreen;
+		win->x  = win->internal.oldX;
+		win->y = win->internal.oldY;
+		win->w = win->internal.oldW;
+		win->h = win->internal.oldH;
+		return;
+	}
+
+	win->internal.oldX = win->x;
+	win->internal.oldY = win->y;
+	win->internal.oldW = win->w;
+	win->internal.oldH = win->h;
+	win->internal.oldMode = mon->mode;
+	win->internal.flags |= RGFW_windowFullscreen;
+
+	RGFW_window_setBorder(win, 0);
+
+    SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon->x, (i32)mon->y, 0, 0, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE);
+	win->x = mon->x;
+	win->y = mon->y;
+
+	RGFW_monitor_scaleToWindow(mon, win);
+    SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon->mode.w, (i32)mon->mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE);
+	win->w = mon->mode.w;
+	win->h = mon->mode.h;
+}
+
+void RGFW_window_maximize(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_window_hide(win);
+	ShowWindow(win->src.window, SW_MAXIMIZE);
+	RGFW_window_fetchSize(win, NULL, NULL);
+}
+
+void RGFW_window_minimize(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	ShowWindow(win->src.window, SW_MINIMIZE);
+}
+
+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
+    RGFW_ASSERT(win != NULL);
+    if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+    else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+}
+
+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
+	SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
+	SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
+}
+
+void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
+
+RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
+	return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
+}
+
+void RGFW_stopCheckEvents(void) {
+	PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0);
+}
+
+void RGFW_waitForEvent(i32 waitMS) {
+	MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
+}
+
+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
+    UINT vsc = RGFW_rgfwToApiKey(key);
+    BYTE keyboardState[256] = {0};
+
+    if (!GetKeyboardState(keyboardState))
+        return key;
+
+    UINT vk = MapVirtualKeyW(vsc, MAPVK_VSC_TO_VK);
+    HKL layout = GetKeyboardLayout(0);
+
+    wchar_t charBuffer[4] = {0};
+    int result = ToUnicodeEx(vk, vsc, keyboardState, charBuffer, 1, 0, layout);
+
+    if (result == 1 && charBuffer[0] < 256) {
+        return (RGFW_key)charBuffer[0];
+	}
+
+    switch (vk) {
+        case VK_F1:  return RGFW_keyF1;
+        case VK_F2:  return RGFW_keyF2;
+        case VK_F3:  return RGFW_keyF3;
+        case VK_F4:  return RGFW_keyF4;
+        case VK_F5:  return RGFW_keyF5;
+        case VK_F6:  return RGFW_keyF6;
+        case VK_F7:  return RGFW_keyF7;
+        case VK_F8:  return RGFW_keyF8;
+        case VK_F9:  return RGFW_keyF9;
+        case VK_F10: return RGFW_keyF10;
+        case VK_F11: return RGFW_keyF11;
+        case VK_F12: return RGFW_keyF12;
+        case VK_F13: return RGFW_keyF13;
+        case VK_F14: return RGFW_keyF14;
+        case VK_F15: return RGFW_keyF15;
+        case VK_F16: return RGFW_keyF16;
+        case VK_F17: return RGFW_keyF17;
+        case VK_F18: return RGFW_keyF18;
+        case VK_F19: return RGFW_keyF19;
+        case VK_F20: return RGFW_keyF20;
+        case VK_F21: return RGFW_keyF21;
+        case VK_F22: return RGFW_keyF22;
+        case VK_F23: return RGFW_keyF23;
+        case VK_F24: return RGFW_keyF24;
+        case VK_LSHIFT:   return RGFW_keyShiftL;
+        case VK_RSHIFT:   return RGFW_keyShiftR;
+        case VK_LCONTROL: return RGFW_keyControlL;
+        case VK_RCONTROL: return RGFW_keyControlR;
+        case VK_LMENU:    return RGFW_keyAltL;
+        case VK_RMENU:    return RGFW_keyAltR;
+        case VK_LWIN:     return RGFW_keySuperL;
+        case VK_RWIN:     return RGFW_keySuperR;
+        case VK_CAPITAL:  return RGFW_keyCapsLock;
+        case VK_NUMLOCK:  return RGFW_keyNumLock;
+        case VK_SCROLL:   return RGFW_keyScrollLock;
+        case VK_UP:       return RGFW_keyUp;
+        case VK_DOWN:     return RGFW_keyDown;
+        case VK_LEFT:     return RGFW_keyLeft;
+        case VK_RIGHT:    return RGFW_keyRight;
+        case VK_HOME:     return RGFW_keyHome;
+        case VK_END:      return RGFW_keyEnd;
+        case VK_PRIOR:    return RGFW_keyPageUp;
+        case VK_NEXT:     return RGFW_keyPageDown;
+        case VK_INSERT:   return RGFW_keyInsert;
+        case VK_APPS:     return RGFW_keyMenu;
+        case VK_ADD:      return RGFW_keyPadPlus;
+        case VK_SUBTRACT: return RGFW_keyPadMinus;
+        case VK_MULTIPLY: return RGFW_keyPadMultiply;
+        case VK_DIVIDE:   return RGFW_keyPadSlash;
+        case VK_RETURN:   return RGFW_keyPadReturn;
+        case VK_DECIMAL:  return RGFW_keyPadPeriod;
+        case VK_NUMPAD0: return RGFW_keyPad0;
+        case VK_NUMPAD1: return RGFW_keyPad1;
+        case VK_NUMPAD2: return RGFW_keyPad2;
+        case VK_NUMPAD3: return RGFW_keyPad3;
+        case VK_NUMPAD4: return RGFW_keyPad4;
+        case VK_NUMPAD5: return RGFW_keyPad5;
+        case VK_NUMPAD6: return RGFW_keyPad6;
+        case VK_NUMPAD7: return RGFW_keyPad7;
+        case VK_NUMPAD8: return RGFW_keyPad8;
+        case VK_NUMPAD9: return RGFW_keyPad9;
+        case VK_SNAPSHOT: return RGFW_keyPrintScreen;
+        case VK_PAUSE:    return RGFW_keyPause;
+        default: return RGFW_keyNULL;
+    }
+
+    return RGFW_keyNULL;
+}
+
+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
+    RECT area;
+    GetClientRect(win->src.window, &area);
+
+    win->w = area.right;
+    win->h = area.bottom;
+
+	return RGFW_window_getSize(win, w, h);
+}
+
+void RGFW_pollEvents(void) {
+	RGFW_resetPrevState();
+    MSG msg;
+    while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
+		TranslateMessage(&msg);
+		DispatchMessageA(&msg);
+	}
+}
+
+RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
+}
+
+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	#ifndef __cplusplus
+	WINDOWPLACEMENT placement = {0};
+	#else
+	WINDOWPLACEMENT placement = {};
+	#endif
+	GetWindowPlacement(win->src.window, &placement);
+	return placement.showCmd == SW_SHOWMINIMIZED;
+}
+
+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	#ifndef __cplusplus
+	WINDOWPLACEMENT placement = {0};
+	#else
+	WINDOWPLACEMENT placement = {};
+	#endif
+	GetWindowPlacement(win->src.window, &placement);
+	return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
+}
+
+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
+    MONITORINFOEX mi;
+	mi.cbSize = sizeof(MONITORINFOEX);
+	GetMonitorInfoA(monitor->node->hMonitor, (LPMONITORINFO)&mi);
+
+    if (x) *x = mi.rcWork.left;
+    if (y) *y = mi.rcWork.top;
+    if (width) *width = mi.rcWork.right - mi.rcWork.left;
+    if (height) *height = mi.rcWork.bottom - mi.rcWork.top;
+
+	return RGFW_TRUE;
+}
+
+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+    WORD values[3][256];
+
+    HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
+    GetDeviceGammaRamp(dc, values);
+    DeleteDC(dc);
+
+	if (ramp) {
+	    memcpy(ramp->red,   values[0], sizeof(values[0]));
+		memcpy(ramp->green, values[1], sizeof(values[1]));
+	    memcpy(ramp->blue,  values[2], sizeof(values[2]));
+	}
+
+    return sizeof(values[0]) / sizeof(WORD);
+}
+
+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+    WORD values[3][256];
+    if (ramp->count != 256) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errX11, "Win32: Gamma ramp size must be 256");
+        return RGFW_FALSE;
+    }
+
+    memcpy(values[0], ramp->red,   sizeof(values[0]));
+    memcpy(values[1], ramp->green, sizeof(values[1]));
+    memcpy(values[2], ramp->blue,  sizeof(values[2]));
+
+    HDC dc = CreateDCW(L"DISPLAY", monitor->node->adapterName, NULL, NULL);
+    SetDeviceGammaRamp(dc, values);
+    DeleteDC(dc);
+	return RGFW_TRUE;
+}
+
+BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
+BOOL CALLBACK RGFW_win32_getMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+	RGFW_UNUSED(hMonitor);
+	RGFW_UNUSED(hdcMonitor);
+	RGFW_UNUSED(lprcMonitor);
+	RGFW_UNUSED(dwData);
+
+    MONITORINFOEXW mi;
+    ZeroMemory(&mi, sizeof(mi));
+    mi.cbSize = sizeof(mi);
+
+    if (GetMonitorInfoW(hMonitor, (MONITORINFO*) &mi)) {
+		RGFW_monitorNode* node = (RGFW_monitorNode*)dwData;
+        if (wcscmp(mi.szDevice, node->adapterName) == 0) {
+            node->hMonitor = hMonitor;
+		}
+    }
+
+	return TRUE;
+}
+
+RGFWDEF void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode);
+void RGFW_win32_getMode(DEVMODEW* dm, RGFW_monitorMode* mode) {
+	mode->w = (i32)dm->dmPelsWidth;
+	mode->h = (i32)dm->dmPelsHeight;
+	RGFW_splitBPP(dm->dmBitsPerPel, mode);
+
+    switch (dm->dmDisplayFrequency) {
+		case 119:
+		case 59:
+		case 29:
+			mode->refreshRate = ((float)(dm->dmDisplayFrequency + 1) * 1000.0f) / 1001.f;
+			break;
+		default:
+			mode->refreshRate = (float)dm->dmDisplayFrequency;
+			break;
+    }
+}
+
+size_t RGFW_monitor_getModesPtr(RGFW_monitor* monitor, RGFW_monitorMode** modes){
+	size_t count = 0;
+	DWORD modeIndex = 0;
+
+	for (;;) {
+		DEVMODEW dm;
+		ZeroMemory(&dm, sizeof(dm));
+		dm.dmSize = sizeof(dm);
+
+		if (!EnumDisplaySettingsW(monitor->node->adapterName, modeIndex, &dm))
+			break;
+
+		if (ChangeDisplaySettingsExW(monitor->node->adapterName, &dm, NULL, CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL) {
+			continue;
+		}
+
+		modeIndex++;
+
+		if (dm.dmBitsPerPel < 15)
+			continue;
+
+		if (modes) {
+			RGFW_monitorMode mode;
+			RGFW_win32_getMode(&dm, &mode);
+
+			size_t i;
+			for (i = 0; i < count;  i++) {
+				if (RGFW_monitorModeCompare(&(*modes)[i], &mode, RGFW_monitorAll) == RGFW_TRUE) {
+					break;
+				}
+			}
+
+			if (i < count) {
+				continue;
+			}
+
+			(*modes)[count] = mode;
+		}
+
+		count += 1;
+	}
+
+	return count;
+}
+
+RGFWDEF void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd);
+void RGFW_win32_createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* dd) {
+	DEVMODEW dm;
+	ZeroMemory(&dm, sizeof(dm));
+	dm.dmSize = sizeof(dm);
+
+	if (!EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
+		return;
+	}
+
+	RGFW_monitorNode* node = RGFW_monitors_add(NULL);
+
+	wcscpy(node->adapterName, adapter->DeviceName);
+	wcscpy(node->deviceName, dd->DeviceName);
+
+	RGFW_createUTF8FromWideStringWin32(dd->DeviceString, node->mon.name, sizeof(node->mon.name));
+	node->mon.name[sizeof(node->mon.name) - 1] = '\0';
+
+	RECT rect;
+	rect.left = (LONG)dm.dmPosition.x;
+	rect.top = (LONG)dm.dmPosition.y;
+	rect.right = (LONG)((LONG)dm.dmPosition.x + (LONG)dm.dmPelsWidth);
+	rect.bottom = (LONG)((long)dm.dmPosition.y + (LONG)dm.dmPelsHeight);
+	EnumDisplayMonitors(NULL, &rect, RGFW_win32_getMonitorHandle, (LPARAM)node);
+
+	RGFW_win32_getMode(&dm, &node->mon.mode);
+
+	MONITORINFOEXW monitorInfo;
+	monitorInfo.cbSize = sizeof(MONITORINFOEXW);
+	GetMonitorInfoW(node->hMonitor, (LPMONITORINFO)&monitorInfo);
+
+	node->mon.x = monitorInfo.rcMonitor.left;
+	node->mon.y = monitorInfo.rcMonitor.top;
+
+	HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL);
+
+	float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
+	float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSY);
+
+	node->mon.scaleX = dpiX / 96.0f;
+	node->mon.scaleY = dpiY / 96.0f;
+	node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
+
+	node->mon.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
+	node->mon.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
+	DeleteDC(hdc);
+
+#ifndef RGFW_NO_DPI
+	RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
+	RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
+
+	if (GetDpiForMonitor != NULL) {
+		u32 x, y;
+		GetDpiForMonitor(node->hMonitor, MDT_EFFECTIVE_DPI, &x, &y);
+		node->mon.scaleX = (float) (x) / (float) 96.0f;
+		node->mon.scaleY = (float) (y) / (float) 96.0f;
+		node->mon.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
+	}
+#endif
+
+	if (monitorInfo.dwFlags & MONITORINFOF_PRIMARY) {
+		_RGFW->monitors.primary = node;
+	}
+
+	RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
+}
+
+void RGFW_pollMonitors(void) {
+	for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
+		node->disconnected = RGFW_TRUE;
+	}
+
+	/* loop through display adapters (GPU) */
+	DISPLAY_DEVICEW adapter;
+	DWORD adapterNum;
+	for (adapterNum = 0; ; adapterNum++) {
+        ZeroMemory(&adapter, sizeof(adapter));
+		adapter.cb = sizeof(adapter);
+
+		if (!EnumDisplayDevicesW(NULL, adapterNum, &adapter, 0))
+			break;
+
+		if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
+			continue;
+
+		DISPLAY_DEVICEW dd;
+		dd.cb = sizeof(dd);
+
+		/* loop through display devices (monitors) */
+		DWORD deviceNum;
+		for (deviceNum = 0; ; deviceNum++) {
+            ZeroMemory(&dd, sizeof(dd));
+            dd.cb = sizeof(dd);
+
+			if (!EnumDisplayDevicesW(adapter.DeviceName, deviceNum, &dd, 0))
+				break;
+
+			if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
+				continue;
+
+			RGFW_monitorNode* node;
+			for (node = _RGFW->monitors.list.head; node; node = node->next) {
+				if (node->disconnected == RGFW_TRUE && wcscmp(node->deviceName, dd.DeviceName) == 0) {
+					node->disconnected = RGFW_FALSE;
+					EnumDisplayMonitors(NULL, NULL, RGFW_win32_getMonitorHandle, (LPARAM) &node->mon);
+					break;
+				}
+			}
+
+			if (node) {
+				continue;
+			}
+
+			RGFW_win32_createMonitor(&adapter, &dd);
+		}
+
+		/* if there are no display devices, just use the monitor directly (hack borrowed from GLFW (I'm not giving it back)) */
+        if (deviceNum == 0) {
+   			RGFW_monitorNode* node;
+			for (node = _RGFW->monitors.list.head; node; node = node->next) {
+				if (node->disconnected == RGFW_TRUE && wcscmp(node->adapterName, adapter.DeviceName) == 0) {
+					node->disconnected = RGFW_FALSE;
+					break;
+				}
+			}
+
+			if (node) {
+				continue;
+			}
+
+			RGFW_win32_createMonitor(&adapter, NULL);
+        }
+	}
+
+	RGFW_monitors_refresh();
+}
+
+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
+	HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
+	RGFW_monitorNode* node = _RGFW->monitors.list.head;
+
+	for (node = _RGFW->monitors.list.head; node; node = node->next) {
+		if (node->hMonitor == src) {
+			return &node->mon;
+		}
+	}
+
+	return RGFW_getPrimaryMonitor();
+}
+
+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
+	DEVMODEW dm;
+	ZeroMemory(&dm, sizeof(dm));
+	dm.dmSize = sizeof(dm);
+
+	dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
+	dm.dmPelsWidth = (u32)mode->w;
+	dm.dmPelsHeight = (u32)mode->h;
+
+	dm.dmFields |= DM_DISPLAYFREQUENCY;
+	dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
+
+	dm.dmFields |= DM_BITSPERPEL;
+	dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
+
+	if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
+		if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) {
+			RGFW_win32_getMode(&dm, &mon->mode);
+			return RGFW_TRUE;
+		}
+		return RGFW_FALSE;
+	} else return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
+HMONITOR src = mon->node->hMonitor;
+
+	MONITORINFOEX  monitorInfo;
+	monitorInfo.cbSize = sizeof(MONITORINFOEX);
+	GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
+
+	DEVMODEW dm;
+	ZeroMemory(&dm, sizeof(dm));
+	dm.dmSize = sizeof(dm);
+
+	DWORD index = 0;
+
+	for (;;) {
+		if (EnumDisplaySettingsW(mon->node->adapterName, index, &dm) == 0) {
+			break;
+		}
+
+		index += 1;
+
+		if (request & RGFW_monitorScale) {
+			dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
+			dm.dmPelsWidth = (u32)mode->w;
+			dm.dmPelsHeight = (u32)mode->h;
+		}
+
+		if (request & RGFW_monitorRefresh) {
+			dm.dmFields |= DM_DISPLAYFREQUENCY;
+			dm.dmDisplayFrequency = (DWORD)mode->refreshRate;
+		}
+
+		if (request & RGFW_monitorRGB) {
+			dm.dmFields |= DM_BITSPERPEL;
+			dm.dmBitsPerPel = (DWORD)(mode->red + mode->green + mode->blue);
+		}
+
+		if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
+			if (ChangeDisplaySettingsExW(mon->node->adapterName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) {
+				RGFW_win32_getMode(&dm, &mon->mode);
+				return RGFW_TRUE;
+			}
+			return RGFW_FALSE;
+		}
+	}
+
+	return RGFW_FALSE;
+}
+
+HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon);
+HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon) {
+	BITMAPV5HEADER bi;
+	ZeroMemory(&bi, sizeof(bi));
+	bi.bV5Size = sizeof(bi);
+	bi.bV5Width = (i32)w;
+	bi.bV5Height = -((LONG) h);
+	bi.bV5Planes = 1;
+	bi.bV5BitCount = (WORD)32;
+	bi.bV5Compression = BI_RGB;
+	HDC dc = GetDC(NULL);
+	u8* target = NULL;
+
+	HBITMAP color = CreateDIBSection(dc,
+		(BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
+		NULL, (DWORD) 0);
+
+	RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format, NULL);
+    ReleaseDC(NULL, dc);
+
+	HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL);
+
+	ICONINFO ii;
+	ZeroMemory(&ii, sizeof(ii));
+	ii.fIcon = icon;
+	ii.xHotspot = (u32)w / 2;
+	ii.yHotspot = (u32)h / 2;
+	ii.hbmMask = mask;
+	ii.hbmColor = color;
+
+	HICON handle = CreateIconIndirect(&ii);
+
+	DeleteObject(color);
+	DeleteObject(mask);
+
+	return handle;
+}
+
+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
+	u32 mouseIcon = 0;
+
+    switch (mouse) {
+		case RGFW_mouseNormal: mouseIcon = OCR_NORMAL; break;
+		case RGFW_mouseArrow: mouseIcon = OCR_NORMAL; break;
+		case RGFW_mouseIbeam: mouseIcon = OCR_IBEAM; break;
+		case RGFW_mouseWait: mouseIcon = OCR_WAIT; break;
+		case RGFW_mouseCrosshair: mouseIcon = OCR_CROSS; break;
+		case RGFW_mouseProgress: mouseIcon = OCR_APPSTARTING; break;
+		case RGFW_mouseResizeNWSE: mouseIcon = OCR_SIZENWSE; break;
+		case RGFW_mouseResizeNESW: mouseIcon = OCR_SIZENESW; break;
+		case RGFW_mouseResizeEW: mouseIcon = OCR_SIZEWE; break;
+		case RGFW_mouseResizeNS: mouseIcon = OCR_SIZENS; break;
+		case RGFW_mouseResizeAll: mouseIcon = OCR_SIZEALL; break;
+		case RGFW_mouseNotAllowed: mouseIcon = OCR_NO; break;
+		case RGFW_mousePointingHand: mouseIcon = OCR_HAND; break;
+		case RGFW_mouseResizeNW: mouseIcon = OCR_SIZENWSE; break;
+		case RGFW_mouseResizeN: mouseIcon = OCR_SIZENS; break;
+		case RGFW_mouseResizeNE: mouseIcon = OCR_SIZENESW; break;
+		case RGFW_mouseResizeE: mouseIcon = OCR_SIZEWE; break;
+		case RGFW_mouseResizeSE: mouseIcon = OCR_SIZENWSE; break;
+		case RGFW_mouseResizeS: mouseIcon = OCR_SIZENS; break;
+		case RGFW_mouseResizeSW: mouseIcon = OCR_SIZENESW; break;
+		case RGFW_mouseResizeW: mouseIcon = OCR_SIZEWE; break;
+		default: return NULL;
+    }
+
+	char* icon = MAKEINTRESOURCEA(mouseIcon);
+	return LoadCursorA(NULL, icon);
+}
+
+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) {
+	HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE);
+	return cursor;
+}
+
+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win && mouse);
+	SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
+	SetCursor((HCURSOR)mouse);
+
+	return RGFW_FALSE;
+}
+
+void RGFW_freeMouse(RGFW_mouse* mouse) {
+	RGFW_ASSERT(mouse);
+	DestroyCursor((HCURSOR)mouse);
+}
+
+void RGFW_window_hide(RGFW_window* win) {
+	ShowWindow(win->src.window, SW_HIDE);
+}
+
+void RGFW_window_show(RGFW_window* win) {
+	if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
+	ShowWindow(win->src.window, SW_RESTORE);
+}
+
+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
+	if (RGFW_window_isInFocus(win) && request) {
+		return;
+	}
+
+	FLASHWINFO desc;
+	RGFW_MEMZERO(&desc, sizeof(desc));
+
+    desc.cbSize = sizeof(desc);
+    desc.hwnd = win->src.window;
+
+    switch (request) {
+		case RGFW_flashCancel:
+			desc.dwFlags = FLASHW_STOP;
+			break;
+		case RGFW_flashBriefly:
+			desc.dwFlags = FLASHW_TRAY;
+			desc.uCount = 1;
+			break;
+		case RGFW_flashUntilFocused:
+			desc.dwFlags = (FLASHW_TRAY | FLASHW_TIMERNOFG);
+			break;
+		default: break;
+    }
+
+    FlashWindowEx(&desc);
+}
+
+#define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
+void RGFW_deinitPlatform(void) {
+    #ifndef RGFW_NO_DPI
+        RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
+    #endif
+
+    #ifndef RGFW_NO_WINMM
+        timeEndPeriod(1);
+        #ifndef RGFW_NO_LOAD_WINMM
+            RGFW_FREE_LIBRARY(RGFW_winmm_dll);
+        #endif
+    #endif
+
+    RGFW_FREE_LIBRARY(RGFW_wgl_dll);
+
+    RGFW_freeMouse(_RGFW->hiddenMouse);
+}
+
+
+void RGFW_window_closePlatform(RGFW_window* win) {
+	RemovePropW(win->src.window, L"RGFW");
+	ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
+	DestroyWindow(win->src.window); /*!< delete window */
+
+	if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
+	if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
+}
+
+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+
+	win->x = x;
+	win->y = y;
+	SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE);
+}
+
+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+	win->w = w;
+	win->h = h;
+	RECT rect = { 0, 0, w, h};
+	DWORD style = RGFW_winapi_window_getStyle(win, win->internal.flags);
+	DWORD exStyle = RGFW_winapi_window_getExStyle(win, win->internal.flags);
+	AdjustWindowRectEx(&rect, style, FALSE, exStyle);
+	SetWindowPos(win->src.window, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void RGFW_window_setName(RGFW_window* win, const char* name) {
+	RGFW_ASSERT(win != NULL);
+	if (name == NULL) name = "\0";
+
+	wchar_t wide_name[256];
+	MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
+	SetWindowTextW(win->src.window, wide_name);
+}
+
+#ifndef RGFW_NO_PASSTHROUGH
+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
+	RGFW_ASSERT(win != NULL);
+	COLORREF key = 0;
+	BYTE alpha = 0;
+	DWORD flags = 0;
+	i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
+
+	if (exStyle & WS_EX_LAYERED)
+		GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
+
+	if (passthrough)
+		exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
+	else {
+		exStyle &= ~WS_EX_TRANSPARENT;
+		if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
+			exStyle &= ~WS_EX_LAYERED;
+	}
+
+	SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
+
+	if (passthrough)
+		SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
+}
+#endif
+
+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
+	RGFW_ASSERT(win != NULL);
+	#ifndef RGFW_WIN95
+		if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
+		if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
+
+		if (data == NULL) {
+			HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
+			if (type & RGFW_iconWindow)
+				SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
+			if (type & RGFW_iconTaskbar)
+				SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
+			return RGFW_TRUE;
+		}
+
+		if (type & RGFW_iconWindow) {
+			win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE);
+			SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
+		}
+		if (type & RGFW_iconTaskbar) {
+			win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE);
+			SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
+		}
+		return RGFW_TRUE;
+	#else
+		RGFW_UNUSED(img);
+		RGFW_UNUSED(type);
+		return RGFW_FALSE;
+	#endif
+}
+
+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
+	/* Open the clipboard */
+	if (OpenClipboard(NULL) == 0)
+		return -1;
+
+	/* Get the clipboard data as a Unicode string */
+	HANDLE hData = GetClipboardData(CF_UNICODETEXT);
+	if (hData == NULL) {
+		CloseClipboard();
+		return -1;
+	}
+
+	wchar_t* wstr = (wchar_t*) GlobalLock(hData);
+
+	RGFW_ssize_t textLen = 0;
+
+	{
+		setlocale(LC_ALL, "en_US.UTF-8");
+
+		textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
+		if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
+			textLen = 0;
+
+		if (str != NULL && textLen) {
+			if (textLen > 1)
+				wcstombs(str, wstr, (size_t)(textLen));
+
+			str[textLen - 1] = '\0';
+		}
+	}
+
+	/* Release the clipboard data */
+	GlobalUnlock(hData);
+	CloseClipboard();
+
+	return textLen;
+}
+
+void RGFW_writeClipboard(const char* text, u32 textLen) {
+	HANDLE object;
+	WCHAR* buffer;
+
+	object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
+	if (!object)
+		return;
+
+	buffer = (WCHAR*) GlobalLock(object);
+	if (!buffer) {
+		GlobalFree(object);
+		return;
+	}
+
+	MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
+	GlobalUnlock(object);
+
+	if (!OpenClipboard(_RGFW->root->src.window)) {
+		GlobalFree(object);
+		return;
+	}
+
+	EmptyClipboard();
+	SetClipboardData(CF_UNICODETEXT, object);
+	CloseClipboard();
+}
+
+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+	win->internal.lastMouseX = x - win->x;
+	win->internal.lastMouseY = y - win->y;
+	SetCursorPos(x, y);
+}
+
+#ifdef RGFW_OPENGL
+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) {
+	const char* extensions = NULL;
+
+    RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB");
+    RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT");
+
+    if (proc)
+        extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC());
+    else if (proc2)
+        extensions = ((const char*(*)(void))proc2)();
+    return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len);
+}
+
+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
+    RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
+    if (proc)
+        return proc;
+
+    return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
+}
+
+void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
+     if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
+		return;
+
+	HDC dummy_dc = GetDC(dummyWin);
+	u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+
+	PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};
+
+	int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
+	SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
+
+	HGLRC dummy_context = wglCreateContext(dummy_dc);
+
+	HGLRC cur = wglGetCurrentContext();
+	wglMakeCurrent(dummy_dc, dummy_context);
+
+	wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
+	wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
+
+    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
+    if (wglSwapIntervalEXT == NULL) {
+        RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext,  "Failed to load swap interval function");
+    }
+
+	wglMakeCurrent(dummy_dc, cur);
+	wglDeleteContext(dummy_context);
+	ReleaseDC(dummyWin, dummy_dc);
+}
+
+#define WGL_ACCELERATION_ARB             0x2003
+#define WGL_FULL_ACCELERATION_ARB        0x2027
+#define WGL_DRAW_TO_WINDOW_ARB           0x2001
+#define WGL_PIXEL_TYPE_ARB               0x2013
+#define WGL_TYPE_RGBA_ARB                0x202b
+#define WGL_SUPPORT_OPENGL_ARB           0x2010
+#define WGL_COLOR_BITS_ARB               0x2014
+#define WGL_DOUBLE_BUFFER_ARB            0x2011
+#define WGL_ALPHA_BITS_ARB               0x201b
+#define WGL_DEPTH_BITS_ARB               0x2022
+#define WGL_STENCIL_BITS_ARB             0x2023
+#define WGL_STEREO_ARB                  0x2012
+#define WGL_AUX_BUFFERS_ARB              0x2024
+#define WGL_RED_BITS_ARB                 0x2015
+#define WGL_GREEN_BITS_ARB               0x2017
+#define WGL_BLUE_BITS_ARB                0x2019
+#define WGL_ACCUM_RED_BITS_ARB           0x201e
+#define WGL_ACCUM_GREEN_BITS_ARB         0x201f
+#define WGL_ACCUM_BLUE_BITS_ARB          0x2020
+#define WGL_ACCUM_ALPHA_BITS_ARB         0x2021
+#define WGL_COLORSPACE_SRGB_EXT          0x3089
+#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB  0x31b3
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB         0x2097
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB    0x0000
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB   0x2098
+#define WGL_CONTEXT_FLAGS_ARB            0x2094
+#define WGL_ACCESS_READ_WRITE_NV         0x00000001
+#define WGL_COVERAGE_SAMPLES_NV          0x2042
+#define WGL_CONTEXT_ES_PROFILE_BIT_EXT   0x00000004
+#define WGL_CONTEXT_PROFILE_MASK_ARB               0x9126
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB            0x00000001
+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB   0x00000002
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_MAJOR_VERSION_ARB               0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB               0x2092
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB             0x20A9
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
+#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
+
+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
+	const char flushControl[] = "WGL_ARB_context_flush_control";
+	const char noError[] = "WGL_ARB_create_context_no_error";
+	const char robustness[] = "WGL_ARB_create_context_robustness";
+
+	win->src.ctx.native = ctx;
+	win->src.gfxType = RGFW_gfxNativeOpenGL;
+
+	PIXELFORMATDESCRIPTOR pfd;
+	pfd.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
+	pfd.nVersion     = 1;
+	pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+	pfd.iPixelType   = PFD_TYPE_RGBA;
+	pfd.iLayerType   = PFD_MAIN_PLANE;
+	pfd.cColorBits   = 32;
+	pfd.cAlphaBits   = 8;
+	pfd.cDepthBits   = 24;
+	pfd.cStencilBits = (BYTE)hints->stencil;
+	pfd.cAuxBuffers  = (BYTE)hints->auxBuffers;
+	if (hints->stereo) pfd.dwFlags |= PFD_STEREO;
+
+	/* try to create the pixel format we want for OpenGL and then try to create an OpenGL context for the specified version */
+	if (hints->renderer == RGFW_glSoftware)
+		pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
+
+	/* get pixel format, default to a basic pixel format */
+	int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
+	if (wglChoosePixelFormatARB != NULL) {
+		i32 pixel_format_attribs[50];
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, pixel_format_attribs, 50);
+
+		RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
+		RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1);
+		RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
+		RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1);
+		RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32);
+		RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1);
+		RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha);
+		RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth);
+		RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil);
+		RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo);
+		RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers);
+		RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red);
+		RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue);
+		RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green);
+		RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed);
+		RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen);
+		RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue);
+		RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha);
+
+		if(hints->sRGB) {
+			if (hints->profile != RGFW_glES)
+				RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1);
+			else
+				RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB);
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples);
+
+		RGFW_attribStack_pushAttribs(&stack, 0, 0);
+
+		int new_pixel_format;
+		UINT num_formats;
+		wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
+		if (!num_formats)
+			RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL");
+		else pixel_format = new_pixel_format;
+	}
+
+	PIXELFORMATDESCRIPTOR suggested;
+	if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
+		!SetPixelFormat(win->src.hdc, pixel_format, &pfd))
+			RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format");
+
+	if (wglCreateContextAttribsARB != NULL) {
+		/* create OpenGL/WGL context for the specified version */
+		i32 attribs[40];
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, attribs, 50);
+
+
+		i32 mask = 0;
+		switch (hints->profile) {
+			case RGFW_glES: mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break;
+			case RGFW_glCompatibility: mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break;
+			case RGFW_glForwardCompatibility: mask |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; break;
+			case RGFW_glCore: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
+			default: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break;
+		}
+
+		RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask);
+
+		if (hints->minor || hints->major) {
+			RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major);
+			RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor);
+		}
+
+		if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError)))
+			RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError);
+
+		if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) {
+			if (hints->releaseBehavior == RGFW_glReleaseFlush) {
+				RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); /* WGL_CONTEXT_RELEASE_BEHAVIOR_ARB */
+			} else if (hints->releaseBehavior == RGFW_glReleaseNone) {
+				RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
+			}
+		}
+
+		i32 flags = 0;
+		if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+		if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
+		if (flags) {
+			RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags);
+		}
+
+
+		RGFW_attribStack_pushAttribs(&stack, 0, 0);
+
+		win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
+	}
+
+	if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context.");
+		win->src.ctx.native->ctx = wglCreateContext(win->src.hdc);
+	}
+
+	ReleaseDC(win->src.window, win->src.hdc);
+	win->src.hdc = GetDC(win->src.window);
+
+	if (hints->share) {
+		wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx);
+	}
+
+	wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx);
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
+	return RGFW_TRUE;
+}
+
+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
+	wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */
+	win->src.ctx.native->ctx = NULL;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
+}
+
+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
+	if (win == NULL)
+		wglMakeCurrent(NULL, NULL);
+	else
+		wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx);
+}
+void* RGFW_getCurrentContext_OpenGL(void) {
+	return wglGetCurrentContext();
+}
+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
+	RGFW_ASSERT(win->src.ctx.native);
+	SwapBuffers(win->src.hdc);
+}
+
+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
+	RGFW_ASSERT(win != NULL);
+    if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval");
+}
+#endif
+
+RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) {
+    i32 size = 0;
+    if (source == NULL) {
+        return RGFW_FALSE;
+	}
+	size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
+	if (!size) {
+		return RGFW_FALSE;
+	}
+
+	if (size > (i32)max)
+		size = (i32)max;
+
+	if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) {
+		return RGFW_FALSE;
+	}
+
+	output[size] = 0;
+	return RGFW_TRUE;
+}
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
+	WGPUSurfaceDescriptor surfaceDesc = {0};
+	WGPUSurfaceSourceWindowsHWND fromHwnd = {0};
+    fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
+    fromHwnd.hwnd = window->src.window;
+
+	fromHwnd.hinstance = GetModuleHandle(NULL);
+
+    surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain;
+    return wgpuInstanceCreateSurface(instance, &surfaceDesc);
+}
+#endif
+
+#endif /* RGFW_WINDOWS */
+
+/*
+	End of Windows defines
+*/
+
+
+
+/*
+
+	Start of MacOS defines
+
+
+*/
+
+#if defined(RGFW_MACOS)
+/*
+	based on silicon.h
+	start of cocoa wrapper
+*/
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <objc/runtime.h>
+#include <objc/message.h>
+#include <mach/mach_time.h>
+
+#include <Carbon/Carbon.h>
+
+typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
+PFN_TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc;
+#define TISCopyCurrentKeyboardLayoutInputSource TISCopyCurrentKeyboardLayoutInputSourceSrc
+
+typedef CFDataRef (*PFN_TISGetInputSourceProperty)(TISInputSourceRef, CFStringRef);
+PFN_TISGetInputSourceProperty TISGetInputSourcePropertySrc;
+#define TISGetInputSourceProperty TISGetInputSourcePropertySrc
+
+typedef u8 (*PFN_LMGetKbdType)(void);
+PFN_LMGetKbdType LMGetKbdTypeSrc;
+#define LMGetKbdType LMGetKbdTypeSrc
+
+CFStringRef kTISPropertyUnicodeKeyLayoutDataSrc;
+
+#ifndef  __OBJC__
+typedef CGRect NSRect;
+typedef CGPoint NSPoint;
+typedef CGSize NSSize;
+
+typedef const char* NSPasteboardType;
+typedef unsigned long NSUInteger;
+typedef long NSInteger;
+typedef NSInteger NSModalResponse;
+
+typedef enum NSRequestUserAttentionType {
+	NSCriticalRequest = 0,
+    NSInformationalRequest = 10
+} NSRequestUserAttentionType;
+
+typedef enum NSApplicationActivationPolicy {
+	NSApplicationActivationPolicyRegular,
+	NSApplicationActivationPolicyAccessory,
+	NSApplicationActivationPolicyProhibited
+} NSApplicationActivationPolicy;
+
+typedef RGFW_ENUM(u32, NSBackingStoreType) {
+	NSBackingStoreRetained = 0,
+		NSBackingStoreNonretained = 1,
+		NSBackingStoreBuffered = 2
+};
+
+typedef RGFW_ENUM(u32, NSWindowStyleMask) {
+	NSWindowStyleMaskBorderless = 0,
+		NSWindowStyleMaskTitled = 1 << 0,
+		NSWindowStyleMaskClosable = 1 << 1,
+		NSWindowStyleMaskMiniaturizable = 1 << 2,
+		NSWindowStyleMaskResizable = 1 << 3,
+		NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
+		NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
+		NSWindowStyleMaskFullScreen = 1 << 14,
+		NSWindowStyleMaskFullSizeContentView = 1 << 15,
+		NSWindowStyleMaskUtilityWindow = 1 << 4,
+		NSWindowStyleMaskDocModalWindow = 1 << 6,
+		NSWindowStyleMaskNonactivatingpanel = 1 << 7,
+		NSWindowStyleMaskHUDWindow = 1 << 13
+};
+
+#define NSPasteboardTypeString "public.utf8-plain-text"
+
+typedef RGFW_ENUM(i32, NSDragOperation) {
+	NSDragOperationNone = 0,
+		NSDragOperationCopy = 1,
+		NSDragOperationLink = 2,
+		NSDragOperationGeneric = 4,
+		NSDragOperationPrivate = 8,
+		NSDragOperationMove = 16,
+		NSDragOperationDelete = 32,
+		NSDragOperationEvery = (int)ULONG_MAX
+};
+
+typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
+	NSOpenGLContextParameterSwapInterval            = 222, /* 1 param.  0 -> Don't sync, 1 -> Sync to vertical retrace     */
+		NSOpenGLContextParametectxaceOrder            = 235, /* 1 param.  1 -> Above Window (default), -1 -> Below Window    */
+		NSOpenGLContextParametectxaceOpacity          = 236, /* 1 param.  1-> Surface is opaque (default), 0 -> non-opaque   */
+		NSOpenGLContextParametectxaceBackingSize      = 304, /* 2 params.  Width/height of surface backing size              */
+		NSOpenGLContextParameterReclaimResources        = 308, /* 0 params.                                                    */
+		NSOpenGLContextParameterCurrentRendererID       = 309, /* 1 param.   Retrieves the current renderer ID                 */
+		NSOpenGLContextParameterGPUVertexProcessing     = 310, /* 1 param.   Currently processing vertices with GPU (get)      */
+		NSOpenGLContextParameterGPUFragmentProcessing   = 311, /* 1 param.   Currently processing fragments with GPU (get)     */
+		NSOpenGLContextParameterHasDrawable             = 314, /* 1 param.   Boolean returned if drawable is attached          */
+		NSOpenGLContextParameterMPSwapsInFlight         = 315, /* 1 param.   Max number of swaps queued by the MP GL engine    */
+
+		NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params.  Set or get the swap rectangle {x, y, w, h} */
+		NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
+		NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
+		NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
+		NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param.   Surface volatile state */
+};
+
+typedef RGFW_ENUM(NSInteger, NSWindowButton) {
+    NSWindowCloseButton            = 0,
+    NSWindowMiniaturizeButton      = 1,
+    NSWindowZoomButton             = 2,
+    NSWindowToolbarButton          = 3,
+    NSWindowDocumentIconButton     = 4,
+    NSWindowDocumentVersionsButton = 6,
+    NSWindowFullScreenButton       = 7,
+};
+
+#define NSPasteboardTypeURL "public.url"
+#define NSPasteboardTypeFileURL "public.file-url"
+#define NSTrackingMouseEnteredAndExited   0x01
+#define NSTrackingMouseMoved              0x02
+#define NSTrackingCursorUpdate            0x04
+#define NSTrackingActiveWhenFirstResponder 0x10
+#define NSTrackingActiveInKeyWindow       0x20
+#define NSTrackingActiveInActiveApp       0x40
+#define NSTrackingActiveAlways            0x80
+#define NSTrackingAssumeInside            0x100
+#define NSTrackingInVisibleRect           0x200
+#define NSTrackingEnabledDuringMouseDrag  0x400
+enum {
+	NSOpenGLPFAAllRenderers =   1,	/* choose from all available renderers          */
+	NSOpenGLPFATripleBuffer =   3,	/* choose a triple buffered pixel format        */
+	NSOpenGLPFADoubleBuffer      =   5,	/* choose a double buffered pixel format        */
+	NSOpenGLPFAAuxBuffers   =   7,	/* number of aux buffers                        */
+	NSOpenGLPFAColorSize       =   8,	/* number of color buffer bits                  */
+	NSOpenGLPFAAlphaSize  =  11,	/* number of alpha component bits               */
+	NSOpenGLPFADepthSize   =  12,	/* number of depth buffer bits                  */
+	NSOpenGLPFAStencilSize   =  13,	/* number of stencil buffer bits                */
+	NSOpenGLPFAAccumSize       =  14,	/* number of accum buffer bits                  */
+	NSOpenGLPFAMinimumPolicy   =  51,	/* never choose smaller buffers than requested  */
+	NSOpenGLPFAMaximumPolicy =  52,	/* choose largest buffers of type requested     */
+	NSOpenGLPFASampleBuffers     =  55,	/* number of multi sample buffers               */
+	NSOpenGLPFASamples            =  56,	/* number of samples per multi sample buffer    */
+	NSOpenGLPFAAuxDepthStencil     =  57,	/* each aux buffer has its own depth stencil    */
+	NSOpenGLPFAColorFloat   =  58,	/* color buffers store floating point pixels    */
+	NSOpenGLPFAMultisample   =  59,    /* choose multisampling                         */
+	NSOpenGLPFASupersample    =  60,    /* choose supersampling                         */
+	NSOpenGLPFASampleAlpha     =  61,    /* request alpha filtering                      */
+	NSOpenGLPFARendererID       =  70,	/* request renderer by ID                       */
+	NSOpenGLPFANoRecovery   =  72,	/* disable all failure recovery systems         */
+	NSOpenGLPFAAccelerated      =  73,	/* choose a hardware accelerated renderer       */
+	NSOpenGLPFAClosestPolicy   =  74,	/* choose the closest color buffer to request   */
+	NSOpenGLPFABackingStore     =  76,	/* back buffer contents are valid after swap    */
+	NSOpenGLPFAScreenMask     =  84,	/* bit mask of supported physical screens       */
+	NSOpenGLPFAAllowOfflineRenderers  =  96,  /* allow use of offline renderers               */
+	NSOpenGLPFAAcceleratedCompute   =  97,	/* choose a hardware accelerated compute device */
+	NSOpenGLPFAOpenGLProfile      =  99,    /* specify an OpenGL Profile to use             */
+	NSOpenGLProfileVersionLegacy     = 0x1000, /* The requested profile is a legacy (pre-OpenGL 3.0) profile. */
+	NSOpenGLProfileVersion3_2Core    = 0x3200, /* The 3.2 Profile of OpenGL */
+	NSOpenGLProfileVersion4_1Core  = 0x3200, /* The 4.1 profile of OpenGL */
+	NSOpenGLPFAVirtualScreenCount      = 128,	/* number of virtual screens in this format     */
+	NSOpenGLPFAStereo                 =   6,
+	NSOpenGLPFAOffScreen             =  53,
+	NSOpenGLPFAFullScreen           =  54,
+	NSOpenGLPFASingleRenderer      =  71,
+	NSOpenGLPFARobust                 =  75,
+	NSOpenGLPFAMPSafe           =  78,
+	NSOpenGLPFAWindow                 =  80,
+	NSOpenGLPFAMultiScreen =    81,
+	NSOpenGLPFACompliant   =   83,
+	NSOpenGLPFAPixelBuffer            =  90,
+	NSOpenGLPFARemotePixelBuffer =  91,
+};
+
+typedef RGFW_ENUM(u32, NSEventType) {        /* various types of events */
+	NSEventTypeApplicationDefined = 15,
+};
+typedef unsigned long long NSEventMask;
+
+typedef enum NSEventModifierFlags {
+	NSEventModifierFlagCapsLock = 1 << 16,
+	NSEventModifierFlagShift = 1 << 17,
+	NSEventModifierFlagControl = 1 << 18,
+	NSEventModifierFlagOption = 1 << 19,
+	NSEventModifierFlagCommand = 1 << 20,
+	NSEventModifierFlagNumericPad = 1 << 21
+} NSEventModifierFlags;
+
+typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
+	NSBitmapFormatAlphaFirst = 1 << 0,       /* 0 means is alpha last (RGBA, CMYKA, etc.) */
+		NSBitmapFormatAlphaNonpremultiplied = 1 << 1,       /* 0 means is premultiplied */
+		NSBitmapFormatFloatingpointSamples = 1 << 2,  /* 0 is integer */
+
+		NSBitmapFormatSixteenBitLittleEndian = (1 << 8),
+		NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9),
+		NSBitmapFormatSixteenBitBigEndian = (1 << 10),
+		NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11)
+};
+
+#else
+#import <AppKit/AppKit.h>
+#include <Foundation/Foundation.h>
+#endif /* notdef __OBJC__ */
+
+#ifdef __arm64__
+	/* ARM just uses objc_msgSend */
+#define abi_objc_msgSend_stret objc_msgSend
+#define abi_objc_msgSend_fpret objc_msgSend
+#else /* __i386__ */
+	/* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
+#define abi_objc_msgSend_stret objc_msgSend_stret
+#define abi_objc_msgSend_fpret objc_msgSend_fpret
+#endif
+
+#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
+#define objc_msgSend_bool(x, y)			((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
+#define objc_msgSend_void(x, y)			((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
+#define objc_msgSend_void_id(x, y, z)		((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
+#define objc_msgSend_uint(x, y)			((NSUInteger (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
+#define objc_msgSend_void_bool(x, y, z)		((void (*)(id, SEL, BOOL))objc_msgSend)  ((id)(x), (SEL)y, (BOOL)z)
+#define objc_msgSend_bool_void(x, y)		((BOOL (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
+#define objc_msgSend_void_SEL(x, y, z)		((void (*)(id, SEL, SEL))objc_msgSend)  ((id)(x), (SEL)y, (SEL)z)
+#define objc_msgSend_id(x, y)				((id (*)(id, SEL))objc_msgSend)  ((id)(x), (SEL)y)
+#define objc_msgSend_id_id(x, y, z)			((id (*)(id, SEL, id))objc_msgSend)  ((id)(x), (SEL)y, (id)z)
+#define objc_msgSend_id_bool(x, y, z)			((BOOL (*)(id, SEL, id))objc_msgSend)  ((id)(x), (SEL)y, (id)z)
+#define objc_msgSend_int(x, y, z) 				((id (*)(id, SEL, int))objc_msgSend)  ((id)(x), (SEL)y, (int)z)
+#define objc_msgSend_arr(x, y, z)				 	((id (*)(id, SEL, int))objc_msgSend)  ((id)(x), (SEL)y, (int)z)
+#define objc_msgSend_ptr(x, y, z) 					((id (*)(id, SEL, void*))objc_msgSend)  ((id)(x), (SEL)y, (void*)z)
+#define objc_msgSend_class(x, y) 					((id (*)(Class, SEL))objc_msgSend)  ((Class)(x), (SEL)y)
+#define objc_msgSend_class_char(x, y, z) 			((id (*)(Class, SEL, char*))objc_msgSend)  ((Class)(x), (SEL)y, (char*)z)
+
+#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
+RGFWDEF id NSString_stringWithUTF8String(const char* str);
+id NSString_stringWithUTF8String(const char* str) {
+	return ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
+}
+
+RGFWDEF float RGFW_cocoaYTransform(float y);
+float RGFW_cocoaYTransform(float y) { return (float)(CGDisplayBounds(CGMainDisplayID()).size.height - (double)y - (double)1.0f); }
+
+const char* NSString_to_char(id str);
+const char* NSString_to_char(id str) {
+	return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
+}
+
+unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
+unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
+	return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
+}
+
+id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits);
+id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
+	SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
+
+	return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
+		(NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
+}
+
+id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
+id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
+	Class nsclass = objc_getClass("NSColor");
+	SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
+	return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
+		((id)nsclass, func, red, green, blue, alpha);
+}
+
+id NSPasteboard_generalPasteboard(void);
+id NSPasteboard_generalPasteboard(void) {
+	return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
+}
+
+id* cstrToNSStringArray(char** strs, size_t len);
+id* cstrToNSStringArray(char** strs, size_t len) {
+	static id nstrs[6];
+	size_t i;
+	for (i = 0; i < len; i++)
+		nstrs[i] = NSString_stringWithUTF8String(strs[i]);
+
+	return nstrs;
+}
+
+const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
+const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
+	SEL func = sel_registerName("stringForType:");
+	id nsstr = NSString_stringWithUTF8String((const char*)dataType);
+	id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
+	const char* str = NSString_to_char(nsString);
+	if (len != NULL)
+		*len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
+	return str;
+}
+
+id c_array_to_NSArray(void* array, size_t len);
+id c_array_to_NSArray(void* array, size_t len) {
+	return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len);
+}
+
+
+void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
+void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
+	id* ntypes = cstrToNSStringArray((char**)newTypes, len);
+
+	id array = c_array_to_NSArray(ntypes, len);
+	objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
+	NSRelease(array);
+}
+
+NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
+NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
+	id* ntypes = cstrToNSStringArray((char**)newTypes, len);
+
+	SEL func = sel_registerName("declareTypes:owner:");
+
+	id array = c_array_to_NSArray(ntypes, len);
+
+	NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
+		(pasteboard, func, array, owner);
+	NSRelease(array);
+
+	return output;
+}
+
+#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
+
+/*
+	End of cocoa wrapper
+*/
+
+static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) {
+	RGFW_UNUSED(_cmd);
+    struct objc_super s = { self, class_getSuperclass(object_getClass(self)) };
+
+    CGRect rect;
+    rect.origin.x = 0;
+    rect.origin.y = 0;
+    rect.size.width = (double)win->w;
+    rect.size.height = (double)win->h;
+
+    self = ((id (*)(struct objc_super*, SEL, CGRect))objc_msgSendSuper)(
+        &s, sel_registerName("initWithFrame:"), rect
+    );
+
+    if (self != nil) {
+        object_setInstanceVariable(self, "RGFW_window", win);
+        object_setInstanceVariable(self, "trackingArea", nil);
+
+        object_setInstanceVariable(
+            self, "markedText",
+            ((id (*)(id, SEL))objc_msgSend)(
+                ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")),
+                sel_registerName("init")
+            )
+        );
+
+        ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas"));
+
+        ((void (*)(id, SEL, id))objc_msgSend)(
+            self, sel_registerName("registerForDraggedTypes:"),
+            ((id (*)(Class, SEL, id))objc_msgSend)(
+                objc_getClass("NSArray"),
+                sel_registerName("arrayWithObject:"),
+                ((id (*)(Class, SEL, const char*))objc_msgSend)(
+                    objc_getClass("NSString"),
+                    sel_registerName("stringWithUTF8String:"),
+                    "public.url"
+                )
+            )
+        );
+    }
+
+    return self;
+}
+
+static u32 RGFW_OnClose(id self) {
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
+	if (win == NULL) return true;
+
+	RGFW_windowCloseCallback(win);
+	return false;
+}
+
+/* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
+static bool RGFW__osxAcceptsFirstResponder(void) { return true; }
+static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
+
+static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) {
+	RGFW_UNUSED(sel);
+
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL)
+		return 0;
+
+	NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
+	RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionEnter, (i32) p.x, (i32) (win->h - p.y));
+	return NSDragOperationCopy;
+}
+static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) {
+	RGFW_UNUSED(sel);
+
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL)
+		return 0;
+	if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy;
+
+	NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
+	RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionMove, (i32) p.x, (i32) (win->h - p.y));
+	return NSDragOperationCopy;
+}
+static bool RGFW__osxPrepareForDragOperation(id self) {
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
+		return true;
+
+	if (!(win->internal.flags & RGFW_windowAllowDND)) {
+		return false;
+	}
+
+	return true;
+}
+
+static void RGFW__osxDraggingEnded(id self, SEL sel, id sender) {
+	RGFW_UNUSED(sel);
+
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL)
+		return;
+	if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return;
+
+	NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
+	RGFW_dataDragCallback(win, RGFW_dataFile, RGFW_dndActionExit, (i32) p.x, (i32) (win->h - p.y));
+	return;
+}
+
+static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) {
+	RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag)))
+		return false;
+
+	/* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
+
+	id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
+
+	/* Get the types of data available on the pasteboard */
+	id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
+
+	/* Get the string type for file URLs */
+	id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
+
+	/* Check if the pasteboard contains file URLs */
+	if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard.");
+		return 0;
+	}
+
+	id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
+	int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
+
+	if (count == 0)
+		return 0;
+
+	u32 i;
+    for (i = 0; i < (u32)count; i++) {
+		id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
+		const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
+		int string_count = ((int (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("count"));
+
+		RGFW_dataDropCallback(win, filePath, (size_t)string_count + 1, RGFW_dataFile);
+	}
+
+	return false;
+}
+
+#ifndef RGFW_NO_IOKIT
+#include <IOKit/IOKitLib.h>
+
+float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID);
+float RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) {
+    float refreshRate = 0;
+    io_iterator_t it;
+    io_service_t service;
+    CFNumberRef indexRef, clockRef, countRef;
+    u32 clock, count;
+
+#ifdef kIOMainPortDefault
+    if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
+#elif defined(kIOMasterPortDefault)
+    if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0)
+#endif
+        return RGFW_FALSE;
+
+    while ((service = IOIteratorNext(it)) != 0) {
+        u32 index;
+        indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions);
+        if (indexRef == 0) continue;
+
+        if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) {
+            CFRelease(indexRef);
+            break;
+        }
+
+        CFRelease(indexRef);
+    }
+
+    if (service) {
+        clockRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelClock"), kCFAllocatorDefault, kNilOptions);
+        if (clockRef) {
+            if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) {
+                countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions);
+                if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) {
+					refreshRate = (float)((double)clock / (double) count);
+                    CFRelease(countRef);
+                }
+            }
+            CFRelease(clockRef);
+        }
+    }
+
+    IOObjectRelease(it);
+    return refreshRate;
+}
+#endif
+
+void RGFW_moveToMacOSResourceDir(void) {
+	char resourcesPath[256];
+
+	CFBundleRef bundle = CFBundleGetMainBundle();
+	if (!bundle)
+		return;
+
+	CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
+	CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
+
+	if (
+		CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
+		CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
+		) {
+		CFRelease(last);
+		CFRelease(resourcesURL);
+		return;
+	}
+
+	CFRelease(last);
+	CFRelease(resourcesURL);
+
+	chdir(resourcesPath);
+}
+
+static void RGFW__osxDidChangeScreenParameters(id self, SEL _cmd, id notification) {
+	RGFW_UNUSED(self); RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
+	RGFW_pollMonitors();
+}
+
+static void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
+	RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
+
+}
+static void RGFW__osxWindowMiniaturize(id self, SEL sel) {
+	RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	RGFW_windowMinimizedCallback(win);
+
+}
+
+static void RGFW__osxWindowBecameKey(id self, SEL sel) {
+	RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	RGFW_windowFocusCallback(win, RGFW_TRUE);
+}
+
+static void RGFW__osxWindowResignKey(id self, SEL sel) {
+	RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	RGFW_windowFocusCallback(win, RGFW_FALSE);
+}
+
+static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) {
+	RGFW_UNUSED(_cmd); RGFW_UNUSED(notification);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	NSRect frame;
+	if (win->src.view) frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
+	else return;
+
+	if (frame.size.width == 0 || frame.size.height == 0) return;
+	win->w = (i32)frame.size.width;
+	win->h = (i32)frame.size.height;
+
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon == NULL) return;
+
+	if ((i32)mon->mode.w == win->w && (i32)mon->mode.h - 102 <= win->h) {
+		RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h);
+	} else if (win->internal.flags & RGFW_windowMaximize) {
+		RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h);
+	}
+
+	RGFW_windowResizedCallback(win, win->w, win->h);
+}
+
+static void RGFW__osxWindowMove(id self, SEL sel) {
+	RGFW_UNUSED(sel);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
+	NSRect content = ((NSRect(*)(id, SEL, NSRect))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("contentRectForFrameRect:"), frame);
+
+	float y = RGFW_cocoaYTransform((float)(content.origin.y + content.size.height - 1));
+
+	RGFW_windowMovedCallback(win, (i32)content.origin.x, (i32)y);
+}
+
+static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
+	RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon == NULL) return;
+
+	RGFW_scaleUpdatedCallback(win, mon->scaleX, mon->scaleY);
+}
+
+static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; }
+
+static void RGFW__osxUpdateLayer(id self, SEL _cmd) {
+	RGFW_UNUSED(self); RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+	RGFW_windowRefreshCallback(win, 0, 0, win->w, win->h);
+}
+
+static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
+	RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+	object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+	float y = RGFW_cocoaYTransform((float)(rect.size.height - 1));
+
+	RGFW_windowRefreshCallback(win, (i32)rect.origin.x, (i32)y, (i32)rect.size.width, (i32)rect.size.height);
+}
+
+static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+    NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
+    RGFW_mouseNotifyCallback(win, (i32)p.x, (i32)(win->h - p.y), 1);
+}
+
+static void RGFW__osxMouseExited(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd); RGFW_UNUSED(event);
+	RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+	RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE);
+}
+
+static void RGFW__osxKeyDown(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return;
+
+    u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
+
+	RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
+	RGFW_bool repeat = RGFW_isKeyDown(value);
+
+    RGFW_keyCallback(win, value, win->internal.mod, repeat, 1);
+
+	id nsstring = ((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"));
+    const char* string = NSString_to_char(nsstring);
+	size_t count = (size_t)((int (*)(id, SEL))objc_msgSend)(nsstring, sel_registerName("length"));
+
+	for (size_t index = 0; index < count;
+			RGFW_keyCharCallback(win, RGFW_decodeUTF8(&string[index], &index))
+		);
+}
+
+static void RGFW__osxKeyUp(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+	RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return;
+
+    u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode"));
+
+    RGFW_key value = (u8)RGFW_apiKeyToRGFW(key);
+
+    RGFW_keyCallback(win, value, win->internal.mod, RGFW_FALSE, 0);
+}
+
+static void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+    RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+	RGFW_key value = 0;
+	RGFW_bool pressed = RGFW_FALSE;
+
+    u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags"));
+    RGFW_keyUpdateKeyModsEx(win,
+                          ((u32)(flags & NSEventModifierFlagCapsLock) % 255),
+                          ((flags & NSEventModifierFlagNumericPad) % 255),
+                          ((flags & NSEventModifierFlagControl) % 255),
+                          ((flags & NSEventModifierFlagOption) % 255),
+                          ((flags & NSEventModifierFlagShift) % 255),
+                          ((flags & NSEventModifierFlagCommand) % 255), 0);
+    u8 i;
+    for (i = 0; i < 9; i++)
+        _RGFW->keyboard[i + RGFW_keyCapsLock].prev = _RGFW->keyboard[i + RGFW_keyCapsLock].current;
+
+    for (i = 0; i < 5; i++) {
+        u32 shift = (1 << (i + 16));
+        RGFW_key key = i + RGFW_keyCapsLock;
+        if ((flags & shift) && !RGFW_isKeyDown((u8)key)) {
+			pressed = RGFW_TRUE;
+            value = (u8)key;
+            break;
+        }
+        if (!(flags & shift) && RGFW_isKeyDown((u8)key)) {
+			pressed = RGFW_FALSE;
+            value = (u8)key;
+            break;
+        }
+    }
+
+	RGFW_keyCallback(win, value, win->internal.mod, RGFW_isKeyDown(value) && pressed, pressed);
+
+	if (value != RGFW_keyCapsLock) {
+		RGFW_keyCallback(win, value + 4, win->internal.mod, RGFW_isKeyDown(value + 4) && pressed, pressed);
+	}
+
+}
+
+static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+    RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+	if (win == NULL) return;
+
+    NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow"));
+
+	CGFloat vecX = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
+    CGFloat vecY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
+
+    RGFW_mouseMotionCallback(win, (i32)p.x, (i32)(win->h - p.y));
+	RGFW_rawMotionCallback(win, (float)vecX, (float)vecY);
+}
+
+static void RGFW__osxMouseDown(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+    RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+    u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
+
+	RGFW_mouseButton value = 0;
+    switch (buttonNumber) {
+        case 0: value = RGFW_mouseLeft; break;
+        case 1: value = RGFW_mouseRight; break;
+        case 2: value = RGFW_mouseMiddle; break;
+        default: value = (u8)buttonNumber;
+    }
+
+    RGFW_mouseButtonCallback(win, value, 1);
+}
+
+static void RGFW__osxMouseUp(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+    RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+    u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber"));
+
+	RGFW_mouseButton value = 0;
+	switch (buttonNumber) {
+        case 0: value = RGFW_mouseLeft; break;
+        case 1: value = RGFW_mouseRight; break;
+        case 2: value = RGFW_mouseMiddle; break;
+        default: value = (u8)buttonNumber;
+    }
+
+    RGFW_mouseButtonCallback(win, value, 0);
+}
+
+static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) {
+	RGFW_UNUSED(_cmd);
+    RGFW_window* win = NULL;
+    object_getInstanceVariable(self, "RGFW_window", (void**)&win);
+    if (win == NULL) return;
+
+    float deltaX = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX"));
+	float deltaY = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY"));
+
+    RGFW_mouseScrollCallback(win, deltaX, deltaY);
+}
+
+RGFW_format RGFW_nativeFormat(void) { return RGFW_formatRGBA8; }
+
+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	surface->data = data;
+	surface->w = w;
+	surface->h = h;
+	surface->format = format;
+	surface->native.format = RGFW_formatRGBA8;
+
+	surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4));
+	return RGFW_TRUE;
+}
+
+void RGFW_surface_freePtr(RGFW_surface* surface) {
+	RGFW_FREE(surface->native.buffer);
+}
+
+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+	int minW = RGFW_MIN(win->w, surface->w);
+	int minH = RGFW_MIN(win->h, surface->h);
+
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon == NULL) return;
+
+	minW =  (i32)((float)minW * mon->pixelRatio);
+	minH = (i32)((float)minH * mon->pixelRatio);
+
+	surface->native.rep = (void*)NSBitmapImageRep_initWithBitmapData(&surface->native.buffer, minW, minH, 8, 4, true, false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * 4, 32);
+
+	id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
+	NSSize size = (NSSize){(double)minW, (double)minH};
+	image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
+
+	RGFW_copyImageData(NSBitmapImageRep_bitmapData((id)surface->native.rep), surface->w, minH, RGFW_formatRGBA8, surface->data, surface->native.format, surface->convertFunc);
+	((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), (id)surface->native.rep);
+
+	id layer = ((id (*)(id, SEL))objc_msgSend)((id)win->src.view, sel_getUid("layer"));
+	((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
+
+	NSRelease(image);
+	NSRelease(surface->native.rep);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+}
+
+void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; }
+
+void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) {
+	objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer:"), (id)layer);
+}
+
+void* RGFW_getLayer_OSX(void) {
+	return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
+}
+void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; }
+
+void RGFW_initKeycodesPlatform(void) {
+	_RGFW->keycodes[0x1D] = RGFW_key0;
+	_RGFW->keycodes[0x12] = RGFW_key1;
+	_RGFW->keycodes[0x13] = RGFW_key2;
+	_RGFW->keycodes[0x14] = RGFW_key3;
+	_RGFW->keycodes[0x15] = RGFW_key4;
+	_RGFW->keycodes[0x17] = RGFW_key5;
+	_RGFW->keycodes[0x16] = RGFW_key6;
+	_RGFW->keycodes[0x1A] = RGFW_key7;
+	_RGFW->keycodes[0x1C] = RGFW_key8;
+	_RGFW->keycodes[0x19] = RGFW_key9;
+	_RGFW->keycodes[0x00] = RGFW_keyA;
+	_RGFW->keycodes[0x0B] = RGFW_keyB;
+	_RGFW->keycodes[0x08] = RGFW_keyC;
+	_RGFW->keycodes[0x02] = RGFW_keyD;
+	_RGFW->keycodes[0x0E] = RGFW_keyE;
+	_RGFW->keycodes[0x03] = RGFW_keyF;
+	_RGFW->keycodes[0x05] = RGFW_keyG;
+	_RGFW->keycodes[0x04] = RGFW_keyH;
+	_RGFW->keycodes[0x22] = RGFW_keyI;
+	_RGFW->keycodes[0x26] = RGFW_keyJ;
+	_RGFW->keycodes[0x28] = RGFW_keyK;
+	_RGFW->keycodes[0x25] = RGFW_keyL;
+	_RGFW->keycodes[0x2E] = RGFW_keyM;
+	_RGFW->keycodes[0x2D] = RGFW_keyN;
+	_RGFW->keycodes[0x1F] = RGFW_keyO;
+	_RGFW->keycodes[0x23] = RGFW_keyP;
+	_RGFW->keycodes[0x0C] = RGFW_keyQ;
+	_RGFW->keycodes[0x0F] = RGFW_keyR;
+	_RGFW->keycodes[0x01] = RGFW_keyS;
+	_RGFW->keycodes[0x11] = RGFW_keyT;
+	_RGFW->keycodes[0x20] = RGFW_keyU;
+	_RGFW->keycodes[0x09] = RGFW_keyV;
+	_RGFW->keycodes[0x0D] = RGFW_keyW;
+	_RGFW->keycodes[0x07] = RGFW_keyX;
+	_RGFW->keycodes[0x10] = RGFW_keyY;
+	_RGFW->keycodes[0x06] = RGFW_keyZ;
+	_RGFW->keycodes[0x27] = RGFW_keyApostrophe;
+	_RGFW->keycodes[0x2A] = RGFW_keyBackSlash;
+	_RGFW->keycodes[0x2B] = RGFW_keyComma;
+	_RGFW->keycodes[0x18] = RGFW_keyEquals;
+	_RGFW->keycodes[0x32] = RGFW_keyBacktick;
+	_RGFW->keycodes[0x21] = RGFW_keyBracket;
+	_RGFW->keycodes[0x1B] = RGFW_keyMinus;
+	_RGFW->keycodes[0x2F] = RGFW_keyPeriod;
+	_RGFW->keycodes[0x1E] = RGFW_keyCloseBracket;
+	_RGFW->keycodes[0x29] = RGFW_keySemicolon;
+	_RGFW->keycodes[0x2C] = RGFW_keySlash;
+	_RGFW->keycodes[0x0A] = RGFW_keyWorld1;
+	_RGFW->keycodes[0x33] = RGFW_keyBackSpace;
+	_RGFW->keycodes[0x39] = RGFW_keyCapsLock;
+	_RGFW->keycodes[0x75] = RGFW_keyDelete;
+	_RGFW->keycodes[0x7D] = RGFW_keyDown;
+	_RGFW->keycodes[0x77] = RGFW_keyEnd;
+	_RGFW->keycodes[0x24] = RGFW_keyEnter;
+	_RGFW->keycodes[0x35] = RGFW_keyEscape;
+	_RGFW->keycodes[0x7A] = RGFW_keyF1;
+	_RGFW->keycodes[0x78] = RGFW_keyF2;
+	_RGFW->keycodes[0x63] = RGFW_keyF3;
+	_RGFW->keycodes[0x76] = RGFW_keyF4;
+	_RGFW->keycodes[0x60] = RGFW_keyF5;
+	_RGFW->keycodes[0x61] = RGFW_keyF6;
+	_RGFW->keycodes[0x62] = RGFW_keyF7;
+	_RGFW->keycodes[0x64] = RGFW_keyF8;
+	_RGFW->keycodes[0x65] = RGFW_keyF9;
+	_RGFW->keycodes[0x6D] = RGFW_keyF10;
+	_RGFW->keycodes[0x67] = RGFW_keyF11;
+	_RGFW->keycodes[0x6F] = RGFW_keyF12;
+	_RGFW->keycodes[0x69] = RGFW_keyPrintScreen;
+	_RGFW->keycodes[0x6B] = RGFW_keyF14;
+	_RGFW->keycodes[0x71] = RGFW_keyF15;
+	_RGFW->keycodes[0x6A] = RGFW_keyF16;
+	_RGFW->keycodes[0x40] = RGFW_keyF17;
+	_RGFW->keycodes[0x4F] = RGFW_keyF18;
+	_RGFW->keycodes[0x50] = RGFW_keyF19;
+	_RGFW->keycodes[0x5A] = RGFW_keyF20;
+	_RGFW->keycodes[0x73] = RGFW_keyHome;
+	_RGFW->keycodes[0x72] = RGFW_keyInsert;
+	_RGFW->keycodes[0x7B] = RGFW_keyLeft;
+	_RGFW->keycodes[0x3A] = RGFW_keyAltL;
+	_RGFW->keycodes[0x3B] = RGFW_keyControlL;
+	_RGFW->keycodes[0x38] = RGFW_keyShiftL;
+	_RGFW->keycodes[0x37] = RGFW_keySuperL;
+	_RGFW->keycodes[0x6E] = RGFW_keyMenu;
+	_RGFW->keycodes[0x47] = RGFW_keyNumLock;
+	_RGFW->keycodes[0x79] = RGFW_keyPageDown;
+	_RGFW->keycodes[0x74] = RGFW_keyPageUp;
+	_RGFW->keycodes[0x7C] = RGFW_keyRight;
+	_RGFW->keycodes[0x3D] = RGFW_keyAltR;
+	_RGFW->keycodes[0x3E] = RGFW_keyControlR;
+	_RGFW->keycodes[0x3C] = RGFW_keyShiftR;
+	_RGFW->keycodes[0x36] = RGFW_keySuperR;
+	_RGFW->keycodes[0x31] = RGFW_keySpace;
+	_RGFW->keycodes[0x30] = RGFW_keyTab;
+	_RGFW->keycodes[0x7E] = RGFW_keyUp;
+	_RGFW->keycodes[0x52] = RGFW_keyPad0;
+	_RGFW->keycodes[0x53] = RGFW_keyPad1;
+	_RGFW->keycodes[0x54] = RGFW_keyPad2;
+	_RGFW->keycodes[0x55] = RGFW_keyPad3;
+	_RGFW->keycodes[0x56] = RGFW_keyPad4;
+	_RGFW->keycodes[0x57] = RGFW_keyPad5;
+	_RGFW->keycodes[0x58] = RGFW_keyPad6;
+	_RGFW->keycodes[0x59] = RGFW_keyPad7;
+	_RGFW->keycodes[0x5B] = RGFW_keyPad8;
+	_RGFW->keycodes[0x5C] = RGFW_keyPad9;
+	_RGFW->keycodes[0x45] = RGFW_keyPadSlash;
+	_RGFW->keycodes[0x41] = RGFW_keyPadPeriod;
+	_RGFW->keycodes[0x4B] = RGFW_keyPadSlash;
+	_RGFW->keycodes[0x4C] = RGFW_keyPadReturn;
+	_RGFW->keycodes[0x51] = RGFW_keyPadEqual;
+	_RGFW->keycodes[0x43] = RGFW_keyPadMultiply;
+	_RGFW->keycodes[0x4E] = RGFW_keyPadMinus;
+}
+
+i32 RGFW_initPlatform(void) {
+	_RGFW->tisBundle = (void*)CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
+
+	TISGetInputSourcePropertySrc = (PFN_TISGetInputSourceProperty)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISGetInputSourceProperty"));
+	TISCopyCurrentKeyboardLayoutInputSourceSrc = (PFN_TISCopyCurrentKeyboardLayoutInputSource)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
+	LMGetKbdTypeSrc = (PFN_LMGetKbdType)CFBundleGetFunctionPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("LMGetKbdType"));
+
+	CFStringRef* cfStr = (CFStringRef*)CFBundleGetDataPointerForName((CFBundleRef)_RGFW->tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));;
+	if (cfStr) kTISPropertyUnicodeKeyLayoutDataSrc = *cfStr;
+
+	class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0);
+
+	/* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
+	class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP)(void*)RGFW__osxAcceptsFirstResponder, 0);
+	class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0);
+
+	_RGFW->NSApp = objc_msgSend_id(objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
+
+	NSRetain(_RGFW->NSApp);
+
+	_RGFW->customNSAppDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWNSAppDelegate", 0);
+	class_addMethod((Class)_RGFW->customNSAppDelegateClass, sel_registerName("applicationDidChangeScreenParameters:"), (IMP)RGFW__osxDidChangeScreenParameters, "v@:@");
+	objc_registerClassPair((Class)_RGFW->customNSAppDelegateClass);
+	_RGFW->customNSAppDelegate = objc_msgSend_id(NSAlloc(_RGFW->customNSAppDelegateClass), sel_registerName("init"));
+
+	objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), _RGFW->customNSAppDelegate);
+
+	((void (*)(id, SEL, NSUInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
+
+	_RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0);
+	_RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0);
+	for (size_t i = 0; i < 2; i++) {
+		class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "v@:");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP)RGFW__osxScrollWheel, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP)RGFW__osxKeyDown, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP)RGFW__osxKeyUp, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP)RGFW__osxMouseMoved, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP)RGFW__osxMouseEntered, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP)RGFW__osxMouseExited, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP)RGFW__osxFlagsChanged, "v@:@");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP)RGFW__osxAcceptsFirstResponder, "B@:");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP)RGFW__osxWantsUpdateLayer, "B@:");
+		class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP)RGFW__osxUpdateLayer, "v@:");
+		objc_registerClassPair((Class)_RGFW->customViewClasses[i]);
+	}
+
+	_RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0);
+	class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP)RGFW__osxDidWindowResize, "v@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "l@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "l@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@");
+	class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@");
+	objc_registerClassPair((Class)_RGFW->customWindowDelegateClass);
+	return 0;
+}
+
+void RGFW_osx_initView(RGFW_window* win) {
+	NSRect contentRect;
+	contentRect.origin.x = 0;
+	contentRect.origin.y = 0;
+	contentRect.size.width = (double)win->w;
+	contentRect.size.height = (double)win->h;
+	((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), contentRect);
+
+
+	if (RGFW_COCOA_FRAME_NAME)
+		objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
+
+	object_setInstanceVariable((id)win->src.view, "RGFW_window", win);
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
+	objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
+	objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"),  4);
+
+	id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc"));
+	trackingArea = ((id (*)(id, SEL, NSRect, NSUInteger, id, id))objc_msgSend)(
+		trackingArea,
+		sel_registerName("initWithRect:options:owner:userInfo:"),
+		contentRect,
+		NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect,
+		(id)win->src.view,
+		nil
+	);
+
+	((void (*)(id, SEL, id))objc_msgSend)((id)win->src.view, sel_registerName("addTrackingArea:"), trackingArea);
+	((void (*)(id, SEL))objc_msgSend)(trackingArea, sel_registerName("release"));
+}
+
+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	/* RR Create an autorelease pool */
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+	RGFW_window_setMouseDefault(win);
+
+	NSRect windowRect;
+	windowRect.origin.x = (double)win->x;
+	windowRect.origin.y = (double)RGFW_cocoaYTransform((float)(win->y + win->h - 1));
+	windowRect.size.width = (double)win->w;
+	windowRect.size.height = (double)win->h;
+	NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled);
+
+	if (!(flags & RGFW_windowNoResize))
+		macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable);
+	if (!(flags & RGFW_windowNoBorder))
+		macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled);
+	{
+		void* nsclass = objc_getClass("NSWindow");
+		SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
+
+		win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
+			(NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false);
+	}
+
+	id str = NSString_stringWithUTF8String(name);
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
+
+	win->src.delegate = (void*)objc_msgSend_id(NSAlloc((Class)_RGFW->customWindowDelegateClass), sel_registerName("init"));
+	object_setInstanceVariable((id)win->src.delegate, "RGFW_window", win);
+
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), (id)win->src.delegate);
+
+	if (flags & RGFW_windowAllowDND) {
+		win->internal.flags |= RGFW_windowAllowDND;
+
+		NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
+		NSregisterForDraggedTypes((id)win->src.window, types, 3);
+	}
+
+	objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true);
+
+	if (flags & RGFW_windowTransparent) {
+		objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
+
+		objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
+		NSColor_colorWithSRGB(0, 0, 0, 0));
+	}
+
+	/* Show the window */
+	objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
+
+	if (_RGFW->root == NULL) {
+		objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
+	}
+
+	objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
+
+	NSRetain(win->src.window);
+
+	win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win);
+	return win;
+}
+
+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
+	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
+	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
+	double offset = 0;
+
+	RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border);
+	NSBackingStoreType storeType = (NSBackingStoreType)(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView);
+	if (border)
+		storeType = (NSBackingStoreType)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable);
+	if (!(win->internal.flags & RGFW_windowNoResize)) {
+		storeType = (NSBackingStoreType)(storeType | (NSBackingStoreType)NSWindowStyleMaskResizable);
+	}
+
+	((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
+
+	if (!border) {
+		id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"),  NSWindowMiniaturizeButton);
+		id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
+		objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
+
+		offset = (double)(frame.size.height - content.size.height);
+	}
+
+	RGFW_window_resize(win, win->w, win->h + (i32)offset);
+	win->h -= (i32)offset;
+}
+
+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
+	RGFW_ASSERT(_RGFW->root != NULL);
+
+	CGEventRef e = CGEventCreate(NULL);
+	CGPoint point = CGEventGetLocation(e);
+	CFRelease(e);
+
+	if (x) *x = (i32)point.x;
+	if (y) *y = (i32)point.y;
+	return RGFW_TRUE;
+}
+
+void RGFW_stopCheckEvents(void) {
+	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
+
+	id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
+		(objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
+			NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
+
+	((void (*)(id, SEL, id, bool))objc_msgSend)
+		((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
+
+	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
+}
+
+void RGFW_waitForEvent(i32 waitMS) {
+	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
+
+	void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
+				(objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
+
+	SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
+	id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
+		((id)_RGFW->NSApp, eventFunc,
+			ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
+
+	if (e) {
+		((void (*)(id, SEL, id, bool))objc_msgSend)
+			((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1);
+	}
+
+	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
+}
+
+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
+    u16 keycode = (u16)RGFW_rgfwToApiKey(key);
+    TISInputSourceRef source = TISCopyCurrentKeyboardLayoutInputSource();
+    if (source == NULL)
+        return key;
+
+    CFDataRef layoutData = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutDataSrc);
+
+    if (layoutData == NULL) {
+        CFRelease(source);
+        return key;
+    }
+
+    UCKeyboardLayout *layout = (UCKeyboardLayout*)(void*)CFDataGetBytePtr(layoutData);
+
+    UInt32 deadKeyState = 0;
+    UniChar chars[4];
+    UniCharCount len = 0;
+	u32 type =  LMGetKbdType();
+	OSStatus status = UCKeyTranslate(layout, keycode, kUCKeyActionDown, 0, type, kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 4, &len, chars );
+
+    CFRelease(source);
+
+    if (status == noErr && len == 1 && chars[0] < 256) {
+        return (RGFW_key)chars[0];
+    }
+
+	return key;
+}
+
+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
+	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
+
+	win->w = (i32)content.size.width;
+	win->h = (i32)content.size.height;
+
+	return RGFW_window_getSize(win, w, h);
+}
+
+void RGFW_pollEvents(void) {
+	RGFW_resetPrevState();
+
+	id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
+	SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
+
+	while (1) {
+		void* date = NULL;
+		id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
+			((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
+
+		if (e == NULL) {
+			break;
+		}
+
+		objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e);
+	}
+
+	objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
+}
+
+
+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) {
+	RGFW_ASSERT(win != NULL);
+
+	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
+
+	win->x = x;
+	win->y = (i32)RGFW_cocoaYTransform((float)y + (float)content.size.height - 1.0f);
+
+	((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y});
+}
+
+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
+	RGFW_ASSERT(win != NULL);
+
+	NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
+	NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
+	float offset = (float)(frame.size.height - content.size.height);
+
+	win->w = w;
+	win->h = h;
+
+
+	((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"),  (NSRect){{0, 0}, {(double)win->w, (double)win->h}});
+	((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
+		((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{(double)win->x, (double)win->y}, {(double)win->w, (double)win->h + (double)offset}}, true, true);
+}
+
+void RGFW_window_focus(RGFW_window* win) {
+	RGFW_ASSERT(win);
+	objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
+	((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
+}
+
+void RGFW_window_raise(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
+    	objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
+}
+
+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+	if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return;
+	if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return;
+
+	if (fullscreen) {
+		win->internal.oldX = win->x;
+		win->internal.oldY = win->y;
+		win->internal.oldW = win->w;
+		win->internal.oldH = win->h;
+
+		win->internal.flags |= RGFW_windowFullscreen;
+
+		RGFW_monitor* mon = RGFW_window_getMonitor(win);
+		RGFW_monitor_scaleToWindow(mon, win);
+
+		RGFW_window_setBorder(win, RGFW_FALSE);
+
+		if (mon != NULL) {
+			win->x = mon->x;
+			win->y = mon->y;
+			win->w = mon->mode.w;
+			win->h = mon->mode.h;
+			RGFW_window_resize(win, mon->mode.w, mon->mode.h);
+			RGFW_window_move(win, mon->x, mon->y);
+		}
+
+		((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
+		objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), 25);
+	}
+
+	objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
+
+	if (!fullscreen) {
+		win->x  = win->internal.oldX;
+		win->y  = win->internal.oldY;
+		win->w  = win->internal.oldW;
+		win->h = win->internal.oldH;
+		win->internal.flags &= ~(u32)RGFW_windowFullscreen;
+
+		RGFW_window_resize(win, win->w, win->h);
+		RGFW_window_move(win, win->x, win->y);
+	}
+}
+
+void RGFW_window_maximize(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	if (RGFW_window_isMaximized(win)) return;
+
+	win->internal.flags |= RGFW_windowMaximize;
+	objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
+	RGFW_window_fetchSize(win, NULL, NULL);
+}
+
+void RGFW_window_minimize(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
+}
+
+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
+    RGFW_ASSERT(win != NULL);
+    if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
+    else 		  objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
+}
+
+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
+	objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
+	objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
+
+	if (opacity)
+		objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
+
+}
+
+void RGFW_window_restore(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	if (RGFW_window_isMaximized(win))
+		objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
+
+	objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
+	RGFW_window_show(win);
+}
+
+RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
+	return level > kCGNormalWindowLevelKey;
+}
+
+void RGFW_window_setName(RGFW_window* win, const char* name) {
+	RGFW_ASSERT(win != NULL);
+	if (name == NULL) name = "\0";
+
+	id str = NSString_stringWithUTF8String(name);
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
+}
+
+#ifndef RGFW_NO_PASSTHROUGH
+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
+	objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
+}
+#endif
+
+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) {
+	if (w == 0 && h == 0) {  w = 1; h = 1; };
+
+	((void (*)(id, SEL, NSSize))objc_msgSend)
+		((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h});
+}
+
+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) {
+	((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
+}
+
+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) {
+	if (w == 0 && h == 0) {
+		RGFW_monitor* mon = RGFW_window_getMonitor(win);
+		if (mon != NULL) {
+			w = mon->mode.w;
+			h = mon->mode.h;
+		}
+	}
+
+	((void (*)(id, SEL, NSSize))objc_msgSend)
+		((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h});
+}
+
+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_UNUSED(type);
+
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+	if (data == NULL) {
+		objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL);
+		objc_msgSend_bool_void(pool, sel_registerName("drain"));
+		return RGFW_TRUE;
+	}
+
+	id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
+	RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
+
+	id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
+
+	objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
+
+	objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
+
+	NSRelease(dock_image);
+	NSRelease(representation);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+
+	return RGFW_TRUE;
+}
+
+id NSCursor_arrowStr(const char* str);
+id NSCursor_arrowStr(const char* str) {
+	void* nclass = objc_getClass("NSCursor");
+	SEL func = sel_registerName(str);
+	id mouse = (id) objc_msgSend_id(nclass, func);
+	NSRetain(mouse);
+	return mouse;
+}
+
+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
+	switch (mouse) {
+        case RGFW_mouseNormal: return NSCursor_arrowStr("arrowCursor");
+        case RGFW_mouseArrow: return NSCursor_arrowStr("arrowCursor");
+        case RGFW_mouseIbeam: return NSCursor_arrowStr("IBeamCursor");
+        case RGFW_mouseCrosshair: return NSCursor_arrowStr("crosshairCursor");
+        case RGFW_mousePointingHand: return NSCursor_arrowStr("pointingHandCursor");
+        case RGFW_mouseResizeEW: return NSCursor_arrowStr("resizeLeftRightCursor");
+        case RGFW_mouseResizeE: return NSCursor_arrowStr("resizeLeftRightCursor");
+        case RGFW_mouseResizeW: return NSCursor_arrowStr("resizeLeftRightCursor");
+        case RGFW_mouseResizeNS: return NSCursor_arrowStr("resizeUpDownCursor");
+        case RGFW_mouseResizeN: return NSCursor_arrowStr("resizeUpDownCursor");
+        case RGFW_mouseResizeS: return NSCursor_arrowStr("resizeUpDownCursor");
+        case RGFW_mouseResizeNWSE: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
+        case RGFW_mouseResizeNW: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
+        case RGFW_mouseResizeSE: return NSCursor_arrowStr("_windowResizeNorthWestSouthEastCursor");
+        case RGFW_mouseResizeNESW: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
+        case RGFW_mouseResizeNE: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
+        case RGFW_mouseResizeSW: return NSCursor_arrowStr("_windowResizeNorthEastSouthWestCursor");
+        case RGFW_mouseResizeAll: return NSCursor_arrowStr("openHandCursor");
+        case RGFW_mouseNotAllowed: return NSCursor_arrowStr("operationNotAllowedCursor");
+        case RGFW_mouseWait: return NSCursor_arrowStr("arrowCursor");
+        case RGFW_mouseProgress: return NSCursor_arrowStr("arrowCursor");
+        default: return NULL;
+    }
+	return NULL;
+}
+
+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) {
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+	if (data == NULL) {
+		objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
+
+		objc_msgSend_bool_void(pool, sel_registerName("drain"));
+		return NULL;
+	}
+
+	id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32);
+	RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format, NULL);
+
+	id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h}));
+
+	objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
+
+	id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
+		(NSAlloc(objc_getClass("NSCursor")),  sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
+
+	NSRelease(cursor_image);
+	NSRelease(representation);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+
+	return (void*)cursor;
+}
+
+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
+	CGDisplayShowCursor(kCGDirectMainDisplay);
+	objc_msgSend_void((id)mouse, sel_registerName("set"));
+	win->src.mouse = mouse;
+	return RGFW_TRUE;
+}
+
+void RGFW_freeMouse(RGFW_mouse* mouse) {
+	RGFW_ASSERT(mouse);
+	NSRelease((id)mouse);
+}
+
+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
+	RGFW_window_showMouseFlags(win, show);
+	if (show)   CGDisplayShowCursor(kCGDirectMainDisplay);
+	else        CGDisplayHideCursor(kCGDirectMainDisplay);
+}
+
+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win); RGFW_UNUSED(state);
+}
+
+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win);
+	CGAssociateMouseAndMouseCursorPosition(!(state == RGFW_TRUE));
+}
+
+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) {
+	RGFW_UNUSED(win);
+
+	win->internal.lastMouseX = x - win->x;
+	win->internal.lastMouseY = y - win->y;
+	CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y});
+}
+
+
+void RGFW_window_hide(RGFW_window* win) {
+	objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
+}
+
+void RGFW_window_show(RGFW_window* win) {
+	if (win->internal.flags & RGFW_windowFocusOnShow)
+		((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
+
+	((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
+	objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
+}
+
+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) {
+	if (RGFW_window_isInFocus(win) && request) {
+		return;
+	}
+
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+	if (_RGFW->flash) {
+		((void (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("cancelUserAttentionRequest:"), _RGFW->flash);
+	}
+
+	switch (request) {
+		case RGFW_flashBriefly:
+			_RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSInformationalRequest);
+			break;
+		case RGFW_flashUntilFocused:
+			_RGFW->flash = ((NSInteger (*)(id, SEL, NSInteger))objc_msgSend) ((id)_RGFW->NSApp, sel_registerName("requestUserAttention:"), NSCriticalRequest);
+			break;
+		default: break;
+	}
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+}
+
+RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
+	return visible == NO && !RGFW_window_isMinimized(win);
+}
+
+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
+}
+
+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
+	return b;
+}
+
+RGFWDEF id RGFW_getNSScreenForDisplayUInt(u32 uintNum);
+id RGFW_getNSScreenForDisplayUInt(u32 uintNum) {
+	Class NSScreenClass = objc_getClass("NSScreen");
+
+	id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
+
+	NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
+    NSUInteger i;
+	for (i = 0; i < count; i++) {
+		id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
+		id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
+		id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
+		id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
+
+		if (CGDisplayUnitNumber((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"))) == uintNum) {
+			return screen;
+		}
+	}
+
+	return NULL;
+}
+
+float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode);
+float RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
+	if (mode) {
+		float refreshRate = (float)CGDisplayModeGetRefreshRate(mode);
+		if (refreshRate != 0)  return refreshRate;
+	}
+
+#ifndef RGFW_NO_IOKIT
+    float res = RGFW_osx_getFallbackRefreshRate(display);
+    if (res != 0) return res;
+#else
+    RGFW_UNUSED(display);
+#endif
+    return 60;
+}
+
+void RGFW_pollMonitors(void) {
+	u32 count;
+
+	if (CGGetActiveDisplayList(0, NULL, &count) != kCGErrorSuccess) {
+		return;
+	}
+
+	CGDirectDisplayID* displays = (CGDirectDisplayID*)RGFW_ALLOC(sizeof(CGDirectDisplayID) * count);
+	if (CGGetActiveDisplayList(count, displays, &count) != kCGErrorSuccess) {
+		return;
+	}
+
+
+	for (RGFW_monitorNode* node = _RGFW->monitors.list.head; node; node = node->next) {
+		node->disconnected = RGFW_TRUE;
+	}
+
+	CGDirectDisplayID primary = CGMainDisplayID();
+
+	u32 i;
+	for (i = 0; i < count; i++) {
+		RGFW_monitor monitor;
+
+		u32 uintNum = CGDisplayUnitNumber(displays[i]);
+		id screen = RGFW_getNSScreenForDisplayUInt(uintNum);
+
+		RGFW_monitorNode* node;
+		for (node = _RGFW->monitors.list.head; node; node = node->next) {
+			if (node->uintNum == uintNum) break;
+		}
+
+		if (node) {
+			node->screen = (void*)screen;
+			node->display = displays[i];
+			node->disconnected = RGFW_FALSE;
+			if (displays[i] == primary) {
+				_RGFW->monitors.primary = node;
+			}
+			continue;
+		}
+
+		const char name[] = "MacOS\0";
+		RGFW_MEMCPY(monitor.name, name, 6);
+
+		CGRect bounds = CGDisplayBounds(displays[i]);
+		monitor.x = (i32)bounds.origin.x;
+		monitor.y = (i32)RGFW_cocoaYTransform((float)(bounds.origin.y + bounds.size.height - 1));
+
+		CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
+		monitor.mode.w = (i32)CGDisplayModeGetWidth(mode);
+		monitor.mode.h = (i32)CGDisplayModeGetHeight(mode);
+		monitor.mode.src = (void*)mode;
+		monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
+
+		monitor.mode.refreshRate = RGFW_osx_getRefreshRate(displays[i], mode);
+		CFRelease(mode);
+
+		CGSize screenSizeMM = CGDisplayScreenSize(displays[i]);
+		monitor.physW = (float)screenSizeMM.width / 25.4f;
+		monitor.physH = (float)screenSizeMM.height / 25.4f;
+
+		float ppi_width = ((float)monitor.mode.w / monitor.physW);
+		float ppi_height = ((float)monitor.mode.h / monitor.physH);
+
+		monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
+		float dpi = 96.0f * monitor.pixelRatio;
+
+		monitor.scaleX = ((((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
+		monitor.scaleY = ((((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
+
+		node = RGFW_monitors_add(&monitor);
+
+		node->screen = (void*)screen;
+		node->uintNum = uintNum;
+		node->display = displays[i];
+
+		if (displays[i] == primary) {
+			_RGFW->monitors.primary = node;
+		}
+
+		RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
+	}
+
+	RGFW_FREE(displays);
+
+	RGFW_monitors_refresh();
+}
+
+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) {
+	NSRect frameRect = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)monitor->node->screen, sel_registerName("visibleFrame"));
+
+    if (x) *x = (i32)frameRect.origin.x;
+    if (y) *y = (i32)RGFW_cocoaYTransform((float)(frameRect.origin.y + frameRect.size.height - (double)1.0f));
+    if (width) *width = (i32)frameRect.size.width;
+    if (height) *height = (i32)frameRect.size.height;
+
+	return RGFW_TRUE;
+}
+
+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+    u32 size = CGDisplayGammaTableCapacity(monitor->node->display);
+    CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(size * 3 * sizeof(CGGammaValue));
+
+    CGGetDisplayTransferByTable(monitor->node->display, size, values, values + size, values + size * 2, &size);
+
+    for (u32 i = 0;  ramp && i < size; i++) {
+        ramp->red[i] = (u16) (values[i] * 65535);
+        ramp->green[i] = (u16) (values[i + size] * 65535);
+        ramp->blue[i] = (u16) (values[i + size * 2] * 65535);
+    }
+
+    RGFW_FREE(values);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+	return size;
+}
+
+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) {
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+    CGGammaValue* values = (CGGammaValue*)RGFW_ALLOC(ramp->count * 3 * sizeof(CGGammaValue));
+
+    for (u32 i = 0;  i < ramp->count;  i++) {
+        values[i] = ramp->red[i] / 65535.f;
+        values[i + ramp->count] = ramp->green[i] / 65535.f;
+        values[i + ramp->count * 2] = ramp->blue[i] / 65535.f;
+    }
+
+    CGSetDisplayTransferByTable(monitor->node->display, (u32)ramp->count, values, values + ramp->count, values + ramp->count * 2);
+
+    RGFW_FREE(values);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+
+	return RGFW_TRUE;
+}
+
+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) {
+    CGDirectDisplayID display = mon->node->display;
+    CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
+
+    if (allModes == NULL) {
+        return RGFW_FALSE;
+	}
+
+	size_t count = (size_t)CFArrayGetCount(allModes);
+
+    CFIndex i;
+    for (i = 0; i < (CFIndex)count && modes; i++) {
+        CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
+
+		RGFW_monitorMode foundMode;
+		foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
+		foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
+		foundMode.refreshRate =  RGFW_osx_getRefreshRate(display, cmode);
+		foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
+		foundMode.src = (void*)cmode;
+		(*modes)[i] = foundMode;
+    }
+
+    CFRelease(allModes);
+	return count;
+}
+
+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) {
+	if (CGDisplaySetDisplayMode(mon->node->display, (CGDisplayModeRef)mode->src, NULL) == kCGErrorSuccess) {
+		return RGFW_TRUE;
+	}
+
+	return RGFW_FALSE;
+}
+
+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) {
+    CGDirectDisplayID display = mon->node->display;
+    CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
+
+    if (allModes == NULL) {
+        return RGFW_FALSE;
+	}
+
+	CGDisplayModeRef native = NULL;
+
+    CFIndex i;
+    for (i = 0; i < CFArrayGetCount(allModes); i++) {
+        CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
+
+		RGFW_monitorMode foundMode;
+		foundMode.w = (i32)CGDisplayModeGetWidth(cmode);
+		foundMode.h = (i32)CGDisplayModeGetHeight(cmode);
+		foundMode.refreshRate =  RGFW_osx_getRefreshRate(display, cmode);
+		foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
+		foundMode.src = (void*)cmode;
+
+		if (RGFW_monitorModeCompare(mode, &foundMode, request)) {
+			native = cmode;
+			mon->mode = foundMode;
+			break;
+        }
+    }
+
+    CFRelease(allModes);
+
+	if (native) {
+		if (CGDisplaySetDisplayMode(display, native, NULL) == kCGErrorSuccess) {
+			return RGFW_TRUE;
+		}
+	}
+
+	return RGFW_FALSE;
+}
+
+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
+	id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
+	id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
+	id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
+	id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
+
+	CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
+
+	RGFW_monitorNode* node = _RGFW->monitors.list.head;
+	for (node = _RGFW->monitors.list.head; node; node = node->next) {
+		if (node->display == display && (id)node->screen == screen) {
+			break;
+		}
+	}
+
+    if (node == NULL) {
+		node = _RGFW->monitors.primary ? _RGFW->monitors.primary : _RGFW->monitors.list.head;
+	}
+
+	if (node == NULL) return NULL;
+	return &node->mon;
+}
+
+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
+	size_t clip_len;
+	char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
+	if (clip == NULL) return -1;
+
+	if (str != NULL) {
+		if (strCapacity < clip_len)
+			return 0;
+
+		RGFW_MEMCPY(str, clip, clip_len);
+
+		str[clip_len] = '\0';
+	}
+
+	return (RGFW_ssize_t)clip_len;
+}
+
+void RGFW_writeClipboard(const char* text, u32 textLen) {
+	RGFW_UNUSED(textLen);
+
+	NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
+	NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
+
+	SEL func = sel_registerName("setString:forType:");
+	((bool (*)(id, SEL, id, id))objc_msgSend)
+		(NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char*)NSPasteboardTypeString));
+}
+
+#ifdef RGFW_OPENGL
+void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
+void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
+	((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
+		(context, sel_registerName("setValues:forParameter:"), vals, param);
+}
+
+
+/* MacOS OpenGL API spares us yet again (there are no extensions) */
+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; }
+
+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
+    static CFBundleRef RGFWnsglFramework = NULL;
+    if (RGFWnsglFramework == NULL)
+		RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+
+	CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
+
+	RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
+
+	CFRelease(symbolName);
+
+	return symbol;
+}
+
+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
+	win->src.ctx.native = ctx;
+	win->src.gfxType = RGFW_gfxNativeOpenGL;
+
+	i32 attribs[40];
+	size_t render_type_index = 0;
+	{
+		RGFW_attribStack stack;
+		RGFW_attribStack_init(&stack, attribs, 40);
+
+		i32 colorBits = (i32)(hints->red + hints->green +  hints->blue + hints->alpha) / 4;
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits);
+
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha);
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth);
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil);
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers);
+		RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy);
+		if (hints->samples) {
+			RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1);
+			RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples);
+		} else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0);
+
+		if (hints->doubleBuffer)
+			RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer);
+
+		#ifdef RGFW_COCOA_GRAPHICS_SWITCHING
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching);
+		#endif
+		#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
+		if (hints->stereo) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo);
+		#endif
+
+		/* macOS has the surface attribs and the OpenGL attribs connected for some reason maybe this is to give macOS more control to limit openGL/the OpenGL version? */
+		RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile,
+						(hints->major >= 4) ? NSOpenGLProfileVersion4_1Core  : (hints->major >= 3) ?
+															NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
+
+		if (hints->major <= 2) {
+			i32 accumSize = (i32)(hints->accumRed + hints->accumGreen +  hints->accumBlue + hints->accumAlpha) / 4;
+			RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize);
+		}
+
+		if (hints->renderer == RGFW_glSoftware) {
+			RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID);
+		} else {
+			RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated);
+		}
+		render_type_index = stack.count - 1;
+
+		RGFW_attribStack_pushAttribs(&stack, 0, 0);
+	}
+
+	void* format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
+	if (format == NULL) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL");
+
+		assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0])));
+		attribs[render_type_index] = NSOpenGLPFARendererID;
+		attribs[render_type_index + 1] = kCGLRendererGenericFloatID;
+		attribs[render_type_index + 3] = 0;
+
+		format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs);
+		if (format == NULL)
+			RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed");
+		else
+			RGFW_debugCallback(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering");
+	}
+
+	/* the pixel format can be passed directly to OpenGL context creation to create a context
+		this is because the format also includes information about the OpenGL version (which may be a bad thing) */
+
+	if (win->src.view)
+		NSRelease(win->src.view);
+	win->src.view = (id) ((id(*)(id, SEL, NSRect, u32*))objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]),
+							sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}, (u32*)format);
+
+	id share = NULL;
+	if (hints->share) {
+		share = (id)hints->share->ctx;
+	}
+
+	win->src.ctx.native->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")),
+												 sel_registerName("initWithFormat:shareContext:"),
+												 (id)format, share);
+
+	win->src.ctx.native->format = format;
+
+	objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx);
+	if (win->internal.flags & RGFW_windowTransparent) {
+		i32 opacity = 0;
+		#define NSOpenGLCPSurfaceOpacity 236
+		NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity);
+
+	}
+
+	objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
+
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
+	objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true);
+	objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"),  4);
+
+	RGFW_window_swapInterval_OpenGL(win, 0);
+
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
+	return RGFW_TRUE;
+}
+
+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
+	objc_msgSend_void(ctx->format, sel_registerName("release"));
+	win->src.ctx.native->format = NULL;
+
+	objc_msgSend_void(ctx->ctx, sel_registerName("release"));
+	win->src.ctx.native->ctx = NULL;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
+}
+
+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
+	if (win) RGFW_ASSERT(win->src.ctx.native);
+	if (win != NULL)
+		objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext"));
+	else
+		objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
+}
+void* RGFW_getCurrentContext_OpenGL(void) {
+	return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
+}
+
+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
+	RGFW_ASSERT(win && win->src.ctx.native);
+	objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer"));
+}
+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) {
+	RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL);
+	NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter)222);
+}
+#endif
+
+void RGFW_deinitPlatform(void) {
+	objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("setDelegate:"), NULL);
+
+	objc_msgSend_void_id(_RGFW->NSApp, sel_registerName("stop:"), NULL);
+	NSRelease(_RGFW->NSApp);
+	_RGFW->NSApp = NULL;
+
+	NSRelease(_RGFW->customNSAppDelegate);
+
+	_RGFW->customNSAppDelegate = NULL;
+
+	objc_disposeClassPair((Class)_RGFW->customViewClasses[0]);
+	objc_disposeClassPair((Class)_RGFW->customViewClasses[1]);
+	objc_disposeClassPair((Class)_RGFW->customWindowDelegateClass);
+	objc_disposeClassPair((Class)_RGFW->customNSAppDelegateClass);
+}
+
+void RGFW_window_closePlatform(RGFW_window* win) {
+	objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), NULL);
+	NSRelease((id)win->src.delegate);
+	NSRelease(win->src.view);
+
+	objc_msgSend_id(win->src.window, sel_registerName("close"));
+	NSRelease(win->src.window);
+}
+
+#ifdef RGFW_VULKAN
+VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
+    RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
+	RGFW_ASSERT(surface != NULL);
+
+    *surface = VK_NULL_HANDLE;
+	id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
+	pool = objc_msgSend_id(pool, sel_registerName("init"));
+
+    id nsView = (id)win->src.view;
+    if (!nsView) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
+        return -1;
+    }
+
+
+    id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
+
+	void* metalLayer = RGFW_getLayer_OSX();
+	if (metalLayer == NULL) {
+		 return -1;
+	}
+	((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
+    ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
+
+	VkResult result;
+/*
+	VkMetalSurfaceCreateInfoEXT macos;
+	macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
+	macos.slayer = metalLayer;
+	RGFW_MEMZERO(&macos, sizeof(macos));
+    result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
+*/
+
+	VkMacOSSurfaceCreateInfoMVK macos;
+	RGFW_MEMZERO(&macos, sizeof(macos));
+	macos.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
+	macos.pView = nsView;
+
+    result = vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
+
+	objc_msgSend_bool_void(pool, sel_registerName("drain"));
+
+	return result;
+}
+#endif
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
+	WGPUSurfaceDescriptor surfaceDesc = {0};
+    id* nsView = (id*)window->src.view;
+    if (!nsView) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errMetal, "NSView is NULL for macOS window");
+        return NULL;
+    }
+
+    ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES);
+    id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer"));
+
+	void* metalLayer = RGFW_getLayer_OSX();
+	if (metalLayer == NULL) {
+		 return NULL;
+	}
+	((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer);
+	layer = metalLayer;
+
+    WGPUSurfaceSourceMetalLayer fromMetal = {0};
+    fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
+#ifdef  __OBJC__
+	fromMetal.layer = (__bridge CAMetalLayer*)layer; /* Use __bridge for ARC compatibility if mixing C/Obj-C */
+#else
+	fromMetal.layer = layer;
+#endif
+
+    surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain;
+    return wgpuInstanceCreateSurface(instance, &surfaceDesc);
+}
+#endif
+
+#endif /* RGFW_MACOS */
+
+/*
+	End of MaOS defines
+*/
+
+/*
+	WASM defines
+*/
+
+#ifdef RGFW_WASM
+EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+	RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE;
+
+	static u8 fullscreen = RGFW_FALSE;
+	static i32 originalW, originalH;
+
+	if (fullscreen == RGFW_FALSE) {
+		originalW = _RGFW->root->w;
+		originalH = _RGFW->root->h;
+	}
+
+	fullscreen = !fullscreen;
+	_RGFW->root->w = E->screenWidth;
+	_RGFW->root->h =  E->screenHeight;
+
+	EM_ASM("Module.canvas.focus();");
+
+	if (fullscreen == RGFW_FALSE) {
+		_RGFW->root->w = originalW;
+		_RGFW->root->h = originalH;
+	} else {
+		#if __EMSCRIPTEN_major__  >= 1 && __EMSCRIPTEN_minor__  >= 29 && __EMSCRIPTEN_tiny__  >= 0
+			EmscriptenFullscreenStrategy FSStrat = {0};
+			FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
+			FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
+			FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
+			emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
+		#else
+			emscripten_request_fullscreen("#canvas", 1);
+		#endif
+	}
+
+	emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h);
+	RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h);
+	return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
+
+	RGFW_windowFocusCallback(_RGFW->root, 1);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E);
+
+	RGFW_windowFocusCallback(_RGFW->root, 0);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+	RGFW_mouseMotionCallback(_RGFW->root, E->targetX, E->targetY);
+	RGFW_rawMotionCallback(_RGFW->root, E->movementX, E->movementY);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	int button = E->button;
+	if (button > 2)
+		button += 2;
+
+	RGFW_mouseButtonCallback(_RGFW->root, button, 1);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	int button = E->button;
+	if (button > 2)
+		button += 2;
+
+	RGFW_mouseButtonCallback(_RGFW->root, button, 0);
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY);
+
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE;
+
+    size_t i;
+    for (i = 0; i < (size_t)E->numTouches; i++) {
+        RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
+		RGFW_rawMotionCallback(_RGFW->root, 0, 0);
+	    RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1);
+    }
+
+	return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseMotionFlag)) return EM_TRUE;
+
+    size_t i;
+    for (i = 0; i < (size_t)E->numTouches; i++) {
+        RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
+		RGFW_rawMotionCallback(_RGFW->root, 0, 0);
+    }
+    return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) {
+	RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
+
+	if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE;
+
+    size_t i;
+    for (i = 0; i < (size_t)E->numTouches; i++) {
+		RGFW_mouseMotionCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY);
+		RGFW_rawMotionCallback(_RGFW->root, 0, 0);
+		RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0);
+    }
+	return EM_TRUE;
+}
+
+EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; }
+
+RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash);
+
+void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* code, u32 codepoint, RGFW_bool press) {
+	const char* iCode = code;
+
+	u32 hash = 0;
+	while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
+
+	u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash);
+
+	RGFW_keyCallback(_RGFW->root, physicalKey, _RGFW->root->internal.mod,  RGFW_isKeyDown((u8)physicalKey) && press, press);
+	if (press) {
+;		RGFW_keyCharCallback(_RGFW->root, codepoint);
+	}
+}
+
+void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
+	RGFW_keyUpdateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll);
+}
+
+void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(char* file, size_t size) {
+	RGFW_dataDropCallback(_RGFW->root, file, size, RGFW_dataFile);
+}
+
+void EMSCRIPTEN_KEEPALIVE RGFW_webFree(void* ptr) { free(ptr); }
+
+void RGFW_stopCheckEvents(void) {
+	_RGFW->stopCheckEvents_bool = RGFW_TRUE;
+}
+
+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) {
+	surface->data = data;
+	surface->w = w;
+	surface->h = h;
+	surface->format = format;
+	return RGFW_TRUE;
+}
+
+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) {
+	/* TODO: Needs fixing. */
+	RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format, surface->convertFunc);
+	EM_ASM_({
+		var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
+		let context = document.getElementById("canvas").getContext("2d");
+		let image = context.getImageData(0, 0, $1, $2);
+		image.data.set(data);
+		context.putImageData(image, 0, $4 - $2);
+	}, surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h));
+}
+
+void RGFW_surface_freePtr(RGFW_surface* surface) { }
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+
+void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
+
+void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
+    FILE* file = fopen(path, "w+");
+	if (file == NULL)
+		return;
+
+    fwrite(data, sizeof(char), len, file);
+    fclose(file);
+}
+
+void RGFW_initKeycodesPlatform(void) {
+	_RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_keyBacktick;
+	_RGFW->keycodes[DOM_VK_0] = RGFW_key0;
+	_RGFW->keycodes[DOM_VK_1] = RGFW_key1;
+	_RGFW->keycodes[DOM_VK_2] = RGFW_key2;
+	_RGFW->keycodes[DOM_VK_3] = RGFW_key3;
+	_RGFW->keycodes[DOM_VK_4] = RGFW_key4;
+	_RGFW->keycodes[DOM_VK_5] = RGFW_key5;
+	_RGFW->keycodes[DOM_VK_6] = RGFW_key6;
+	_RGFW->keycodes[DOM_VK_7] = RGFW_key7;
+	_RGFW->keycodes[DOM_VK_8] = RGFW_key8;
+	_RGFW->keycodes[DOM_VK_9] = RGFW_key9;
+	_RGFW->keycodes[DOM_VK_SPACE] = RGFW_keySpace;
+	_RGFW->keycodes[DOM_VK_A] = RGFW_keyA;
+	_RGFW->keycodes[DOM_VK_B] = RGFW_keyB;
+	_RGFW->keycodes[DOM_VK_C] = RGFW_keyC;
+	_RGFW->keycodes[DOM_VK_D] = RGFW_keyD;
+	_RGFW->keycodes[DOM_VK_E] = RGFW_keyE;
+	_RGFW->keycodes[DOM_VK_F] = RGFW_keyF;
+	_RGFW->keycodes[DOM_VK_G] = RGFW_keyG;
+	_RGFW->keycodes[DOM_VK_H] = RGFW_keyH;
+	_RGFW->keycodes[DOM_VK_I] = RGFW_keyI;
+	_RGFW->keycodes[DOM_VK_J] = RGFW_keyJ;
+	_RGFW->keycodes[DOM_VK_K] = RGFW_keyK;
+	_RGFW->keycodes[DOM_VK_L] = RGFW_keyL;
+	_RGFW->keycodes[DOM_VK_M] = RGFW_keyM;
+	_RGFW->keycodes[DOM_VK_N] = RGFW_keyN;
+	_RGFW->keycodes[DOM_VK_O] = RGFW_keyO;
+	_RGFW->keycodes[DOM_VK_P] = RGFW_keyP;
+	_RGFW->keycodes[DOM_VK_Q] = RGFW_keyQ;
+	_RGFW->keycodes[DOM_VK_R] = RGFW_keyR;
+	_RGFW->keycodes[DOM_VK_S] = RGFW_keyS;
+	_RGFW->keycodes[DOM_VK_T] = RGFW_keyT;
+	_RGFW->keycodes[DOM_VK_U] = RGFW_keyU;
+	_RGFW->keycodes[DOM_VK_V] = RGFW_keyV;
+	_RGFW->keycodes[DOM_VK_W] = RGFW_keyW;
+	_RGFW->keycodes[DOM_VK_X] = RGFW_keyX;
+	_RGFW->keycodes[DOM_VK_Y] = RGFW_keyY;
+	_RGFW->keycodes[DOM_VK_Z] = RGFW_keyZ;
+	_RGFW->keycodes[DOM_VK_PERIOD] = RGFW_keyPeriod;
+	_RGFW->keycodes[DOM_VK_COMMA] = RGFW_keyComma;
+	_RGFW->keycodes[DOM_VK_SLASH] = RGFW_keySlash;
+	_RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_keyBracket;
+	_RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_keyCloseBracket;
+	_RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_keySemicolon;
+	_RGFW->keycodes[DOM_VK_QUOTE] = RGFW_keyApostrophe;
+	_RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_keyBackSlash;
+	_RGFW->keycodes[DOM_VK_RETURN] = RGFW_keyReturn;
+	_RGFW->keycodes[DOM_VK_DELETE] = RGFW_keyDelete;
+	_RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_keyNumLock;
+	_RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_keyPadSlash;
+	_RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_keyPadMultiply;
+	_RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_keyPadMinus;
+	_RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_keyPad1;
+	_RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_keyPad2;
+	_RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_keyPad3;
+	_RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_keyPad4;
+	_RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_keyPad5;
+	_RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_keyPad6;
+	_RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_keyPad9;
+	_RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_keyPad0;
+	_RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_keyPadPeriod;
+	_RGFW->keycodes[DOM_VK_RETURN] = RGFW_keyPadReturn;
+	_RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_keyMinus;
+	_RGFW->keycodes[DOM_VK_EQUALS] = RGFW_keyEquals;
+	_RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_keyBackSpace;
+	_RGFW->keycodes[DOM_VK_TAB] = RGFW_keyTab;
+	_RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_keyCapsLock;
+	_RGFW->keycodes[DOM_VK_SHIFT] = RGFW_keyShiftL;
+	_RGFW->keycodes[DOM_VK_CONTROL] = RGFW_keyControlL;
+	_RGFW->keycodes[DOM_VK_ALT] = RGFW_keyAltL;
+	_RGFW->keycodes[DOM_VK_META] = RGFW_keySuperL;
+	_RGFW->keycodes[DOM_VK_F1] = RGFW_keyF1;
+	_RGFW->keycodes[DOM_VK_F2] = RGFW_keyF2;
+	_RGFW->keycodes[DOM_VK_F3] = RGFW_keyF3;
+	_RGFW->keycodes[DOM_VK_F4] = RGFW_keyF4;
+	_RGFW->keycodes[DOM_VK_F5] = RGFW_keyF5;
+	_RGFW->keycodes[DOM_VK_F6] = RGFW_keyF6;
+	_RGFW->keycodes[DOM_VK_F7] = RGFW_keyF7;
+	_RGFW->keycodes[DOM_VK_F8] = RGFW_keyF8;
+	_RGFW->keycodes[DOM_VK_F9] = RGFW_keyF9;
+	_RGFW->keycodes[DOM_VK_F10] = RGFW_keyF10;
+	_RGFW->keycodes[DOM_VK_F11] = RGFW_keyF11;
+	_RGFW->keycodes[DOM_VK_F12] = RGFW_keyF12;
+	_RGFW->keycodes[DOM_VK_UP] = RGFW_keyUp;
+	_RGFW->keycodes[DOM_VK_DOWN] = RGFW_keyDown;
+	_RGFW->keycodes[DOM_VK_LEFT] = RGFW_keyLeft;
+	_RGFW->keycodes[DOM_VK_RIGHT] = RGFW_keyRight;
+	_RGFW->keycodes[DOM_VK_INSERT] = RGFW_keyInsert;
+	_RGFW->keycodes[DOM_VK_END] = RGFW_keyEnd;
+	_RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_keyPageUp;
+	_RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_keyPageDown;
+	_RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_keyEscape;
+	_RGFW->keycodes[DOM_VK_HOME] = RGFW_keyHome;
+	_RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_keyScrollLock;
+	_RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_keyPrintScreen;
+	_RGFW->keycodes[DOM_VK_PAUSE] = RGFW_keyPause;
+	_RGFW->keycodes[DOM_VK_F13]  = RGFW_keyF13;
+	_RGFW->keycodes[DOM_VK_F14]  = RGFW_keyF14;
+	_RGFW->keycodes[DOM_VK_F15]  = RGFW_keyF15;
+	_RGFW->keycodes[DOM_VK_F16]  = RGFW_keyF16;
+	_RGFW->keycodes[DOM_VK_F17]  = RGFW_keyF17;
+	_RGFW->keycodes[DOM_VK_F18]  = RGFW_keyF18;
+	_RGFW->keycodes[DOM_VK_F19]  = RGFW_keyF19;
+	_RGFW->keycodes[DOM_VK_F20]  = RGFW_keyF20;
+	_RGFW->keycodes[DOM_VK_F21]  = RGFW_keyF21;
+	_RGFW->keycodes[DOM_VK_F22]  = RGFW_keyF22;
+	_RGFW->keycodes[DOM_VK_F23]  = RGFW_keyF23;
+	_RGFW->keycodes[DOM_VK_F24]  = RGFW_keyF24;
+}
+
+i32 RGFW_initPlatform(void) {
+	RGFW_monitorNode* node = NULL;
+	RGFW_monitor monitor;
+
+	monitor.name[0] = '\0';
+
+	monitor.x = 0;
+	monitor.y = 0;
+
+	monitor.pixelRatio = EM_ASM_DOUBLE({return window.devicePixelRatio || 1;});
+	monitor.mode.w = EM_ASM_INT({return window.innerWidth || 0;});
+	monitor.mode.h = EM_ASM_INT({return window.innerHeight || 0;});
+
+	monitor.physW = (float)RGFW_ROUND((float)monitor.mode.w * monitor.pixelRatio);
+	monitor.physH = (float)RGFW_ROUND((float)monitor.mode.h * monitor.pixelRatio);
+
+	float dpi = 96.0f * monitor.pixelRatio;
+	monitor.scaleX = dpi / 96.0f;
+	monitor.scaleY = dpi / 96.0f;
+
+	RGFW_splitBPP(32, &monitor.mode);
+
+	monitor.mode.refreshRate = 0;
+
+	node = RGFW_monitors_add(&monitor);
+	if (node != NULL) {
+		_RGFW->monitors.primary = node;
+		RGFW_monitorCallback(_RGFW->root, &node->mon, RGFW_TRUE);
+	}
+
+	return 0;
+}
+
+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) {
+	emscripten_set_canvas_element_size("#canvas", win->w, win->h);
+	emscripten_set_window_title(name);
+
+	/* load callbacks */
+    emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
+    emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
+    emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
+    emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
+    emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
+    emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
+    emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
+    emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
+    emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
+    emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
+    emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
+    emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
+
+	if (flags & RGFW_windowAllowDND)  {
+		win->internal.flags |= RGFW_windowAllowDND;
+	}
+
+	EM_ASM({
+		window.addEventListener("keydown",
+			(event) => {
+				var code = stringToNewUTF8(event.code);
+				Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
+
+				var codepoint = event.key.charCodeAt(0);
+				if(codepoint < 0x7f && event.key.length > 1) {
+					codepoint = 0;
+				}
+
+				Module._RGFW_handleKeyEvent(code, codepoint, 1);
+				Module._RGFW_webFree(code);
+			},
+		true);
+		window.addEventListener("keyup",
+			(event) => {
+				var code = stringToNewUTF8(event.code);
+				Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
+				Module._RGFW_handleKeyEvent(code, 0, 0);
+				Module._RGFW_webFree(code);
+			},
+		true);
+	});
+
+    EM_ASM({
+		var canvas = document.getElementById('canvas');
+        canvas.addEventListener('drop', function(e) {
+            e.preventDefault();
+            if (e.dataTransfer.file < 0)
+				return;
+
+			var count = e.dataTransfer.files.length;
+
+			/* Read and save the files to emscripten's files */
+			var drop_dir = '.rgfw_dropped_files';
+			Module._RGFW_mkdir(drop_dir);
+
+			for (var i = 0; i < count; i++) {
+				var file = e.dataTransfer.files[i];
+
+				var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
+				var reader = new FileReader();
+
+				reader.onloadend = (e) => {
+					if (reader.readyState != 2) {
+						out('failed to read dropped file: '+file.name+': '+reader.error);
+					}
+					else {
+						var data = e.target.result;
+
+						Module._RGFW_writeFile(path, new Uint8Array(data), file.size);
+					}
+				};
+
+				reader.readAsArrayBuffer(file);
+				var filename = stringToNewUTF8(path);
+
+				Module._Emscripten_onDrop(filename, path.length + 1);
+				free(filename);
+			}
+
+        }, true);
+
+        canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
+    });
+
+	return win;
+}
+
+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) {
+	return key;
+}
+
+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) {
+	return RGFW_window_getSize(win, w, h);
+}
+
+void RGFW_pollEvents(void) {
+	static int using_asyncify = -1;
+	if (using_asyncify == -1) using_asyncify = EM_ASM_INT({ return 'Asyncify' in Module; });
+
+	RGFW_resetPrevState();
+	if (using_asyncify) {
+		emscripten_sleep(0);
+	}
+}
+
+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) {
+	RGFW_UNUSED(win);
+	emscripten_set_canvas_element_size("#canvas", w, h);
+}
+
+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon mouse) {
+	char* cursorName = NULL;
+
+	switch (mouse) {
+		case RGFW_mouseNormal:       cursorName = (char*)"default"; break;
+		case RGFW_mouseArrow:        cursorName = (char*)"default"; break;
+		case RGFW_mouseIbeam:        cursorName = (char*)"text"; break;
+		case RGFW_mouseCrosshair:    cursorName = (char*)"crosshair"; break;
+		case RGFW_mousePointingHand: cursorName = (char*)"pointer"; break;
+		case RGFW_mouseResizeEW:     cursorName = (char*)"ew-resize"; break;
+		case RGFW_mouseResizeNS:     cursorName = (char*)"ns-resize"; break;
+		case RGFW_mouseResizeNWSE:   cursorName = (char*)"nwse-resize"; break;
+		case RGFW_mouseResizeNESW:   cursorName = (char*)"nesw-resize"; break;
+		case RGFW_mouseResizeNW:     cursorName = (char*)"nw-resize"; break;
+		case RGFW_mouseResizeN:      cursorName = (char*)"n-resize"; break;
+		case RGFW_mouseResizeNE:     cursorName = (char*)"ne-resize"; break;
+		case RGFW_mouseResizeE:      cursorName = (char*)"e-resize"; break;
+		case RGFW_mouseResizeSE:     cursorName = (char*)"se-resize"; break;
+		case RGFW_mouseResizeS:      cursorName = (char*)"s-resize"; break;
+		case RGFW_mouseResizeSW:     cursorName = (char*)"sw-resize"; break;
+		case RGFW_mouseResizeW:      cursorName = (char*)"w-resize"; break;
+		case RGFW_mouseResizeAll:    cursorName = (char*)"move"; break;
+		case RGFW_mouseNotAllowed:   cursorName = (char*)"not-allowed"; break;
+		case RGFW_mouseWait:         cursorName = (char*)"wait"; break;
+		case RGFW_mouseProgress:     cursorName = (char*)"progress"; break;
+		default:                     return NULL;
+	}
+
+	return (RGFW_mouse*)cursorName;
+}
+
+/* NOTE: I don't know if this is possible */
+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); }
+/* this one might be possible but it looks iffy */
+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; }
+
+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) {
+	RGFW_ASSERT(win != NULL);
+	RGFW_ASSERT(mouse != NULL);
+
+	EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, (char*)mouse);
+	return RGFW_TRUE;
+}
+void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
+
+void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
+	RGFW_window_showMouseFlags(win, show);
+	if (show)
+		RGFW_window_setMouseDefault(win);
+	else
+		EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
+}
+
+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) {
+    if(x) *x = EM_ASM_INT({
+        return window.mouseX || 0;
+    });
+    if (y) *y = EM_ASM_INT({
+        return window.mouseY || 0;
+    });
+    return RGFW_TRUE;
+}
+
+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
+	RGFW_UNUSED(win);
+
+    EM_ASM_({
+        var canvas = document.getElementById('canvas');
+        if ($0) {
+            canvas.style.pointerEvents = 'none';
+        } else {
+            canvas.style.pointerEvents = 'auto';
+        }
+    }, passthrough);
+}
+
+void RGFW_writeClipboard(const char* text, u32 textLen) {
+	RGFW_UNUSED(textLen);
+	EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
+}
+
+
+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
+	RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
+	/*
+		placeholder code for later
+		I'm not sure if this is possible do the the async stuff
+	*/
+	return 0;
+}
+
+#ifdef RGFW_OPENGL
+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
+	win->src.ctx.native = ctx;
+	win->src.gfxType = RGFW_gfxNativeOpenGL;
+
+	EmscriptenWebGLContextAttributes attrs;
+	emscripten_webgl_init_context_attributes(&attrs);
+	attrs.alpha = hints->alpha;
+	attrs.depth = hints->depth;
+	attrs.stencil = hints->stencil;
+	attrs.antialias = hints->samples;
+	attrs.premultipliedAlpha = EM_TRUE;
+	attrs.preserveDrawingBuffer = EM_FALSE;
+
+	if (hints->doubleBuffer == 0)
+		attrs.renderViaOffscreenBackBuffer = 0;
+	else
+		attrs.renderViaOffscreenBackBuffer = hints->auxBuffers;
+
+	attrs.failIfMajorPerformanceCaveat = EM_FALSE;
+
+	attrs.enableExtensionsByDefault = EM_TRUE;
+
+	if (hints->profile == RGFW_glWeb) {
+		attrs.majorVersion = (hints->major == 0) ? 1 : hints->major;
+		attrs.minorVersion = hints->minor;
+	} else {
+		attrs.majorVersion = (hints->major == 0) ? 1 : ( (hints->major > 1) ? hints->major - 1 : hints->major );
+		attrs.minorVersion = hints->minor;
+	}
+
+	attrs.explicitSwapControl = EM_TRUE;
+	win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs);
+
+	if (win->src.ctx.native->ctx == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_warningOpenGL, "WebGL: Failed to create an OpenGL Context with explicit swap control.");
+		attrs.explicitSwapControl = EM_FALSE;
+		win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs);
+	}
+
+	if (win->src.ctx.native->ctx == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL Context with the requested attributes, falling back to defaults.");
+		win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs);
+	}
+
+	if (win->src.ctx.native->ctx == 0) {
+		RGFW_debugCallback(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL Context.");
+		return RGFW_FALSE;
+	}
+
+	emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
+
+	#ifdef LEGACY_GL_EMULATION
+	EM_ASM("Module.useWebGL = true; GLImmediate.init();");
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized.");
+    #endif
+
+	RGFW_window_swapInterval_OpenGL(win, 0);
+
+	return RGFW_TRUE;
+}
+
+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) {
+	emscripten_webgl_destroy_context(ctx->ctx);
+	win->src.ctx.native->ctx = 0;
+	RGFW_debugCallback(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed.");
+}
+
+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
+	if (win) RGFW_ASSERT(win->src.ctx.native);
+	if (win == NULL)
+	    emscripten_webgl_make_context_current(0);
+	else
+	    emscripten_webgl_make_context_current(win->src.ctx.native->ctx);
+}
+
+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
+	RGFW_ASSERT(win && win->src.ctx.native);
+	emscripten_webgl_commit_frame();
+}
+void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
+
+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) {
+    return EM_ASM_INT({
+        var ext = UTF8ToString($0, $1);
+        var canvas = document.querySelector('canvas');
+        var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+        if (!gl) return 0;
+
+        var supported = gl.getSupportedExtensions();
+        return supported && supported.includes(ext) ? 1 : 0;
+    }, extension, len);
+    return RGFW_FALSE;
+}
+
+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) {
+    return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
+    return NULL;
+}
+
+#endif
+
+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
+
+void RGFW_deinitPlatform(void) { }
+
+void RGFW_window_closePlatform(RGFW_window* win) { }
+
+int RGFW_innerWidth(void) {   return EM_ASM_INT({ return window.innerWidth; });  }
+int RGFW_innerHeight(void) {  return EM_ASM_INT({ return window.innerHeight; });  }
+
+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win); RGFW_UNUSED(state);
+}
+
+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) {
+	RGFW_UNUSED(win);
+	if (state) {
+		emscripten_request_pointerlock("#canvas", 1);
+	} else {
+		emscripten_exit_pointerlock();
+	}
+}
+
+void RGFW_window_setName(RGFW_window* win, const char* name) {
+	RGFW_UNUSED(win);
+	if (name == NULL) name = "\0";
+
+	emscripten_set_window_title(name);
+}
+
+void RGFW_window_maximize(RGFW_window* win) {
+	RGFW_ASSERT(win != NULL);
+
+	RGFW_monitor* mon = RGFW_window_getMonitor(win);
+	if (mon != NULL) {
+		RGFW_window_resize(win, mon->mode.w, mon->mode.h);
+	}
+
+	RGFW_window_move(win, 0, 0);
+	RGFW_window_fetchSize(win, NULL, NULL);
+}
+
+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
+	RGFW_ASSERT(win != NULL);
+	if (fullscreen) {
+		win->internal.flags |= RGFW_windowFullscreen;
+		EM_ASM( Module.requestFullscreen(false, true); );
+		return;
+	}
+	win->internal.flags &= ~(u32)RGFW_windowFullscreen;
+	EM_ASM( Module.exitFullscreen(false, true); );
+}
+
+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
+	RGFW_UNUSED(win);
+	EM_ASM({
+		var element = document.getElementById("canvas");
+		if (element)
+		  element.style.opacity = $1;
+	  }, "elementId", opacity);
+}
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) {
+	WGPUSurfaceDescriptor surfaceDesc = {0};
+	WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0};
+    canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
+    canvasDesc.selector = (WGPUStringView){.data = "#canvas", .length = 7};
+
+    surfaceDesc.nextInChain = &canvasDesc.chain;
+    return wgpuInstanceCreateSurface(instance, &surfaceDesc);
+}
+#endif
+
+RGFW_key RGFW_WASMPhysicalToRGFW(u32 hash) {
+	switch(hash) {             /* 0x0000 */
+		case 0x67243A2DU /* Escape             */: return RGFW_keyEscape;               /* 0x0001 */
+		case 0x67251058U /* Digit0             */: return RGFW_key0;                    /* 0x0002 */
+		case 0x67251059U /* Digit1             */: return RGFW_key1;                    /* 0x0003 */
+		case 0x6725105AU /* Digit2             */: return RGFW_key2;                    /* 0x0004 */
+		case 0x6725105BU /* Digit3             */: return RGFW_key3;                    /* 0x0005 */
+		case 0x6725105CU /* Digit4             */: return RGFW_key4;                    /* 0x0006 */
+		case 0x6725105DU /* Digit5             */: return RGFW_key5;                    /* 0x0007 */
+		case 0x6725105EU /* Digit6             */: return RGFW_key6;                    /* 0x0008 */
+		case 0x6725105FU /* Digit7             */: return RGFW_key7;                    /* 0x0009 */
+		case 0x67251050U /* Digit8             */: return RGFW_key8;                    /* 0x000A */
+		case 0x67251051U /* Digit9             */: return RGFW_key9;                    /* 0x000B */
+		case 0x92E14DD3U /* Minus              */: return RGFW_keyMinus;                /* 0x000C */
+		case 0x92E1FBACU /* Equal              */: return RGFW_keyEquals;                /* 0x000D */
+		case 0x36BF1CB5U /* Backspace          */: return RGFW_keyBackSpace;            /* 0x000E */
+		case 0x7B8E51E2U  /* Tab                */: return RGFW_keyTab;                  /* 0x000F */
+		case 0x2C595B51U /* KeyQ               */: return RGFW_keyQ;                    /* 0x0010 */
+		case 0x2C595B57U /* KeyW               */: return RGFW_keyW;                    /* 0x0011 */
+		case 0x2C595B45U /* KeyE               */: return RGFW_keyE;                    /* 0x0012 */
+		case 0x2C595B52U /* KeyR               */: return RGFW_keyR;                    /* 0x0013 */
+		case 0x2C595B54U /* KeyT               */: return RGFW_keyT;                    /* 0x0014 */
+		case 0x2C595B59U /* KeyY               */: return RGFW_keyY;                    /* 0x0015 */
+		case 0x2C595B55U /* KeyU               */: return RGFW_keyU;                    /* 0x0016 */
+		case 0x2C595B4FU /* KeyO               */: return RGFW_keyO;                    /* 0x0018 */
+		case 0x2C595B50U /* KeyP               */: return RGFW_keyP;                    /* 0x0019 */
+		case 0x45D8158CU /* BracketLeft        */: return RGFW_keyCloseBracket;         /* 0x001A */
+		case 0xDEEABF7CU /* BracketRight       */: return RGFW_keyBracket;        /* 0x001B */
+		case 0x92E1C5D2U /* Enter              */: return RGFW_keyReturn;                /* 0x001C */
+		case 0xE058958CU /* ControlLeft        */: return RGFW_keyControlL;         /* 0x001D */
+		case 0x2C595B41U /* KeyA               */: return RGFW_keyA;                    /* 0x001E */
+		case 0x2C595B53U /* KeyS               */: return RGFW_keyS;                    /* 0x001F */
+		case 0x2C595B44U /* KeyD               */: return RGFW_keyD;                    /* 0x0020 */
+		case 0x2C595B46U /* KeyF               */: return RGFW_keyF;                    /* 0x0021 */
+		case 0x2C595B47U /* KeyG               */: return RGFW_keyG;                    /* 0x0022 */
+		case 0x2C595B48U /* KeyH               */: return RGFW_keyH;                    /* 0x0023 */
+		case 0x2C595B4AU /* KeyJ               */: return RGFW_keyJ;                    /* 0x0024 */
+		case 0x2C595B4BU /* KeyK               */: return RGFW_keyK;                    /* 0x0025 */
+		case 0x2C595B4CU /* KeyL               */: return RGFW_keyL;                    /* 0x0026 */
+		case 0x2707219EU /* Semicolon          */: return RGFW_keySemicolon;            /* 0x0027 */
+		case 0x92E0B58DU /* Quote              */: return RGFW_keyApostrophe;                /* 0x0028 */
+		case 0x36BF358DU /* Backquote          */: return RGFW_keyBacktick;            /* 0x0029 */
+		case 0x26B1958CU /* ShiftLeft          */: return RGFW_keyShiftL;           /* 0x002A */
+		case 0x36BF2438U /* Backslash          */: return RGFW_keyBackSlash;            /* 0x002B */
+		case 0x2C595B5AU /* KeyZ               */: return RGFW_keyZ;                    /* 0x002C */
+		case 0x2C595B58U /* KeyX               */: return RGFW_keyX;                    /* 0x002D */
+		case 0x2C595B43U /* KeyC               */: return RGFW_keyC;                    /* 0x002E */
+		case 0x2C595B56U /* KeyV               */: return RGFW_keyV;                    /* 0x002F */
+		case 0x2C595B42U /* KeyB               */: return RGFW_keyB;                    /* 0x0030 */
+		case 0x2C595B4EU /* KeyN               */: return RGFW_keyN;                    /* 0x0031 */
+		case 0x2C595B4DU /* KeyM               */: return RGFW_keyM;                    /* 0x0032 */
+		case 0x92E1A1C1U /* Comma              */: return RGFW_keyComma;                /* 0x0033 */
+		case 0x672FFAD4U /* Period             */: return RGFW_keyPeriod;               /* 0x0034 */
+		case 0x92E0A438U /* Slash              */: return RGFW_keySlash;                /* 0x0035 */
+		case 0xC5A6BF7CU /* ShiftRight         */: return RGFW_keyShiftR;
+		case 0x5D64DA91U /* NumpadMultiply     */: return RGFW_keyPadMultiply;
+		case 0xC914958CU /* AltLeft            */: return RGFW_keyAltL;             /* 0x0038 */
+		case 0x92E09CB5U /* Space              */: return RGFW_keySpace;                /* 0x0039 */
+		case 0xB8FAE73BU  /* CapsLock           */: return RGFW_keyCapsLock;            /* 0x003A */
+		case 0x7174B789U /* F1                 */: return RGFW_keyF1;                   /* 0x003B */
+		case 0x7174B78AU /* F2                 */: return RGFW_keyF2;                   /* 0x003C */
+		case 0x7174B78BU /* F3                 */: return RGFW_keyF3;                   /* 0x003D */
+		case 0x7174B78CU /* F4                 */: return RGFW_keyF4;                   /* 0x003E */
+		case 0x7174B78DU /* F5                 */: return RGFW_keyF5;                   /* 0x003F */
+		case 0x7174B78EU /* F6                 */: return RGFW_keyF6;                   /* 0x0040 */
+		case 0x7174B78FU /* F7                 */: return RGFW_keyF7;                   /* 0x0041 */
+		case 0x7174B780U /* F8                 */: return RGFW_keyF8;                   /* 0x0042 */
+		case 0x7174B781U /* F9                 */: return RGFW_keyF9;                   /* 0x0043 */
+		case 0x7B8E57B0U  /* F10                */: return RGFW_keyF10;                  /* 0x0044 */
+		case 0xC925FCDFU /* Numpad7            */: return RGFW_keyPadMultiply;             /* 0x0047 */
+		case 0xC925FCD0U /* Numpad8            */: return RGFW_keyPad8;             /* 0x0048 */
+		case 0xC925FCD1U /* Numpad9            */: return RGFW_keyPad9;             /* 0x0049 */
+		case 0x5EA3E8A4U /* NumpadSubtract     */: return RGFW_keyMinus;      /* 0x004A */
+		case 0xC925FCDCU /* Numpad4            */: return RGFW_keyPad4;             /* 0x004B */
+		case 0xC925FCDDU /* Numpad5            */: return RGFW_keyPad5;             /* 0x004C */
+		case 0xC925FCDEU /* Numpad6            */: return RGFW_keyPad6;             /* 0x004D */
+		case 0xC925FCD9U /* Numpad1            */: return RGFW_keyPad1;             /* 0x004F */
+		case 0xC925FCDAU /* Numpad2            */: return RGFW_keyPad2;             /* 0x0050 */
+		case 0xC925FCDBU /* Numpad3            */: return RGFW_keyPad3;             /* 0x0051 */
+		case 0xC925FCD8U /* Numpad0            */: return RGFW_keyPad0;             /* 0x0052 */
+		case 0x95852DACU /* NumpadDecimal      */: return RGFW_keyPeriod;       /* 0x0053 */
+		case 0x7B8E57B1U  /* F11                */: return RGFW_keyF11;                  /* 0x0057 */
+		case 0x7B8E57B2U  /* F12                */: return RGFW_keyF12;                  /* 0x0058 */
+		case 0x7B8E57B3U /* F13                */: return DOM_PK_F13;                  /* 0x0064 */
+		case 0x7B8E57B4U /* F14                */: return DOM_PK_F14;                  /* 0x0065 */
+		case 0x7B8E57B5U /* F15                */: return DOM_PK_F15;                  /* 0x0066 */
+		case 0x7B8E57B6U /* F16                */: return DOM_PK_F16;                  /* 0x0067 */
+		case 0x7B8E57B7U /* F17                */: return DOM_PK_F17;                  /* 0x0068 */
+		case 0x7B8E57B8U /* F18                */: return DOM_PK_F18;                  /* 0x0069 */
+		case 0x7B8E57B9U /* F19                */: return DOM_PK_F19;                  /* 0x006A */
+		case 0x7B8E57A8U /* F20                */: return DOM_PK_F20;                  /* 0x006B */
+		case 0x7B8E57A9U /* F21                */: return DOM_PK_F21;                  /* 0x006C */
+		case 0x7B8E57AAU /* F22                */: return DOM_PK_F22;                  /* 0x006D */
+		case 0x7B8E57ABU /* F23                */: return DOM_PK_F23;                  /* 0x006E */
+		case 0x7393FBACU /* NumpadEqual        */: return RGFW_keyPadReturn;
+		case 0xB88EBF7CU  /* AltRight           */: return RGFW_keyAltR;            /* 0xE038 */
+		case 0xC925873BU /* NumLock            */: return RGFW_keyNumLock;             /* 0xE045 */
+		case 0x2C595F45U /* Home               */: return RGFW_keyHome;                 /* 0xE047 */
+		case 0xC91BB690U /* ArrowUp            */: return RGFW_keyUp;             /* 0xE048 */
+		case 0x672F9210U /* PageUp             */: return RGFW_keyPageUp;              /* 0xE049 */
+		case 0x3799258CU /* ArrowLeft          */: return RGFW_keyLeft;           /* 0xE04B */
+		case 0x4CE33F7CU /* ArrowRight         */: return RGFW_keyRight;          /* 0xE04D */
+		case 0x7B8E55DCU  /* End                */: return RGFW_keyEnd;                  /* 0xE04F */
+		case 0x3799379EU /* ArrowDown          */: return RGFW_keyDown;           /* 0xE050 */
+		case 0xBA90179EU /* PageDown           */: return RGFW_keyPageDown;            /* 0xE051 */
+		case 0x6723CB2CU /* Insert             */: return RGFW_keyInsert;               /* 0xE052 */
+		case 0x6725C50DU /* Delete             */: return RGFW_keyDelete;               /* 0xE053 */
+		case 0x6723658CU /* OSLeft             */: return RGFW_keySuperL;              /* 0xE05B */
+		case 0x39643F7CU /* MetaRight          */: return RGFW_keySuperR;           /* 0xE05C */
+		case 0x380B9C8CU /* NumpadAdd          */: return DOM_PK_NUMPAD_ADD;           /* 0x004E */
+		default: return DOM_PK_UNKNOWN;
+	}
+
+	return 0;
+}
+
+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) {
+	RGFW_UNUSED(win);
+	return RGFW_getPrimaryMonitor();
+}
+
+/* unsupported functions */
+void RGFW_pollMonitors(void) { }
+void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
+void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; }
+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { RGFW_UNUSED(monitor); RGFW_UNUSED(x); RGFW_UNUSED(width); RGFW_UNUSED(height); return RGFW_FALSE; }
+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return 0; }
+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { RGFW_UNUSED(monitor); RGFW_UNUSED(ramp); return RGFW_FALSE; }
+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { RGFW_UNUSED(mon); RGFW_UNUSED(modes); return 0; }
+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); return RGFW_FALSE; }
+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win);  RGFW_UNUSED(x); RGFW_UNUSED(y);  }
+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win);  RGFW_UNUSED(w); RGFW_UNUSED(h);  }
+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h);  }
+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win);  RGFW_UNUSED(w); RGFW_UNUSED(h);  }
+void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
+void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border);  }
+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_UNUSED(win); RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format);  RGFW_UNUSED(type); return RGFW_FALSE;  }
+void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
+void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_UNUSED(win); RGFW_UNUSED(request); }
+RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
+RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
+void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); }
+#endif
+
+/* end of web asm defines */
+
+/*
+	* RGFW function pointer backend, made to allow you to compile for Wayland but fallback to X11
+*/
+#ifdef RGFW_DYNAMIC
+typedef RGFW_window* (*RGFW_createWindowPlatform_ptr)(const char* name, RGFW_windowFlags flags, RGFW_window* win);
+typedef RGFW_bool (*RGFW_getMouse_ptr)(i32* x, i32* y);
+typedef RGFW_key (*RGFW_physicalToMappedKey_ptr)(RGFW_key key);
+typedef void (*RGFW_pollEvents_ptr)(void);
+typedef RGFW_bool (*RGFW_window_fetchSize_ptr)(RGFW_window* win, i32* w, i32* h);
+typedef void (*RGFW_pollMonitors_ptr)(void);
+typedef void (*RGFW_window_move_ptr)(RGFW_window* win, i32 x, i32 y);
+typedef void (*RGFW_window_resize_ptr)(RGFW_window* win, i32 w, i32 h);
+typedef void (*RGFW_window_setAspectRatio_ptr)(RGFW_window* win, i32 w, i32 h);
+typedef void (*RGFW_window_setMinSize_ptr)(RGFW_window* win, i32 w, i32 h);
+typedef void (*RGFW_window_setMaxSize_ptr)(RGFW_window* win, i32 w, i32 h);
+typedef void (*RGFW_window_maximize_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_focus_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_raise_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_setFullscreen_ptr)(RGFW_window* win, RGFW_bool fullscreen);
+typedef void (*RGFW_window_setFloating_ptr)(RGFW_window* win, RGFW_bool floating);
+typedef void (*RGFW_window_setOpacity_ptr)(RGFW_window* win, u8 opacity);
+typedef void (*RGFW_window_minimize_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_restore_ptr)(RGFW_window* win);
+typedef RGFW_bool (*RGFW_window_isFloating_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_setName_ptr)(RGFW_window* win, const char* name);
+typedef void (*RGFW_window_setMousePassthrough_ptr)(RGFW_window* win, RGFW_bool passthrough);
+typedef RGFW_bool (*RGFW_window_setIconEx_ptr)(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type);
+typedef RGFW_mouse* (*RGFW_createMouse_ptr)(u8* data, i32 w, i32 h, RGFW_format format);
+typedef RGFW_mouse* (*RGFW_createMouseStandard_ptr)(RGFW_mouseIcon icons);
+typedef RGFW_bool (*RGFW_window_setMousePlatform_ptr)(RGFW_window* win, RGFW_mouse* mouse);
+typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y);
+typedef void (*RGFW_window_hide_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_show_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_flash_ptr)(RGFW_window* win, RGFW_flashRequest request);
+typedef RGFW_ssize_t (*RGFW_readClipboardPtr_ptr)(char* str, size_t strCapacity);
+typedef void (*RGFW_writeClipboard_ptr)(const char* text, u32 textLen);
+typedef RGFW_bool (*RGFW_window_isHidden_ptr)(RGFW_window* win);
+typedef RGFW_bool (*RGFW_window_isMinimized_ptr)(RGFW_window* win);
+typedef RGFW_bool (*RGFW_window_isMaximized_ptr)(RGFW_window* win);
+typedef RGFW_bool (*RGFW_monitor_requestMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request);
+typedef RGFW_bool (*RGFW_monitor_getWorkarea_ptr)(RGFW_monitor* mon, i32* x, i32* y, i32* w, i32* h);
+typedef size_t (*RGFW_monitor_getModesPtr_ptr)(RGFW_monitor* mon, RGFW_monitorMode** modes);
+typedef size_t (*RGFW_monitor_getGammaRampPtr_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
+typedef RGFW_bool (*RGFW_monitor_setGammaRamp_ptr) (RGFW_monitor* monitor, RGFW_gammaRamp* ramp);
+typedef RGFW_bool (*RGFW_monitor_setMode_ptr)(RGFW_monitor* mon, RGFW_monitorMode* mode);
+typedef RGFW_monitor* (*RGFW_window_getMonitor_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_closePlatform_ptr)(RGFW_window* win);
+typedef RGFW_format (*RGFW_nativeFormat_ptr)(void);
+typedef RGFW_bool (*RGFW_createSurfacePtr_ptr)(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface);
+typedef void (*RGFW_window_blitSurface_ptr)(RGFW_window* win, RGFW_surface* surface);
+typedef void (*RGFW_surface_freePtr_ptr)(RGFW_surface* surface);
+typedef void (*RGFW_freeMouse_ptr)(RGFW_mouse* mouse);
+typedef void (*RGFW_window_setBorder_ptr)(RGFW_window* win, RGFW_bool border);
+typedef void (*RGFW_window_captureMousePlatform_ptr)(RGFW_window* win, RGFW_bool state);
+typedef void (*RGFW_window_setRawMouseModePlatform_ptr)(RGFW_window* win, RGFW_bool state);
+#ifdef RGFW_OPENGL
+typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win);
+typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void);
+typedef void (*RGFW_window_swapBuffers_OpenGL_ptr)(RGFW_window* win);
+typedef void (*RGFW_window_swapInterval_OpenGL_ptr)(RGFW_window* win, i32 swapInterval);
+typedef RGFW_bool (*RGFW_extensionSupportedPlatform_OpenGL_ptr)(const char* extension, size_t len);
+typedef RGFW_proc (*RGFW_getProcAddress_OpenGL_ptr)(const char* procname);
+typedef RGFW_bool (*RGFW_window_createContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
+typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx);
+#endif
+#ifdef RGFW_WEBGPU
+typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance);
+#endif
+
+/* Structure to hold all function pointers */
+typedef struct RGFW_FunctionPointers {
+	RGFW_nativeFormat_ptr nativeFormat;
+	RGFW_createSurfacePtr_ptr createSurfacePtr;
+    RGFW_window_blitSurface_ptr window_blitSurface;
+	RGFW_surface_freePtr_ptr surface_freePtr;
+	RGFW_freeMouse_ptr freeMouse;
+    RGFW_window_setBorder_ptr window_setBorder;
+    RGFW_window_captureMousePlatform_ptr window_captureMousePlatform;
+	RGFW_window_setRawMouseModePlatform_ptr window_setRawMouseModePlatform;
+    RGFW_createWindowPlatform_ptr createWindowPlatform;
+    RGFW_getMouse_ptr getGlobalMouse;
+	RGFW_physicalToMappedKey_ptr physicalToMappedKey;
+    RGFW_window_fetchSize_ptr window_fetchSize;
+	RGFW_pollEvents_ptr pollEvents;
+    RGFW_pollMonitors_ptr pollMonitors;
+    RGFW_window_move_ptr window_move;
+    RGFW_window_resize_ptr window_resize;
+    RGFW_window_setAspectRatio_ptr window_setAspectRatio;
+    RGFW_window_setMinSize_ptr window_setMinSize;
+    RGFW_window_setMaxSize_ptr window_setMaxSize;
+    RGFW_window_maximize_ptr window_maximize;
+    RGFW_window_focus_ptr window_focus;
+    RGFW_window_raise_ptr window_raise;
+    RGFW_window_setFullscreen_ptr window_setFullscreen;
+    RGFW_window_setFloating_ptr window_setFloating;
+    RGFW_window_setOpacity_ptr window_setOpacity;
+    RGFW_window_minimize_ptr window_minimize;
+    RGFW_window_restore_ptr window_restore;
+    RGFW_window_isFloating_ptr window_isFloating;
+    RGFW_window_setName_ptr window_setName;
+    RGFW_window_setMousePassthrough_ptr window_setMousePassthrough;
+    RGFW_window_setIconEx_ptr window_setIconEx;
+    RGFW_createMouse_ptr createMouse;
+    RGFW_createMouseStandard_ptr createMouseStandard;
+    RGFW_window_setMousePlatform_ptr window_setMousePlatform;
+    RGFW_window_moveMouse_ptr window_moveMouse;
+    RGFW_window_hide_ptr window_hide;
+    RGFW_window_show_ptr window_show;
+    RGFW_window_flash_ptr window_flash;
+    RGFW_readClipboardPtr_ptr readClipboardPtr;
+    RGFW_writeClipboard_ptr writeClipboard;
+    RGFW_window_isHidden_ptr window_isHidden;
+    RGFW_window_isMinimized_ptr window_isMinimized;
+    RGFW_window_isMaximized_ptr window_isMaximized;
+    RGFW_monitor_requestMode_ptr monitor_requestMode;
+    RGFW_monitor_getWorkarea_ptr monitor_getWorkarea;
+	RGFW_monitor_getModesPtr_ptr monitor_getModesPtr;
+	RGFW_monitor_getGammaRampPtr_ptr monitor_getGammaRampPtr;
+	RGFW_monitor_setGammaRamp_ptr monitor_setGammaRamp;
+	RGFW_monitor_setMode_ptr monitor_setMode;
+    RGFW_window_getMonitor_ptr window_getMonitor;
+    RGFW_window_closePlatform_ptr window_closePlatform;
+#ifdef RGFW_OPENGL
+    RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL;
+    RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL;
+    RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL;
+    RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL;
+    RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL;
+    RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL;
+    RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL;
+    RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL;
+#endif
+#ifdef RGFW_WEBGPU
+    RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU;
+#endif
+} RGFW_functionPointers;
+
+RGFW_functionPointers RGFW_api;
+
+RGFW_format RGFW_nativeFormat(void) { return RGFW_api.nativeFormat(); }
+RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); }
+void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_api.surface_freePtr(surface); }
+void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_api.freeMouse(mouse); }
+void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api.window_blitSurface(win, surface); }
+void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); }
+void RGFW_window_captureMousePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_captureMousePlatform(win, state); }
+void RGFW_window_setRawMouseModePlatform(RGFW_window* win, RGFW_bool state) { RGFW_api.window_setRawMouseModePlatform(win, state); }
+RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); }
+RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); }
+RGFW_key RGFW_physicalToMappedKey(RGFW_key key) { return RGFW_api.physicalToMappedKey(key); }
+void RGFW_pollEvents(void) { RGFW_api.pollEvents(); }
+RGFW_bool RGFW_window_fetchSize(RGFW_window* win, i32* w, i32* h) { return RGFW_api.window_fetchSize(win, w, h); }
+void RGFW_pollMonitors(void) { RGFW_api.pollMonitors(); }
+void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); }
+void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); }
+void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); }
+void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); }
+void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); }
+void RGFW_window_maximize(RGFW_window* win) { RGFW_api.window_maximize(win); }
+void RGFW_window_focus(RGFW_window* win) { RGFW_api.window_focus(win); }
+void RGFW_window_raise(RGFW_window* win) { RGFW_api.window_raise(win); }
+void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); }
+void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); }
+void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); }
+void RGFW_window_minimize(RGFW_window* win) { RGFW_api.window_minimize(win); }
+void RGFW_window_restore(RGFW_window* win) { RGFW_api.window_restore(win); }
+RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return RGFW_api.window_isFloating(win); }
+void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_api.window_setName(win, name); }
+
+#ifndef RGFW_NO_PASSTHROUGH
+void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); }
+#endif
+
+RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type) { return RGFW_api.window_setIconEx(win, data, w, h, format, type); }
+RGFW_mouse* RGFW_createMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.createMouse(data, w, h, format); }
+RGFW_mouse* RGFW_createMouseStandard(RGFW_mouseIcon icon) { return RGFW_api.createMouseStandard(icon); }
+RGFW_bool RGFW_window_setMousePlatform(RGFW_window* win, RGFW_mouse* mouse) { return RGFW_api.window_setMousePlatform(win, mouse); }
+void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); }
+void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); }
+void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); }
+void RGFW_window_flash(RGFW_window* win, RGFW_flashRequest request) { RGFW_api.window_flash(win, request); }
+RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { return RGFW_api.readClipboardPtr(str, strCapacity); }
+void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_api.writeClipboard(text, textLen); }
+RGFW_bool RGFW_window_isHidden(RGFW_window* win) { return RGFW_api.window_isHidden(win); }
+RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { return RGFW_api.window_isMinimized(win); }
+RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return RGFW_api.window_isMaximized(win); }
+RGFW_bool RGFW_monitor_requestMode(RGFW_monitor* mon, RGFW_monitorMode* mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); }
+RGFW_bool RGFW_monitor_getWorkarea(RGFW_monitor* monitor, i32* x, i32* y, i32* width, i32* height) { return  RGFW_api.monitor_getWorkarea(monitor, x, y, width, height); }
+size_t RGFW_monitor_getGammaRampPtr(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_getGammaRampPtr(monitor, ramp); }
+RGFW_bool RGFW_monitor_setGammaRamp(RGFW_monitor* monitor, RGFW_gammaRamp* ramp) { return RGFW_api.monitor_setGammaRamp(monitor, ramp); }
+size_t RGFW_monitor_getModesPtr(RGFW_monitor* mon, RGFW_monitorMode** modes) { return RGFW_api.monitor_getModesPtr(mon, modes); }
+RGFW_bool RGFW_monitor_setMode(RGFW_monitor* mon, RGFW_monitorMode* mode) { return RGFW_api.monitor_setMode(mon, mode); }
+RGFW_monitor* RGFW_window_getMonitor(RGFW_window* win) { return RGFW_api.window_getMonitor(win); }
+void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform(win); }
+
+#ifdef RGFW_OPENGL
+RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); }
+RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { return RGFW_api.getProcAddress_OpenGL(procname); }
+RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); }
+void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); }
+void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { RGFW_api.window_makeCurrentContext_OpenGL(win); }
+void* RGFW_getCurrentContext_OpenGL(void) { return RGFW_api.getCurrentContext_OpenGL(); }
+void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_api.window_swapBuffers_OpenGL(win); }
+void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); }
+#endif
+
+#ifdef RGFW_WEBGPU
+WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); }
+#endif
+#endif  /* RGFW_DYNAMIC */
+
+/*
+ * start of X11 AND wayland defines
+ * this allows a single executable to support x11 AND wayland
+ * falling back to x11 if wayland fails to initalize
+*/
+#if defined(RGFW_WAYLAND) && defined(RGFW_X11)
+void RGFW_load_X11(void) {
+	RGFW_api.nativeFormat = RGFW_nativeFormat_X11;
+	RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11;
+    RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11;
+	RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11;
+	RGFW_api.freeMouse = RGFW_freeMouse_X11;
+    RGFW_api.window_setBorder = RGFW_window_setBorder_X11;
+    RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_X11;
+	RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_X11;
+	RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11;
+    RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11;
+    RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_X11;
+    RGFW_api.pollEvents = RGFW_pollEvents_X11;
+    RGFW_api.window_fetchSize = RGFW_window_fetchSize_X11;
+    RGFW_api.pollMonitors = RGFW_pollMonitors_X11;
+    RGFW_api.window_move = RGFW_window_move_X11;
+    RGFW_api.window_resize = RGFW_window_resize_X11;
+    RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11;
+    RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11;
+    RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11;
+    RGFW_api.window_maximize = RGFW_window_maximize_X11;
+    RGFW_api.window_focus = RGFW_window_focus_X11;
+    RGFW_api.window_raise = RGFW_window_raise_X11;
+    RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11;
+    RGFW_api.window_setFloating = RGFW_window_setFloating_X11;
+    RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11;
+    RGFW_api.window_minimize = RGFW_window_minimize_X11;
+    RGFW_api.window_restore = RGFW_window_restore_X11;
+    RGFW_api.window_isFloating = RGFW_window_isFloating_X11;
+    RGFW_api.window_setName = RGFW_window_setName_X11;
+#ifndef RGFW_NO_PASSTHROUGH
+    RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11;
+#endif
+    RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11;
+    RGFW_api.createMouse = RGFW_createMouse_X11;
+	RGFW_api.createMouseStandard = RGFW_createMouseStandard_X11;
+    RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_X11;
+    RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11;
+    RGFW_api.window_hide = RGFW_window_hide_X11;
+    RGFW_api.window_show = RGFW_window_show_X11;
+    RGFW_api.window_flash = RGFW_window_flash_X11;
+    RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11;
+    RGFW_api.writeClipboard = RGFW_writeClipboard_X11;
+    RGFW_api.window_isHidden = RGFW_window_isHidden_X11;
+    RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11;
+    RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11;
+    RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11;
+    RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_X11;
+    RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_X11;
+    RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_X11;
+	RGFW_api.monitor_setMode = RGFW_monitor_setMode_X11;
+    RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11;
+    RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11;
+#ifdef RGFW_OPENGL
+    RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11;
+    RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11;
+	RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11;
+    RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11;
+	RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11;
+    RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11;
+    RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11;
+    RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11;
+#endif
+#ifdef RGFW_WEBGPU
+    RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11;
+#endif
+}
+
+void RGFW_load_Wayland(void) {
+	RGFW_api.nativeFormat = RGFW_nativeFormat_Wayland;
+	RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland;
+	RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland;
+    RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland;
+	RGFW_api.freeMouse = RGFW_freeMouse_Wayland;
+	RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland;
+    RGFW_api.window_captureMousePlatform = RGFW_window_captureMousePlatform_Wayland;
+	RGFW_api.window_setRawMouseModePlatform = RGFW_window_setRawMouseModePlatform_Wayland;
+    RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland;
+    RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland;
+    RGFW_api.physicalToMappedKey = RGFW_physicalToMappedKey_Wayland;
+    RGFW_api.pollEvents = RGFW_pollEvents_Wayland;
+    RGFW_api.window_fetchSize = RGFW_window_fetchSize_Wayland;
+    RGFW_api.pollMonitors = RGFW_pollMonitors_Wayland;
+    RGFW_api.window_move = RGFW_window_move_Wayland;
+    RGFW_api.window_resize = RGFW_window_resize_Wayland;
+    RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland;
+    RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland;
+    RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland;
+    RGFW_api.window_maximize = RGFW_window_maximize_Wayland;
+    RGFW_api.window_focus = RGFW_window_focus_Wayland;
+    RGFW_api.window_raise = RGFW_window_raise_Wayland;
+    RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland;
+    RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland;
+    RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland;
+    RGFW_api.window_minimize = RGFW_window_minimize_Wayland;
+    RGFW_api.window_restore = RGFW_window_restore_Wayland;
+    RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland;
+    RGFW_api.window_setName = RGFW_window_setName_Wayland;
+#ifndef RGFW_NO_PASSTHROUGH
+    RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland;
+#endif
+    RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland;
+    RGFW_api.createMouse = RGFW_createMouse_Wayland;
+	RGFW_api.createMouseStandard = RGFW_createMouseStandard_Wayland;
+    RGFW_api.window_setMousePlatform = RGFW_window_setMousePlatform_Wayland;
+    RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland;
+    RGFW_api.window_hide = RGFW_window_hide_Wayland;
+    RGFW_api.window_show = RGFW_window_show_Wayland;
+    RGFW_api.window_flash = RGFW_window_flash_X11;
+    RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland;
+    RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland;
+    RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland;
+    RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland;
+    RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland;
+    RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland;
+    RGFW_api.monitor_getModesPtr = RGFW_monitor_getModesPtr_Wayland;
+    RGFW_api.monitor_setGammaRamp = RGFW_monitor_setGammaRamp_Wayland;
+    RGFW_api.monitor_getGammaRampPtr = RGFW_monitor_getGammaRampPtr_Wayland;
+	RGFW_api.monitor_setMode = RGFW_monitor_setMode_Wayland;
+    RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland;
+    RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland;
+#ifdef RGFW_OPENGL
+    RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland;
+    RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland;
+	RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland;
+    RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland;
+	RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland;
+    RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland;
+    RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland;
+    RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland;
+#endif
+#ifdef RGFW_WEBGPU
+    RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland;
+#endif
+}
+#endif /* wayland AND x11 */
+/* end of X11 AND wayland defines */
+
+#endif /* RGFW_IMPLEMENTATION */
+
+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
+}
+#endif
+
+#if _MSC_VER
+	#pragma warning( pop )
+#endif
diff --git a/raylib/src/external/RGFW/deps/minigamepad.h b/raylib/src/external/RGFW/deps/minigamepad.h
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/RGFW/deps/minigamepad.h
@@ -0,0 +1,5242 @@
+/*
+*
+*   minigamepad - alpha
+
+* Copyright (C) 2025 ColleagueRiley
+*
+* libpng license
+*
+* 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.
+*
+*
+*/
+
+/*
+    (MAKE SURE MG_IMPLEMENTATION is in exactly one header or you use -D MG_IMPLEMENTATION)
+    #define MG_IMPLEMENTATION - makes it so source code is included with header
+*/
+
+/*
+    #define MG_IMPLEMENTATION - (required) makes it so the source code is included
+    #define MG_ALLOC x  - choose the default allocation function (defaults to standard malloc)
+    #define MG_FREE x  - choose the default deallocation function (defaults to standard free)
+
+    #define MG_EXPORT - use when building minigamepad
+    #define MG_IMPORT - use when linking with minigamepad (not as a single-header)
+
+    #define MG_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
+    #define mg_bool x - choose what type to use for bool, by default u32 is used
+
+    #define MG_MAX_GAMEPADS x - set the max number of gamepads (4 by default)
+*/
+
+
+
+/*
+    Credits :
+        GLFW and SDL - used as a resource
+        https:///github.com/MysteriousJ/Joystick-Input-Examples - good resoruce for learning how to use gamepad code
+
+        contributors : (feel free to put yourself here if you contribute)
+*/
+
+#if _MSC_VER
+    #if _MSC_VER < 600
+        #define MG_C89
+    #endif
+#else
+    #if defined(__STDC__) && !defined(__STDC_VERSION__)
+        #define MG_C89
+    #endif
+#endif
+
+#ifndef MG_UNUSED
+    #define MG_UNUSED(x) (void)(x)
+#endif
+
+#ifndef MG_ALLOC
+    #include <stdlib.h>
+    #define MG_ALLOC malloc
+    #define MG_FREE free
+#endif
+
+#ifndef MG_ASSERT
+    #include <assert.h>
+    #define MG_ASSERT assert
+#endif
+
+#if !defined(MG_MEMCPY) || !defined(MG_STRNCMP) || !defined(MG_STRNCPY) || !defined(MG_MEMSET) || !defined(MG_STRCSPN) || !defined(MG_STRSPN)
+    #include <string.h>
+#endif
+
+#ifndef MG_MEMSET
+    #define MG_MEMSET(ptr, value, num) memset(ptr, value, num)
+#endif
+
+#ifndef MG_MEMCPY
+    #define MG_MEMCPY(dist, src, len) memcpy(dist, src, len)
+#endif
+
+#ifndef MG_STRNCMP
+    #define MG_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
+#endif
+
+#ifndef MG_STRNCPY
+    #define MG_STRNCPY(dist, src, len) strncpy(dist, src, len)
+#endif
+
+#ifndef MG_STRCSPN
+    #define MG_STRCSPN(str1, str2) strcspn(str1, str2)
+#endif
+
+#ifndef MG_STRSPN
+    #define MG_STRSPN(str1, str2) strspn(str1, str2)
+#endif
+
+#if !defined(MG_SPRINTF) || !defined(MG_FPRINTF)
+    #include <stdio.h>
+#endif
+
+
+#if !defined(MG_SPRINTF)
+    #define MG_SPRINTF sprintf
+#endif
+
+#if !defined(MG_FPRINTF)
+    #define MG_FPRINTF fprintf
+#endif
+
+#ifndef MG_FABS
+#include <math.h>
+#define MG_FABS(x) fabs(x)
+#endif
+
+#if defined(MG_EXPORT) ||  defined(MG_IMPORT)
+    #if defined(_WIN32)
+        #if defined(__TINYC__) && (defined(MG_EXPORT) ||  defined(MG_IMPORT))
+            #define __declspec(x) __attribute__((x))
+        #endif
+
+        #if defined(MG_EXPORT)
+            #define MG_API __declspec(dllexport)
+        #else
+            #define MG_API __declspec(dllimport)
+        #endif
+    #else
+        #if defined(MG_EXPORT)
+            #define MG_API __attribute__((visibility("default")))
+        #endif
+    #endif
+    #ifndef MG_API
+        #define MG_API
+    #endif
+#endif
+
+#ifndef MG_API
+    #ifdef MG_C89
+        #define MG_API
+    #else
+        #define MG_API inline
+    #endif
+#endif
+
+#ifndef MG_ENUM
+    #define MG_ENUM(type, name) type name; enum
+#endif
+
+
+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
+    extern "C" {
+#endif
+
+    /* makes sure the header file part is only defined once by default */
+#ifndef MG_HEADER
+
+#define MG_HEADER
+
+#ifdef __EMSCRIPTEN__
+    #define MG_WASM
+#elif defined(_WIN32) || defined(__WIN32) || defined(__WIN32__)
+    #define MG_WINDOWS
+#elif defined(__linux__)
+    #define MG_LINUX
+#elif defined(__APPLE__)
+    #define MG_MACOS
+#endif
+
+#ifndef MG_INT_DEFINED
+    #ifdef MG_USE_INT /* optional for any system that might not have stdint.h */
+        typedef unsigned char       u8;
+        typedef signed char         i8;
+        typedef unsigned short     u16;
+        typedef signed short       i16;
+        typedef unsigned long int  u32;
+        typedef signed long int    i32;
+        typedef unsigned long long u64;
+        typedef signed long long   i64;
+
+
+        typedef signed long mg_ssize_t;
+        typedef unsigned long mg_size_t;
+    #else /* use stdint standard types instead of c "standard" types */
+        #include <stdint.h>
+        #include <stddef.h>
+
+        typedef uint8_t     u8;
+        typedef int8_t      i8;
+        typedef uint16_t   u16;
+        typedef int16_t    i16;
+        typedef uint32_t   u32;
+        typedef int32_t    i32;
+        typedef uint64_t   u64;
+        typedef int64_t    i64;
+
+#ifdef __linux__
+        #include <sys/types.h>
+        typedef ssize_t mg_ssize_t;
+#endif
+        typedef size_t mg_size_t;
+    #endif
+    #define MG_INT_DEFINED
+#endif
+
+#ifndef MG_BOOL_DEFINED
+    #define MG_BOOL_DEFINED
+    typedef u8 mg_bool;
+#endif
+
+#define MG_BOOL(x) (mg_bool)((x) ? MG_TRUE : MG_FALSE) /* force an value to be 0 or 1 */
+#define MG_TRUE (mg_bool)1
+#define MG_FALSE (mg_bool)0
+
+#ifndef MG_MAX_GAMEPADS
+    #define MG_MAX_GAMEPADS 4
+#endif
+
+#ifndef MG_MAX_EVENTS
+    #define MG_MAX_EVENTS 32
+#endif
+
+/**!
+ * @brief global stucture for the source API data of all the gamepads
+*/
+typedef struct mg_gamepads_src mg_gamepads_src;
+
+/**!
+ * @brief global stucture for the data of all the gamepads
+*/
+typedef struct mg_gamepads mg_gamepads;
+
+/**!
+ * @brief the source API data of the gamepad object
+*/
+typedef struct mg_gamepad_src mg_gamepad_src;
+
+/**!
+ * @brief data stucture for gamepad objects
+*/
+typedef struct mg_gamepad mg_gamepad;
+
+/**!
+ * @brief source gamepad list object
+*/
+typedef struct mg_gamepad_list {
+    mg_gamepad* head; /* head node of the list */
+    mg_gamepad* cur; /* current/tail node of the list */
+    mg_size_t count; /* number of nodes */
+} mg_gamepad_list;
+
+/**!
+ * @brief abstract constants for gamepad buttons
+*/
+typedef MG_ENUM(i8, mg_button) {
+    MG_BUTTON_UNKNOWN = -1,
+    MG_BUTTON_SOUTH,           /**< Bottom face button (e.g. Xbox A button) */
+    MG_BUTTON_EAST,            /**< Right face button (e.g. Xbox B button) */
+    MG_BUTTON_WEST,            /**< Left face button (e.g. Xbox X button) */
+    MG_BUTTON_NORTH,           /**< Top face button (e.g. Xbox Y button) */
+    MG_BUTTON_BACK,             /**< back (or select) button on the gamepad */
+    MG_BUTTON_GUIDE,            /**< guide button on the controller (e.g. the Xbox button or ps button) */
+    MG_BUTTON_START,            /**< start button on the gamepad */
+    MG_BUTTON_LEFT_STICK,       /**< left stick button (L3) */
+    MG_BUTTON_RIGHT_STICK,      /**< left shoulder button (R4) */
+    MG_BUTTON_LEFT_SHOULDER,    /**< left shoulder button (L1) */
+    MG_BUTTON_RIGHT_SHOULDER,   /**< left shoulder button (R1) */
+    MG_BUTTON_DPAD_LEFT,        /**< dpad left button */
+    MG_BUTTON_DPAD_RIGHT,       /**< dpad right button */
+    MG_BUTTON_DPAD_UP,          /**< dpad up button */
+    MG_BUTTON_DPAD_DOWN,        /**< dpad down button */
+    MG_BUTTON_LEFT_TRIGGER,     /**< left trigger button (L2) */
+    MG_BUTTON_RIGHT_TRIGGER,    /**< right trigger button (R2) */
+ /* extras */
+    MG_BUTTON_MISC1,           /**< Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button) */
+    MG_BUTTON_RIGHT_PADDLE1,   /**< Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) */
+    MG_BUTTON_LEFT_PADDLE1,    /**< Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) */
+    MG_BUTTON_RIGHT_PADDLE2,   /**< Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) */
+    MG_BUTTON_LEFT_PADDLE2,    /**< Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) */
+    MG_BUTTON_TOUCHPAD,        /**< PS4/PS5 touchpad button */
+    MG_BUTTON_MISC2,           /**< Additional button */
+    MG_BUTTON_MISC3,           /**< Additional button */
+    MG_BUTTON_MISC4,           /**< Additional button */
+    MG_BUTTON_MISC5,           /**< Additional button */
+    MG_BUTTON_MISC6,           /**< Additional button */
+    MG_BUTTON_COUNT
+};
+
+/**!
+ * @brief abstract constants for gamepad axes
+*/
+typedef MG_ENUM(i8, mg_axis) {
+    MG_AXIS_UNKNOWN = -1, /**< */
+    MG_AXIS_LEFT_X, /**< X axis of the left stick */
+    MG_AXIS_LEFT_Y, /**< Y axis of the left stick */
+    MG_AXIS_RIGHT_X, /**< X axis of the right stick */
+    MG_AXIS_RIGHT_Y, /**< Y axis of the left stick */
+    MG_AXIS_LEFT_TRIGGER, /**< Axis of the left triggle (0 - 1) */
+    MG_AXIS_RIGHT_TRIGGER, /**< Axis of the right triggle (0 - 1) */
+    MG_AXIS_HAT_DPAD_LEFT_RIGHT, /**< d-pad left-right hat value  */
+    MG_AXIS_HAT_DPAD_LEFT = MG_AXIS_HAT_DPAD_LEFT_RIGHT,
+    MG_AXIS_HAT_DPAD_RIGHT = MG_AXIS_HAT_DPAD_LEFT_RIGHT,
+    MG_AXIS_HAT_DPAD_UP_DOWN, /**<  d-pad up-down hat value */
+    MG_AXIS_HAT_DPAD_UP = MG_AXIS_HAT_DPAD_UP_DOWN, /**< */
+    MG_AXIS_HAT_DPAD_DOWN = MG_AXIS_HAT_DPAD_UP_DOWN,
+/* extras */
+    MG_AXIS_THROTTLE,
+    MG_AXIS_RUDDER,
+    MG_AXIS_WHEEL,
+    MG_AXIS_GAS,
+    MG_AXIS_BRAKE,
+    MG_AXIS_HAT1X,
+    MG_AXIS_HAT1Y,
+    MG_AXIS_HAT2X,
+    MG_AXIS_HAT2Y,
+    MG_AXIS_HAT3X,
+    MG_AXIS_HAT3Y,
+    MG_AXIS_PRESSURE,
+    MG_AXIS_DISTANCE,
+    MG_AXIS_TILT_X,
+    MG_AXIS_TILT_Y,
+    MG_AXIS_TOOL_WIDTH,
+    MG_AXIS_VOLUME,
+    MG_AXIS_PROFILE,
+    MG_AXIS_MISC,
+
+    MG_AXIS_COUNT
+};
+
+/**!
+ * @brief the type of event in the queue
+*/
+typedef MG_ENUM(u8, mg_event_type) {
+    MG_EVENT_NONE = 0, /**< no/null event */
+    MG_EVENT_GAMEPAD_CONNECT, /**< a new gamepad connected */
+    MG_EVENT_GAMEPAD_DISCONNECT, /**< a gamepad was disconnected */
+    MG_EVENT_BUTTON_PRESS, /**< gamepad button was pressed */
+    MG_EVENT_BUTTON_RELEASE, /**< gamepad button was released */
+    MG_EVENT_AXIS_MOVE /**< gamepad axis was moved/changed */
+};
+
+/**!
+ * @brief button (press or release) event type
+*/
+typedef struct mg_button_state {
+    mg_bool supported; /* if the button is supported or not by the gamepad */
+    mg_bool current; /* the current state of the button */
+    mg_bool prev; /* the previous state of the button */
+} mg_button_state;
+
+/**!
+ * @brief axis motion event type
+*/
+typedef struct mg_axis_state {
+    mg_bool supported; /* if the axis is supported or not by the gamepad */
+    float value; /* the current value of the axis */
+    float deadzone; /* deadzones of the axis */
+} mg_axis_state;
+
+/**!
+ * @brief event structure for processing event data
+*/
+typedef struct mg_event {
+    mg_event_type type; /* the type of event */
+    mg_button button; /* button value */
+    mg_axis axis; /* axis value */
+    mg_gamepad* gamepad; /* which gamepad */
+} mg_event;
+
+/**!
+ * @brief stucture for all event data for collecting events
+*/
+typedef struct mg_events {
+    mg_event queue[MG_MAX_EVENTS]; /* event queue array for collecting the frame's events */
+    size_t len; /* the number of events in the array */
+} mg_events;
+
+/* callbacks */
+/**!
+ * @brief type for the connection callback function
+*/
+typedef void (*mg_gamepad_connection_func)(mg_gamepad* gamepad, mg_bool connected);
+
+/**!
+ * @brief type for the button state callback function
+*/
+typedef void (*mg_gamepad_button_func)(mg_gamepad* gamepad, mg_button button, mg_bool pressed);
+
+/**!
+ * @brief type for the axis move callback function
+*/
+typedef void (*mg_gamepad_axis_func)(mg_gamepad* gamepad, mg_axis);
+
+/**!
+ * @brief init gamepads, api and internal data
+ * @param pointer to a pre-allocated gamepads object
+*/
+MG_API void mg_gamepads_init(mg_gamepads* gamepads);
+
+/**!
+ * @brief enable or disable the event queue [disabled by default and enabled by default when mg_gamepads_check_event is called]
+ * @param gamepads object to modify
+*/
+MG_API void mg_gamepads_set_queue_events(mg_gamepads* gamepads, mg_bool queue_events);
+
+/**!
+ * @brief poll information on the gamepads
+ * @param gamepads object that needs to be updated
+ * @return returns a boolean value if there was an event or not to process
+*/
+MG_API mg_bool mg_gamepads_poll(mg_gamepads* gamepads);
+
+/**!
+ * @brief check and pop top event in the gamepad's event queue, does not poll for events
+ * @param gamepads object that needs to be updated
+ * @param pointer to a event object to fill the event with [can be NULL]
+ * @return returns a boolean value if there was an event or not to process
+*/
+MG_API mg_bool mg_gamepads_check_queued_event(mg_gamepads* gamepads, mg_event* event);
+
+/**!
+ * @brief poll for events if they weren't already polled then check and pop the top event in the event queue
+ * @param gamepads object that needs to be updated
+ * @param pointer to a event object to fill the event with [can be NULL]
+ * @return returns a boolean value if there was an event or not to process
+*/
+MG_API mg_bool mg_gamepads_check_event(mg_gamepads* gamepads, mg_event* event);
+
+/**!
+ * @brief free internal gamepads data
+ * @param gamepads object
+*/
+MG_API void mg_gamepads_free(mg_gamepads* gamepads);
+
+/**!
+ * @brief returns if a button of a gamepad was pressed or not
+ * @param gamepad object
+ * @param button to check
+ * @return boolean value button for if the button was pressed
+*/
+
+MG_API mg_bool mg_gamepad_button_is_pressed(mg_gamepad* gamepad, mg_button button);
+
+
+/* add a new mapping */
+/**!
+ * @brief returns if a button of a gamepad was released down or not
+ * @param the gamepad object
+ * @param button to check
+ * @return the boolean value for if the button was released
+*/
+
+MG_API mg_bool mg_gamepad_button_is_released(mg_gamepad* gamepad, mg_button button);
+
+/* add a new mapping */
+/**!
+ * @brief returns if a button of a gamepad is down or not
+ * @param the gamepad object
+ * @param the button to check
+ * @return the boolean state of the button
+*/
+
+MG_API mg_bool mg_gamepad_button_is_down(mg_gamepad* gamepad, mg_button button);
+
+/* add a new mapping */
+/**!
+ * @brief returns the axis value of an axis of a gamepad
+ * @param the source gamepad object
+ * @param the axis to check
+ * @return the current floating point value of the axis
+*/
+
+MG_API float mg_gamepad_axis_value(mg_gamepad* gamepad, mg_axis axis);
+
+/* add a new mapping */
+/**!
+ * @brief set the function object for gamepad connection events
+ * @param the function object to use
+ * @return the original function object in use
+*/
+
+MG_API mg_gamepad_connection_func mg_set_gamepad_connected_callback(mg_gamepad_connection_func func);
+
+/**!
+ * @brief set the function object for gamepad release events
+ * @param the function object to use
+ * @return the original function object in use
+*/
+MG_API mg_gamepad_button_func mg_set_gamepad_release_callback(mg_gamepad_button_func func);
+
+/**!
+ * @brief set the function object for gamepad axis movement aevents
+ * @param the function object to use
+ * @return the current function object in use
+*/
+MG_API mg_gamepad_axis_func mg_set_gamepad_axis_callback(mg_gamepad_axis_func func);
+
+/**!
+ * @brief set the gamepad disconnected callback function object
+ * @param the function object to use
+ * @return the original value of the disconnected callback
+*/
+
+MG_API mg_gamepad_connection_func mg_set_gamepad_disconnected_callback(mg_gamepad_connection_func func);
+
+/**!
+ * @brief set the gamepad press callbqack function to use
+ * @param the function object to use
+ * @return the original value of the gamepad press callback
+*/
+MG_API mg_gamepad_button_func mg_set_gamepad_press_callback(mg_gamepad_button_func func);
+
+/* add a new mapping */
+/**!
+ * @brief update the mappings the gamepads object uses with a new mapping
+ * @param the new mapping string
+ * @return returns a boolean value based on success
+*/
+MG_API mg_bool mg_update_gamepad_mappings(mg_gamepads* gamepads, const char* string);
+
+/**!
+ * @brief fetch the string name of a button (for testing)
+ * @param the button enum value
+ * @return constant c-string that represents the button's name
+*/
+MG_API const char* mg_button_get_name(mg_button button);
+
+/**!
+ * @brief fetch the string name of a axis (for testing)
+ * @param the axis enum value
+ * @return constant c-string that represents the axis's name
+*/
+MG_API const char* mg_axis_get_name(mg_axis axis);
+
+#endif /* MG_HEADER */
+
+#if (defined(MG_NATIVE) || defined(MG_IMPLEMENTATION)) && !defined(MG_NATIVE_HEADER)
+#define MG_NATIVE_HEADER
+
+#ifdef MG_LINUX
+
+struct mg_input_absinfo {
+    i32 value;
+    i32 minimum;
+    i32 maximum;
+    i32 fuzz;
+    i32 flat;
+    i32 resolution;
+};
+
+struct mg_gamepad_src {
+    int fd;
+    u8 keyMap[512];
+    u8 absMap[64];
+    struct mg_input_absinfo absInfo[64];
+    char full_path[256];
+};
+
+#elif defined(MG_WINDOWS)
+
+struct mg_gamepad_src {
+    void* device;
+    u32 xinput_index;
+};
+
+#elif defined(MG_MACOS)
+
+struct mg_gamepad_src {
+    void* device;
+    void* events;
+};
+
+#elif defined(MG_WASM)
+
+struct mg_gamepad_src {
+    int index;
+};
+
+#endif
+
+struct mg_mapping;
+
+struct mg_gamepad {
+    char name[128];
+    char guid[33];
+
+    mg_button_state buttons[MG_BUTTON_COUNT];
+    mg_axis_state axes[MG_AXIS_COUNT];
+
+    mg_bool connected;
+    mg_size_t index; /* index in gamepad array */
+
+    struct mg_mapping* mapping;
+    struct mg_gamepad* prev;
+    struct mg_gamepad* next;
+    mg_gamepad_src src;
+};
+
+#ifdef MG_LINUX
+#include <linux/input.h>
+#include <linux/input-event-codes.h>
+
+struct mg_gamepads_src {
+    int inotify, watch;
+};
+#elif defined(MG_WINDOWS)
+struct mg_gamepads_src {
+    void* dinput;
+    void* ginput;
+    void* dummy_win;
+};
+#elif defined(MG_MACOS)
+struct mg_gamepads_src {
+    void* hidManager;
+};
+#elif defined(MG_WASM)
+struct mg_gamepads_src {
+    int TODO;
+};
+#endif
+
+struct mg_gamepads {
+    mg_gamepad gamepads[MG_MAX_GAMEPADS];
+
+    mg_gamepad_list list;
+    mg_gamepad_list free_list;
+
+    mg_events events;
+
+    mg_bool queue_events;
+    mg_bool polled_events;
+
+    mg_gamepads_src src;
+};
+
+#endif /* MG_NATIVE */
+
+#ifdef MG_IMPLEMENTATION
+
+/* gamepads->src.global API */
+/* find a valid unused gamepad or return NULL */
+MG_API mg_gamepad* mg_gamepad_find(mg_gamepads* gamepads);
+MG_API void mg_gamepad_release(mg_gamepads* gamepads, mg_gamepad* gamepad);
+MG_API void mg_list_swap_gamepad(mg_gamepad_list* from, mg_gamepad_list* to, mg_gamepad* gamepad);
+
+/* gamepads->src.platform-specific API */
+MG_API void mg_gamepads_init_platform(mg_gamepads* gamepads);
+/* updates gamepad structure by checking if any new gamepads are connected and adding them */
+MG_API mg_bool mg_gamepads_poll_platform(mg_gamepads* gamepads, mg_events* events);
+MG_API void mg_gamepads_free_platform(mg_gamepads* gamepads);
+MG_API mg_bool mg_gamepad_update_platform(mg_gamepad* gamepad, mg_events* events);
+MG_API void mg_gamepad_release_platform(mg_gamepad* gamepad);
+MG_API mg_button mg_get_gamepad_button_platform(u32 button);
+MG_API mg_axis mg_get_gamepad_axis_platform(u32 axis);
+
+/* gamepads->src.mappings API */
+MG_API struct mg_mapping* mg_gamepad_find_valid_mapping(mg_gamepad* gamepad);
+MG_API mg_button mg_get_gamepad_button(mg_gamepad* gamepad, u8 button);
+MG_API mg_axis mg_get_gamepad_axis(mg_gamepad* gamepad, u8 axis);
+MG_API void mg_mappings_init(void);
+/* public/global API implementation */
+
+mg_bool mg_gamepad_button_is_pressed(mg_gamepad* gamepad, mg_button button) {
+    return gamepad->buttons[button].current;
+}
+
+mg_bool mg_gamepad_button_is_released(mg_gamepad* gamepad, mg_button button) {
+    return gamepad->buttons[button].prev && !gamepad->buttons[button].current;
+}
+
+mg_bool mg_gamepad_button_is_down(mg_gamepad* gamepad, mg_button button) {
+    return gamepad->buttons[button].prev && gamepad->buttons[button].current;
+}
+
+float mg_gamepad_axis_value(mg_gamepad* gamepad, mg_axis axis) {
+    return gamepad->axes[axis].value;
+}
+
+static mg_gamepad_connection_func mg_gamepad_connected_callback = NULL;
+
+mg_gamepad_connection_func mg_set_gamepad_connected_callback(mg_gamepad_connection_func func) {
+    mg_gamepad_connection_func prev = mg_gamepad_connected_callback;
+    mg_gamepad_connected_callback = func;
+    return prev;
+}
+
+static mg_gamepad_connection_func mg_gamepad_disconnected_callback = NULL;
+
+mg_gamepad_connection_func mg_set_gamepad_disconnected_callback(mg_gamepad_connection_func func) {
+    mg_gamepad_connection_func prev = mg_gamepad_disconnected_callback;
+    mg_gamepad_disconnected_callback = func;
+    return prev;
+}
+
+static mg_gamepad_button_func mg_gamepad_press_callback = NULL;
+
+mg_gamepad_button_func mg_set_gamepad_press_callback(mg_gamepad_button_func func) {
+    mg_gamepad_button_func prev = mg_gamepad_press_callback;
+    mg_gamepad_press_callback = func;
+    return prev;
+}
+
+static mg_gamepad_button_func mg_gamepad_release_callback = NULL;
+#define mg_release_callback(gamepad, button) if (mg_gamepad_release_callback) mg_gamepad_release_callback(gamepad, button, MG_FALSE)
+
+mg_gamepad_button_func mg_set_gamepad_release_callback(mg_gamepad_button_func func) {
+    mg_gamepad_button_func prev = mg_gamepad_release_callback;
+    mg_gamepad_release_callback = func;
+    return prev;
+}
+
+static mg_gamepad_axis_func mg_gamepad_axis_callback = NULL;
+mg_gamepad_axis_func mg_set_gamepad_axis_callback(mg_gamepad_axis_func func) {
+    mg_gamepad_axis_func prev = mg_gamepad_axis_callback;
+    mg_gamepad_axis_callback = func;
+    return prev;
+}
+
+void mg_handle_event(mg_events* events, mg_event_type type, mg_button btn, mg_axis axis, mg_bool state, float value, mg_gamepad* gamepad) {
+    mg_event event;
+    event.gamepad = gamepad;
+    event.axis = axis;
+    event.button = btn;
+
+    switch (type) {
+        case MG_EVENT_GAMEPAD_CONNECT:
+        case MG_EVENT_GAMEPAD_DISCONNECT:
+            if (state) {
+                type = MG_EVENT_GAMEPAD_CONNECT;
+                if (mg_gamepad_connected_callback) mg_gamepad_connected_callback(gamepad, state);
+            } else {
+                type = MG_EVENT_GAMEPAD_DISCONNECT;
+                if (mg_gamepad_disconnected_callback) mg_gamepad_disconnected_callback(gamepad, state);
+            }
+            break;
+        case MG_EVENT_BUTTON_PRESS:
+        case MG_EVENT_BUTTON_RELEASE:
+            if (state == gamepad->buttons[btn].current) {
+                return;
+            }
+
+            gamepad->buttons[btn].prev = gamepad->buttons[btn].current;
+            gamepad->buttons[btn].current = state;
+            if (state) {
+                type = MG_EVENT_BUTTON_PRESS;
+                if (mg_gamepad_press_callback) mg_gamepad_press_callback(gamepad, btn, state);
+            }
+            else {
+                type = MG_EVENT_BUTTON_RELEASE;
+                if (mg_gamepad_release_callback) mg_gamepad_release_callback(gamepad, btn, state);
+            }
+            break;
+        case MG_EVENT_AXIS_MOVE:
+            if (value == gamepad->axes[axis].value) {
+                return;
+            }
+
+            gamepad->axes[axis].value = value;
+            if (mg_gamepad_axis_callback) mg_gamepad_axis_callback(gamepad, axis);
+            break;
+        default: break;
+    }
+
+    /* push event */
+    if (events == NULL || events->len >= MG_MAX_EVENTS) {
+        return;
+    }
+
+    event.type = type;
+    events->len += 1;
+    events->queue[MG_MAX_EVENTS - events->len] = event;
+}
+
+#define mg_handle_connection_event(events, state, gamepad) mg_handle_event(events, MG_EVENT_GAMEPAD_CONNECT, 0, 0, state, 0, gamepad)
+#define mg_handle_button_event(events, btn, state, gamepad) mg_handle_event(events, MG_EVENT_BUTTON_PRESS, btn, 0, state, 0, gamepad)
+#define mg_handle_axis_event(events, axis, value, gamepad) mg_handle_event(events, MG_EVENT_AXIS_MOVE, 0, axis, 0, value, gamepad)
+
+void mg_gamepads_init(mg_gamepads* gamepads) {
+    MG_ASSERT(gamepads != NULL);
+
+    gamepads->polled_events = MG_FALSE;
+    gamepads->queue_events = MG_FALSE;
+
+    mg_mappings_init();
+    MG_MEMSET(gamepads, 0, sizeof(mg_gamepads));
+
+    /* create free list */
+    gamepads->free_list.head = &gamepads->gamepads[0];
+    gamepads->free_list.cur = gamepads->free_list.head;
+
+    {
+        mg_size_t i;
+        for (i = 0; i < MG_MAX_GAMEPADS; i++) {
+            gamepads->free_list.cur->prev = NULL;
+            gamepads->free_list.cur->next = NULL;
+
+            if (i) {
+                gamepads->free_list.cur->prev = &gamepads->gamepads[i - 1];
+            }
+
+            if (i != MG_MAX_GAMEPADS - 1) {
+                gamepads->free_list.cur->next = &gamepads->gamepads[i + 1];
+                gamepads->free_list.cur = gamepads->free_list.cur->next;
+            }
+        }
+    }
+
+    mg_gamepads_init_platform(gamepads);
+}
+
+void mg_gamepads_set_queue_events(mg_gamepads* gamepads, mg_bool queue_events) {
+    gamepads->polled_events = queue_events;
+}
+
+mg_bool mg_gamepads_poll(mg_gamepads* gamepads) {
+    mg_gamepad* cur;
+    mg_bool out = MG_FALSE;
+
+    mg_events* events = (gamepads->queue_events) ? &gamepads->events : NULL;
+
+    if (mg_gamepads_poll_platform(gamepads, events)) {
+        out = MG_TRUE;
+    }
+
+    for (cur = gamepads->list.head; cur != NULL; cur = cur->next) {
+        if (mg_gamepad_update_platform(cur, events)) {
+            out = MG_TRUE;
+        }
+    }
+
+    return out;
+}
+
+mg_bool mg_events_pop(mg_events* events, mg_event* ev) {
+    MG_ASSERT(events->len <= MG_MAX_EVENTS);
+
+    if (events->len == 0) {
+        return MG_FALSE;
+    }
+
+    if (ev) {
+        *ev = events->queue[MG_MAX_EVENTS - events->len];
+    }
+
+    events->len -= 1;
+    return MG_TRUE;
+}
+
+mg_bool mg_gamepads_check_event(mg_gamepads* gamepads, mg_event* event) {
+    if (gamepads->events.len == 0 && gamepads->polled_events == MG_FALSE) {
+        gamepads->queue_events = MG_TRUE;
+        mg_gamepads_poll(gamepads);
+        gamepads->polled_events = MG_TRUE;
+    }
+
+    if (mg_gamepads_check_queued_event(gamepads, event) == MG_FALSE) {
+        gamepads->polled_events = MG_FALSE;
+        return MG_FALSE;
+    }
+
+    return MG_TRUE;
+}
+
+mg_bool mg_gamepads_check_queued_event(mg_gamepads* gamepads, mg_event* event) {
+    MG_ASSERT(gamepads != NULL);
+    gamepads->polled_events = MG_TRUE;
+
+    /* check queued events */
+    return mg_events_pop(&gamepads->events, event);
+}
+
+void mg_gamepads_free(mg_gamepads* gamepads) {
+    mg_gamepad* cur;
+    MG_ASSERT(gamepads != NULL);
+
+    mg_gamepads_free_platform(gamepads);
+
+    for (cur = gamepads->list.cur; cur != NULL; cur = cur->prev) {
+        mg_gamepad_release(gamepads, cur);
+    }
+    MG_MEMSET(gamepads, 0, sizeof(mg_gamepads));
+}
+
+void mg_list_swap_gamepad(mg_gamepad_list* from, mg_gamepad_list* to, mg_gamepad* gamepad) {
+    if (gamepad->prev != NULL) {
+        gamepad->prev->next = gamepad->next;
+    }
+
+    if (gamepad->next != NULL) {
+        gamepad->next->prev = gamepad->prev;
+    }
+
+    if (from->cur == gamepad) {
+        from->cur = gamepad->prev;
+    }
+
+    if (from->head == gamepad) {
+        from->head = gamepad->next;
+    }
+
+    MG_MEMSET(gamepad, 0, sizeof(mg_gamepad));
+
+    if (to->head == NULL) {
+        to->head = gamepad;
+        to->cur = NULL;
+    } else if (to->cur) {
+        to->cur->next = gamepad;
+    }
+
+    gamepad->prev = to->cur;
+    to->cur = gamepad;
+}
+
+mg_gamepad* mg_gamepad_find(mg_gamepads* gamepads) {
+    mg_gamepad* gamepad = gamepads->free_list.cur;
+    if (gamepad == NULL)
+        return NULL;
+
+    mg_list_swap_gamepad(&gamepads->free_list, &gamepads->list, gamepad);
+    gamepad->index = (mg_size_t)(gamepad - gamepads->gamepads);
+    return gamepad;
+}
+
+
+void mg_gamepad_release(mg_gamepads* gamepads, mg_gamepad* gamepad) {
+    mg_gamepad_release_platform(gamepad);
+    mg_list_swap_gamepad(&gamepads->list, &gamepads->free_list, gamepad);
+}
+
+/*
+ * start of linux
+ */
+
+#if defined(MG_LINUX)
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/input.h>
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+mg_gamepad* mg_linux_setup_gamepad(mg_gamepads* gamepads, const char* full_path) {
+    int fd = 0;
+    struct input_id id = {0};
+    char evBits[(EV_CNT + 7) / 8] = {0};
+    char keyBits[(KEY_CNT + 7) / 8] = {0};
+    char absBits[(ABS_CNT + 7) / 8] = {0};
+    u32 i, btn, axis;
+    mg_size_t buttonCount = 0, axisCount = 0;
+
+    mg_gamepad* gamepad = mg_gamepad_find(gamepads);
+    if (gamepad == NULL) {
+        return NULL;
+    }
+
+    MG_STRNCPY(gamepad->src.full_path, full_path, 256);
+
+    gamepad->src.fd = open(full_path, O_RDWR);
+
+    fd = gamepad->src.fd;
+    if (fd <= 0) {
+        mg_gamepad_release(gamepads, gamepad);
+        return NULL;
+    }
+
+    if (ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
+        ioctl(fd, EVIOCGID, &id) < 0 ||
+        ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
+        ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0
+    ) {
+        mg_gamepad_release(gamepads, gamepad);
+        return NULL;
+    }
+
+    #define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
+    if (!isBitSet(EV_ABS, evBits)) {
+        mg_gamepad_release(gamepads, gamepad);
+        return NULL;
+    }
+
+    memset(gamepad->buttons, 0, sizeof(gamepad->buttons));
+    memset(gamepad->buttons, 0, sizeof(gamepad->axes));
+
+    /* go through any buttons a gamepad would have */
+    for (i = BTN_MISC; i < KEY_CNT; i++) {
+        if (!isBitSet(i, keyBits))
+            continue;
+
+        gamepad->src.keyMap[i - BTN_MISC] = (u8)buttonCount;
+        buttonCount++;
+    }
+
+    /* go through any axes a gamepad would have */
+    for (i = 0; i < ABS_CNT; i++) {
+        if (!isBitSet(i, absBits))
+            continue;
+
+        if (ioctl(fd, EVIOCGABS(i), (struct input_absinfo*)&gamepad->src.absInfo[i]) < 0)
+            continue;
+
+        gamepad->src.absMap[i] = (u8)axisCount;
+        axisCount++;
+    }
+
+    if ((axisCount == 0 && buttonCount == 0) || buttonCount > MG_BUTTON_COUNT + 10) {
+        mg_gamepad_release(gamepads, gamepad);
+        return NULL;
+    }
+
+    /* Generate a joystick GUID that matches the SDL 2.0.5+ one (sourced from GLFW) */
+    if (ioctl(gamepad->src.fd, EVIOCGNAME(sizeof(gamepad->name)), gamepad->name) < 0)
+        MG_STRNCPY(gamepad->name, "Unknown", sizeof(gamepad->name));
+
+    if (id.vendor && id.product && id.version) {
+        MG_SPRINTF(gamepad->guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000",
+                 id.bustype & 0xff, id.bustype >> 8,
+                 id.vendor & 0xff,  id.vendor >> 8,
+                 id.product & 0xff, id.product >> 8,
+                 id.version & 0xff, id.version >> 8);
+    } else {
+        const char* name = (const char*)gamepad->name;
+        MG_SPRINTF(gamepad->guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
+                 id.bustype & 0xff, id.bustype >> 8,
+                 name[0], name[1], name[2], name[3],
+                 name[4], name[5], name[6], name[7],
+                 name[8], name[9], name[10]);
+    }
+
+    gamepad->mapping = mg_gamepad_find_valid_mapping(gamepad);
+
+    for (btn = BTN_MISC; btn < KEY_CNT; btn++) {
+        mg_button key = mg_get_gamepad_button(gamepad, gamepad->src.keyMap[btn - BTN_MISC]);
+        if (key == MG_BUTTON_UNKNOWN)
+            key = mg_get_gamepad_button_platform(btn);
+        if (key == MG_BUTTON_UNKNOWN)
+            continue;
+
+        if (gamepad->buttons[key].supported)
+            continue;
+
+        if (!isBitSet(btn, keyBits)) {
+            gamepad->buttons[key].supported = MG_FALSE;
+            continue;
+        }
+
+        gamepad->buttons[key].supported = MG_TRUE;
+        gamepad->buttons[key].current = 0;
+    }
+
+    for (axis = 0; axis < ABS_CNT; axis++) {
+        mg_axis key;
+        float deadzone = 0;
+        if (!isBitSet(axis, absBits)) {
+            continue;
+        }
+
+        switch (axis) {
+            case ABS_HAT0X:
+                gamepad->buttons[MG_BUTTON_DPAD_LEFT].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_DPAD_LEFT].current = 0;
+                gamepad->buttons[MG_BUTTON_DPAD_RIGHT].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_DPAD_RIGHT].current = 0;
+                deadzone = 0;
+                break;
+            case ABS_HAT0Y:
+                gamepad->buttons[MG_BUTTON_DPAD_UP].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_DPAD_UP].current = 0;
+                gamepad->buttons[MG_BUTTON_DPAD_DOWN].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_DPAD_DOWN].current = 0;
+                deadzone = 0;
+                break;
+            case ABS_HAT1X:
+            case ABS_HAT1Y:
+            case ABS_HAT2X:
+            case ABS_HAT2Y:
+            case ABS_HAT3X:
+            case ABS_HAT3Y:
+                deadzone = 0;
+                break;
+            case ABS_Z:
+                gamepad->buttons[MG_BUTTON_LEFT_TRIGGER].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_LEFT_TRIGGER].current = 0;
+
+                gamepad->axes[MG_AXIS_LEFT_TRIGGER].supported = MG_TRUE;
+                gamepad->axes[MG_AXIS_LEFT_TRIGGER].value = 0;
+                deadzone = 0;
+                break;
+            case ABS_RZ:
+                gamepad->buttons[MG_BUTTON_RIGHT_TRIGGER].supported = MG_TRUE;
+                gamepad->buttons[MG_BUTTON_RIGHT_TRIGGER].current = 0;
+
+                gamepad->axes[MG_AXIS_RIGHT_TRIGGER].supported = MG_TRUE;
+                gamepad->axes[MG_AXIS_RIGHT_TRIGGER].value = 0;
+                deadzone = 0;
+                break;
+            default:
+                deadzone = 0.15f;
+                break;
+        }
+
+        key = mg_get_gamepad_axis(gamepad, gamepad->src.absMap[axis]);
+        if (key == MG_AXIS_UNKNOWN) {
+            key = mg_get_gamepad_axis_platform(axis);
+        }
+        if (key == MG_AXIS_UNKNOWN)
+            continue;
+
+        gamepad->axes[key].supported = MG_TRUE;
+        gamepad->axes[key].value = 0;
+        gamepad->axes[key].deadzone = deadzone;
+    }
+
+    #undef isBitSet
+
+    {
+        i32 flags = fcntl(gamepad->src.fd, F_GETFL, 0);
+        fcntl(gamepad->src.fd, F_SETFL, flags | O_NONBLOCK);
+    }
+    gamepad->connected = MG_TRUE;
+
+    return gamepad;
+}
+
+void mg_gamepad_release_platform(mg_gamepad* gamepad) {
+    close(gamepad->src.fd);
+}
+
+
+void mg_gamepads_init_platform(mg_gamepads* gamepads) {
+    struct dirent *dp;
+    DIR *dfd;
+    char full_path[256];
+
+    gamepads->src.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+    if (gamepads->src.inotify > 0) {
+        /* HACK: Register for IN_ATTRIB to get notified when udev is done
+               This works well in practice but the MG_TRUE way is libudev */
+
+        gamepads->src.watch = inotify_add_watch(gamepads->src.inotify, "/dev/input/", IN_CREATE | IN_ATTRIB | IN_DELETE);
+    }
+
+    /* open the directory where all the devices are gonna be */
+    if ((dfd = opendir("/dev/input/")) == NULL) {
+        MG_FPRINTF(stderr, "Can't open /dev/input/\n");
+        return;
+    }
+
+    /* for each file found: */
+    while ((dp = readdir(dfd)) != NULL) {
+        /* get the full path of it (size of path + size of file name) */
+        const char path[] = "/dev/input/";
+        mg_gamepad* gamepad;
+
+        MG_STRNCPY(full_path, path, sizeof(full_path));
+        MG_STRNCPY(&full_path[sizeof(path) - 1], dp->d_name, sizeof(full_path) - sizeof(path));
+        full_path[255] = '\0';
+        gamepad = (mg_gamepad*)mg_linux_setup_gamepad(gamepads, (const char*)full_path);
+        if (gamepad) {
+            mg_handle_connection_event(&gamepads->events, MG_TRUE, gamepad);
+        }
+    }
+
+    closedir(dfd);
+}
+
+mg_bool mg_gamepads_poll_platform(mg_gamepads* gamepads, mg_events* events) {
+    mg_ssize_t offset = 0;
+    char buffer[16384];
+    char full_path[256];
+    const char path[] = "/dev/input/";
+    mg_ssize_t size;
+
+    if (gamepads->src.inotify <= 0)
+        return MG_FALSE;
+
+    size = read(gamepads->src.inotify, buffer, sizeof(buffer));
+
+    while (size > offset) {
+        const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
+
+        offset += (mg_ssize_t)sizeof(struct inotify_event) + e->len;
+
+        if (strncmp(e->name, "event", 5) != 0) {
+            continue;
+        }
+
+        MG_STRNCPY(full_path, path, sizeof(full_path));
+        MG_STRNCPY(&full_path[sizeof(path) - 1], e->name, sizeof(full_path) - sizeof(path));
+        full_path[255] = '\0';
+
+        if (e->mask & (IN_CREATE | IN_ATTRIB)) {
+            mg_gamepad* gamepad = mg_linux_setup_gamepad(gamepads, full_path);
+            if (gamepad) {
+                mg_handle_connection_event(events, MG_TRUE, gamepad);
+                return MG_TRUE;
+            }
+        }
+
+        else if (e->mask & IN_DELETE) {
+            mg_gamepad* cur;
+            for (cur = gamepads->list.head; cur != NULL; cur = cur->next) {
+                if (MG_STRNCMP(cur->src.full_path, full_path, sizeof(cur->src.full_path)) == 0) {
+                    mg_handle_connection_event(events, MG_FALSE, cur);
+                    mg_gamepad_release(gamepads, cur);
+                    return MG_TRUE;
+                }
+            }
+        }
+    }
+
+    return MG_FALSE;
+}
+
+void mg_gamepads_free_platform(mg_gamepads* gamepads) {
+    if (gamepads->src.inotify > 0) {
+        if (gamepads->src.watch > 0)
+            inotify_rm_watch(gamepads->src.inotify, gamepads->src.watch);
+
+        close(gamepads->src.inotify);
+    }
+
+    gamepads->src.inotify = 0;
+    gamepads->src.watch = 0;
+}
+
+mg_bool mg_gamepad_update_platform(mg_gamepad* gamepad, mg_events* events) {
+    mg_bool event_handled = MG_FALSE;
+    struct input_event ev;
+
+    i8 i;
+    if (gamepad->connected == MG_FALSE) return MG_FALSE;
+
+    for (i = 0; i < 2; i++) {
+        mg_button button = MG_BUTTON_LEFT_TRIGGER + i;
+        mg_axis axis = MG_AXIS_LEFT_TRIGGER + i;
+        mg_handle_button_event(events, button, MG_BOOL(gamepad->axes[axis].value >= 0.98f), gamepad);
+    }
+
+    for (i = 0; i < 2; i++) {
+        mg_button button = MG_BUTTON_DPAD_LEFT + (mg_button)(i * 2);
+        mg_button button2 = MG_BUTTON_DPAD_LEFT + 1 + (mg_button)(i * 2);
+        mg_axis axis = (mg_axis)(MG_AXIS_HAT_DPAD_LEFT + i);
+
+        mg_handle_button_event(events, button, gamepad->axes[axis].value < 0, gamepad);
+        mg_handle_button_event(events, button2, gamepad->axes[axis].value > 0, gamepad);
+    }
+
+
+    MG_MEMSET(&ev, 0, sizeof(ev));
+    while (read(gamepad->src.fd, &ev, sizeof(ev)) > 0) {
+        if (ev.type != EV_KEY && ev.type != EV_ABS) continue;
+
+        switch (ev.type) {
+            case EV_KEY: {
+                mg_button btn = mg_get_gamepad_button(gamepad, (u8)(gamepad->src.keyMap[ev.code - BTN_MISC]));
+                if (btn == MG_BUTTON_UNKNOWN) {
+                    btn = mg_get_gamepad_button_platform(ev.code);
+                }
+
+                if (btn == MG_BUTTON_UNKNOWN) {
+                    break;
+                }
+
+                mg_handle_button_event(events, btn, MG_BOOL(ev.value), gamepad);
+                event_handled = MG_TRUE;
+                break;
+            }
+            case EV_ABS: {
+                float deadzone, event_val;
+
+                mg_axis axis = mg_get_gamepad_axis(gamepad, gamepad->src.absMap[ev.code]);
+                const struct mg_input_absinfo info = gamepad->src.absInfo[ev.code];
+                float normalized = (float)ev.value;
+                const float range = (float)(info.maximum - info.minimum);
+
+                if (axis == MG_AXIS_UNKNOWN)
+                    axis = mg_get_gamepad_axis_platform(ev.code);
+                if (axis == MG_AXIS_UNKNOWN) {
+                    break;
+                }
+
+                if (range) {
+                    /* Normalize to 0.0 -> 1.0 */
+                    normalized = (normalized - (float)info.minimum) / range;
+                    /* Normalize to -1.0 -> 1.0 */
+                    normalized = normalized * 2.0f - 1.0f;
+                }
+
+                deadzone = gamepad->axes[axis].deadzone;
+                event_val = normalized;
+                if (MG_FABS(event_val) < deadzone) {
+                    event_val = 0;
+                }
+
+                mg_handle_axis_event(events, axis, event_val, gamepad);
+                event_handled = MG_TRUE;
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    return event_handled;
+}
+
+mg_button mg_get_gamepad_button_platform(u32 button) {
+    switch (button) {
+        case BTN_WEST:
+            return MG_BUTTON_WEST;
+        case BTN_A:
+            return MG_BUTTON_SOUTH;
+        case BTN_NORTH:
+            return MG_BUTTON_NORTH;
+        case BTN_EAST:
+            return MG_BUTTON_EAST;
+        case BTN_BACK:
+            return MG_BUTTON_BACK;
+        case BTN_MODE:
+            return MG_BUTTON_GUIDE;
+        case BTN_START:
+            return MG_BUTTON_START;
+        case BTN_THUMBL:
+            return MG_BUTTON_LEFT_STICK;
+        case BTN_THUMBR:
+            return MG_BUTTON_RIGHT_STICK;
+        case BTN_TL:
+            return MG_BUTTON_LEFT_SHOULDER;
+        case BTN_DPAD_UP:
+            return MG_BUTTON_DPAD_UP;
+        case BTN_DPAD_DOWN:
+            return MG_BUTTON_DPAD_DOWN;
+        case BTN_DPAD_LEFT:
+            return MG_BUTTON_DPAD_LEFT;
+        case BTN_DPAD_RIGHT:
+            return MG_BUTTON_DPAD_RIGHT;
+        case BTN_TR:
+            return MG_BUTTON_RIGHT_SHOULDER;
+        case BTN_TOUCH:
+            return MG_BUTTON_TOUCHPAD;
+        case BTN_TRIGGER_HAPPY4:
+            return MG_BUTTON_RIGHT_PADDLE1;
+        case BTN_TRIGGER_HAPPY6:
+            return MG_BUTTON_RIGHT_PADDLE2;
+        case BTN_TRIGGER_HAPPY7:
+            return MG_BUTTON_LEFT_PADDLE1;
+        case BTN_TRIGGER_HAPPY8:
+            return MG_BUTTON_LEFT_PADDLE2;
+
+        case BTN_SELECT:
+            return MG_BUTTON_MISC1;
+        case BTN_TRIGGER_HAPPY2:
+            return MG_BUTTON_MISC2;
+        case BTN_TRIGGER_HAPPY3:
+            return MG_BUTTON_MISC3;
+        case BTN_TRIGGER_HAPPY9:
+            return MG_BUTTON_MISC5;
+        case BTN_TRIGGER_HAPPY10:
+            return MG_BUTTON_MISC6;
+
+        case BTN_TRIGGER:     return MG_BUTTON_WEST;
+        case BTN_THUMB:       return MG_BUTTON_SOUTH;
+        case BTN_THUMB2:      return MG_BUTTON_EAST;
+        case BTN_TOP:         return MG_BUTTON_NORTH;
+        case BTN_TOP2:        return MG_BUTTON_START;
+        case BTN_PINKIE:      return MG_BUTTON_LEFT_SHOULDER;
+        case BTN_BASE:        return MG_BUTTON_RIGHT_SHOULDER;
+        case BTN_BASE2:       return MG_BUTTON_BACK;
+
+        case BTN_BASE3: return MG_BUTTON_BACK;
+        case BTN_BASE4: return MG_BUTTON_START;
+        case BTN_BASE5: return MG_BUTTON_START;
+        case BTN_BASE6: return MG_BUTTON_RIGHT_STICK;
+        default:
+            return MG_BUTTON_UNKNOWN;
+    }
+    return MG_BUTTON_UNKNOWN;
+}
+
+mg_axis mg_get_gamepad_axis_platform(u32 axis) {
+    switch (axis) {
+        case ABS_X:
+           return MG_AXIS_LEFT_X;
+        case ABS_Y:
+           return MG_AXIS_LEFT_Y;
+        case ABS_Z:
+           return MG_AXIS_LEFT_TRIGGER;
+        case ABS_RX:
+           return MG_AXIS_RIGHT_X;
+        case ABS_RY:
+           return MG_AXIS_RIGHT_Y;
+        case ABS_RZ:
+           return MG_AXIS_RIGHT_TRIGGER;
+        case ABS_THROTTLE:
+           return MG_AXIS_THROTTLE;
+        case ABS_RUDDER:
+           return MG_AXIS_RUDDER;
+        case ABS_WHEEL:
+           return MG_AXIS_WHEEL;
+        case ABS_GAS:
+           return MG_AXIS_GAS;
+        case ABS_BRAKE:
+           return MG_AXIS_BRAKE;
+        case ABS_HAT0X:
+           return MG_AXIS_HAT_DPAD_LEFT_RIGHT;
+        case ABS_HAT0Y:
+           return MG_AXIS_HAT_DPAD_UP_DOWN;
+        case ABS_HAT1X:
+           return MG_AXIS_HAT1X;
+        case ABS_HAT1Y:
+           return MG_AXIS_HAT1Y;
+        case ABS_HAT2X:
+           return MG_AXIS_HAT2X;
+        case ABS_HAT2Y:
+           return MG_AXIS_HAT2Y;
+        case ABS_HAT3X:
+           return MG_AXIS_HAT3X;
+        case ABS_HAT3Y:
+           return MG_AXIS_HAT3Y;
+        case ABS_PRESSURE:
+           return MG_AXIS_PRESSURE;
+        case ABS_DISTANCE:
+           return MG_AXIS_DISTANCE;
+        case ABS_TILT_X:
+           return MG_AXIS_TILT_X;
+        case ABS_TILT_Y:
+           return MG_AXIS_TILT_Y;
+        case ABS_TOOL_WIDTH:
+           return MG_AXIS_TOOL_WIDTH;
+        case ABS_VOLUME:
+           return MG_AXIS_VOLUME;
+        case ABS_PROFILE:
+           return MG_AXIS_PROFILE;
+        case ABS_MISC:
+           return MG_AXIS_MISC;
+        default:
+           return MG_AXIS_UNKNOWN;
+    }
+
+    return MG_AXIS_UNKNOWN;
+}
+#endif /* MG_LINUX */
+
+/*
+ * start of windows
+ */
+
+#if defined(MG_WINDOWS)
+
+#ifdef __cplusplus
+#define MG_REF_GUID(g) *(g)
+#else
+#define MG_REF_GUID(g) (g)
+#endif
+
+#include <xinput.h>
+#include <dinput.h>
+
+#ifndef DIDFT_OPTIONAL
+#define DIDFT_OPTIONAL          0x80000000
+#endif
+
+typedef void (*mg_proc)(void); /* function pointer equivalent of void* */
+
+MG_API void mg_xinput_fetch_gamepads(mg_gamepads* gamepads, mg_events* events);
+
+mg_gamepad* mg_xinput_list[XUSER_MAX_COUNT];
+typedef DWORD (* PFN_XInputGetState)(DWORD,XINPUT_STATE*);
+typedef DWORD (* PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
+typedef DWORD (* PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
+typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
+typedef HRESULT (WINAPI * PFN_GameInputCreate)(void* gameinput);
+
+HINSTANCE mg_gameinput_dll = NULL;
+HINSTANCE mg_xinput_dll = NULL;
+HINSTANCE mg_dinput_dll = NULL;
+
+PFN_GameInputCreate GameInputCreateSrc = NULL;
+
+PFN_XInputGetState XInputGetStateSrc = NULL;
+PFN_XInputGetKeystroke XInputGetKeystrokeSrc = NULL;
+PFN_XInputGetCapabilities XInputGetCapabilitiesSrc = NULL;
+PFN_DirectInput8Create DInput8CreateSrc = NULL;
+
+const GUID MG_IID_IDirectInput8W =
+    {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}};
+const GUID MG_GUID_XAxis =
+    {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_YAxis =
+    {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_ZAxis =
+    {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_RxAxis =
+    {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_RyAxis =
+    {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_RzAxis =
+    {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_Slider =
+    {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+const GUID MG_GUID_POV =
+    {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
+
+static DIOBJECTDATAFORMAT mg_objectDataFormats[] = {
+    { &MG_GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
+    { &MG_GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &MG_GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &MG_GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { &MG_GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+    { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
+};
+
+const DIDATAFORMAT mg_dataFormat = {
+    sizeof(DIDATAFORMAT),
+    sizeof(DIOBJECTDATAFORMAT),
+    DIDFT_ABSAXIS,
+    sizeof(DIJOYSTATE),
+    sizeof(mg_objectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
+    mg_objectDataFormats
+};
+
+mg_bool mg_supportsXInput(const GUID* guid) {
+    RAWINPUTDEVICELIST* list;
+    unsigned int count = 0;
+    mg_size_t i;
+
+    if (mg_xinput_dll == NULL) {
+        return MG_FALSE;
+    }
+
+    if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
+        return MG_FALSE;
+
+    list = (RAWINPUTDEVICELIST*)malloc(count * sizeof(RAWINPUTDEVICELIST));
+    MG_MEMSET(list, 0, count * sizeof(RAWINPUTDEVICELIST));
+
+    if ((int)GetRawInputDeviceList(list, &count, sizeof(RAWINPUTDEVICELIST)) == -1) {
+        free(list);
+        return MG_FALSE;
+    }
+
+    for (i = 0;  i < count;  i++) {
+        RID_DEVICE_INFO rdi = {0};
+        char name[256];
+        UINT size = sizeof(rdi);
+
+        rdi.cbSize = sizeof(rdi);
+
+        if (list[i].dwType != RIM_TYPEHID)
+            continue;
+
+        if ((int)GetRawInputDeviceInfoA(list[i].hDevice, RIDI_DEVICEINFO, &rdi, &size) == -1) {
+            continue;
+        }
+
+        if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
+            continue;
+
+        MG_MEMSET(name, 0, sizeof(name));
+        size = sizeof(name);
+
+        if ((int)GetRawInputDeviceInfoA(list[i].hDevice, RIDI_DEVICENAME, name, &size) == -1) {
+            break;
+        }
+
+        name[sizeof(name) - 1] = '\0';
+        if (strstr((char*)name, "IG_")) {
+            free(list);
+            return MG_TRUE;
+        }
+    }
+
+    free(list);
+    return MG_FALSE;
+}
+
+#include <math.h>
+
+BOOL CALLBACK DirectInputEnumDevicesCallback(LPCDIDEVICEINSTANCE inst, LPVOID userData) {
+    mg_gamepads* gamepads = (mg_gamepads*)userData;
+    mg_gamepad* gamepad;
+    u32 i;
+    DIDEVCAPS caps;
+    DIPROPDWORD dipd;
+    /* avoid clones */
+
+    if (mg_supportsXInput(&inst->guidProduct)) {
+        return DIENUM_CONTINUE;
+    }
+
+    gamepad = mg_gamepad_find(gamepads);
+    if (gamepad == NULL) return FALSE;
+
+    gamepad->src.device = NULL;
+
+    if (FAILED(IDirectInput8_CreateDevice((IDirectInput8*)gamepads->src.dinput, MG_REF_GUID(&inst->guidInstance), (IDirectInputDevice8**)&gamepad->src.device, NULL))) {
+        mg_gamepad_release(gamepads, gamepad);
+        return DIENUM_CONTINUE;
+    }
+
+
+    if (FAILED(IDirectInputDevice8_SetDataFormat((IDirectInputDevice8*)gamepad->src.device, &mg_dataFormat ))) {
+        mg_gamepad_release(gamepads, gamepad);
+        return DIENUM_CONTINUE;
+    }
+
+    MG_MEMSET(&caps, 0, sizeof(caps));
+    caps.dwSize = sizeof(DIDEVCAPS);
+
+    IDirectInputDevice8_GetCapabilities((IDirectInputDevice8*)gamepad->src.device, &caps);
+
+    MG_MEMSET(&dipd, 0, sizeof(dipd));
+    dipd.diph.dwSize = sizeof(dipd);
+    dipd.diph.dwHeaderSize = sizeof(dipd.diph);
+    dipd.diph.dwHow = DIPH_DEVICE;
+    dipd.dwData = DIPROPAXISMODE_ABS;
+
+    if (FAILED(IDirectInputDevice8_SetProperty((IDirectInputDevice8*)gamepad->src.device, DIPROP_AXISMODE, &dipd.diph))) {
+        mg_gamepad_release(gamepads, gamepad);
+        return DIENUM_CONTINUE;
+    }
+
+   if (!WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)inst->tszInstanceName, -1, gamepad->name, sizeof(gamepad->name), NULL, NULL)) {
+        mg_gamepad_release(gamepads, gamepad);
+        return DIENUM_STOP;
+    }
+
+    if (memcmp(&inst->guidProduct.Data4[2], "PIDVID", 6) == 0) {
+        MG_SPRINTF(gamepad->guid, "03000000%02x%02x0000%02x%02x000000000000",
+                (uint8_t) inst->guidProduct.Data1,
+                (uint8_t) (inst->guidProduct.Data1 >> 8),
+                (uint8_t) (inst->guidProduct.Data1 >> 16),
+                (uint8_t) (inst->guidProduct.Data1 >> 24));
+    } else {
+        MG_SPRINTF(gamepad->guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
+                gamepad->name[0], gamepad->name[1], gamepad->name[2], gamepad->name[3],
+                gamepad->name[4], gamepad->name[5], gamepad->name[6], gamepad->name[7],
+                gamepad->name[8], gamepad->name[9], gamepad->name[10]);
+    }
+
+
+    gamepad->mapping = mg_gamepad_find_valid_mapping(gamepad);
+
+{
+    HRESULT result;
+    DIJOYSTATE state;
+    MG_MEMSET(&state, 0, sizeof(state));
+
+    IDirectInputDevice8_Acquire((IDirectInputDevice8*)gamepad->src.device);
+    IDirectInputDevice8_Poll((IDirectInputDevice8*)gamepad->src.device);
+
+    result = IDirectInputDevice8_GetDeviceState((IDirectInputDevice8*)gamepad->src.device, sizeof(state), &state);
+    if (FAILED(result)) {
+        mg_gamepad_release(gamepads, gamepad);
+        return DIENUM_CONTINUE;
+    }
+}
+
+    for (i = 0; i < caps.dwButtons; i++) {
+        mg_button key = mg_get_gamepad_button(gamepad, (u8)i);
+        if (key == MG_BUTTON_UNKNOWN) {
+            key = mg_get_gamepad_button_platform(i);
+            if (key == MG_BUTTON_UNKNOWN) continue;
+        }
+
+        if (gamepad->buttons[key].supported)
+            continue;
+
+        gamepad->buttons[key].supported = MG_TRUE;
+        gamepad->buttons[key].current = 0;
+    }
+
+    for (i = 0; i < caps.dwAxes; i++) {
+        mg_axis key = mg_get_gamepad_axis(gamepad, (u8)i);
+        if (key == MG_AXIS_UNKNOWN) {
+            key = mg_get_gamepad_axis_platform(i);
+            if (key == MG_AXIS_UNKNOWN) continue;
+        }
+
+        if (gamepad->axes[key].supported)
+            continue;
+
+        gamepad->axes[key].supported = MG_TRUE;
+        gamepad->axes[key].value = 0;
+    }
+
+    if (caps.dwPOVs) {
+        const mg_axis povs[2] = {
+            MG_AXIS_HAT_DPAD_UP_DOWN,
+            MG_AXIS_HAT_DPAD_LEFT_RIGHT,
+        };
+
+        for (i = 0; i < 2; i++) {
+            mg_axis key = povs[i];
+            gamepad->axes[key].supported = MG_TRUE;
+            gamepad->axes[key].value = 0;
+        }
+    }
+
+    gamepad->connected = MG_TRUE;
+    mg_handle_connection_event(&gamepads->events, MG_TRUE, gamepad);
+
+    return DIENUM_CONTINUE;
+}
+
+#include <dbt.h>
+
+static LRESULT CALLBACK mg_winproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+    mg_gamepads* gamepads = (mg_gamepads*)GetPropW(hWnd, L"gamepads");
+    if (gamepads == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
+
+    switch (message)    {
+        case WM_DEVICECHANGE: {
+                if (gamepads->src.dinput) {
+                    IDirectInput8_EnumDevices((IDirectInput8*)gamepads->src.dinput,
+                               DI8DEVCLASS_GAMECTRL,
+                               DirectInputEnumDevicesCallback,
+                               (void*)gamepads,
+                               DIEDFL_ATTACHEDONLY);
+                }
+
+                mg_xinput_fetch_gamepads(gamepads, &gamepads->events);
+            break;
+        }
+    }
+
+    return DefWindowProcW(hWnd, message, wParam, lParam);
+}
+
+
+void mg_gamepads_init_platform(mg_gamepads* gamepads) {
+    HINSTANCE hInstance = GetModuleHandle(0);
+    WNDCLASSW Class;
+
+    if (mg_gameinput_dll == NULL) {
+        /* load gameinput dll and functions (if it's available) */
+        static const char* names[] = {"gameinput.lib", "gameinput.dll"};
+
+        uint32_t i;
+        for (i = 0; i < sizeof(names) / sizeof(const char*);  i++) {
+            mg_gameinput_dll = LoadLibraryA(names[i]);
+            if (mg_gameinput_dll) {
+                GameInputCreateSrc = (PFN_GameInputCreate)(mg_proc)GetProcAddress(mg_gameinput_dll, "GameInputCreate");
+            }
+        }
+
+
+        if (mg_gameinput_dll && GameInputCreateSrc) {
+            /*HRESULT hr = GameInputCreateSrc(&gamepads->src.ginput);
+            MG_UNUSED(hr); TODO */
+        }
+    }
+
+    /* init global gamepads->src.data */
+    if (mg_xinput_dll == NULL) {
+        /* load xinput dll and functions (if it's available) */
+        static const char* names[] = {"xinput0_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"};
+
+        uint32_t i;
+        for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSrc == NULL || XInputGetKeystrokeSrc != NULL);  i++) {
+            mg_xinput_dll = LoadLibraryA(names[i]);
+            if (mg_xinput_dll) {
+                XInputGetStateSrc = (PFN_XInputGetState)(mg_proc)GetProcAddress(mg_xinput_dll, "XInputGetState");
+                XInputGetKeystrokeSrc = (PFN_XInputGetKeystroke)(mg_proc)GetProcAddress(mg_xinput_dll, "XInputGetKeystroke");
+                XInputGetCapabilitiesSrc =  (PFN_XInputGetCapabilities)(mg_proc)GetProcAddress(mg_xinput_dll, "XInputGetCapabilities");
+            }
+        }
+
+        if (mg_xinput_dll) {
+            mg_xinput_fetch_gamepads(gamepads, &gamepads->events);
+        }
+    }
+
+    if (mg_dinput_dll == NULL && DInput8CreateSrc == NULL) {
+        /* load directinput dll and functions  */
+        mg_dinput_dll = LoadLibraryA("dinput8.dll");
+        if (mg_dinput_dll)
+            DInput8CreateSrc = (PFN_DirectInput8Create)(mg_proc)GetProcAddress(mg_dinput_dll, "DirectInput8Create");
+    }
+
+    if (DInput8CreateSrc) {
+        if (FAILED(DInput8CreateSrc(hInstance,
+                                      DIRECTINPUT_VERSION,
+                                      MG_REF_GUID(&MG_IID_IDirectInput8W),
+                                      (void**) &gamepads->src.dinput,
+                                      NULL)) ||
+            FAILED(IDirectInput8_EnumDevices((IDirectInput8*)gamepads->src.dinput,
+                                 DI8DEVCLASS_GAMECTRL,
+                                 DirectInputEnumDevicesCallback,
+                                 (void*)gamepads,
+                                 DIEDFL_ALLDEVICES))) {
+            mg_dinput_dll = NULL;
+        }
+    }
+
+    MG_MEMSET(&Class, 0, sizeof(Class));
+
+    Class.hInstance = hInstance;
+    Class.lpfnWndProc = mg_winproc;
+    Class.cbClsExtra = sizeof(mg_gamepads*);
+    Class.lpszClassName = L"minigamepadclass";
+
+    RegisterClassW(&Class);
+
+    gamepads->src.dummy_win = CreateWindowW(Class.lpszClassName, (wchar_t*)"", 0, 0, 0, 0, 0, 0, 0, hInstance, 0);
+
+    SetPropW((HWND)gamepads->src.dummy_win, L"gamepads", gamepads);
+}
+
+#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
+    /* MINGW PLEASE FIX THIS */
+    #define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
+#endif
+
+static const char* mg_xinput_gamepad_name(const XINPUT_CAPABILITIES xic) {
+    switch (xic.SubType) {
+        case XINPUT_DEVSUBTYPE_WHEEL:
+            return "XInput Wheel";
+        case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+            return "XInput Arcade Stick";
+        case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
+            return "XInput Flight Stick";
+        case XINPUT_DEVSUBTYPE_DANCE_PAD:
+            return "XInput Dance Pad";
+        case XINPUT_DEVSUBTYPE_GUITAR:
+            return "XInput Guitar";
+        case XINPUT_DEVSUBTYPE_DRUM_KIT:
+            return "XInput Drum Kit";
+        case XINPUT_DEVSUBTYPE_GAMEPAD: {
+            if (xic.Flags & XINPUT_CAPS_WIRELESS)
+                return "Wireless Xbox Controller";
+            else
+                return "Xbox Controller";
+        }
+    }
+
+    return "Unknown XInput Device";
+}
+
+void mg_xinput_fetch_gamepads(mg_gamepads* gamepads, mg_events* events) {
+    DWORD dwResult, i;
+    if (mg_xinput_dll == NULL) return;
+
+    for (i = 0; i < XUSER_MAX_COUNT; i++) {
+        mg_gamepad* gamepad = mg_xinput_list[i];
+        XINPUT_STATE state;
+        mg_button button;
+        mg_axis axis;
+        char* name;
+        XINPUT_CAPABILITIES xic;
+
+        MG_MEMSET(&state, 0, sizeof(state));
+
+        dwResult = XInputGetStateSrc(i, &state);
+
+        if ((dwResult == ERROR_SUCCESS && gamepad) ||
+            (dwResult != ERROR_SUCCESS && gamepad == NULL)
+        )
+            continue;
+
+        if (dwResult != ERROR_SUCCESS) {
+            gamepad->src.xinput_index = 0;
+            mg_xinput_list[i] = NULL;
+            mg_handle_connection_event(events, MG_FALSE, gamepad);
+            mg_gamepad_release(gamepads, gamepad);
+
+            continue;
+        }
+
+        if (XInputGetCapabilitiesSrc(i, 0, &xic) != ERROR_SUCCESS)
+            continue;
+
+        gamepad = mg_gamepad_find(gamepads);
+
+        gamepad->src.xinput_index = i + 1;
+        MG_SPRINTF(gamepad->guid, "78696e707574%02x000000000000000000", xic.SubType & 0xff);
+
+        for (button = 0; button < MG_BUTTON_MISC1; button++) {
+            if (button == MG_BUTTON_GUIDE) continue;
+
+            gamepad->buttons[button].supported = MG_TRUE;
+            gamepad->buttons[button].current = MG_FALSE;
+            gamepad->buttons[button].prev = MG_FALSE;
+        }
+
+        for (axis = 0; axis < MG_AXIS_HAT_DPAD_LEFT_RIGHT; axis++) {
+            gamepad->axes[axis].value = 0;
+            gamepad->axes[axis].supported = MG_TRUE;
+        }
+
+        name = (char*)mg_xinput_gamepad_name(xic);
+        MG_STRNCPY(gamepad->name, name, sizeof(gamepad->name));
+
+        gamepad->connected = MG_TRUE;
+        mg_xinput_list[i] = gamepad;
+        mg_handle_connection_event(events, MG_TRUE, gamepad);
+    }
+}
+
+mg_bool mg_gamepads_poll_platform(mg_gamepads* gamepads, mg_events* events) {
+    mg_bool out = MG_FALSE;
+    MSG msg;
+
+    MG_UNUSED(gamepads); MG_UNUSED(events);
+
+    while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+
+    return out;
+}
+
+void mg_gamepads_free_platform(mg_gamepads* gamepads) {
+    DestroyWindow((HWND)gamepads->src.dummy_win);
+
+    if (mg_xinput_dll) {
+        FreeLibrary(mg_xinput_dll);
+        mg_xinput_dll = NULL;
+    }
+
+    if (mg_dinput_dll) {
+        if (gamepads->src.dinput)
+            IDirectInput8_Release((IDirectInput8*)gamepads->src.dinput);
+
+        FreeLibrary(mg_dinput_dll);
+    }
+}
+
+
+const u32 mg_xinput_map[MG_BUTTON_MISC1] = {
+    XINPUT_GAMEPAD_A,
+    XINPUT_GAMEPAD_B,
+    XINPUT_GAMEPAD_X,
+    XINPUT_GAMEPAD_Y,
+    XINPUT_GAMEPAD_BACK,
+    0,
+    XINPUT_GAMEPAD_START,
+    XINPUT_GAMEPAD_LEFT_THUMB,
+    XINPUT_GAMEPAD_RIGHT_THUMB,
+    XINPUT_GAMEPAD_LEFT_SHOULDER,
+    XINPUT_GAMEPAD_RIGHT_SHOULDER,
+    XINPUT_GAMEPAD_DPAD_LEFT,
+    XINPUT_GAMEPAD_DPAD_RIGHT,
+    XINPUT_GAMEPAD_DPAD_UP,
+    XINPUT_GAMEPAD_DPAD_DOWN,
+    0, 0
+};
+
+mg_bool mg_gamepad_update_platform(mg_gamepad* gamepad, mg_events* events) {
+
+    if (gamepad->connected == MG_FALSE) {
+/*        mg_gamepad_release(gamepad); */
+        return MG_FALSE;
+    }
+
+    if (gamepad->src.xinput_index) {
+        DWORD dwResult;
+        XINPUT_STATE state;
+        DWORD i = gamepad->src.xinput_index - 1;
+        mg_button button;
+
+        if (gamepad != mg_xinput_list[i]) {
+            gamepad->connected = MG_FALSE;
+            return MG_TRUE;
+        }
+
+        MG_MEMSET(&state, 0, sizeof(state));
+        dwResult = XInputGetStateSrc(i, &state);
+        if (dwResult != ERROR_SUCCESS) {
+            gamepad->connected = MG_FALSE;
+            mg_handle_connection_event(events, MG_FALSE, gamepad);
+            return MG_TRUE;
+        }
+
+        for (button = 0; button < MG_BUTTON_MISC1; button++) {
+            u32 btn = mg_xinput_map[button];
+            mg_bool btn_state;
+
+            if (btn == 0) continue;
+            btn_state = MG_BOOL((state.Gamepad.wButtons & btn));
+
+            mg_handle_button_event(events, button, btn_state, gamepad);
+        }
+
+        mg_handle_button_event(events, MG_BUTTON_LEFT_TRIGGER, MG_BOOL(gamepad->axes[MG_AXIS_LEFT_TRIGGER].value > 0), gamepad);
+        mg_handle_button_event(events, MG_BUTTON_RIGHT_TRIGGER, MG_BOOL(gamepad->axes[MG_AXIS_RIGHT_TRIGGER].value > 0), gamepad);
+
+        mg_handle_axis_event(events, MG_AXIS_LEFT_TRIGGER, (state.Gamepad.bLeftTrigger / 127.5f - 1.0f), gamepad);
+        mg_handle_axis_event(events, MG_AXIS_RIGHT_TRIGGER, (state.Gamepad.bRightTrigger / 127.5f - 1.0f), gamepad);
+
+        mg_handle_axis_event(events, MG_AXIS_LEFT_X, (state.Gamepad.sThumbLX + 0.5f) / 32767.5f, gamepad);
+        mg_handle_axis_event(events, MG_AXIS_LEFT_Y, -(state.Gamepad.sThumbLY + 0.5f) / 32767.5f, gamepad);
+
+        mg_handle_axis_event(events, MG_AXIS_RIGHT_X, (state.Gamepad.sThumbRX + 0.5f) / 32767.5f, gamepad);
+        mg_handle_axis_event(events, MG_AXIS_RIGHT_Y, -(state.Gamepad.sThumbRY + 0.5f) / 32767.5f, gamepad);
+   }
+
+    if (gamepad->src.device) {
+        u32 i;
+        DIDEVCAPS caps;
+        DIJOYSTATE state;
+        HRESULT result;
+        LONG axes_state[6];
+
+        MG_MEMSET(&caps, 0, sizeof(caps));
+        caps.dwSize = sizeof(DIDEVCAPS);
+
+        IDirectInputDevice8_GetCapabilities((IDirectInputDevice8*)gamepad->src.device, &caps);
+        IDirectInputDevice8_Poll((IDirectInputDevice8*)gamepad->src.device);
+        result = IDirectInputDevice8_GetDeviceState((IDirectInputDevice8*)gamepad->src.device, sizeof(state), &state);
+        if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) {
+            IDirectInputDevice8_Acquire((IDirectInputDevice8*)gamepad->src.device);
+            IDirectInputDevice8_Poll((IDirectInputDevice8*)gamepad->src.device);
+
+            result = IDirectInputDevice8_GetDeviceState((IDirectInputDevice8*)gamepad->src.device, sizeof(state), &state);
+        }
+
+        if (FAILED(result)) {
+            gamepad->connected = MG_FALSE;
+            mg_handle_connection_event(events, MG_FALSE, gamepad);
+            return MG_FALSE;
+        }
+
+        for (i = 0; i < caps.dwButtons; i++) {
+            mg_button key = mg_get_gamepad_button(gamepad, (u8)i);
+            if (key == MG_BUTTON_UNKNOWN) {
+                key = mg_get_gamepad_button_platform(i);
+                if (key == MG_BUTTON_UNKNOWN) continue;
+            }
+
+            mg_handle_button_event(events, key, MG_BOOL(state.rgbButtons[i]), gamepad);
+        }
+
+        memcpy(&axes_state, &state, sizeof(axes_state));
+
+        for (i = 0; i < 6; i++) {
+            float value;
+            mg_axis key = mg_get_gamepad_axis(gamepad, (u8)i);
+            if (key == MG_AXIS_UNKNOWN) {
+                key = mg_get_gamepad_axis_platform(i);
+                if (key == MG_AXIS_UNKNOWN) continue;
+            }
+
+            /* NOTE: this doesn't work with triggers because triggers are combined into one input
+             * TODO: fix this (or just use xinput)
+             * */
+            value = (((float)axes_state[i] + 0.5f) / 32767.5f) - 1.0f;
+            mg_handle_axis_event(events, key, value, gamepad);
+        }
+
+        if (caps.dwPOVs) {
+            DWORD pov = state.rgdwPOV[0];
+
+            if (pov != 0xFFFF) {
+                float angle = (float)pov / (45.0f * DI_DEGREES);
+                i32 x = 0, y = 0;
+
+                switch ((u32)angle) {
+                    case 0: /* up */       x = 0;  y = -1; break;
+                    case 1: /* up-right */ x = 1;  y = -1; break;
+                    case 2: /* right */    x = 1;  y = 0;  break;
+                    case 3: /* down-right */ x = 1; y = 1; break;
+                    case 4: /* down */     x = 0;  y = 1;  break;
+                    case 5: /* down-left */ x = -1; y = 1; break;
+                    case 6: /* left */     x = -1; y = 0;  break;
+                    case 7: /* up-left */  x = -1; y = -1; break;
+                }
+
+                mg_handle_button_event(events, MG_BUTTON_DPAD_LEFT, x < 0, gamepad);
+                mg_handle_button_event(events, MG_BUTTON_DPAD_RIGHT, x > 0, gamepad);
+                mg_handle_button_event(events, MG_BUTTON_DPAD_UP, y < 0, gamepad);
+                mg_handle_button_event(events, MG_BUTTON_DPAD_DOWN, y > 0, gamepad);
+            } else {
+                mg_handle_axis_event(events, MG_AXIS_HAT_DPAD_LEFT_RIGHT, (float)0.0f, gamepad);
+                mg_handle_axis_event(events, MG_AXIS_HAT_DPAD_UP_DOWN, (float)0.0f, gamepad);
+            }
+        }
+    }
+
+    return MG_FALSE;
+}
+
+void mg_gamepad_release_platform(mg_gamepad* gamepad) {
+    if (gamepad->src.device) {
+        IDirectInputDevice8_Release((IDirectInputDevice8*)gamepad->src.device);
+    }
+
+    if (gamepad->src.xinput_index) {
+        mg_xinput_list[gamepad->src.xinput_index - 1] = NULL;
+    }
+}
+
+mg_button mg_get_gamepad_button_platform(u32 button) {
+    /* TODO */
+    switch (button) {
+        default: break;
+    }
+    return MG_BUTTON_UNKNOWN;
+}
+
+mg_axis mg_get_gamepad_axis_platform(u32 axis) {
+    /* TODO */
+    switch (axis) {
+        case 2: return MG_AXIS_LEFT_TRIGGER;
+        case 5: return MG_AXIS_RIGHT_TRIGGER;
+        default: break;
+    }
+
+    return MG_AXIS_UNKNOWN;
+}
+#endif /* MG_WINDOWS */
+
+/*
+ * start of macos
+ */
+
+#if defined(MG_MACOS)
+#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDManager.h>
+
+void mg_osx_input_value_changed_callback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
+    mg_gamepad* gamepad = (mg_gamepad*)context;
+
+    IOHIDElementRef element = IOHIDValueGetElement(value);
+
+    IOHIDDeviceRef device = IOHIDElementGetDevice(element);
+
+    uint32_t usagePage = IOHIDElementGetUsagePage(element);
+    uint32_t usage = IOHIDElementGetUsage(element);
+
+    CFIndex intValue = IOHIDValueGetIntegerValue(value);
+    MG_UNUSED(result); MG_UNUSED(sender);
+
+    if ((IOHIDDeviceRef)gamepad->src.device != device)
+        return;
+
+    switch (usagePage) {
+        case kHIDPage_Button: {
+            mg_button btn = mg_get_gamepad_button(gamepad, (u8)usage);
+            if (btn == 0)
+                btn = mg_get_gamepad_button_platform(usage);
+            if (btn == 0)
+                break;
+
+            mg_handle_button_event((mg_events*)gamepad->src.events, btn, MG_BOOL(intValue), gamepad);
+            break;
+        }
+        case kHIDPage_GenericDesktop: {
+            CFIndex logicalMin = IOHIDElementGetLogicalMin(element);
+            CFIndex logicalMax = IOHIDElementGetLogicalMax(element);
+            mg_axis btn = mg_get_gamepad_axis(gamepad, (u8)usage);
+            if (btn == 0)
+                btn = mg_get_gamepad_axis_platform(usage);
+            if (btn == 0)
+                break;
+
+            if (logicalMax <= logicalMin) return;
+            if (intValue < logicalMin) intValue = logicalMin;
+            if (intValue > logicalMax) intValue = logicalMax;
+
+            mg_handle_axis_event((mg_events*)gamepad->src.events, btn, (-1.0f + ((intValue - logicalMin) * 2.0f) / (float)(logicalMax - logicalMin)), gamepad);
+        }
+    }
+}
+
+
+void mg_osx_device_added_callback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) {
+    mg_gamepad* gamepad;
+    mg_gamepads* gamepads = (mg_gamepads*)context;
+
+    CFIndex i;
+    CFArrayRef elements;
+    CFTypeRef property;
+    u32 vendor = 0, product = 0, version = 0;
+    CFStringRef deviceName;
+    CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
+    int usage = 0;
+    if (usageRef)
+        CFNumberGetValue((CFNumberRef)usageRef, (CFNumberType)kCFNumberIntType, (void*)&usage);
+
+    MG_UNUSED(context); MG_UNUSED(result); MG_UNUSED(sender);
+    if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
+        return;
+    }
+
+    elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
+    if (elements == NULL)
+        return;
+
+    gamepad = mg_gamepad_find(gamepads);
+    if (gamepad == NULL) {
+        return;
+    }
+
+    IOHIDDeviceRegisterInputValueCallback(device, mg_osx_input_value_changed_callback, gamepad);
+
+    deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
+    if (deviceName)
+        CFStringGetCString(deviceName, gamepad->name, sizeof(gamepad->name), kCFStringEncodingUTF8);
+    else
+        MG_STRNCPY(gamepad->name, "Unknown", sizeof(gamepad->name));
+
+    property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
+    if (property)
+        CFNumberGetValue((CFNumberRef)property, (CFNumberType)kCFNumberSInt32Type, (void*)&vendor);
+
+    property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
+    if (property)
+        CFNumberGetValue((CFNumberRef)property, kCFNumberSInt32Type, (void*)&product);
+
+    property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
+    if (property)
+        CFNumberGetValue((CFNumberRef)property, (CFNumberType)kCFNumberSInt32Type, (void*)&version);
+
+    if (vendor && product) {
+        MG_SPRINTF(gamepad->guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000",
+                (u8) vendor, (u8) (vendor >> 8),
+                (u8) product, (u8) (product >> 8),
+                (u8) version, (u8) (version >> 8));
+    }
+    else {
+        MG_SPRINTF(gamepad->guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
+                gamepad->name[0],  gamepad->name[1],  gamepad->name[2],  gamepad->name[3],
+                gamepad->name[4], gamepad->name[5],  gamepad->name[6],  gamepad->name[7],
+                gamepad->name[8], gamepad->name[9],  gamepad->name[10]);
+    }
+
+
+    gamepad->mapping = mg_gamepad_find_valid_mapping(gamepad);
+    gamepad->connected = MG_TRUE;
+
+    for (i = 0;  i < CFArrayGetCount(elements);  i++) {
+        u32 elm_usage = 0, page = 0;
+        IOHIDElementType type;
+        IOHIDElementRef native = (IOHIDElementRef)
+            CFArrayGetValueAtIndex(elements, i);
+        if (CFGetTypeID(native) != IOHIDElementGetTypeID())
+            continue;
+
+        type = IOHIDElementGetType(native);
+        if ((type != kIOHIDElementTypeInput_Axis) &&
+            (type != kIOHIDElementTypeInput_Button) &&
+            (type != kIOHIDElementTypeInput_Misc))
+        {
+            continue;
+        }
+
+
+        elm_usage = IOHIDElementGetUsage(native);
+        page = IOHIDElementGetUsagePage(native);
+
+        switch (page) {
+            case kHIDPage_Button: {
+                mg_button btn = mg_get_gamepad_button(gamepad, (u8)elm_usage);
+                if (btn == 0)
+                    btn = mg_get_gamepad_button_platform(elm_usage);
+                if (btn == 0)
+                    break;
+
+                gamepad->buttons[btn].prev = 0;
+                gamepad->buttons[btn].current = 0;
+                gamepad->buttons[btn].supported = MG_TRUE;
+                break;
+            }
+            case kHIDPage_GenericDesktop: {
+                mg_axis btn = mg_get_gamepad_axis(gamepad, (u8)elm_usage);
+                if (btn == 0)
+                    btn = mg_get_gamepad_axis_platform(elm_usage);
+                if (btn == 0)
+                    break;
+
+                gamepad->axes[btn].value = 0.0f;
+                gamepad->axes[btn].supported = MG_TRUE;
+                break;
+            }
+        }
+    }
+
+    gamepad->src.events = (void*)&gamepads->events;
+    mg_handle_connection_event(&gamepads->events, MG_TRUE, gamepad);
+    CFRelease(elements);
+}
+
+void mg_osx_device_removed_callback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {
+    mg_gamepads* gamepads = (mg_gamepads*)context;
+    mg_gamepad* cur = NULL;
+
+    CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
+    int usage = 0;
+    if (usageRef)
+        CFNumberGetValue((CFNumberRef)usageRef, (CFNumberType)kCFNumberIntType, (void*)&usage);
+
+    MG_UNUSED(context); MG_UNUSED(result); MG_UNUSED(sender); MG_UNUSED(device);
+    if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
+        return;
+    }
+
+    for (cur = gamepads->list.head; cur; cur = cur->next) {
+        if ((IOHIDDeviceRef)cur->src.device == device) {
+            mg_handle_connection_event(&gamepads->events, MG_FALSE, cur);
+            mg_gamepad_release(gamepads, cur);
+            return;
+        }
+    }
+}
+
+void mg_gamepads_init_platform(mg_gamepads* gamepads) {
+    const int filter[] = {kHIDPage_GenericDesktop};
+
+    CFMutableDictionaryRef matchingDictionary;
+    gamepads->src.hidManager = (void*)IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+
+    matchingDictionary = CFDictionaryCreateMutable(
+        kCFAllocatorDefault,
+        0,
+        &kCFTypeDictionaryKeyCallBacks,
+        &kCFTypeDictionaryValueCallBacks
+    );
+    if (!matchingDictionary) {
+        CFRelease((IOHIDManagerRef)gamepads->src.hidManager);
+        return;
+    }
+
+    CFDictionarySetValue(
+        matchingDictionary,
+        CFSTR(kIOHIDDeviceUsagePageKey),
+        CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, filter)
+    );
+
+    IOHIDManagerSetDeviceMatching((IOHIDManagerRef)gamepads->src.hidManager, matchingDictionary);
+  CFRelease(matchingDictionary);
+
+    IOHIDManagerRegisterDeviceMatchingCallback((IOHIDManagerRef)gamepads->src.hidManager, mg_osx_device_added_callback, gamepads);
+    IOHIDManagerRegisterDeviceRemovalCallback((IOHIDManagerRef)gamepads->src.hidManager, mg_osx_device_removed_callback, gamepads);
+
+    IOHIDManagerScheduleWithRunLoop((IOHIDManagerRef)gamepads->src.hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+
+    IOHIDManagerOpen((IOHIDManagerRef)gamepads->src.hidManager, kIOHIDOptionsTypeNone);
+
+    /* Execute the run loop once in order to register any initially-attached joysticks */
+    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
+
+}
+
+mg_bool mg_gamepads_poll_platform(mg_gamepads* gamepads, mg_events* events) {
+    MG_UNUSED(gamepads); MG_UNUSED(events);
+    return MG_FALSE;
+}
+
+void mg_gamepads_free_platform(mg_gamepads* gamepads) {
+    CFRelease((IOHIDManagerRef)gamepads->src.hidManager);
+}
+
+mg_bool mg_gamepad_update_platform(mg_gamepad* gamepad, mg_events* events) {
+    gamepad->src.events = (void*)events;
+    return MG_FALSE;
+}
+
+
+void mg_gamepad_release_platform(mg_gamepad* gamepads) {
+    MG_UNUSED(gamepads);
+}
+
+mg_button mg_get_gamepad_button_platform(u32 button) {
+    switch (button) {
+        case kHIDUsage_GD_DPadUp: return MG_BUTTON_DPAD_UP;
+        case kHIDUsage_GD_DPadRight:  return MG_BUTTON_DPAD_RIGHT;
+        case kHIDUsage_GD_DPadDown:  return MG_BUTTON_DPAD_DOWN;
+        case kHIDUsage_GD_DPadLeft:  return MG_BUTTON_DPAD_LEFT;
+        case kHIDUsage_GD_SystemMainMenu:  return MG_BUTTON_GUIDE;
+        case kHIDUsage_GD_Select:  return MG_BUTTON_BACK;
+        case kHIDUsage_GD_Start: return MG_BUTTON_START;
+        case kHIDUsage_Button_1: return MG_BUTTON_SOUTH;
+        case kHIDUsage_Button_2: return MG_BUTTON_WEST;
+        case kHIDUsage_Button_3: return MG_BUTTON_EAST;
+        case kHIDUsage_Button_4: return MG_BUTTON_NORTH;
+        case kHIDUsage_Button_5: return MG_BUTTON_LEFT_SHOULDER;
+        case kHIDUsage_Button_6: return MG_BUTTON_RIGHT_SHOULDER;
+        case kHIDUsage_Button_7: return MG_BUTTON_LEFT_TRIGGER;
+        case kHIDUsage_Button_8: return MG_BUTTON_RIGHT_TRIGGER;
+        case kHIDUsage_Button_9: return MG_BUTTON_LEFT_STICK;
+        case kHIDUsage_Button_10: return MG_BUTTON_RIGHT_STICK;
+        default: break;
+    }
+
+    return MG_BUTTON_UNKNOWN;
+}
+
+mg_axis mg_get_gamepad_axis_platform(u32 axis) {
+    switch (axis) {
+        case kHIDUsage_GD_X: return MG_AXIS_LEFT_X;
+        case kHIDUsage_GD_Y: return MG_AXIS_LEFT_Y;
+        case kHIDUsage_GD_Z: return MG_AXIS_LEFT_TRIGGER;
+        case kHIDUsage_GD_Rx: return MG_AXIS_RIGHT_X;
+        case kHIDUsage_GD_Ry: return MG_AXIS_RIGHT_Y;
+        case kHIDUsage_GD_Rz: return MG_AXIS_RIGHT_TRIGGER;
+        default: break;
+    }
+    return MG_AXIS_UNKNOWN;
+}
+#endif /* MG_MACOS */
+
+/*
+ * start of wasm
+ */
+
+#if defined(MG_WASM)
+#include <emscripten/html5.h>
+
+mg_gamepad* mg_wasm_gamepads[MG_MAX_GAMEPADS];
+
+
+EM_BOOL mg_emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
+    mg_gamepad* gamepad;
+    mg_gamepads* gamepads = (mg_gamepads*)userData;
+    if (gamepads == NULL) {
+        return 0;
+    }
+
+    MG_UNUSED(eventType);
+
+    gamepad = mg_wasm_gamepads[gamepadEvent->index];
+
+    if (gamepadEvent->connected) {
+        mg_button button;
+        mg_axis axis;
+
+        if (gamepad) {
+            mg_gamepad_release(gamepads, mg_wasm_gamepads[gamepadEvent->index]);
+        }
+
+        gamepad = mg_gamepad_find(gamepads);
+        if (gamepad == NULL) {
+            return 0;
+        }
+
+        for (button = 0; button < MG_BUTTON_MISC1; button++) {
+            gamepad->buttons[button].supported = MG_TRUE;
+            gamepad->buttons[button].current = MG_FALSE;
+            gamepad->buttons[button].prev = MG_FALSE;
+        }
+
+        for (axis = 0; axis < MG_AXIS_HAT_DPAD_LEFT_RIGHT; axis++) {
+            gamepad->axes[axis].value = 0;
+            gamepad->axes[axis].supported = MG_TRUE;
+        }
+
+        gamepad->connected = MG_TRUE;
+        mg_wasm_gamepads[gamepadEvent->index] = gamepad;
+    } else {
+        mg_gamepad_release(gamepads, mg_wasm_gamepads[gamepadEvent->index]);
+        mg_wasm_gamepads[gamepadEvent->index] = NULL;
+    }
+
+    return 1; /* The event was consumed by the callback handler */
+}
+
+void mg_gamepads_init_platform(mg_gamepads* gamepads) {
+    emscripten_set_gamepadconnected_callback(gamepads, 1, mg_emscripten_on_gamepad);
+    emscripten_set_gamepaddisconnected_callback(gamepads, 1, mg_emscripten_on_gamepad);
+
+    emscripten_sample_gamepad_data();
+}
+
+mg_bool mg_gamepads_poll_platform(mg_gamepads* gamepads, mg_events* events) {
+    MG_UNUSED(gamepads);  MG_UNUSED(events);
+    return MG_FALSE;
+}
+
+void mg_gamepads_free_platform(mg_gamepads* gamepads) {
+    MG_UNUSED(gamepads);
+}
+
+mg_bool mg_gamepad_update_platform(mg_gamepad* gamepad, mg_events* events) {
+    int i = gamepad->src.index;
+    int j;
+    EmscriptenGamepadEvent gamepadState;
+
+    emscripten_sample_gamepad_data();
+
+    if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
+        return MG_FALSE;
+
+    for (j = 0; j < gamepadState.numButtons; j++) {
+        mg_button map[] = {
+            MG_BUTTON_SOUTH, MG_BUTTON_EAST, MG_BUTTON_WEST, MG_BUTTON_NORTH,
+            MG_BUTTON_LEFT_SHOULDER, MG_BUTTON_RIGHT_SHOULDER, MG_BUTTON_LEFT_TRIGGER, MG_BUTTON_RIGHT_TRIGGER,
+            MG_BUTTON_BACK, MG_BUTTON_START,
+            MG_BUTTON_LEFT_STICK, MG_BUTTON_RIGHT_STICK,
+            MG_BUTTON_DPAD_UP, MG_BUTTON_DPAD_DOWN, MG_BUTTON_DPAD_LEFT, MG_BUTTON_DPAD_RIGHT,
+            MG_BUTTON_GUIDE
+        };
+        mg_button btn = MG_BUTTON_UNKNOWN;
+        if (j < (int)(sizeof(map) / sizeof(mg_button)))
+            btn = map[j];
+        if (btn == MG_BUTTON_UNKNOWN)
+            continue;
+
+        mg_handle_button_event(events, btn, MG_BOOL(gamepadState.digitalButton[j]), gamepad);
+    }
+
+    for (j = 0; j < gamepadState.numAxes; j += 2) {
+        mg_axis map[] = {
+            MG_AXIS_LEFT_X, MG_AXIS_LEFT_Y,
+            MG_AXIS_RIGHT_X, MG_AXIS_RIGHT_Y,
+            MG_AXIS_LEFT_TRIGGER, MG_AXIS_LEFT_TRIGGER
+        };
+        mg_axis btn = MG_AXIS_UNKNOWN;
+        if (j < (int)(sizeof(map) / sizeof(mg_axis)))
+            btn = map[j];
+        if (btn == MG_AXIS_UNKNOWN)
+            continue;
+
+        mg_handle_axis_event(events, btn, (float)gamepadState.axis[j], gamepad);
+    }
+
+    return MG_FALSE;
+}
+
+void mg_gamepad_release_platform(mg_gamepad* gamepad) {
+    mg_wasm_gamepads[gamepad->src.index] = NULL;
+}
+
+mg_button mg_get_gamepad_button_platform(u32 button) {
+    /* TODO */
+    MG_UNUSED(button);
+    return MG_BUTTON_UNKNOWN;
+}
+
+mg_axis mg_get_gamepad_axis_platform(u32 axis) {
+    /* TODO */
+    MG_UNUSED(axis);
+    return MG_AXIS_UNKNOWN;
+}
+
+#endif
+
+extern const char* sdl_db[];
+
+typedef struct mg_element {
+    unsigned char         type;
+    unsigned char         index;
+    signed char          axisScale;
+    signed char          axisOffset;
+} mg_element;
+
+typedef struct mg_mapping {
+    char            name[128];
+    char            guid[33];
+    mg_element buttons[16];
+    mg_element axes[6];
+
+    mg_button rButtons[256];
+    mg_axis rAxes[MG_AXIS_COUNT];
+} mg_mapping;
+
+#define MG_JOYSTICK_AXIS     1
+#define MG_JOYSTICK_BUTTON   2
+#define MG_JOYSTICK_HATBIT   3
+
+typedef struct mappings_data {
+    mg_mapping       mappings[1300];
+    int               mappingCount;
+    int               mappingMax;
+} mappings_data;
+
+mappings_data mappings;
+
+mg_button mg_get_gamepad_button(mg_gamepad* gamepad, u8 btn) {
+    if (gamepad->mapping == NULL) {
+        return MG_BUTTON_UNKNOWN;
+    }
+
+    return gamepad->mapping->rButtons[btn];
+}
+
+mg_axis mg_get_gamepad_axis(mg_gamepad* gamepad, u8 axis) {
+    if (gamepad->mapping == NULL) {
+        return MG_AXIS_UNKNOWN;
+    }
+
+    if (axis >= MG_AXIS_COUNT) {
+        return MG_AXIS_UNKNOWN;
+    }
+
+    return gamepad->mapping->rAxes[axis];
+}
+
+void updateGamepadGUID(char* guid) {
+#ifdef __APPLE__
+    if ((strncmp(&guid[4], "000000000000", 12) == 0) &&
+        (strncmp(&guid[20], "000000000000", 12) == 0))
+    {
+        char original[33];
+        MG_STRNCPY(original, guid, sizeof(original) - 1);
+        MG_SPRINTF(guid,"03000000%.4s0000%.4s000000000000",
+                original, original + 16);
+    }
+#elif defined(_WIN32)
+    if (strncmp(&guid[20], "504944564944", 12) == 0) {
+        char original[33];
+        MG_STRNCPY(original, guid, sizeof(original) - 1);
+        MG_SPRINTF(guid, "03000000%.4s0000%.4s000000000000",
+                original, original + 4);
+    }
+#else
+    (void)(guid); /* prevent unused warning */
+#endif
+}
+
+MG_API mg_mapping* findMapping(const char* guid);
+mg_mapping* findMapping(const char* guid) {
+    int i;
+    for (i = 0;  i < mappings.mappingCount;  i++) {
+        if (strncmp(mappings.mappings[i].guid, guid, sizeof(mappings.mappings[i].guid)) == 0) {
+            return &mappings.mappings[i];
+        }
+    }
+
+    return NULL;
+}
+
+MG_API mg_mapping* findMappingPermisive(const char* guid);
+mg_mapping* findMappingPermisive(const char* guid) {
+    int i;
+    for (i = 0;  i < mappings.mappingCount;  i++) {
+        if (strncmp(mappings.mappings[i].guid, guid, sizeof(mappings.mappings[i].guid) - 8) == 0) {
+            return &mappings.mappings[i];
+        }
+    }
+
+    return NULL;
+}
+
+mg_mapping* mg_gamepad_find_valid_mapping(mg_gamepad* js) {
+    mg_mapping* mapping = findMapping(js->guid);
+    if (mapping == NULL) {
+        mapping = findMappingPermisive(js->guid);
+        if (mapping == NULL)
+            return NULL;
+    }
+
+    return mapping;
+}
+
+typedef struct mg_field {
+    const char* name;
+    mg_size_t len;
+    u8 val;
+    mg_element* element;
+} mg_field;
+
+
+MG_API mg_bool parseMapping(mg_mapping* mapping, const char* string);
+mg_bool parseMapping(mg_mapping* mapping, const char* string) {
+    const char* substr = string;
+    mg_size_t i, length, len;
+    mg_field fields[] = {
+        { "platform", 8,     0, NULL },
+        { "a", 1,             MG_BUTTON_SOUTH , NULL},
+        { "b", 1,           MG_BUTTON_EAST , NULL},
+        { "x", 1,            MG_BUTTON_WEST , NULL},
+        { "y", 1,            MG_BUTTON_NORTH , NULL},
+        { "back", 4,          MG_BUTTON_BACK , NULL},
+        { "start", 5,         MG_BUTTON_START , NULL},
+        { "guide", 5,         MG_BUTTON_GUIDE , NULL},
+        { "leftshoulder", 12,  MG_BUTTON_LEFT_SHOULDER , NULL},
+        { "rightshoulder", 13, MG_BUTTON_RIGHT_SHOULDER , NULL},
+        { "leftstick", 9,     MG_BUTTON_LEFT_STICK , NULL},
+        { "rightstick", 10,    MG_BUTTON_RIGHT_STICK , NULL},
+        { "dpup",   4,       MG_BUTTON_DPAD_UP , NULL},
+        { "dpright", 7,       MG_BUTTON_DPAD_RIGHT , NULL},
+        { "dpdown", 6,       MG_BUTTON_DPAD_DOWN , NULL},
+        { "dpleft", 6,        MG_BUTTON_DPAD_LEFT , NULL},
+        { "lefttrigger", 11,   MG_BUTTON_LEFT_TRIGGER , NULL},
+        { "righttrigger", 12,  MG_BUTTON_RIGHT_TRIGGER , NULL },
+
+        { "lefttrigger", 11,   MG_AXIS_LEFT_TRIGGER, NULL},
+        { "righttrigger", 12,  MG_AXIS_RIGHT_TRIGGER, NULL },
+        { "leftx",  5,       MG_AXIS_LEFT_X, NULL },
+        { "lefty",  5,       MG_AXIS_LEFT_Y, NULL } ,
+        { "rightx", 6,       MG_AXIS_RIGHT_X, NULL},
+        { "righty", 6,        MG_AXIS_RIGHT_Y, NULL }
+    };
+
+    len = (sizeof(fields) / sizeof(mg_field));
+
+    for (i = 1; i < len - 8; i++) {
+        fields[i].element = &mapping->buttons[fields[i].val];
+    }
+
+    for (i = len - 8; i < len; i++) {
+        fields[i].element = &mapping->axes[fields[i].val];
+    }
+
+    length = MG_STRCSPN(substr, ",");
+    if (length != 32 || substr[length] != ',') {
+        return MG_FALSE;
+    }
+
+    MG_MEMCPY(mapping->guid, substr, length);
+    substr += length + 1;
+
+    length = MG_STRCSPN(substr, ",");
+    if (length >= sizeof(mapping->name) || substr[length] != ',') {
+        return MG_FALSE;
+    }
+
+    MG_MEMCPY(mapping->name, substr, length);
+    substr += length + 1;
+
+    while (substr[0]) {
+        /* TODO: Implement output modifiers */
+        char mod = 0;;
+        if (substr[0] == '+' || substr[0] == '-') {
+            mod = substr[0];
+            substr++;
+        }
+
+        for (i = 0;  i < sizeof(fields) / sizeof(fields[0]);  i++) {
+            int8_t minimum = -1;
+            int8_t maximum = 1;
+            mg_element* e;
+
+            switch (mod) {
+                case '+':
+                    minimum = 0;
+                    break;
+                case '-':
+                    maximum = 0;
+                    break;
+                default: break;
+            }
+
+            length = fields[i].len;
+            if (strncmp(substr, fields[i].name, length) != 0 || substr[length] != ':')
+                continue;
+            substr += length + 1;
+
+            if (fields[i].element == NULL) {
+                #if defined(_WIN32)
+                    const char name[] = "Windows";
+                #elif defined(__APPLE__)
+                    const char name[] = "Mac OS X";
+                #elif defined(EMSCRIPTEN)
+                    const char name[] = "Web";
+                #elif defined(__linux__)
+                    const char name[] = "Linux";
+                #else
+                    const char name[] = "";
+                #endif
+                if (strncmp(substr, name, sizeof(name)) != 0)
+                    return MG_FALSE;
+
+                break;
+            }
+
+            e = fields[i].element;
+            if (e >= mapping->axes && e <= &mapping->axes[6] && substr[0] == 'b') {
+                continue;
+            }
+
+            switch (substr[0]) {
+                case '+':
+                    minimum = 0;
+                    substr += 1;
+                    break;
+                case '-':
+                    maximum = 0;
+                    substr += 1;
+                    break;
+                default: break;
+            }
+
+            switch (substr[0]) {
+                case 'a':
+
+                    e->type = MG_JOYSTICK_AXIS;
+                    e->axisScale = (signed char)(2 / (maximum - minimum));
+                    e->axisOffset = (signed char)(-(maximum + minimum));
+
+                    if (substr[0] == '~') {
+                        e->axisScale = -e->axisScale;
+                        e->axisOffset = -e->axisOffset;
+                    }
+                    e->index = (uint8_t) strtoul(&substr[1], (char**) &substr, 10);
+                    break;
+                case 'b':
+                    e->type = MG_JOYSTICK_BUTTON;
+                    e->index = (uint8_t) strtoul(&substr[1], (char**) &substr, 10);
+                    break;
+                case 'h': {
+                    const unsigned long hat = strtoul(&substr[1], (char**) &substr, 10);
+                    const unsigned long bit = strtoul(&substr[1], (char**) &substr, 10);
+
+                    e->type = MG_JOYSTICK_HATBIT;
+                    e->index = (uint8_t) ((hat << 4) | bit);
+
+                    break;
+                }
+                default: break;
+            }
+
+            break;
+        }
+
+        substr += MG_STRCSPN(substr, ",");
+        substr += MG_STRSPN(substr, ",");
+    }
+
+    for (i = 0;  i < 32;  i++) {
+        if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F')
+            mapping->guid[i] += 'a' - 'A';
+    }
+
+    for (i = 0; i < 255; i++) {
+        mg_size_t y;
+        mapping->rButtons[i] = MG_BUTTON_UNKNOWN;
+        for (y = 0; y < 16; y++) {
+            mg_element e = mapping->buttons[y];
+            if (e.index == i) {
+                mapping->rButtons[i] = (mg_button)y;
+                break;
+            }
+        }
+    }
+
+    for (i = 0; i < MG_AXIS_COUNT; i++) {
+        mg_size_t y;
+        mapping->rAxes[i] = MG_AXIS_UNKNOWN;
+        for (y = 0; y < 6; y++) {
+            mg_element e = mapping->axes[y];
+            if (e.index == i) {
+                mapping->rAxes[i] = (mg_axis)y;
+                break;
+            }
+        }
+    }
+
+    updateGamepadGUID(mapping->guid);
+    return MG_TRUE;
+}
+
+mg_bool mg_update_gamepad_mappings(mg_gamepads* gamepads, const char* string) {
+    const char* substr = string;
+    mg_gamepad* cur;
+    mg_mapping mapping;
+    mg_size_t length;
+    char line[1024];
+
+    if (mappings.mappingCount >= mappings.mappingMax) {
+        return MG_FALSE;
+    }
+
+    while (*substr) {
+        if (!(*substr >= '0' && *substr <= '9') &&
+            !(*substr >= 'a' && *substr <= 'f') &&
+            !(*substr >= 'A' && *substr <= 'F')) {
+                substr += MG_STRCSPN(substr, "\r\n");
+                substr += MG_STRSPN(substr, "\r\n");
+                break;
+        }
+
+        length = MG_STRCSPN(substr, "\r\n");
+        if (length < sizeof(line)) {
+            MG_MEMSET(&mapping, 0, sizeof(mapping));
+            MG_MEMCPY(line, substr, length);
+            line[length] = '\0';
+
+            if (parseMapping(&mapping, line)) {
+                mg_mapping* previous = findMapping(mapping.guid);
+                if (previous)
+                    *previous = mapping;
+                else {
+                    mappings.mappingCount++;
+                    /*mappings.mappings =
+                            realloc(mappings.mappings,
+                                          sizeof(mg_mapping) * (mg_size_t)mappings.mappingCount);*/
+                    mappings.mappings[mappings.mappingCount - 1] = mapping;
+                }
+            }
+        }
+
+        substr += length;
+    }
+
+    for (cur = gamepads->list.head; cur; cur = cur->next) {
+        cur->mapping = mg_gamepad_find_valid_mapping(cur);
+    }
+
+    return MG_TRUE;
+}
+
+const char * sdl_db[] = {
+#ifdef _WIN32
+"03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,",
+"03000000fa190000918d000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,",
+"03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,",
+"03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,",
+"03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,",
+"03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,",
+"03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,",
+"03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,",
+"03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,",
+"03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,",
+"03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,",
+"03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,",
+"03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,",
+"03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,",
+"03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,",
+"03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,",
+"03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,",
+"03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001b30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001d30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,",
+"030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
+"03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,",
+"0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,",
+"03000000020500000913000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,",
+"03000000373500000710000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000373500004610000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,",
+"03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,",
+"03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
+"03000000380800001889000000000000,AtGames Legends Gamer Pro,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b14,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,",
+"030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,",
+"030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,",
+"030000008a3500000402000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,",
+"03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,",
+"030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,",
+"030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
+"03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
+"030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,",
+"030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,",
+"030000005a1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,",
+"030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,",
+"030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,",
+"030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,",
+"030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
+"030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,",
+"030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,",
+"030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
+"03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,",
+"030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,",
+"03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"03000095090000010000000000000000,Elecom JC-U609,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,",
+"0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,",
+"03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,",
+"030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,",
+"03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000062000001801000000000000,EMS TrioLinker Plus II,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
+"03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,",
+"03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,",
+"03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,",
+"03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,",
+"03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,",
+"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,",
+"03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,",
+"0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,",
+"03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,",
+"03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,",
+"030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000c9110000f055000000000000,GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
+"030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,",
+"030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,",
+"03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,",
+"030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,",
+"03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,",
+"030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008800000000000000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
+"030000000d0f00008700000000000000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,",
+"030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,",
+"030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,",
+"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,",
+"03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,",
+"03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,",
+"03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,",
+"03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,",
+"03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,",
+"03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,",
+"03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,",
+"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,",
+"03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,",
+"03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,",
+"03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,",
+"03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,",
+"03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,",
+"03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,",
+"030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,",
+"030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,",
+"03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,",
+"03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,",
+"03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,",
+"03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
+"03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,",
+"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,",
+"030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,",
+"03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,",
+"03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,",
+"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
+"030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,",
+"030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,",
+"03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
+"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
+"03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,",
+"0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000242f0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,",
+"03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,",
+"03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,",
+"030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,",
+"0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,",
+"0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,",
+"030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,",
+"030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,",
+"030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,",
+"03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,",
+"03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,",
+"03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,",
+"03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,",
+"03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,",
+"030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,",
+"03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,",
+"0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,",
+"03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,",
+"03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,",
+"03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,",
+"03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,",
+"03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
+"03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
+"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
+"030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,",
+"030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,",
+"03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,",
+"03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,",
+"030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000004b120000014d000000000000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
+"030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+"03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
+"03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,",
+"03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d62000003340000000000000,PowerA OPS Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000d62000002640000000000000,PowerA OPS Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,",
+"03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,",
+"030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,",
+"030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,",
+"03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,",
+"03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,",
+"03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,",
+"03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
+"03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,",
+"03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,",
+"03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,",
+"03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,",
+"030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,",
+"030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,",
+"030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,",
+"030000009b280000d000000000000000,Raphnet Dreamcast Adapter,a:b1,b:b0,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,lefttrigger:+a5,leftx:a0,lefty:a1,righttrigger:+a2,start:b3,x:b5,y:b4,",
+"030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,",
+"030000009b2800003c00000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,",
+"030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,",
+"030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,",
+"030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"030000009b2800002600000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800002e00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800002f00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,",
+"030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,",
+"030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,",
+"030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,",
+"03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"0300000032150000a602000000000000,Razer Huntsman V3 Pro,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,",
+"03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,",
+"03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,",
+"03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,",
+"03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,",
+"03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,",
+"0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,",
+"0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,",
+"03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,",
+"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,",
+"03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
+"030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,",
+"030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,",
+"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,",
+"03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,",
+"03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
+"03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,",
+"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
+"03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,",
+"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
+"03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,",
+"03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,",
+"03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,",
+"03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,",
+"03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,",
+"03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,",
+"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,",
+"0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,",
+"03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,",
+"03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,",
+"03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"030000008f0e00000910000000000000,Sony DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
+"03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
+"03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000fe1400002a23000000000000,Sony PlayStation Adapter,a:b0,b:b1,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,x:b2,y:b3,",
+"030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d9040000160f000000000000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"030000004c0500003713000000000000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,",
+"03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,",
+"030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,",
+"03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,",
+"030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,",
+"03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,",
+"030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,",
+"03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,",
+"03000000790000001c18000000000000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000790000002601000000000000,TGZ Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,",
+"030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f0400000ed0000000000000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f04000008d0000000000000,Thrustmaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
+"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000003d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f04000009d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,",
+"03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,",
+"03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,",
+"03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,",
+"03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
+"03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,",
+"03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,",
+"03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,",
+"03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,",
+"03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,",
+"03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,",
+"03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,",
+"03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,",
+"030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000a102000000000000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,",
+"03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,",
+"03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,",
+"03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,",
+"03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,",
+"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,",
+"030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,",
+"03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,",
+"03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,"
+#elif defined(__APPLE__)
+"030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,",
+"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,",
+"03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,",
+"03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,",
+"03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,",
+"03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00002690000000010000,8BitDo NEOGEO,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,",
+"03000000c82d00003028000000010000,8Bitdo SFC30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,",
+"03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001d30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,",
+"03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"0300000008100000e501000019040000,Anbernic Handheld,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,",
+"03000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
+"03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
+"03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,",
+"03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,",
+"03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
+"030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,",
+"030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,",
+"030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,",
+"03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
+"03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
+"03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,",
+"03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,",
+"03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00008800000000010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00008700000000010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,",
+"030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,",
+"03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,",
+"03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,",
+"03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,",
+"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,",
+"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,",
+"03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,",
+"03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,",
+"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
+"03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,",
+"0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,",
+"0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,",
+"03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
+"03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
+"030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,",
+"030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,",
+"030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,",
+"03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,",
+"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,",
+"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
+"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
+"030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,",
+"030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,",
+"03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
+"030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,",
+"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000222c00000225000000010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,",
+"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000632500002305000000010000,Redragon Saturn,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,",
+"03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,",
+"03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,",
+"03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,",
+"0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,",
+"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,",
+"030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,",
+"03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,",
+"03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,",
+"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,",
+"03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,",
+"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,",
+"030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
+"030000004c050000da0c000000010000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"030000004c0500003713000000010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,",
+"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,",
+"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,",
+"05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,",
+"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,",
+"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,",
+"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,",
+"030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,",
+"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f0400000ed0000000020000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
+"03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,",
+"03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,",
+"03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,",
+"030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,",
+"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,",
+"030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4~,start:b8,x:b2,y:b3,",
+"030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+"030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,"
+#elif defined(TARGET_OS_IPHONE)
+"05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,",
+"05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,",
+"05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,",
+"05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,",
+"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,",
+"05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,platform:iOS,",
+"05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,platform:iOS,",
+"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,",
+"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,",
+"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS,",
+"050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS,",
+"050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,",
+"050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS,",
+"050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,",
+"050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,",
+"050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,platform:iOS,",
+"050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,",
+"05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,",
+"05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,",
+"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,",
+"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,",
+"050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,",
+"050000005e040000130b0000df870001,Xbox Series Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,",
+"050000005e040000130b0000ff870001,Xbox Series Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,"
+#elif defined(__linux__)
+    "03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,",
+"03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,",
+"03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00000a20000000020000,8BitDo M30 Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,start:b7,x:b2,y:b3,",
+"03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,",
+"03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00006928000011010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,",
+"05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,",
+"05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,",
+"05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,",
+"03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,",
+"03000000c82d00000060000011010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,",
+"030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,",
+"05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000a31000014010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,",
+"03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,",
+"05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,",
+"03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
+"05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"0300000008100000e501000001010000,Anbernic Handheld,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,",
+"03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,",
+"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
+"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
+"03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,",
+"03000000503200000110000011010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,",
+"05000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,",
+"05000000503200000110000044010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,",
+"05000000503200000110000046010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,",
+"03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
+"03000000503200000210000011010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"05000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"05000000503200000210000045010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"05000000503200000210000046010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
+"030000008a3500000201000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008a3500000202000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000d81d00000b00000010010000,Buffalo BSGP1601,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,",
+"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,",
+"030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,",
+"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
+"03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,",
+"03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,",
+"030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
+"19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000f0250000c283000010010000,Gioteck VX2 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,",
+"190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,",
+"190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,",
+"03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000001010000,GPD Win Max 2 6800U Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
+"030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,",
+"03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00005001000009040000,Hori Fighting Commander Octa Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,",
+"030000000d0f00008800000011010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00008700000011010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,",
+"030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,",
+"030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,",
+"030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f0000ab01000011010000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000000d0f00009601000091000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
+"05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,",
+"03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,",
+"03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,",
+"03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,",
+"030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,",
+"050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,",
+"03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
+"03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,",
+"03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
+"0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000300f00001101000010010000,Jess Tech Colour Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,",
+"050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,",
+"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,",
+"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,",
+"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+    "030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,",
+"030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,",
+"05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,",
+"03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,",
+"03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000120c00000500000000010000,Manta DualShock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,",
+"03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,",
+"0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,",
+"0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
+"03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,",
+"030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,",
+"030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,",
+"030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,",
+"030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
+"030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
+"030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000017050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,",
+"03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,",
+"030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"05000000853200000503000000010000,Nacon MG-X Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,",
+"03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
+"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,",
+"060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,",
+"03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,",
+"060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,",
+"060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,",
+"060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,",
+"050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,",
+"030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,",
+"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,",
+"050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,",
+"05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"050000005a1d00000218000003000000,Nokia GC 5000,a:b9,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
+"030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,",
+"050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,",
+"050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,",
+"030000007e0500001e20000011810000,NSO Sega Genesis Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,",
+"030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,",
+"050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,",
+"050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,",
+"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,",
+"19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,",
+"05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+"05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+"05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,",
+"03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,",
+"03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,",
+"030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,",
+"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000004c050000f20d000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"050000004c050000f20d000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
+"03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,",
+"03000000222c00000225000011010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000222c00000025000011010000,Qanba Dragon Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick PS5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,",
+"03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,",
+"0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,",
+"030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
+"03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
+"030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,",
+"03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,",
+"0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,",
+"190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,",
+"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
+"00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,",
+"03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,",
+"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,",
+"03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,",
+"03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,",
+"03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,",
+"03000000a30600000d5f000010010000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
+"03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,",
+"03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
+"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,",
+"03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
+"03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
+"05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,",
+"03000000952e00004b43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000952e00004d43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
+"03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,",
+"03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,",
+"03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,",
+"03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,",
+"03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
+"03000000666600006706000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
+"030000004c050000da0c000011010000,Sony PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
+"03000000d9040000160f000000010000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"030000004c0500003713000011010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
+"03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
+"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
+"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
+"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,",
+"03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,",
+"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,",
+"03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,",
+"030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
+"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,",
+"030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,",
+"03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,",
+"03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,",
+"030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,",
+"030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,",
+"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
+"030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
+"03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,",
+"03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
+"03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,",
+"030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,",
+"03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,",
+"03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,",
+"03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,",
+"030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
+"06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+"03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
+"03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,",
+"03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+"03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,",
+"05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
+"05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+"030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
+"030000005e0400008e02000072050000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
+"030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
+"030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000dd02000003020000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+   "030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
+"03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+"05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
+"03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,",
+"030000005e0400008e02000020010000,XInput Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+"03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+"03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,"
+#elif defined(__ANDROID_API__)
+"38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,",
+"64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,",
+"64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,",
+"33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,",
+"34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,",
+"38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,",
+"38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,",
+"05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,",
+"32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,",
+"38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,",
+"64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,",
+"66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,",
+"66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,",
+"38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,",
+"61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,",
+"62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,",
+"33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,",
+"38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,",
+"05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,",
+"38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,",
+"32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,",
+"38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"61333362366131643730353063616330,8BitDo Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,",
+"38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,",
+"61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,",
+"05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,",
+"38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,",
+"38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,",
+"33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,",
+"38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,",
+"05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,",
+"63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,",
+"32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
+"4c696e757820342e31392e3137322077,Anbernic Handheld,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,",
+"417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,",
+"35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,",
+"32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4f64696e20436f6e74726f6c6c657200,AYN Odin,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b14,dpright:b13,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:+a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,",
+"4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,",
+"30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,x:b2,y:b3,",
+"05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"476f6f676c65204c4c43205374616469,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"5374616469614e3848532d6532633400,Google Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
+"66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,",
+"65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b18,",
+"31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,",
+"48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,",
+"62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,",
+"31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,",
+"5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,",
+"0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,",
+"5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,",
+"64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,",
+"532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,",
+"65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,",
+"33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,",
+"35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,",
+"4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,",
+"38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"39373064396565646338333134303131,Joy-Con (R),a:b1,b:b2,back:b5,leftstick:b8,leftx:a1~,lefty:a0,start:b6,x:b0,y:b3,",
+"4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,",
+"64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,",
+"6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,",
+"436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,",
+"65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,",
+"37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,",
+"4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,",
+"535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,",
+"30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,",
+"39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,",
+"31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,",
+"37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,",
+"64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b9,x:b2,y:b3,",
+"33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,",
+"30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,",
+"32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,",
+"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,",
+"31316661666466633938376335383661,Nintendo Switch Pro Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,start:b6,x:b3,y:b2,",
+"34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,",
+"36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,",
+"4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,",
+"534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,",
+"050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
+"050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
+"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,",
+"4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,",
+"506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,",
+"61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,",
+"32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,",
+"050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
+"050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,",
+"050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
+"31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,",
+"31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
+"37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,",
+"050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
+"050000004c050000e60c0000fffe3f80,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b2,y:b17,",
+"050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,",
+"37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,",
+"61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,",
+"64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,",
+"36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
+"5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,",
+"32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,",
+"36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,",
+"526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,",
+"61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,",
+"526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"64633735616665613536653363336132,Retroid Pocket,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b19,paddle2:b20,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,",
+"37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,",
+"526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,",
+"64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,",
+"37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,",
+"33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,",
+"36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,",
+"32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,",
+"38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,",
+"61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,",
+"30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,",
+"66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
+"66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,",
+"62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,",
+"38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,",
+"5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,",
+"5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,",
+"62653335326261303663356263626339,Sony PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,",
+"536f6e7920496e746572616374697665,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"576972656c65737320436f6e74726f6c,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,",
+"63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,",
+"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+"0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,",
+"35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,",
+"33313930373536613937326534303931,Taito Egret II Mini Control Panel,a:b25,b:b23,back:b27,guide:b30,leftx:a0,lefty:a1,rightshoulder:b21,righttrigger:b22,start:b28,x:b29,y:b24,",
+"54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,",
+"38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,",
+"050000004f0400000ed00000fffe3f00,Thrustmaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,",
+"30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,",
+"33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,",
+"050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,",
+"050000005e040000e00200000ffe3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,",
+"050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,",
+"050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,",
+"050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,",
+"35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"65316262316265373335666131623538,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
+"050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+"050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,"
+#elif defined(EMSCRIPTEN)
+"\0" /* look into at some point */
+#endif
+};
+
+void mg_mappings_init(void) {
+    mg_size_t i;
+    mappings.mappingCount = 0;
+    mappings.mappingMax = 1300;
+    MG_MEMSET(mappings.mappings, 0, sizeof(mappings.mappings));
+
+    for (i = 0;  i < (sizeof(sdl_db) / sizeof(char*));  i++) {
+        if (parseMapping(&mappings.mappings[mappings.mappingCount], sdl_db[i]))
+            mappings.mappingCount++;
+    }
+}
+
+const char* mg_button_get_name(mg_button btn) {
+    switch (btn) {
+        case MG_BUTTON_COUNT:
+        case MG_BUTTON_UNKNOWN:
+            return "Unknown Button";
+        case MG_BUTTON_SOUTH:
+            return "South Button";
+        case MG_BUTTON_WEST:
+            return "West Button";
+        case MG_BUTTON_NORTH:
+            return "North Button";
+        case MG_BUTTON_EAST:
+            return "East Button";
+        case MG_BUTTON_BACK:
+            return "Back Button";
+        case MG_BUTTON_GUIDE:
+            return "Guide Button";
+        case MG_BUTTON_START:
+            return "Start Button";
+        case MG_BUTTON_LEFT_STICK:
+            return "Left Stick Button";
+        case MG_BUTTON_RIGHT_STICK:
+            return "Right Stick Button";
+        case MG_BUTTON_DPAD_UP:
+            return "D-pad Up";
+        case MG_BUTTON_DPAD_DOWN:
+            return "D-pad Down";
+        case MG_BUTTON_DPAD_LEFT:
+            return "D-pad Left";
+        case MG_BUTTON_DPAD_RIGHT:
+            return "D-pad Right";
+        case MG_BUTTON_LEFT_SHOULDER:
+            return "Left Shoulder Button";
+        case MG_BUTTON_RIGHT_SHOULDER:
+            return "Right Shoulder Button";
+        case MG_BUTTON_LEFT_TRIGGER:
+            return "Left Trigger Button";
+        case MG_BUTTON_RIGHT_TRIGGER:
+            return "Right Trigger Button";
+        case MG_BUTTON_MISC1:
+            return "Misc Button 1";
+        case MG_BUTTON_RIGHT_PADDLE1:
+            return "Paddle 1 Right";
+        case MG_BUTTON_LEFT_PADDLE1:
+            return "Paddle 1 Left";
+        case MG_BUTTON_RIGHT_PADDLE2:
+            return "Paddle 2 Right";
+        case MG_BUTTON_LEFT_PADDLE2:
+            return "Paddle 2 Left";
+        case MG_BUTTON_TOUCHPAD:
+            return "Touchpad";
+        case MG_BUTTON_MISC2:
+            return "Misc Button 2";
+        case MG_BUTTON_MISC3:
+            return "Misc Button 3";
+        case MG_BUTTON_MISC4:
+            return "Misc Button 4";
+        case MG_BUTTON_MISC5:
+            return "Misc Button 5";
+        case MG_BUTTON_MISC6:
+            return "Misc Button 6";
+        default: return NULL;
+    }
+    return NULL;
+}
+
+const char* mg_axis_get_name(mg_axis axis) {
+    switch (axis) {
+        case MG_AXIS_COUNT:
+        case MG_AXIS_UNKNOWN:
+            return "Unknown Axis";
+        case MG_AXIS_LEFT_X:
+            return "X Axis";
+        case MG_AXIS_LEFT_Y:
+            return "Y Axis";
+        case MG_AXIS_LEFT_TRIGGER:
+            return "Z Axis";
+        case MG_AXIS_RIGHT_X:
+            return "RX Axis";
+        case MG_AXIS_RIGHT_Y:
+            return "RY Axis";
+        case MG_AXIS_RIGHT_TRIGGER:
+            return "RZ Axis";
+        case MG_AXIS_THROTTLE:
+            return "Throttle";
+        case MG_AXIS_RUDDER:
+            return "Rudder";
+        case MG_AXIS_WHEEL:
+            return "Wheel";
+        case MG_AXIS_GAS:
+            return "Gas";
+        case MG_AXIS_BRAKE:
+            return "Brake";
+        case MG_AXIS_HAT_DPAD_LEFT_RIGHT:
+            return "Hat D-Pad Left-Right Axis";
+        case MG_AXIS_HAT_DPAD_UP_DOWN:
+            return "Hat D-Pad Up-Down Axis";
+        case MG_AXIS_HAT1X:
+            return "Hat 1 X Axis";
+        case MG_AXIS_HAT1Y:
+            return "Hat 1 Y Axis";
+        case MG_AXIS_HAT2X:
+            return "Hat 2 X Axis";
+        case MG_AXIS_HAT2Y:
+            return "Hat 2 Y Axis";
+        case MG_AXIS_HAT3X:
+            return "Hat 3 X Axis";
+        case MG_AXIS_HAT3Y:
+            return "Hat 3 Y Axis";
+        case MG_AXIS_PRESSURE:
+            return "Pressure Axis";
+        case MG_AXIS_DISTANCE:
+            return "Distance Axis";
+        case MG_AXIS_TILT_X:
+            return "Tilt X Axis";
+        case MG_AXIS_TILT_Y:
+            return "Tilt Y Axis";
+        case MG_AXIS_TOOL_WIDTH:
+            return "Tool Width Axis";
+        case MG_AXIS_VOLUME:
+            return "Volume Axis";
+        case MG_AXIS_PROFILE:
+            return "Profile Axis";
+        case MG_AXIS_MISC:
+            return "Misc Axis";
+        default: break;
+    }
+    return NULL;
+}
+
+#endif /* MG_IMPLEMENTATION */
+
+#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
+}
+#endif
diff --git a/raylib/src/external/cgltf.h b/raylib/src/external/cgltf.h
--- a/raylib/src/external/cgltf.h
+++ b/raylib/src/external/cgltf.h
@@ -1,7 +1,7 @@
 /**
  * cgltf - a single-file glTF 2.0 parser written in C99.
  *
- * Version: 1.14
+ * Version: 1.15
  *
  * Website: https://github.com/jkuhlmann/cgltf
  *
@@ -141,7 +141,7 @@
 typedef struct cgltf_file_options
 {
 	cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data);
-	void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data);
+	void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data, cgltf_size size);
 	void* user_data;
 } cgltf_file_options;
 
@@ -296,6 +296,7 @@
 	cgltf_meshopt_compression_filter_octahedral,
 	cgltf_meshopt_compression_filter_quaternion,
 	cgltf_meshopt_compression_filter_exponential,
+	cgltf_meshopt_compression_filter_color,
 	cgltf_meshopt_compression_filter_max_enum
 } cgltf_meshopt_compression_filter;
 
@@ -308,6 +309,7 @@
 	cgltf_size count;
 	cgltf_meshopt_compression_mode mode;
 	cgltf_meshopt_compression_filter filter;
+	cgltf_bool is_khr;
 } cgltf_meshopt_compression;
 
 typedef struct cgltf_buffer_view
@@ -376,13 +378,29 @@
 	cgltf_extension* extensions;
 } cgltf_image;
 
+typedef enum cgltf_filter_type {
+    cgltf_filter_type_undefined = 0,
+    cgltf_filter_type_nearest = 9728,
+    cgltf_filter_type_linear = 9729,
+    cgltf_filter_type_nearest_mipmap_nearest = 9984,
+    cgltf_filter_type_linear_mipmap_nearest = 9985,
+    cgltf_filter_type_nearest_mipmap_linear = 9986,
+    cgltf_filter_type_linear_mipmap_linear = 9987
+} cgltf_filter_type;
+
+typedef enum cgltf_wrap_mode {
+    cgltf_wrap_mode_clamp_to_edge = 33071,
+    cgltf_wrap_mode_mirrored_repeat = 33648,
+    cgltf_wrap_mode_repeat = 10497
+} cgltf_wrap_mode;
+
 typedef struct cgltf_sampler
 {
 	char* name;
-	cgltf_int mag_filter;
-	cgltf_int min_filter;
-	cgltf_int wrap_s;
-	cgltf_int wrap_t;
+	cgltf_filter_type mag_filter;
+	cgltf_filter_type min_filter;
+	cgltf_wrap_mode wrap_s;
+	cgltf_wrap_mode wrap_t;
 	cgltf_extras extras;
 	cgltf_size extensions_count;
 	cgltf_extension* extensions;
@@ -500,6 +518,14 @@
 	cgltf_texture_view iridescence_thickness_texture;
 } cgltf_iridescence;
 
+typedef struct cgltf_diffuse_transmission
+{
+	cgltf_texture_view diffuse_transmission_texture;
+	cgltf_float diffuse_transmission_factor;
+	cgltf_float diffuse_transmission_color_factor[3];
+	cgltf_texture_view diffuse_transmission_color_texture;
+} cgltf_diffuse_transmission;
+
 typedef struct cgltf_anisotropy
 {
 	cgltf_float anisotropy_strength;
@@ -525,6 +551,7 @@
 	cgltf_bool has_sheen;
 	cgltf_bool has_emissive_strength;
 	cgltf_bool has_iridescence;
+	cgltf_bool has_diffuse_transmission;
 	cgltf_bool has_anisotropy;
 	cgltf_bool has_dispersion;
 	cgltf_pbr_metallic_roughness pbr_metallic_roughness;
@@ -537,6 +564,7 @@
 	cgltf_volume volume;
 	cgltf_emissive_strength emissive_strength;
 	cgltf_iridescence iridescence;
+	cgltf_diffuse_transmission diffuse_transmission;
 	cgltf_anisotropy anisotropy;
 	cgltf_dispersion dispersion;
 	cgltf_texture_view normal_texture;
@@ -743,6 +771,7 @@
 {
 	cgltf_file_type file_type;
 	void* file_data;
+	cgltf_size file_size;
 
 	cgltf_asset asset;
 
@@ -844,6 +873,8 @@
 
 const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view);
 
+const cgltf_accessor* cgltf_find_accessor(const cgltf_primitive* prim, cgltf_attribute_type type, cgltf_int index);
+
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
 cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
@@ -1071,9 +1102,10 @@
 	return cgltf_result_success;
 }
 
-static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data)
+static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data, cgltf_size size)
 {
 	(void)file_options;
+	(void)size;
 	void (*memfree)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
 	memfree(memory_options->user_data, data);
 }
@@ -1220,7 +1252,7 @@
 	}
 
 	cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
-	void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
+	void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data, cgltf_size size) = options->file.release ? options->file.release : cgltf_default_file_release;
 
 	void* file_data = NULL;
 	cgltf_size file_size = 0;
@@ -1234,11 +1266,12 @@
 
 	if (result != cgltf_result_success)
 	{
-		file_release(&options->memory, &options->file, file_data);
+		file_release(&options->memory, &options->file, file_data, file_size);
 		return result;
 	}
 
 	(*out_data)->file_data = file_data;
+	(*out_data)->file_size = file_size;
 
 	return cgltf_result_success;
 }
@@ -1630,8 +1663,8 @@
 			CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->filter != cgltf_meshopt_compression_filter_none, cgltf_result_invalid_gltf);
 
 			CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_octahedral && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
-
 			CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_quaternion && mc->stride != 8, cgltf_result_invalid_gltf);
+			CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_color && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
 		}
 	}
 
@@ -1822,7 +1855,7 @@
 		return;
 	}
 
-	void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release;
+	void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data, cgltf_size size) = data->file.release ? data->file.release : cgltf_default_file_release;
 
 	data->memory.free_func(data->memory.user_data, data->asset.copyright);
 	data->memory.free_func(data->memory.user_data, data->asset.generator);
@@ -1857,7 +1890,7 @@
 
 		if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
 		{
-			file_release(&data->memory, &data->file, data->buffers[i].data);
+			file_release(&data->memory, &data->file, data->buffers[i].data, data->buffers[i].size);
 		}
 		else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
 		{
@@ -2096,7 +2129,7 @@
 
 	data->memory.free_func(data->memory.user_data, data->extensions_required);
 
-	file_release(&data->memory, &data->file, data->file_data);
+	file_release(&data->memory, &data->file, data->file_data, data->file_size);
 
 	data->memory.free_func(data->memory.user_data, data);
 }
@@ -2312,11 +2345,58 @@
 	return result;
 }
 
+const cgltf_accessor* cgltf_find_accessor(const cgltf_primitive* prim, cgltf_attribute_type type, cgltf_int index)
+{
+	for (cgltf_size i = 0; i < prim->attributes_count; ++i)
+	{
+		const cgltf_attribute* attr = &prim->attributes[i];
+		if (attr->type == type && attr->index == index)
+			return attr->data;
+	}
+
+	return NULL;
+}
+
+static const uint8_t* cgltf_find_sparse_index(const cgltf_accessor* accessor, cgltf_size needle)
+{
+	const cgltf_accessor_sparse* sparse = &accessor->sparse;
+	const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
+	const uint8_t* value_data = cgltf_buffer_view_data(sparse->values_buffer_view);
+
+	if (index_data == NULL || value_data == NULL)
+		return NULL;
+
+	index_data += sparse->indices_byte_offset;
+	value_data += sparse->values_byte_offset;
+
+	cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
+
+	cgltf_size offset = 0;
+	cgltf_size length = sparse->count;
+
+	while (length)
+	{
+		cgltf_size rem = length % 2;
+		length /= 2;
+
+		cgltf_size index = cgltf_component_read_index(index_data + (offset + length) * index_stride, sparse->indices_component_type);
+		offset += index < needle ? length + rem : 0;
+	}
+
+	if (offset == sparse->count)
+		return NULL;
+
+	cgltf_size index = cgltf_component_read_index(index_data + offset * index_stride, sparse->indices_component_type);
+	return index == needle ? value_data + offset * accessor->stride : NULL;
+}
+
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
 {
 	if (accessor->is_sparse)
 	{
-		return 0;
+		const uint8_t* element = cgltf_find_sparse_index(accessor, index);
+		if (element)
+			return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
 	}
 	if (accessor->buffer_view == NULL)
 	{
@@ -2460,11 +2540,13 @@
 {
 	if (accessor->is_sparse)
 	{
-		return 0;
+		const uint8_t* element = cgltf_find_sparse_index(accessor, index);
+		if (element)
+			return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
 	}
 	if (accessor->buffer_view == NULL)
 	{
-		memset(out, 0, element_size * sizeof( cgltf_uint ));
+		memset(out, 0, element_size * sizeof(cgltf_uint));
 		return 1;
 	}
 	const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
@@ -2480,7 +2562,9 @@
 {
 	if (accessor->is_sparse)
 	{
-		return 0; // This is an error case, but we can't communicate the error with existing interface.
+		const uint8_t* element = cgltf_find_sparse_index(accessor, index);
+		if (element)
+			return cgltf_component_read_index(element, accessor->component_type);
 	}
 	if (accessor->buffer_view == NULL)
 	{
@@ -2598,7 +2682,10 @@
 		return accessor->count;
 	}
 
-	index_count = accessor->count < index_count ? accessor->count : index_count;
+	cgltf_size numbers_per_element = cgltf_num_components(accessor->type);
+	cgltf_size available_numbers = accessor->count * numbers_per_element;
+
+	index_count = available_numbers < index_count ? available_numbers : index_count;
 	cgltf_size index_component_size = cgltf_component_size(accessor->component_type);
 
 	if (accessor->is_sparse)
@@ -2620,15 +2707,23 @@
 	}
 	element += accessor->offset;
 
-	if (index_component_size == out_component_size && accessor->stride == out_component_size)
+	if (index_component_size == out_component_size && accessor->stride == out_component_size * numbers_per_element)
 	{
 		memcpy(out, element, index_count * index_component_size);
 		return index_count;
 	}
 
+	// Data couldn't be copied with memcpy due to stride being larger than the component size.
+	// OR
 	// The component size of the output array is larger than the component size of the index data, so index data will be padded.
 	switch (out_component_size)
 	{
+	case 1:
+		for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
+		{
+			((uint8_t*)out)[index] = (uint8_t)cgltf_component_read_index(element, accessor->component_type);
+		}
+		break;
 	case 2:
 		for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
 		{
@@ -2642,7 +2737,7 @@
 		}
 		break;
 	default:
-		break;
+		return 0;
 	}
 
 	return index_count;
@@ -4278,6 +4373,52 @@
 	return i;
 }
 
+static int cgltf_parse_json_diffuse_transmission(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_diffuse_transmission* out_diff_transmission)
+{
+	CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
+	int size = tokens[i].size;
+	++i;
+
+	// Defaults
+	cgltf_fill_float_array(out_diff_transmission->diffuse_transmission_color_factor, 3, 1.0f);
+	out_diff_transmission->diffuse_transmission_factor = 0.f;
+	
+	for (int j = 0; j < size; ++j)
+	{
+		CGLTF_CHECK_KEY(tokens[i]);
+
+		if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionFactor") == 0)
+		{
+			++i;
+			out_diff_transmission->diffuse_transmission_factor = cgltf_json_to_float(tokens + i, json_chunk);
+			++i;
+		}
+		else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionTexture") == 0)
+		{
+			i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_diff_transmission->diffuse_transmission_texture);
+		}
+		else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionColorFactor") == 0)
+		{
+			i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_diff_transmission->diffuse_transmission_color_factor, 3);
+		}
+		else if (cgltf_json_strcmp(tokens + i, json_chunk, "diffuseTransmissionColorTexture") == 0)
+		{
+			i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_diff_transmission->diffuse_transmission_color_texture);
+		}
+		else
+		{
+			i = cgltf_skip_json(tokens, i + 1);
+		}
+
+		if (i < 0)
+		{
+			return i;
+		}
+	}
+
+	return i;
+}
+
 static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy)
 {
 	CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
@@ -4406,8 +4547,8 @@
 	(void)options;
 	CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
 
-	out_sampler->wrap_s = 10497;
-	out_sampler->wrap_t = 10497;
+	out_sampler->wrap_s = cgltf_wrap_mode_repeat;
+	out_sampler->wrap_t = cgltf_wrap_mode_repeat;
 
 	int size = tokens[i].size;
 	++i;
@@ -4424,28 +4565,28 @@
 		{
 			++i;
 			out_sampler->mag_filter
-				= cgltf_json_to_int(tokens + i, json_chunk);
+				= (cgltf_filter_type)cgltf_json_to_int(tokens + i, json_chunk);
 			++i;
 		}
 		else if (cgltf_json_strcmp(tokens + i, json_chunk, "minFilter") == 0)
 		{
 			++i;
 			out_sampler->min_filter
-				= cgltf_json_to_int(tokens + i, json_chunk);
+				= (cgltf_filter_type)cgltf_json_to_int(tokens + i, json_chunk);
 			++i;
 		}
 		else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapS") == 0)
 		{
 			++i;
 			out_sampler->wrap_s
-				= cgltf_json_to_int(tokens + i, json_chunk);
+				= (cgltf_wrap_mode)cgltf_json_to_int(tokens + i, json_chunk);
 			++i;
 		}
 		else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
 		{
 			++i;
 			out_sampler->wrap_t
-				= cgltf_json_to_int(tokens + i, json_chunk);
+				= (cgltf_wrap_mode)cgltf_json_to_int(tokens + i, json_chunk);
 			++i;
 		}
 		else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
@@ -4766,6 +4907,11 @@
 					out_material->has_iridescence = 1;
 					i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence);
 				}
+				else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_diffuse_transmission") == 0)
+				{
+					out_material->has_diffuse_transmission = 1;
+					i = cgltf_parse_json_diffuse_transmission(options, tokens, i + 1, json_chunk, &out_material->diffuse_transmission);
+				}
 				else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0)
 				{
 					out_material->has_anisotropy = 1;
@@ -4974,6 +5120,10 @@
 			{
 				out_meshopt_compression->filter = cgltf_meshopt_compression_filter_exponential;
 			}
+			else if (cgltf_json_strcmp(tokens+i, json_chunk, "COLOR") == 0)
+			{
+				out_meshopt_compression->filter = cgltf_meshopt_compression_filter_color;
+			}
 			++i;
 		}
 		else
@@ -5084,6 +5234,12 @@
 					out_buffer_view->has_meshopt_compression = 1;
 					i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
 				}
+				else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_meshopt_compression") == 0)
+				{
+					out_buffer_view->has_meshopt_compression = 1;
+					out_buffer_view->meshopt_compression.is_khr = 1;
+					i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
+				}
 				else
 				{
 					i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_buffer_view->extensions[out_buffer_view->extensions_count++]));
@@ -6628,6 +6784,9 @@
 
 		CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count);
 		CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count);
+
+		CGLTF_PTRFIXUP(data->materials[i].diffuse_transmission.diffuse_transmission_texture.texture, data->textures, data->textures_count);
+		CGLTF_PTRFIXUP(data->materials[i].diffuse_transmission.diffuse_transmission_color_texture.texture, data->textures, data->textures_count);
 
 		CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count);
 	}
diff --git a/raylib/src/external/cgltf_write.h b/raylib/src/external/cgltf_write.h
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/cgltf_write.h
@@ -0,0 +1,1565 @@
+/**
+ * cgltf_write - a single-file glTF 2.0 writer written in C99.
+ *
+ * Version: 1.15
+ *
+ * Website: https://github.com/jkuhlmann/cgltf
+ *
+ * Distributed under the MIT License, see notice at the end of this file.
+ *
+ * Building:
+ * Include this file where you need the struct and function
+ * declarations. Have exactly one source file where you define
+ * `CGLTF_WRITE_IMPLEMENTATION` before including this file to get the
+ * function definitions.
+ *
+ * Reference:
+ * `cgltf_result cgltf_write_file(const cgltf_options* options, const char*
+ * path, const cgltf_data* data)` writes a glTF data to the given file path.
+ * If `options->type` is `cgltf_file_type_glb`, both JSON content and binary
+ * buffer of the given glTF data will be written in a GLB format.
+ * Otherwise, only the JSON part will be written.
+ * External buffers and images are not written out. `data` is not deallocated.
+ *
+ * `cgltf_size cgltf_write(const cgltf_options* options, char* buffer,
+ * cgltf_size size, const cgltf_data* data)` writes JSON into the given memory
+ * buffer. Returns the number of bytes written to `buffer`, including a null
+ * terminator. If buffer is null, returns the number of bytes that would have
+ * been written. `data` is not deallocated.
+ */
+#ifndef CGLTF_WRITE_H_INCLUDED__
+#define CGLTF_WRITE_H_INCLUDED__
+
+#include "cgltf.h"
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+cgltf_result cgltf_write_file(const cgltf_options* options, const char* path, const cgltf_data* data);
+cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef CGLTF_WRITE_H_INCLUDED__ */
+
+/*
+ *
+ * Stop now, if you are only interested in the API.
+ * Below, you find the implementation.
+ *
+ */
+
+#if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__)
+/* This makes MSVC/CLion intellisense work. */
+#define CGLTF_WRITE_IMPLEMENTATION
+#endif
+
+#ifdef CGLTF_WRITE_IMPLEMENTATION
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+#define CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM      (1 << 0)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_UNLIT        (1 << 1)
+#define CGLTF_EXTENSION_FLAG_SPECULAR_GLOSSINESS    (1 << 2)
+#define CGLTF_EXTENSION_FLAG_LIGHTS_PUNCTUAL        (1 << 3)
+#define CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION (1 << 4)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_CLEARCOAT    (1 << 5)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_IOR          (1 << 6)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_SPECULAR     (1 << 7)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_TRANSMISSION (1 << 8)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_SHEEN        (1 << 9)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS     (1 << 10)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME       (1 << 11)
+#define CGLTF_EXTENSION_FLAG_TEXTURE_BASISU        (1 << 12)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13)
+#define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17)
+#define CGLTF_EXTENSION_FLAG_TEXTURE_WEBP          (1 << 18)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_DIFFUSE_TRANSMISSION (1 << 19)
+
+typedef struct {
+	char* buffer;
+	cgltf_size buffer_size;
+	cgltf_size remaining;
+	char* cursor;
+	cgltf_size tmp;
+	cgltf_size chars_written;
+	const cgltf_data* data;
+	int depth;
+	const char* indent;
+	int needs_comma;
+	uint32_t extension_flags;
+	uint32_t required_extension_flags;
+} cgltf_write_context;
+
+#define CGLTF_MIN(a, b) (a < b ? a : b)
+
+#ifdef FLT_DECIMAL_DIG
+	// FLT_DECIMAL_DIG is C11
+	#define CGLTF_DECIMAL_DIG (FLT_DECIMAL_DIG)
+#else
+	#define CGLTF_DECIMAL_DIG 9
+#endif
+
+#define CGLTF_SPRINTF(...) { \
+		assert(context->cursor || (!context->cursor && context->remaining == 0)); \
+		context->tmp = snprintf ( context->cursor, context->remaining, __VA_ARGS__ ); \
+		context->chars_written += context->tmp; \
+		if (context->cursor) { \
+			context->cursor += context->tmp; \
+			context->remaining -= context->tmp; \
+		} }
+
+#define CGLTF_SNPRINTF(length, ...) { \
+		assert(context->cursor || (!context->cursor && context->remaining == 0)); \
+		context->tmp = snprintf ( context->cursor, CGLTF_MIN(length + 1, context->remaining), __VA_ARGS__ ); \
+		context->chars_written += length; \
+		if (context->cursor) { \
+			context->cursor += length; \
+			context->remaining -= length; \
+		} }
+
+#define CGLTF_WRITE_IDXPROP(label, val, start) if (val) { \
+		cgltf_write_indent(context); \
+		CGLTF_SPRINTF("\"%s\": %d", label, (int) (val - start)); \
+		context->needs_comma = 1; }
+
+#define CGLTF_WRITE_IDXARRPROP(label, dim, vals, start) if (vals) { \
+		cgltf_write_indent(context); \
+		CGLTF_SPRINTF("\"%s\": [", label); \
+		for (int i = 0; i < (int)(dim); ++i) { \
+			int idx = (int) (vals[i] - start); \
+			if (i != 0) CGLTF_SPRINTF(","); \
+			CGLTF_SPRINTF(" %d", idx); \
+		} \
+		CGLTF_SPRINTF(" ]"); \
+		context->needs_comma = 1; }
+
+#define CGLTF_WRITE_TEXTURE_INFO(label, info) if (info.texture) { \
+		cgltf_write_line(context, "\"" label "\": {"); \
+		CGLTF_WRITE_IDXPROP("index", info.texture, context->data->textures); \
+		cgltf_write_intprop(context, "texCoord", info.texcoord, 0); \
+		if (info.has_transform) { \
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
+			cgltf_write_texture_transform(context, &info.transform); \
+		} \
+		cgltf_write_line(context, "}"); }
+
+#define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \
+		cgltf_write_line(context, "\"" label "\": {"); \
+		CGLTF_WRITE_IDXPROP("index", info.texture, context->data->textures); \
+		cgltf_write_intprop(context, "texCoord", info.texcoord, 0); \
+		cgltf_write_floatprop(context, "scale", info.scale, 1.0f); \
+		if (info.has_transform) { \
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
+			cgltf_write_texture_transform(context, &info.transform); \
+		} \
+		cgltf_write_line(context, "}"); }
+
+#define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \
+		cgltf_write_line(context, "\"" label "\": {"); \
+		CGLTF_WRITE_IDXPROP("index", info.texture, context->data->textures); \
+		cgltf_write_intprop(context, "texCoord", info.texcoord, 0); \
+		cgltf_write_floatprop(context, "strength", info.scale, 1.0f); \
+		if (info.has_transform) { \
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
+			cgltf_write_texture_transform(context, &info.transform); \
+		} \
+		cgltf_write_line(context, "}"); }
+
+#ifndef CGLTF_CONSTS
+#define GlbHeaderSize 12
+#define GlbChunkHeaderSize 8
+static const uint32_t GlbVersion = 2;
+static const uint32_t GlbMagic = 0x46546C67;
+static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
+static const uint32_t GlbMagicBinChunk = 0x004E4942;
+#define CGLTF_CONSTS
+#endif
+
+static void cgltf_write_indent(cgltf_write_context* context)
+{
+	if (context->needs_comma)
+	{
+		CGLTF_SPRINTF(",\n");
+		context->needs_comma = 0;
+	}
+	else
+	{
+		CGLTF_SPRINTF("\n");
+	}
+	for (int i = 0; i < context->depth; ++i)
+	{
+		CGLTF_SPRINTF("%s", context->indent);
+	}
+}
+
+static void cgltf_write_line(cgltf_write_context* context, const char* line)
+{
+	if (line[0] == ']' || line[0] == '}')
+	{
+		--context->depth;
+		context->needs_comma = 0;
+	}
+	cgltf_write_indent(context);
+	CGLTF_SPRINTF("%s", line);
+	cgltf_size last = (cgltf_size)(strlen(line) - 1);
+	if (line[0] == ']' || line[0] == '}')
+	{
+		context->needs_comma = 1;
+	}
+	if (line[last] == '[' || line[last] == '{')
+	{
+		++context->depth;
+		context->needs_comma = 0;
+	}
+}
+
+static void cgltf_write_strprop(cgltf_write_context* context, const char* label, const char* val)
+{
+	if (val)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"%s\": \"%s\"", label, val);
+		context->needs_comma = 1;
+	}
+}
+
+static void cgltf_write_extras(cgltf_write_context* context, const cgltf_extras* extras)
+{
+	if (extras->data)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"extras\": %s", extras->data);
+		context->needs_comma = 1;
+	}
+	else
+	{
+		cgltf_size length = extras->end_offset - extras->start_offset;
+		if (length > 0 && context->data->json)
+		{
+			char* json_string = ((char*) context->data->json) + extras->start_offset;
+			cgltf_write_indent(context);
+			CGLTF_SPRINTF("%s", "\"extras\": ");
+			CGLTF_SNPRINTF(length, "%.*s", (int)(extras->end_offset - extras->start_offset), json_string);
+			context->needs_comma = 1;
+		}
+	}
+}
+
+static void cgltf_write_stritem(cgltf_write_context* context, const char* item)
+{
+	cgltf_write_indent(context);
+	CGLTF_SPRINTF("\"%s\"", item);
+	context->needs_comma = 1;
+}
+
+static void cgltf_write_intprop(cgltf_write_context* context, const char* label, int val, int def)
+{
+	if (val != def)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"%s\": %d", label, val);
+		context->needs_comma = 1;
+	}
+}
+
+static void cgltf_write_sizeprop(cgltf_write_context* context, const char* label, cgltf_size val, cgltf_size def)
+{
+	if (val != def)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"%s\": %zu", label, val);
+		context->needs_comma = 1;
+	}
+}
+
+static void cgltf_write_floatprop(cgltf_write_context* context, const char* label, float val, float def)
+{
+	if (val != def)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"%s\": ", label);
+		CGLTF_SPRINTF("%.*g", CGLTF_DECIMAL_DIG, val);
+		context->needs_comma = 1;
+
+		if (context->cursor)
+		{
+			char *decimal_comma = strchr(context->cursor - context->tmp, ',');
+			if (decimal_comma)
+			{
+				*decimal_comma = '.';
+			}
+		}
+	}
+}
+
+static void cgltf_write_boolprop_optional(cgltf_write_context* context, const char* label, bool val, bool def)
+{
+	if (val != def)
+	{
+		cgltf_write_indent(context);
+		CGLTF_SPRINTF("\"%s\": %s", label, val ? "true" : "false");
+		context->needs_comma = 1;
+	}
+}
+
+static void cgltf_write_floatarrayprop(cgltf_write_context* context, const char* label, const cgltf_float* vals, cgltf_size dim)
+{
+	cgltf_write_indent(context);
+	CGLTF_SPRINTF("\"%s\": [", label);
+	for (cgltf_size i = 0; i < dim; ++i)
+	{
+		if (i != 0)
+		{
+			CGLTF_SPRINTF(", %.*g", CGLTF_DECIMAL_DIG, vals[i]);
+		}
+		else
+		{
+			CGLTF_SPRINTF("%.*g", CGLTF_DECIMAL_DIG, vals[i]);
+		}
+	}
+	CGLTF_SPRINTF("]");
+	context->needs_comma = 1;
+}
+
+static bool cgltf_check_floatarray(const float* vals, int dim, float val) {
+	while (dim--)
+	{
+		if (vals[dim] != val)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+static int cgltf_int_from_component_type(cgltf_component_type ctype)
+{
+	switch (ctype)
+	{
+		case cgltf_component_type_r_8: return 5120;
+		case cgltf_component_type_r_8u: return 5121;
+		case cgltf_component_type_r_16: return 5122;
+		case cgltf_component_type_r_16u: return 5123;
+		case cgltf_component_type_r_32u: return 5125;
+		case cgltf_component_type_r_32f: return 5126;
+		default: return 0;
+	}
+}
+
+static int cgltf_int_from_primitive_type(cgltf_primitive_type ctype)
+{
+	switch (ctype)
+	{
+		case cgltf_primitive_type_points: return 0;
+		case cgltf_primitive_type_lines: return 1;
+		case cgltf_primitive_type_line_loop: return 2;
+		case cgltf_primitive_type_line_strip: return 3;
+		case cgltf_primitive_type_triangles: return 4;
+		case cgltf_primitive_type_triangle_strip: return 5;
+		case cgltf_primitive_type_triangle_fan: return 6;
+		default: return -1;
+	}
+}
+
+static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode)
+{
+	switch (alpha_mode)
+	{
+		case cgltf_alpha_mode_mask: return "MASK";
+		case cgltf_alpha_mode_blend: return "BLEND";
+		default: return NULL;
+	}
+}
+
+static const char* cgltf_str_from_type(cgltf_type type)
+{
+	switch (type)
+	{
+		case cgltf_type_scalar: return "SCALAR";
+		case cgltf_type_vec2: return "VEC2";
+		case cgltf_type_vec3: return "VEC3";
+		case cgltf_type_vec4: return "VEC4";
+		case cgltf_type_mat2: return "MAT2";
+		case cgltf_type_mat3: return "MAT3";
+		case cgltf_type_mat4: return "MAT4";
+		default: return NULL;
+	}
+}
+
+static cgltf_size cgltf_dim_from_type(cgltf_type type)
+{
+	switch (type)
+	{
+		case cgltf_type_scalar: return 1;
+		case cgltf_type_vec2: return 2;
+		case cgltf_type_vec3: return 3;
+		case cgltf_type_vec4: return 4;
+		case cgltf_type_mat2: return 4;
+		case cgltf_type_mat3: return 9;
+		case cgltf_type_mat4: return 16;
+		default: return 0;
+	}
+}
+
+static const char* cgltf_str_from_camera_type(cgltf_camera_type camera_type)
+{
+	switch (camera_type)
+	{
+		case cgltf_camera_type_perspective: return "perspective";
+		case cgltf_camera_type_orthographic: return "orthographic";
+		default: return NULL;
+	}
+}
+
+static const char* cgltf_str_from_light_type(cgltf_light_type light_type)
+{
+	switch (light_type)
+	{
+		case cgltf_light_type_directional: return "directional";
+		case cgltf_light_type_point: return "point";
+		case cgltf_light_type_spot: return "spot";
+		default: return NULL;
+	}
+}
+
+static void cgltf_write_texture_transform(cgltf_write_context* context, const cgltf_texture_transform* transform)
+{
+	cgltf_write_line(context, "\"extensions\": {");
+	cgltf_write_line(context, "\"KHR_texture_transform\": {");
+	if (cgltf_check_floatarray(transform->offset, 2, 0.0f))
+	{
+		cgltf_write_floatarrayprop(context, "offset", transform->offset, 2);
+	}
+	cgltf_write_floatprop(context, "rotation", transform->rotation, 0.0f);
+	if (cgltf_check_floatarray(transform->scale, 2, 1.0f))
+	{
+		cgltf_write_floatarrayprop(context, "scale", transform->scale, 2);
+	}
+	if (transform->has_texcoord)
+	{
+		cgltf_write_intprop(context, "texCoord", transform->texcoord, -1);
+	}
+	cgltf_write_line(context, "}");
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* asset)
+{
+	cgltf_write_line(context, "\"asset\": {");
+	cgltf_write_strprop(context, "copyright", asset->copyright);
+	cgltf_write_strprop(context, "generator", asset->generator);
+	cgltf_write_strprop(context, "version", asset->version);
+	cgltf_write_strprop(context, "min_version", asset->min_version);
+	cgltf_write_extras(context, &asset->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim)
+{
+	cgltf_write_intprop(context, "mode", cgltf_int_from_primitive_type(prim->type), 4);
+	CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors);
+	CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials);
+	cgltf_write_line(context, "\"attributes\": {");
+	for (cgltf_size i = 0; i < prim->attributes_count; ++i)
+	{
+		const cgltf_attribute* attr = prim->attributes + i;
+		CGLTF_WRITE_IDXPROP(attr->name, attr->data, context->data->accessors);
+	}
+	cgltf_write_line(context, "}");
+
+	if (prim->targets_count)
+	{
+		cgltf_write_line(context, "\"targets\": [");
+		for (cgltf_size i = 0; i < prim->targets_count; ++i)
+		{
+			cgltf_write_line(context, "{");
+			for (cgltf_size j = 0; j < prim->targets[i].attributes_count; ++j)
+			{
+				const cgltf_attribute* attr = prim->targets[i].attributes + j;
+				CGLTF_WRITE_IDXPROP(attr->name, attr->data, context->data->accessors);
+			}
+			cgltf_write_line(context, "}");
+		}
+		cgltf_write_line(context, "]");
+	}
+	cgltf_write_extras(context, &prim->extras);
+
+	if (prim->has_draco_mesh_compression || prim->mappings_count > 0)
+	{
+		cgltf_write_line(context, "\"extensions\": {");
+
+		if (prim->has_draco_mesh_compression)
+		{
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION;
+			if (prim->attributes_count == 0 || prim->indices == 0)
+			{
+				context->required_extension_flags |= CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION;
+			}
+
+			cgltf_write_line(context, "\"KHR_draco_mesh_compression\": {");
+			CGLTF_WRITE_IDXPROP("bufferView", prim->draco_mesh_compression.buffer_view, context->data->buffer_views);
+			cgltf_write_line(context, "\"attributes\": {");
+			for (cgltf_size i = 0; i < prim->draco_mesh_compression.attributes_count; ++i)
+			{
+				const cgltf_attribute* attr = prim->draco_mesh_compression.attributes + i;
+				CGLTF_WRITE_IDXPROP(attr->name, attr->data, context->data->accessors);
+			}
+			cgltf_write_line(context, "}");
+			cgltf_write_line(context, "}");
+		}
+
+		if (prim->mappings_count > 0)
+		{
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS;
+			cgltf_write_line(context, "\"KHR_materials_variants\": {");
+			cgltf_write_line(context, "\"mappings\": [");
+			for (cgltf_size i = 0; i < prim->mappings_count; ++i)
+			{
+				const cgltf_material_mapping* map = prim->mappings + i;
+				cgltf_write_line(context, "{");
+				CGLTF_WRITE_IDXPROP("material", map->material, context->data->materials);
+
+				cgltf_write_indent(context);
+				CGLTF_SPRINTF("\"variants\": [%d]", (int)map->variant);
+				context->needs_comma = 1;
+
+				cgltf_write_extras(context, &map->extras);
+				cgltf_write_line(context, "}");
+			}
+			cgltf_write_line(context, "]");
+			cgltf_write_line(context, "}");
+		}
+
+		cgltf_write_line(context, "}");
+	}
+}
+
+static void cgltf_write_mesh(cgltf_write_context* context, const cgltf_mesh* mesh)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", mesh->name);
+
+	cgltf_write_line(context, "\"primitives\": [");
+	for (cgltf_size i = 0; i < mesh->primitives_count; ++i)
+	{
+		cgltf_write_line(context, "{");
+		cgltf_write_primitive(context, mesh->primitives + i);
+		cgltf_write_line(context, "}");
+	}
+	cgltf_write_line(context, "]");
+
+	if (mesh->weights_count > 0)
+	{
+		cgltf_write_floatarrayprop(context, "weights", mesh->weights, mesh->weights_count);
+	}
+
+	cgltf_write_extras(context, &mesh->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_buffer_view(cgltf_write_context* context, const cgltf_buffer_view* view)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", view->name);
+	CGLTF_WRITE_IDXPROP("buffer", view->buffer, context->data->buffers);
+	cgltf_write_sizeprop(context, "byteLength", view->size, (cgltf_size)-1);
+	cgltf_write_sizeprop(context, "byteOffset", view->offset, 0);
+	cgltf_write_sizeprop(context, "byteStride", view->stride, 0);
+	// NOTE: We skip writing "target" because the spec says its usage can be inferred.
+	cgltf_write_extras(context, &view->extras);
+	cgltf_write_line(context, "}");
+}
+
+
+static void cgltf_write_buffer(cgltf_write_context* context, const cgltf_buffer* buffer)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", buffer->name);
+	cgltf_write_strprop(context, "uri", buffer->uri);
+	cgltf_write_sizeprop(context, "byteLength", buffer->size, (cgltf_size)-1);
+	cgltf_write_extras(context, &buffer->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_material(cgltf_write_context* context, const cgltf_material* material)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", material->name);
+	if (material->alpha_mode == cgltf_alpha_mode_mask)
+	{
+		cgltf_write_floatprop(context, "alphaCutoff", material->alpha_cutoff, 0.5f);
+	}
+	cgltf_write_boolprop_optional(context, "doubleSided", (bool)material->double_sided, false);
+	// cgltf_write_boolprop_optional(context, "unlit", material->unlit, false);
+
+	if (material->unlit)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_UNLIT;
+	}
+
+	if (material->has_pbr_specular_glossiness)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_SPECULAR_GLOSSINESS;
+	}
+
+	if (material->has_clearcoat)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_CLEARCOAT;
+	}
+
+	if (material->has_transmission)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_TRANSMISSION;
+	}
+
+	if (material->has_volume)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME;
+	}
+
+	if (material->has_ior)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IOR;
+	}
+
+	if (material->has_specular)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_SPECULAR;
+	}
+
+	if (material->has_sheen)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_SHEEN;
+	}
+
+	if (material->has_emissive_strength)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH;
+	}
+
+	if (material->has_iridescence)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE;
+	}
+
+	if (material->has_diffuse_transmission)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DIFFUSE_TRANSMISSION;
+	}
+
+	if (material->has_anisotropy)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY;
+	}
+
+	if (material->has_dispersion)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION;
+	}
+
+	if (material->has_pbr_metallic_roughness)
+	{
+		const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness;
+		cgltf_write_line(context, "\"pbrMetallicRoughness\": {");
+		CGLTF_WRITE_TEXTURE_INFO("baseColorTexture", params->base_color_texture);
+		CGLTF_WRITE_TEXTURE_INFO("metallicRoughnessTexture", params->metallic_roughness_texture);
+		cgltf_write_floatprop(context, "metallicFactor", params->metallic_factor, 1.0f);
+		cgltf_write_floatprop(context, "roughnessFactor", params->roughness_factor, 1.0f);
+		if (cgltf_check_floatarray(params->base_color_factor, 4, 1.0f))
+		{
+			cgltf_write_floatarrayprop(context, "baseColorFactor", params->base_color_factor, 4);
+		}
+		cgltf_write_line(context, "}");
+	}
+
+	if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion || material->has_diffuse_transmission)
+	{
+		cgltf_write_line(context, "\"extensions\": {");
+		if (material->has_clearcoat)
+		{
+			const cgltf_clearcoat* params = &material->clearcoat;
+			cgltf_write_line(context, "\"KHR_materials_clearcoat\": {");
+			CGLTF_WRITE_TEXTURE_INFO("clearcoatTexture", params->clearcoat_texture);
+			CGLTF_WRITE_TEXTURE_INFO("clearcoatRoughnessTexture", params->clearcoat_roughness_texture);
+			CGLTF_WRITE_NORMAL_TEXTURE_INFO("clearcoatNormalTexture", params->clearcoat_normal_texture);
+			cgltf_write_floatprop(context, "clearcoatFactor", params->clearcoat_factor, 0.0f);
+			cgltf_write_floatprop(context, "clearcoatRoughnessFactor", params->clearcoat_roughness_factor, 0.0f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_ior)
+		{
+			const cgltf_ior* params = &material->ior;
+			cgltf_write_line(context, "\"KHR_materials_ior\": {");
+			cgltf_write_floatprop(context, "ior", params->ior, 1.5f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_specular)
+		{
+			const cgltf_specular* params = &material->specular;
+			cgltf_write_line(context, "\"KHR_materials_specular\": {");
+			CGLTF_WRITE_TEXTURE_INFO("specularTexture", params->specular_texture);
+			CGLTF_WRITE_TEXTURE_INFO("specularColorTexture", params->specular_color_texture);
+			cgltf_write_floatprop(context, "specularFactor", params->specular_factor, 1.0f);
+			if (cgltf_check_floatarray(params->specular_color_factor, 3, 1.0f))
+			{
+				cgltf_write_floatarrayprop(context, "specularColorFactor", params->specular_color_factor, 3);
+			}
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_transmission)
+		{
+			const cgltf_transmission* params = &material->transmission;
+			cgltf_write_line(context, "\"KHR_materials_transmission\": {");
+			CGLTF_WRITE_TEXTURE_INFO("transmissionTexture", params->transmission_texture);
+			cgltf_write_floatprop(context, "transmissionFactor", params->transmission_factor, 0.0f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_volume)
+		{
+			const cgltf_volume* params = &material->volume;
+			cgltf_write_line(context, "\"KHR_materials_volume\": {");
+			CGLTF_WRITE_TEXTURE_INFO("thicknessTexture", params->thickness_texture);
+			cgltf_write_floatprop(context, "thicknessFactor", params->thickness_factor, 0.0f);
+			if (cgltf_check_floatarray(params->attenuation_color, 3, 1.0f))
+			{
+				cgltf_write_floatarrayprop(context, "attenuationColor", params->attenuation_color, 3);
+			}
+			if (params->attenuation_distance < FLT_MAX)
+			{
+				cgltf_write_floatprop(context, "attenuationDistance", params->attenuation_distance, FLT_MAX);
+			}
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_sheen)
+		{
+			const cgltf_sheen* params = &material->sheen;
+			cgltf_write_line(context, "\"KHR_materials_sheen\": {");
+			CGLTF_WRITE_TEXTURE_INFO("sheenColorTexture", params->sheen_color_texture);
+			CGLTF_WRITE_TEXTURE_INFO("sheenRoughnessTexture", params->sheen_roughness_texture);
+			if (cgltf_check_floatarray(params->sheen_color_factor, 3, 0.0f))
+			{
+				cgltf_write_floatarrayprop(context, "sheenColorFactor", params->sheen_color_factor, 3);
+			}
+			cgltf_write_floatprop(context, "sheenRoughnessFactor", params->sheen_roughness_factor, 0.0f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_pbr_specular_glossiness)
+		{
+			const cgltf_pbr_specular_glossiness* params = &material->pbr_specular_glossiness;
+			cgltf_write_line(context, "\"KHR_materials_pbrSpecularGlossiness\": {");
+			CGLTF_WRITE_TEXTURE_INFO("diffuseTexture", params->diffuse_texture);
+			CGLTF_WRITE_TEXTURE_INFO("specularGlossinessTexture", params->specular_glossiness_texture);
+			if (cgltf_check_floatarray(params->diffuse_factor, 4, 1.0f))
+			{
+				cgltf_write_floatarrayprop(context, "diffuseFactor", params->diffuse_factor, 4);
+			}
+			if (cgltf_check_floatarray(params->specular_factor, 3, 1.0f))
+			{
+				cgltf_write_floatarrayprop(context, "specularFactor", params->specular_factor, 3);
+			}
+			cgltf_write_floatprop(context, "glossinessFactor", params->glossiness_factor, 1.0f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->unlit)
+		{
+			cgltf_write_line(context, "\"KHR_materials_unlit\": {}");
+		}
+		if (material->has_emissive_strength)
+		{
+			cgltf_write_line(context, "\"KHR_materials_emissive_strength\": {");
+			const cgltf_emissive_strength* params = &material->emissive_strength;
+			cgltf_write_floatprop(context, "emissiveStrength", params->emissive_strength, 1.f);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_iridescence)
+		{
+			cgltf_write_line(context, "\"KHR_materials_iridescence\": {");
+			const cgltf_iridescence* params = &material->iridescence;
+			cgltf_write_floatprop(context, "iridescenceFactor", params->iridescence_factor, 0.f);
+			CGLTF_WRITE_TEXTURE_INFO("iridescenceTexture", params->iridescence_texture);
+			cgltf_write_floatprop(context, "iridescenceIor", params->iridescence_ior, 1.3f);
+			cgltf_write_floatprop(context, "iridescenceThicknessMinimum", params->iridescence_thickness_min, 100.f);
+			cgltf_write_floatprop(context, "iridescenceThicknessMaximum", params->iridescence_thickness_max, 400.f);
+			CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_diffuse_transmission)
+		{
+			const cgltf_diffuse_transmission* params = &material->diffuse_transmission;
+			cgltf_write_line(context, "\"KHR_materials_diffuse_transmission\": {");
+			CGLTF_WRITE_TEXTURE_INFO("diffuseTransmissionTexture", params->diffuse_transmission_texture);
+			cgltf_write_floatprop(context, "diffuseTransmissionFactor", params->diffuse_transmission_factor, 0.f);
+			if (cgltf_check_floatarray(params->diffuse_transmission_color_factor, 3, 1.f))
+			{
+				cgltf_write_floatarrayprop(context, "diffuseTransmissionColorFactor", params->diffuse_transmission_color_factor, 3);
+			}
+			CGLTF_WRITE_TEXTURE_INFO("diffuseTransmissionColorTexture", params->diffuse_transmission_color_texture);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_anisotropy)
+		{
+			cgltf_write_line(context, "\"KHR_materials_anisotropy\": {");
+			const cgltf_anisotropy* params = &material->anisotropy;
+			cgltf_write_floatprop(context, "anisotropyStrength", params->anisotropy_strength, 0.f);
+			cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f);
+			CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_dispersion)
+		{
+			cgltf_write_line(context, "\"KHR_materials_dispersion\": {");
+			const cgltf_dispersion* params = &material->dispersion;
+			cgltf_write_floatprop(context, "dispersion", params->dispersion, 0.f);
+			cgltf_write_line(context, "}");
+		}
+		cgltf_write_line(context, "}");
+	}
+
+	CGLTF_WRITE_NORMAL_TEXTURE_INFO("normalTexture", material->normal_texture);
+	CGLTF_WRITE_OCCLUSION_TEXTURE_INFO("occlusionTexture", material->occlusion_texture);
+	CGLTF_WRITE_TEXTURE_INFO("emissiveTexture", material->emissive_texture);
+	if (cgltf_check_floatarray(material->emissive_factor, 3, 0.0f))
+	{
+		cgltf_write_floatarrayprop(context, "emissiveFactor", material->emissive_factor, 3);
+	}
+	cgltf_write_strprop(context, "alphaMode", cgltf_str_from_alpha_mode(material->alpha_mode));
+	cgltf_write_extras(context, &material->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_image(cgltf_write_context* context, const cgltf_image* image)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", image->name);
+	cgltf_write_strprop(context, "uri", image->uri);
+	CGLTF_WRITE_IDXPROP("bufferView", image->buffer_view, context->data->buffer_views);
+	cgltf_write_strprop(context, "mimeType", image->mime_type);
+	cgltf_write_extras(context, &image->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_texture(cgltf_write_context* context, const cgltf_texture* texture)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", texture->name);
+	CGLTF_WRITE_IDXPROP("source", texture->image, context->data->images);
+	CGLTF_WRITE_IDXPROP("sampler", texture->sampler, context->data->samplers);
+
+	if (texture->has_basisu || texture->has_webp)
+	{
+		cgltf_write_line(context, "\"extensions\": {");
+		if (texture->has_basisu)
+		{
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_BASISU;
+			cgltf_write_line(context, "\"KHR_texture_basisu\": {");
+			CGLTF_WRITE_IDXPROP("source", texture->basisu_image, context->data->images);
+			cgltf_write_line(context, "}");
+		}
+		if (texture->has_webp)
+		{
+			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_WEBP;
+			cgltf_write_line(context, "\"EXT_texture_webp\": {");
+			CGLTF_WRITE_IDXPROP("source", texture->webp_image, context->data->images);
+			cgltf_write_line(context, "}");
+		}
+		cgltf_write_line(context, "}");
+	}
+	cgltf_write_extras(context, &texture->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_skin(cgltf_write_context* context, const cgltf_skin* skin)
+{
+	cgltf_write_line(context, "{");
+	CGLTF_WRITE_IDXPROP("skeleton", skin->skeleton, context->data->nodes);
+	CGLTF_WRITE_IDXPROP("inverseBindMatrices", skin->inverse_bind_matrices, context->data->accessors);
+	CGLTF_WRITE_IDXARRPROP("joints", skin->joints_count, skin->joints, context->data->nodes);
+	cgltf_write_strprop(context, "name", skin->name);
+	cgltf_write_extras(context, &skin->extras);
+	cgltf_write_line(context, "}");
+}
+
+static const char* cgltf_write_str_path_type(cgltf_animation_path_type path_type)
+{
+	switch (path_type)
+	{
+	case cgltf_animation_path_type_translation:
+		return "translation";
+	case cgltf_animation_path_type_rotation:
+		return "rotation";
+	case cgltf_animation_path_type_scale:
+		return "scale";
+	case cgltf_animation_path_type_weights:
+		return "weights";
+	default:
+		break;
+	}
+	return "invalid";
+}
+
+static const char* cgltf_write_str_interpolation_type(cgltf_interpolation_type interpolation_type)
+{
+	switch (interpolation_type)
+	{
+	case cgltf_interpolation_type_linear:
+		return "LINEAR";
+	case cgltf_interpolation_type_step:
+		return "STEP";
+	case cgltf_interpolation_type_cubic_spline:
+		return "CUBICSPLINE";
+	default:
+		break;
+	}
+	return "invalid";
+}
+
+static void cgltf_write_path_type(cgltf_write_context* context, const char *label, cgltf_animation_path_type path_type)
+{
+	cgltf_write_strprop(context, label, cgltf_write_str_path_type(path_type));
+}
+
+static void cgltf_write_interpolation_type(cgltf_write_context* context, const char *label, cgltf_interpolation_type interpolation_type)
+{
+	cgltf_write_strprop(context, label, cgltf_write_str_interpolation_type(interpolation_type));
+}
+
+static void cgltf_write_animation_sampler(cgltf_write_context* context, const cgltf_animation_sampler* animation_sampler)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_interpolation_type(context, "interpolation", animation_sampler->interpolation);
+	CGLTF_WRITE_IDXPROP("input", animation_sampler->input, context->data->accessors);
+	CGLTF_WRITE_IDXPROP("output", animation_sampler->output, context->data->accessors);
+	cgltf_write_extras(context, &animation_sampler->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_animation_channel(cgltf_write_context* context, const cgltf_animation* animation, const cgltf_animation_channel* animation_channel)
+{
+	cgltf_write_line(context, "{");
+	CGLTF_WRITE_IDXPROP("sampler", animation_channel->sampler, animation->samplers);
+	cgltf_write_line(context, "\"target\": {");
+	CGLTF_WRITE_IDXPROP("node", animation_channel->target_node, context->data->nodes);
+	cgltf_write_path_type(context, "path", animation_channel->target_path);
+	cgltf_write_line(context, "}");
+	cgltf_write_extras(context, &animation_channel->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_animation(cgltf_write_context* context, const cgltf_animation* animation)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", animation->name);
+
+	if (animation->samplers_count > 0)
+	{
+		cgltf_write_line(context, "\"samplers\": [");
+		for (cgltf_size i = 0; i < animation->samplers_count; ++i)
+		{
+			cgltf_write_animation_sampler(context, animation->samplers + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+	if (animation->channels_count > 0)
+	{
+		cgltf_write_line(context, "\"channels\": [");
+		for (cgltf_size i = 0; i < animation->channels_count; ++i)
+		{
+			cgltf_write_animation_channel(context, animation, animation->channels + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+	cgltf_write_extras(context, &animation->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_sampler(cgltf_write_context* context, const cgltf_sampler* sampler)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", sampler->name);
+	cgltf_write_intprop(context, "magFilter", sampler->mag_filter, 0);
+	cgltf_write_intprop(context, "minFilter", sampler->min_filter, 0);
+	cgltf_write_intprop(context, "wrapS", sampler->wrap_s, 10497);
+	cgltf_write_intprop(context, "wrapT", sampler->wrap_t, 10497);
+	cgltf_write_extras(context, &sampler->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* node)
+{
+	cgltf_write_line(context, "{");
+	CGLTF_WRITE_IDXARRPROP("children", node->children_count, node->children, context->data->nodes);
+	CGLTF_WRITE_IDXPROP("mesh", node->mesh, context->data->meshes);
+	cgltf_write_strprop(context, "name", node->name);
+	if (node->has_matrix)
+	{
+		cgltf_write_floatarrayprop(context, "matrix", node->matrix, 16);
+	}
+	if (node->has_translation)
+	{
+		cgltf_write_floatarrayprop(context, "translation", node->translation, 3);
+	}
+	if (node->has_rotation)
+	{
+		cgltf_write_floatarrayprop(context, "rotation", node->rotation, 4);
+	}
+	if (node->has_scale)
+	{
+		cgltf_write_floatarrayprop(context, "scale", node->scale, 3);
+	}
+	if (node->skin)
+	{
+		CGLTF_WRITE_IDXPROP("skin", node->skin, context->data->skins);
+	}
+
+	bool has_extension = node->light || (node->has_mesh_gpu_instancing && node->mesh_gpu_instancing.attributes_count > 0);
+	if(has_extension)
+		cgltf_write_line(context, "\"extensions\": {");
+
+	if (node->light)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_LIGHTS_PUNCTUAL;
+		cgltf_write_line(context, "\"KHR_lights_punctual\": {");
+		CGLTF_WRITE_IDXPROP("light", node->light, context->data->lights);
+		cgltf_write_line(context, "}");
+	}
+
+	if (node->has_mesh_gpu_instancing && node->mesh_gpu_instancing.attributes_count > 0)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING;
+		context->required_extension_flags |= CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING;
+
+		cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {");
+		{
+			cgltf_write_line(context, "\"attributes\": {");
+			{
+				for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i)
+				{
+					const cgltf_attribute* attr = node->mesh_gpu_instancing.attributes + i;
+					CGLTF_WRITE_IDXPROP(attr->name, attr->data, context->data->accessors);
+				}
+			}
+			cgltf_write_line(context, "}");
+		}
+		cgltf_write_line(context, "}");
+	}
+
+	if (has_extension)
+		cgltf_write_line(context, "}");
+
+	if (node->weights_count > 0)
+	{
+		cgltf_write_floatarrayprop(context, "weights", node->weights, node->weights_count);
+	}
+
+	if (node->camera)
+	{
+		CGLTF_WRITE_IDXPROP("camera", node->camera, context->data->cameras);
+	}
+
+	cgltf_write_extras(context, &node->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_scene(cgltf_write_context* context, const cgltf_scene* scene)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", scene->name);
+	CGLTF_WRITE_IDXARRPROP("nodes", scene->nodes_count, scene->nodes, context->data->nodes);
+	cgltf_write_extras(context, &scene->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_accessor* accessor)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", accessor->name);
+	CGLTF_WRITE_IDXPROP("bufferView", accessor->buffer_view, context->data->buffer_views);
+	cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->component_type), 0);
+	cgltf_write_strprop(context, "type", cgltf_str_from_type(accessor->type));
+	cgltf_size dim = cgltf_dim_from_type(accessor->type);
+	cgltf_write_boolprop_optional(context, "normalized", (bool)accessor->normalized, false);
+	cgltf_write_sizeprop(context, "byteOffset", (int)accessor->offset, 0);
+	cgltf_write_intprop(context, "count", (int)accessor->count, -1);
+	if (accessor->has_min)
+	{
+		cgltf_write_floatarrayprop(context, "min", accessor->min, dim);
+	}
+	if (accessor->has_max)
+	{
+		cgltf_write_floatarrayprop(context, "max", accessor->max, dim);
+	}
+	if (accessor->is_sparse)
+	{
+		cgltf_write_line(context, "\"sparse\": {");
+		cgltf_write_intprop(context, "count", (int)accessor->sparse.count, 0);
+		cgltf_write_line(context, "\"indices\": {");
+		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
+		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views);
+		cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0);
+		cgltf_write_line(context, "}");
+		cgltf_write_line(context, "\"values\": {");
+		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
+		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views);
+		cgltf_write_line(context, "}");
+		cgltf_write_line(context, "}");
+	}
+	cgltf_write_extras(context, &accessor->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_camera(cgltf_write_context* context, const cgltf_camera* camera)
+{
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "type", cgltf_str_from_camera_type(camera->type));
+	if (camera->name)
+	{
+		cgltf_write_strprop(context, "name", camera->name);
+	}
+
+	if (camera->type == cgltf_camera_type_orthographic)
+	{
+		cgltf_write_line(context, "\"orthographic\": {");
+		cgltf_write_floatprop(context, "xmag", camera->data.orthographic.xmag, -1.0f);
+		cgltf_write_floatprop(context, "ymag", camera->data.orthographic.ymag, -1.0f);
+		cgltf_write_floatprop(context, "zfar", camera->data.orthographic.zfar, -1.0f);
+		cgltf_write_floatprop(context, "znear", camera->data.orthographic.znear, -1.0f);
+		cgltf_write_extras(context, &camera->data.orthographic.extras);
+		cgltf_write_line(context, "}");
+	}
+	else if (camera->type == cgltf_camera_type_perspective)
+	{
+		cgltf_write_line(context, "\"perspective\": {");
+
+		if (camera->data.perspective.has_aspect_ratio) {
+			cgltf_write_floatprop(context, "aspectRatio", camera->data.perspective.aspect_ratio, -1.0f);
+		}
+
+		cgltf_write_floatprop(context, "yfov", camera->data.perspective.yfov, -1.0f);
+
+		if (camera->data.perspective.has_zfar) {
+			cgltf_write_floatprop(context, "zfar", camera->data.perspective.zfar, -1.0f);
+		}
+
+		cgltf_write_floatprop(context, "znear", camera->data.perspective.znear, -1.0f);
+		cgltf_write_extras(context, &camera->data.perspective.extras);
+		cgltf_write_line(context, "}");
+	}
+	cgltf_write_extras(context, &camera->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* light)
+{
+	context->extension_flags |= CGLTF_EXTENSION_FLAG_LIGHTS_PUNCTUAL;
+
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "type", cgltf_str_from_light_type(light->type));
+	if (light->name)
+	{
+		cgltf_write_strprop(context, "name", light->name);
+	}
+	if (cgltf_check_floatarray(light->color, 3, 1.0f))
+	{
+		cgltf_write_floatarrayprop(context, "color", light->color, 3);
+	}
+	cgltf_write_floatprop(context, "intensity", light->intensity, 1.0f);
+	cgltf_write_floatprop(context, "range", light->range, 0.0f);
+
+	if (light->type == cgltf_light_type_spot)
+	{
+		cgltf_write_line(context, "\"spot\": {");
+		cgltf_write_floatprop(context, "innerConeAngle", light->spot_inner_cone_angle, 0.0f);
+		cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f);
+		cgltf_write_line(context, "}");
+	}
+	cgltf_write_extras( context, &light->extras );
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_variant(cgltf_write_context* context, const cgltf_material_variant* variant)
+{
+	context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS;
+
+	cgltf_write_line(context, "{");
+	cgltf_write_strprop(context, "name", variant->name);
+	cgltf_write_extras(context, &variant->extras);
+	cgltf_write_line(context, "}");
+}
+
+static void cgltf_write_glb(FILE* file, const void* json_buf, const cgltf_size json_size, const void* bin_buf, const cgltf_size bin_size)
+{
+	char header[GlbHeaderSize];
+	char chunk_header[GlbChunkHeaderSize];
+	char json_pad[3] = { 0x20, 0x20, 0x20 };
+	char bin_pad[3] = { 0, 0, 0 };
+
+	cgltf_size json_padsize = (json_size % 4 != 0) ? 4 - json_size % 4 : 0;
+	cgltf_size bin_padsize = (bin_size % 4 != 0) ? 4 - bin_size % 4 : 0;
+	cgltf_size total_size = GlbHeaderSize + GlbChunkHeaderSize + json_size + json_padsize;
+	if (bin_buf != NULL && bin_size > 0) {
+		total_size += GlbChunkHeaderSize + bin_size + bin_padsize;
+	}
+
+	// Write a GLB header
+	memcpy(header, &GlbMagic, 4);
+	memcpy(header + 4, &GlbVersion, 4);
+	memcpy(header + 8, &total_size, 4);
+	fwrite(header, 1, GlbHeaderSize, file);
+
+	// Write a JSON chunk (header & data)
+	uint32_t json_chunk_size = (uint32_t)(json_size + json_padsize);
+	memcpy(chunk_header, &json_chunk_size, 4);
+	memcpy(chunk_header + 4, &GlbMagicJsonChunk, 4);
+	fwrite(chunk_header, 1, GlbChunkHeaderSize, file);
+
+	fwrite(json_buf, 1, json_size, file);
+	fwrite(json_pad, 1, json_padsize, file);
+
+	if (bin_buf != NULL && bin_size > 0) {
+		// Write a binary chunk (header & data)
+		uint32_t bin_chunk_size = (uint32_t)(bin_size + bin_padsize);
+		memcpy(chunk_header, &bin_chunk_size, 4);
+		memcpy(chunk_header + 4, &GlbMagicBinChunk, 4);
+		fwrite(chunk_header, 1, GlbChunkHeaderSize, file);
+
+		fwrite(bin_buf, 1, bin_size, file);
+		fwrite(bin_pad, 1, bin_padsize, file);
+	}
+}
+
+cgltf_result cgltf_write_file(const cgltf_options* options, const char* path, const cgltf_data* data)
+{
+	cgltf_size expected = cgltf_write(options, NULL, 0, data);
+	char* buffer = (char*) malloc(expected);
+	cgltf_size actual = cgltf_write(options, buffer, expected, data);
+	if (expected != actual) {
+		fprintf(stderr, "Error: expected %zu bytes but wrote %zu bytes.\n", expected, actual);
+	}
+	FILE* file = fopen(path, "wb");
+	if (!file)
+	{
+		return cgltf_result_file_not_found;
+	}
+	// Note that cgltf_write() includes a null terminator, which we omit from the file content.
+	if (options->type == cgltf_file_type_glb) {
+		cgltf_write_glb(file, buffer, actual - 1, data->bin, data->bin_size);
+	} else {
+		// Write a plain JSON file.
+		fwrite(buffer, actual - 1, 1, file);
+	}
+	fclose(file);
+	free(buffer);
+	return cgltf_result_success;
+}
+
+static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extension_flags)
+{
+	if (extension_flags & CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM) {
+		cgltf_write_stritem(context, "KHR_texture_transform");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_UNLIT) {
+		cgltf_write_stritem(context, "KHR_materials_unlit");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_SPECULAR_GLOSSINESS) {
+		cgltf_write_stritem(context, "KHR_materials_pbrSpecularGlossiness");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_LIGHTS_PUNCTUAL) {
+		cgltf_write_stritem(context, "KHR_lights_punctual");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION) {
+		cgltf_write_stritem(context, "KHR_draco_mesh_compression");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_CLEARCOAT) {
+		cgltf_write_stritem(context, "KHR_materials_clearcoat");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IOR) {
+		cgltf_write_stritem(context, "KHR_materials_ior");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_SPECULAR) {
+		cgltf_write_stritem(context, "KHR_materials_specular");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_TRANSMISSION) {
+		cgltf_write_stritem(context, "KHR_materials_transmission");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_SHEEN) {
+		cgltf_write_stritem(context, "KHR_materials_sheen");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS) {
+		cgltf_write_stritem(context, "KHR_materials_variants");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME) {
+		cgltf_write_stritem(context, "KHR_materials_volume");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_TEXTURE_BASISU) {
+		cgltf_write_stritem(context, "KHR_texture_basisu");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_TEXTURE_WEBP) {
+		cgltf_write_stritem(context, "EXT_texture_webp");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH) {
+		cgltf_write_stritem(context, "KHR_materials_emissive_strength");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) {
+		cgltf_write_stritem(context, "KHR_materials_iridescence");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DIFFUSE_TRANSMISSION) {
+		cgltf_write_stritem(context, "KHR_materials_diffuse_transmission");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) {
+		cgltf_write_stritem(context, "KHR_materials_anisotropy");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) {
+		cgltf_write_stritem(context, "EXT_mesh_gpu_instancing");
+	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) {
+		cgltf_write_stritem(context, "KHR_materials_dispersion");
+	}
+}
+
+cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)
+{
+	(void)options;
+	cgltf_write_context ctx;
+	ctx.buffer = buffer;
+	ctx.buffer_size = size;
+	ctx.remaining = size;
+	ctx.cursor = buffer;
+	ctx.chars_written = 0;
+	ctx.data = data;
+	ctx.depth = 1;
+	ctx.indent = "  ";
+	ctx.needs_comma = 0;
+	ctx.extension_flags = 0;
+	ctx.required_extension_flags = 0;
+
+	cgltf_write_context* context = &ctx;
+
+	CGLTF_SPRINTF("{");
+
+	if (data->accessors_count > 0)
+	{
+		cgltf_write_line(context, "\"accessors\": [");
+		for (cgltf_size i = 0; i < data->accessors_count; ++i)
+		{
+			cgltf_write_accessor(context, data->accessors + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	cgltf_write_asset(context, &data->asset);
+
+	if (data->buffer_views_count > 0)
+	{
+		cgltf_write_line(context, "\"bufferViews\": [");
+		for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
+		{
+			cgltf_write_buffer_view(context, data->buffer_views + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->buffers_count > 0)
+	{
+		cgltf_write_line(context, "\"buffers\": [");
+		for (cgltf_size i = 0; i < data->buffers_count; ++i)
+		{
+			cgltf_write_buffer(context, data->buffers + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->images_count > 0)
+	{
+		cgltf_write_line(context, "\"images\": [");
+		for (cgltf_size i = 0; i < data->images_count; ++i)
+		{
+			cgltf_write_image(context, data->images + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->meshes_count > 0)
+	{
+		cgltf_write_line(context, "\"meshes\": [");
+		for (cgltf_size i = 0; i < data->meshes_count; ++i)
+		{
+			cgltf_write_mesh(context, data->meshes + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->materials_count > 0)
+	{
+		cgltf_write_line(context, "\"materials\": [");
+		for (cgltf_size i = 0; i < data->materials_count; ++i)
+		{
+			cgltf_write_material(context, data->materials + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->nodes_count > 0)
+	{
+		cgltf_write_line(context, "\"nodes\": [");
+		for (cgltf_size i = 0; i < data->nodes_count; ++i)
+		{
+			cgltf_write_node(context, data->nodes + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->samplers_count > 0)
+	{
+		cgltf_write_line(context, "\"samplers\": [");
+		for (cgltf_size i = 0; i < data->samplers_count; ++i)
+		{
+			cgltf_write_sampler(context, data->samplers + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	CGLTF_WRITE_IDXPROP("scene", data->scene, data->scenes);
+
+	if (data->scenes_count > 0)
+	{
+		cgltf_write_line(context, "\"scenes\": [");
+		for (cgltf_size i = 0; i < data->scenes_count; ++i)
+		{
+			cgltf_write_scene(context, data->scenes + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->textures_count > 0)
+	{
+		cgltf_write_line(context, "\"textures\": [");
+		for (cgltf_size i = 0; i < data->textures_count; ++i)
+		{
+			cgltf_write_texture(context, data->textures + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->skins_count > 0)
+	{
+		cgltf_write_line(context, "\"skins\": [");
+		for (cgltf_size i = 0; i < data->skins_count; ++i)
+		{
+			cgltf_write_skin(context, data->skins + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->animations_count > 0)
+	{
+		cgltf_write_line(context, "\"animations\": [");
+		for (cgltf_size i = 0; i < data->animations_count; ++i)
+		{
+			cgltf_write_animation(context, data->animations + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->cameras_count > 0)
+	{
+		cgltf_write_line(context, "\"cameras\": [");
+		for (cgltf_size i = 0; i < data->cameras_count; ++i)
+		{
+			cgltf_write_camera(context, data->cameras + i);
+		}
+		cgltf_write_line(context, "]");
+	}
+
+	if (data->lights_count > 0 || data->variants_count > 0)
+	{
+		cgltf_write_line(context, "\"extensions\": {");
+
+		if (data->lights_count > 0)
+		{
+			cgltf_write_line(context, "\"KHR_lights_punctual\": {");
+			cgltf_write_line(context, "\"lights\": [");
+			for (cgltf_size i = 0; i < data->lights_count; ++i)
+			{
+				cgltf_write_light(context, data->lights + i);
+			}
+			cgltf_write_line(context, "]");
+			cgltf_write_line(context, "}");
+		}
+
+		if (data->variants_count)
+		{
+			cgltf_write_line(context, "\"KHR_materials_variants\": {");
+			cgltf_write_line(context, "\"variants\": [");
+			for (cgltf_size i = 0; i < data->variants_count; ++i)
+			{
+				cgltf_write_variant(context, data->variants + i);
+			}
+			cgltf_write_line(context, "]");
+			cgltf_write_line(context, "}");
+		}
+
+		cgltf_write_line(context, "}");
+	}
+
+	if (context->extension_flags != 0)
+	{
+		cgltf_write_line(context, "\"extensionsUsed\": [");
+		cgltf_write_extensions(context, context->extension_flags);
+		cgltf_write_line(context, "]");
+	}
+
+	if (context->required_extension_flags != 0)
+	{
+		cgltf_write_line(context, "\"extensionsRequired\": [");
+		cgltf_write_extensions(context, context->required_extension_flags);
+		cgltf_write_line(context, "]");
+	}
+
+	cgltf_write_extras(context, &data->extras);
+
+	CGLTF_SPRINTF("\n}\n");
+
+	// snprintf does not include the null terminator in its return value, so be sure to include it
+	// in the returned byte count.
+	return 1 + ctx.chars_written;
+}
+
+#endif /* #ifdef CGLTF_WRITE_IMPLEMENTATION */
+
+/* cgltf is distributed under MIT license:
+ *
+ * Copyright (c) 2019-2021 Philip Rideout
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
diff --git a/raylib/src/external/dr_flac.h b/raylib/src/external/dr_flac.h
--- a/raylib/src/external/dr_flac.h
+++ b/raylib/src/external/dr_flac.h
@@ -1,6 +1,6 @@
 /*
 FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
-dr_flac - v0.13.0 - TBD
+dr_flac - v0.13.4 - TBD
 
 David Reid - mackron@gmail.com
 
@@ -126,7 +126,7 @@
 
 #define DRFLAC_VERSION_MAJOR     0
 #define DRFLAC_VERSION_MINOR     13
-#define DRFLAC_VERSION_REVISION  0
+#define DRFLAC_VERSION_REVISION  4
 #define DRFLAC_VERSION_STRING    DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
 
 #include <stddef.h> /* For size_t. */
@@ -331,6 +331,12 @@
     */
     drflac_uint32 type;
 
+    /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
+    drflac_uint32 rawDataSize;
+
+    /* The offset in the stream of the raw data. */
+    drflac_uint64 rawDataOffset;
+
     /*
     A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
     not modify the contents of this buffer. Use the structures below for more meaningful and structured
@@ -338,9 +344,6 @@
     */
     const void* pRawData;
 
-    /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
-    drflac_uint32 rawDataSize;
-
     union
     {
         drflac_streaminfo streaminfo;
@@ -392,6 +395,7 @@
             drflac_uint32 colorDepth;
             drflac_uint32 indexColorCount;
             drflac_uint32 pictureDataSize;
+            drflac_uint64 pictureDataOffset;  /* Offset from the start of the stream. */
             const drflac_uint8* pPictureData;
         } picture;
     } data;
@@ -1543,6 +1547,8 @@
 #define DRFLAC_ZERO_OBJECT(p)               DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
 #endif
 
+#define DRFLAC_MIN(a, b)                    (((a) < (b)) ? (a) : (b))
+
 #define DRFLAC_MAX_SIMD_VECTOR_SIZE                     64  /* 64 for AVX-512 in the future. */
 
 /* Result Codes */
@@ -2712,9 +2718,17 @@
     #if defined(__GNUC__) || defined(__clang__)
         #if defined(DRFLAC_X64)
             {
+                /*
+                A note on lzcnt.
+
+                We check for the presence of the lzcnt instruction at runtime before calling this function, but we still generate this code. I have had
+                a report where the assembler does not recognize the lzcnt instruction. To work around this we are going to use `rep; bsr` instead which
+                has an identical byte encoding as lzcnt, and should hopefully improve compatibility with older assemblers.
+                */
                 drflac_uint64 r;
                 __asm__ __volatile__ (
-                    "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                    "rep; bsr{q %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                    /*"lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
                 );
 
                 return (drflac_uint32)r;
@@ -2723,12 +2737,13 @@
             {
                 drflac_uint32 r;
                 __asm__ __volatile__ (
-                    "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                    "rep; bsr{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                    /*"lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/
                 );
 
                 return r;
             }
-        #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT)   /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
+        #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !(defined(__thumb__) && !defined(__thumb2__)) && !defined(DRFLAC_64BIT)   /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
             {
                 unsigned int r;
                 __asm__ __volatile__ (
@@ -5967,8 +5982,6 @@
                     break;  /* Failed to seek to FLAC frame. */
                 }
             } else {
-                const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
-
                 if (pcmRangeLo > pcmFrameIndex) {
                     /* We seeked too far forward. We need to move our target byte backward and try again. */
                     byteRangeHi = lastSuccessfulSeekOffset;
@@ -5991,12 +6004,14 @@
                             break;  /* Failed to seek to FLAC frame. */
                         }
                     } else {
+                        const double approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0);
+
                         byteRangeLo = lastSuccessfulSeekOffset;
                         if (byteRangeHi < byteRangeLo) {
                             byteRangeHi = byteRangeLo;
                         }
 
-                        targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
+                        targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0) * approxCompressionRatio);
                         if (targetByte > byteRangeHi) {
                             targetByte = byteRangeHi;
                         }
@@ -6389,7 +6404,7 @@
         }
 
         if (p != NULL) {
-            DRFLAC_COPY_MEMORY(p2, p, szOld);
+            DRFLAC_COPY_MEMORY(p2, p, DRFLAC_MIN(szNew, szOld));
             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
         }
 
@@ -6417,12 +6432,23 @@
     We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
     we'll be sitting on byte 42.
     */
-    drflac_uint64 runningFilePos = 42;
-    drflac_uint64 seektablePos   = 0;
-    drflac_uint32 seektableSize  = 0;
+    drflac_uint64 runningFilePos   = 42;
+    drflac_uint64 seektablePos     = 0;
+    drflac_uint32 seektableSize    = 0;
+    drflac_int64  fileSize         = 0;
+    drflac_bool32 hasKnownFileSize = DRFLAC_FALSE;
 
-    (void)onTell;
+    /* We'll be doing some memory allocations here against untrusted data. We'll do a basic validation check that they don't exceed the size of the file. */
+    if (onTell != NULL && onSeek != NULL) {
+        if (onSeek(pUserData, 0, DRFLAC_SEEK_END)) {
+            if (onTell(pUserData, &fileSize)) {
+                hasKnownFileSize = DRFLAC_TRUE;
+            }
 
+            onSeek(pUserData, runningFilePos, DRFLAC_SEEK_SET);
+        }
+    }
+
     for (;;) {
         drflac_metadata metadata;
         drflac_uint8 isLastBlock = 0;
@@ -6431,11 +6457,17 @@
         if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
             return DRFLAC_FALSE;
         }
+
+        if (hasKnownFileSize && (blockSize > ((drflac_uint64)fileSize - runningFilePos))) {
+            return DRFLAC_FALSE;    /* Block size exceeds the size of the file. */
+        }
+
         runningFilePos += 4;
 
         metadata.type = blockType;
-        metadata.pRawData = NULL;
         metadata.rawDataSize = 0;
+        metadata.rawDataOffset = runningFilePos;
+        metadata.pRawData = NULL;
 
         switch (blockType)
         {
@@ -6545,7 +6577,7 @@
                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
                         return DRFLAC_FALSE;
                     }
-                    metadata.data.vorbis_comment.vendor       = pRunningData;                                            pRunningData += metadata.data.vorbis_comment.vendorLength;
+                    metadata.data.vorbis_comment.vendor       = pRunningData;                                   pRunningData += metadata.data.vorbis_comment.vendorLength;
                     metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
 
                     /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */
@@ -6712,59 +6744,161 @@
                 }
 
                 if (onMeta) {
-                    void* pRawData;
-                    const char* pRunningData;
-                    const char* pRunningDataEnd;
+                    drflac_bool32 result = DRFLAC_TRUE;
+                    drflac_uint32 blockSizeRemaining = blockSize;
+                    char* pMime = NULL;
+                    char* pDescription = NULL;
+                    void* pPictureData = NULL;
 
-                    pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
-                    if (pRawData == NULL) {
-                        return DRFLAC_FALSE;
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.type, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
                     }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.type = drflac__be2host_32(metadata.data.picture.type);
 
-                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
-                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
-                        return DRFLAC_FALSE;
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.mimeLength, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
                     }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.mimeLength = drflac__be2host_32(metadata.data.picture.mimeLength);
 
-                    metadata.pRawData = pRawData;
-                    metadata.rawDataSize = blockSize;
+                    if (blockSizeRemaining < metadata.data.picture.mimeLength) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
 
-                    pRunningData    = (const char*)pRawData;
-                    pRunningDataEnd = (const char*)pRawData + blockSize;
+                    pMime = (char*)drflac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
+                    if (pMime == NULL) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
 
-                    metadata.data.picture.type       = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
+                    if (onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= metadata.data.picture.mimeLength;
+                    pMime[metadata.data.picture.mimeLength] = '\0';  /* Null terminate for safety. */
+                    metadata.data.picture.mime = (const char*)pMime;
 
-                    /* Need space for the rest of the block */
-                    if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
-                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
-                        return DRFLAC_FALSE;
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.descriptionLength, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
                     }
-                    metadata.data.picture.mime              = pRunningData;                                   pRunningData += metadata.data.picture.mimeLength;
-                    metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.descriptionLength = drflac__be2host_32(metadata.data.picture.descriptionLength);
 
-                    /* Need space for the rest of the block */
-                    if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
-                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
-                        return DRFLAC_FALSE;
+                    if (blockSizeRemaining < metadata.data.picture.descriptionLength) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
                     }
-                    metadata.data.picture.description     = pRunningData;                                   pRunningData += metadata.data.picture.descriptionLength;
-                    metadata.data.picture.width           = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.height          = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.colorDepth      = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
-                    metadata.data.picture.pPictureData    = (const drflac_uint8*)pRunningData;
 
-                    /* Need space for the picture after the block */
-                    if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */
-                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
-                        return DRFLAC_FALSE;
+                    pDescription = (char*)drflac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); /* +1 for null terminator. */
+                    if (pDescription == NULL) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
                     }
 
-                    onMeta(pUserDataMD, &metadata);
+                    if (onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= metadata.data.picture.descriptionLength;
+                    pDescription[metadata.data.picture.descriptionLength] = '\0';  /* Null terminate for safety. */
+                    metadata.data.picture.description = (const char*)pDescription;
 
-                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.width, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.width = drflac__be2host_32(metadata.data.picture.width);
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.height, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.height = drflac__be2host_32(metadata.data.picture.height);
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.colorDepth, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.colorDepth = drflac__be2host_32(metadata.data.picture.colorDepth);
+
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.indexColorCount, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.indexColorCount = drflac__be2host_32(metadata.data.picture.indexColorCount);
+
+
+                    /* Picture data. */
+                    if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.pictureDataSize, 4) != 4) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+                    blockSizeRemaining -= 4;
+                    metadata.data.picture.pictureDataSize = drflac__be2host_32(metadata.data.picture.pictureDataSize);
+
+                    if (blockSizeRemaining < metadata.data.picture.pictureDataSize) {
+                        result = DRFLAC_FALSE;
+                        goto done_flac;
+                    }
+
+                    /* For the actual image data we want to store the offset to the start of the stream. */
+                    metadata.data.picture.pictureDataOffset = runningFilePos + (blockSize - blockSizeRemaining);
+
+                    /*
+                    For the allocation of image data, we can allow memory allocation to fail, in which case we just leave
+                    the pointer as null. If it fails, we need to fall back to seeking past the image data.
+                    */
+                #ifndef DR_FLAC_NO_PICTURE_METADATA_MALLOC
+                    pPictureData = drflac__malloc_from_callbacks(metadata.data.picture.pictureDataSize, pAllocationCallbacks);
+                    if (pPictureData != NULL) {
+                        if (onRead(pUserData, pPictureData, metadata.data.picture.pictureDataSize) != metadata.data.picture.pictureDataSize) {
+                            result = DRFLAC_FALSE;
+                            goto done_flac;
+                        }
+                    } else
+                #endif
+                    {
+                        /* Allocation failed. We need to seek past the picture data. */
+                        if (!onSeek(pUserData, metadata.data.picture.pictureDataSize, DRFLAC_SEEK_CUR)) {
+                            result = DRFLAC_FALSE;
+                            goto done_flac;
+                        }
+                    }
+
+                    blockSizeRemaining -= metadata.data.picture.pictureDataSize;
+                    (void)blockSizeRemaining;
+
+                    metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData;
+                    
+
+                    /* Only fire the callback if we actually have a way to read the image data. We must have either a valid offset, or a valid data pointer. */
+                    if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) {
+                        onMeta(pUserDataMD, &metadata);
+                    } else {
+                        /* Don't have a valid offset or data pointer, so just pretend we don't have a picture metadata. */
+                    }
+
+                done_flac:
+                    drflac__free_from_callbacks(pMime,        pAllocationCallbacks);
+                    drflac__free_from_callbacks(pDescription, pAllocationCallbacks);
+                    drflac__free_from_callbacks(pPictureData, pAllocationCallbacks);
+
+                    if (result != DRFLAC_TRUE) {
+                        return DRFLAC_FALSE;
+                    }
                 }
             } break;
 
@@ -6800,13 +6934,16 @@
                 */
                 if (onMeta) {
                     void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
-                    if (pRawData == NULL) {
-                        return DRFLAC_FALSE;
-                    }
-
-                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
-                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
-                        return DRFLAC_FALSE;
+                    if (pRawData != NULL) {
+                        if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                            drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                            return DRFLAC_FALSE;
+                        }
+                    } else {
+                        /* Allocation failed. We need to seek past the block. */
+                        if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
+                            return DRFLAC_FALSE;
+                        }
                     }
 
                     metadata.pRawData = pRawData;
@@ -7985,11 +8122,17 @@
             return NULL;
         }
 
+        if ((0xFFFFFFFF - (seekpointCount * sizeof(drflac_seekpoint))) < allocationSize) {
+        #ifndef DR_FLAC_NO_OGG
+            drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
+        #endif
+            return NULL;
+        }
+
         allocationSize += seekpointCount * sizeof(drflac_seekpoint);
     }
 
-
-    pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
+    pFlac = (drflac*)drflac__malloc_from_callbacks((size_t)allocationSize, &allocationCallbacks);
     if (pFlac == NULL) {
     #ifndef DR_FLAC_NO_OGG
         drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
@@ -8699,7 +8842,7 @@
     DRFLAC_ASSERT(pFileStdio != NULL);
     DRFLAC_ASSERT(pCursor    != NULL);
 
-#if defined(_WIN32)
+#if defined(_WIN32) && !defined(NXDK)
     #if defined(_MSC_VER) && _MSC_VER > 1200
         result = _ftelli64(pFileStdio);
     #else
@@ -8821,8 +8964,6 @@
 
     DRFLAC_ASSERT(memoryStream != NULL);
 
-    newCursor = memoryStream->currentReadPos;
-
     if (origin == DRFLAC_SEEK_SET) {
         newCursor = 0;
     } else if (origin == DRFLAC_SEEK_CUR) {
@@ -11702,58 +11843,43 @@
 {                                                                                                                                                                   \
     type* pSampleData = NULL;                                                                                                                                       \
     drflac_uint64 totalPCMFrameCount;                                                                                                                               \
+    type buffer[4096];                                                                                                                                              \
+    drflac_uint64 pcmFramesRead;                                                                                                                                    \
+    size_t sampleDataBufferSize = sizeof(buffer);                                                                                                                   \
                                                                                                                                                                     \
     DRFLAC_ASSERT(pFlac != NULL);                                                                                                                                   \
                                                                                                                                                                     \
-    totalPCMFrameCount = pFlac->totalPCMFrameCount;                                                                                                                 \
-                                                                                                                                                                    \
-    if (totalPCMFrameCount == 0) {                                                                                                                                  \
-        type buffer[4096];                                                                                                                                          \
-        drflac_uint64 pcmFramesRead;                                                                                                                                \
-        size_t sampleDataBufferSize = sizeof(buffer);                                                                                                               \
-                                                                                                                                                                    \
-        pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks);                                                      \
-        if (pSampleData == NULL) {                                                                                                                                  \
-            goto on_error;                                                                                                                                          \
-        }                                                                                                                                                           \
+    totalPCMFrameCount = 0;                                                                                                                                         \
                                                                                                                                                                     \
-        while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) {          \
-            if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) {                                                   \
-                type* pNewSampleData;                                                                                                                               \
-                size_t newSampleDataBufferSize;                                                                                                                     \
+    pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks);                                                          \
+    if (pSampleData == NULL) {                                                                                                                                      \
+        goto on_error;                                                                                                                                              \
+    }                                                                                                                                                               \
                                                                                                                                                                     \
-                newSampleDataBufferSize = sampleDataBufferSize * 2;                                                                                                 \
-                pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks);    \
-                if (pNewSampleData == NULL) {                                                                                                                       \
-                    drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks);                                                                          \
-                    goto on_error;                                                                                                                                  \
-                }                                                                                                                                                   \
+    while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) {              \
+        if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) {                                                       \
+            type* pNewSampleData;                                                                                                                                   \
+            size_t newSampleDataBufferSize;                                                                                                                         \
                                                                                                                                                                     \
-                sampleDataBufferSize = newSampleDataBufferSize;                                                                                                     \
-                pSampleData = pNewSampleData;                                                                                                                       \
+            newSampleDataBufferSize = sampleDataBufferSize * 2;                                                                                                     \
+            pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks);        \
+            if (pNewSampleData == NULL) {                                                                                                                           \
+                drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks);                                                                              \
+                goto on_error;                                                                                                                                      \
             }                                                                                                                                                       \
                                                                                                                                                                     \
-            DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type)));                   \
-            totalPCMFrameCount += pcmFramesRead;                                                                                                                    \
-        }                                                                                                                                                           \
-                                                                                                                                                                    \
-        /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to                                       \
-           protect those ears from random noise! */                                                                                                                 \
-        DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type)));   \
-    } else {                                                                                                                                                        \
-        drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type);                                                                                   \
-        if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) {                                                                                                            \
-            goto on_error;  /* The decoded data is too big. */                                                                                                      \
-        }                                                                                                                                                           \
-                                                                                                                                                                    \
-        pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks);    /* <-- Safe cast as per the check above. */           \
-        if (pSampleData == NULL) {                                                                                                                                  \
-            goto on_error;                                                                                                                                          \
+            sampleDataBufferSize = newSampleDataBufferSize;                                                                                                         \
+            pSampleData = pNewSampleData;                                                                                                                           \
         }                                                                                                                                                           \
                                                                                                                                                                     \
-        totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData);                                                     \
+        DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type)));                       \
+        totalPCMFrameCount += pcmFramesRead;                                                                                                                        \
     }                                                                                                                                                               \
                                                                                                                                                                     \
+    /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to                                           \
+       protect those ears from random noise! */                                                                                                                     \
+    DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type)));       \
+                                                                                                                                                                    \
     if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;                                                                                                          \
     if (channelsOut) *channelsOut = pFlac->channels;                                                                                                                \
     if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount;                                                                                         \
@@ -12077,7 +12203,23 @@
 /*
 REVISION HISTORY
 ================
-v0.13.0 - TBD
+v0.13.4 - TBD
+  - Add a bounds check when allocating memory during metadata processing.
+  - Fix a possible overflow error when parsing picture metadata.
+
+v0.13.3 - 2026-01-17
+  - Fix a compiler compatibility issue with some inlined assembly.
+  - Fix a compilation warning.
+
+v0.13.2 - 2025-12-02
+  - Improve robustness of the parsing of picture metadata to improve support for memory constrained embedded devices.
+  - Fix a warning about an assigned by unused variable.
+  - Improvements to drflac_open_and_read_pcm_frames_*() and family to avoid excessively large memory allocations from malformed files.
+
+v0.13.1 - 2025-09-10
+  - Fix an error with the NXDK build.
+
+v0.13.0 - 2025-07-23
   - API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries:
     - drflac_seek_origin_start   -> DRFLAC_SEEK_SET
     - drflac_seek_origin_current -> DRFLAC_SEEK_CUR
diff --git a/raylib/src/external/dr_mp3.h b/raylib/src/external/dr_mp3.h
--- a/raylib/src/external/dr_mp3.h
+++ b/raylib/src/external/dr_mp3.h
@@ -1,6 +1,6 @@
 /*
 MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
-dr_mp3 - v0.7.0 - TBD
+dr_mp3 - v0.7.4 - TBD
 
 David Reid - mackron@gmail.com
 
@@ -72,7 +72,7 @@
 
 #define DRMP3_VERSION_MAJOR     0
 #define DRMP3_VERSION_MINOR     7
-#define DRMP3_VERSION_REVISION  0
+#define DRMP3_VERSION_REVISION  4
 #define DRMP3_VERSION_STRING    DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
 
 #include <stddef.h> /* For size_t. */
@@ -257,6 +257,10 @@
 Low Level Push API
 ==================
 */
+#define DRMP3_MAX_BITRESERVOIR_BYTES      511
+#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE  2304    /* more than ISO spec's */
+#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES  DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */
+
 typedef struct
 {
     int frame_bytes, channels, sample_rate, layer, bitrate_kbps;
@@ -264,9 +268,34 @@
 
 typedef struct
 {
+    const drmp3_uint8 *buf;
+    int pos, limit;
+} drmp3_bs;
+
+typedef struct
+{
+    const drmp3_uint8 *sfbtab;
+    drmp3_uint16 part_23_length, big_values, scalefac_compress;
+    drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
+    drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
+    drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
+} drmp3_L3_gr_info;
+
+typedef struct
+{
+    drmp3_bs bs;
+    drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
+    drmp3_L3_gr_info gr_info[4];
+    float grbuf[2][576], scf[40], syn[18 + 15][2*32];
+    drmp3_uint8 ist_pos[2][39];
+} drmp3dec_scratch;
+
+typedef struct
+{
     float mdct_overlap[2][9*32], qmf_state[15*2*32];
     int reserv, free_format_bytes;
     drmp3_uint8 header[4], reserv_buf[511];
+    drmp3dec_scratch scratch;
 } drmp3dec;
 
 /* Initializes a low level decoder. */
@@ -592,14 +621,10 @@
 
 #define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset)))
 
-#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE  2304    /* more than ISO spec's */
 #ifndef DRMP3_MAX_FRAME_SYNC_MATCHES
 #define DRMP3_MAX_FRAME_SYNC_MATCHES      10
 #endif
 
-#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES  DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */
-
-#define DRMP3_MAX_BITRESERVOIR_BYTES      511
 #define DRMP3_SHORT_BLOCK_TYPE            2
 #define DRMP3_STOP_BLOCK_TYPE             3
 #define DRMP3_MODE_MONO                   3
@@ -632,10 +657,12 @@
 
 #if !defined(DR_MP3_NO_SIMD)
 
-#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC))
-/* x64 always have SSE2, arm64 always have neon, no need for generic code */
+#if !defined(DR_MP3_ONLY_SIMD) && ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
 #define DR_MP3_ONLY_SIMD
 #endif
+#if !defined(DR_MP3_ONLY_SIMD) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC))
+#define DR_MP3_ONLY_SIMD
+#endif
 
 #if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
 #if defined(_MSC_VER)
@@ -655,7 +682,7 @@
 #define DRMP3_VMUL_S(x, s)  _mm_mul_ps(x, _mm_set1_ps(s))
 #define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3))
 typedef __m128 drmp3_f4;
-#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
+#if (defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)) && !defined(__clang__)
 #define drmp3_cpuid __cpuid
 #else
 static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
@@ -779,12 +806,8 @@
 #define DRMP3_FREE(p) free((p))
 #endif
 
-typedef struct
-{
-    const drmp3_uint8 *buf;
-    int pos, limit;
-} drmp3_bs;
 
+
 typedef struct
 {
     float scf[3*64];
@@ -796,24 +819,6 @@
     drmp3_uint8 tab_offset, code_tab_width, band_count;
 } drmp3_L12_subband_alloc;
 
-typedef struct
-{
-    const drmp3_uint8 *sfbtab;
-    drmp3_uint16 part_23_length, big_values, scalefac_compress;
-    drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
-    drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
-    drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
-} drmp3_L3_gr_info;
-
-typedef struct
-{
-    drmp3_bs bs;
-    drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
-    drmp3_L3_gr_info gr_info[4];
-    float grbuf[2][576], scf[40], syn[18 + 15][2*32];
-    drmp3_uint8 ist_pos[2][39];
-} drmp3dec_scratch;
-
 static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes)
 {
     bs->buf   = data;
@@ -1227,6 +1232,14 @@
     return y;
 }
 
+/*
+I've had reports of GCC 14 throwing an incorrect -Wstringop-overflow warning here. This is an attempt
+to silence this warning.
+*/
+#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__)
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
 static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *ist_pos, drmp3_bs *bs, const drmp3_L3_gr_info *gr, float *scf, int ch)
 {
     static const drmp3_uint8 g_scf_partitions[3][28] = {
@@ -1288,6 +1301,9 @@
         scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift);
     }
 }
+#if (defined(__GNUC__) && (__GNUC__ >= 13)) && !defined(__clang__)
+    #pragma GCC diagnostic pop
+#endif
 
 static const float g_drmp3_pow43[129 + 16] = {
     0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f,
@@ -2299,7 +2315,6 @@
     int i = 0, igr, frame_size = 0, success = 1;
     const drmp3_uint8 *hdr;
     drmp3_bs bs_frame[1];
-    drmp3dec_scratch scratch;
 
     if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3))
     {
@@ -2336,23 +2351,23 @@
 
     if (info->layer == 3)
     {
-        int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr);
+        int main_data_begin = drmp3_L3_read_side_info(bs_frame, dec->scratch.gr_info, hdr);
         if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit)
         {
             drmp3dec_init(dec);
             return 0;
         }
-        success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin);
+        success = drmp3_L3_restore_reservoir(dec, bs_frame, &dec->scratch, main_data_begin);
         if (success && pcm != NULL)
         {
             for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
             {
-                DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
-                drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
-                drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
+                DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
+                drmp3_L3_decode(dec, &dec->scratch, dec->scratch.gr_info + igr*info->channels, info->channels);
+                drmp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, dec->scratch.syn[0]);
             }
         }
-        drmp3_L3_save_reservoir(dec, &scratch);
+        drmp3_L3_save_reservoir(dec, &dec->scratch);
     } else
     {
 #ifdef DR_MP3_ONLY_MP3
@@ -2366,15 +2381,15 @@
 
         drmp3_L12_read_scale_info(hdr, bs_frame, sci);
 
-        DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
+        DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
         for (i = 0, igr = 0; igr < 3; igr++)
         {
-            if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
+            if (12 == (i += drmp3_L12_dequantize_granule(dec->scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
             {
                 i = 0;
-                drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
-                drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
-                DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
+                drmp3_L12_apply_scf_384(sci, sci->scf + igr, dec->scratch.grbuf[0]);
+                drmp3d_synth_granule(dec->qmf_state, dec->scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, dec->scratch.syn[0]);
+                DRMP3_ZERO_MEMORY(dec->scratch.grbuf[0], 576*2*sizeof(float));
                 pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
             }
             if (bs_frame->pos > bs_frame->limit)
@@ -3005,23 +3020,27 @@
                                 ((drmp3_uint32)ape[26] << 16) |
                                 ((drmp3_uint32)ape[27] << 24);
 
-                            streamEndOffset -= 32 + tagSize;
-                            streamLen       -= 32 + tagSize;
-                            
-                            /* Fire a metadata callback for the APE data. Must include both the main content and footer. */
-                            if (onMeta != NULL) {
-                                /* We first need to seek to the start of the APE tag. */
-                                if (onSeek(pUserData, streamEndOffset, DRMP3_SEEK_END)) {
-                                    size_t apeTagSize = (size_t)tagSize + 32;
-                                    drmp3_uint8* pTagData = (drmp3_uint8*)drmp3_malloc(apeTagSize, pAllocationCallbacks);
-                                    if (pTagData != NULL) {
-                                        if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) {
-                                            drmp3__on_meta(pMP3, DRMP3_METADATA_TYPE_APE, pTagData, apeTagSize);
-                                        }
+                            if (32 + tagSize < streamLen) {
+                                streamEndOffset -= 32 + tagSize;
+                                streamLen       -= 32 + tagSize;
+                                
+                                /* Fire a metadata callback for the APE data. Must include both the main content and footer. */
+                                if (onMeta != NULL) {
+                                    /* We first need to seek to the start of the APE tag. */
+                                    if (onSeek(pUserData, streamEndOffset, DRMP3_SEEK_END)) {
+                                        size_t apeTagSize = (size_t)tagSize + 32;
+                                        drmp3_uint8* pTagData = (drmp3_uint8*)drmp3_malloc(apeTagSize, pAllocationCallbacks);
+                                        if (pTagData != NULL) {
+                                            if (onRead(pUserData, pTagData, apeTagSize) == apeTagSize) {
+                                                drmp3__on_meta(pMP3, DRMP3_METADATA_TYPE_APE, pTagData, apeTagSize);
+                                            }
 
-                                        drmp3_free(pTagData, pAllocationCallbacks);
+                                            drmp3_free(pTagData, pAllocationCallbacks);
+                                        }
                                     }
                                 }
+                            } else {
+                                /* The tag size is larger than the stream. Invalid APE tag. */
                             }
                         }
                     }
@@ -3153,7 +3172,6 @@
         {
             drmp3_bs bs;
             drmp3_L3_gr_info grInfo[4];
-            const drmp3_uint8* pTagData = pFirstFrameData;
 
             drmp3_bs_init(&bs, pFirstFrameData + DRMP3_HDR_SIZE, firstFrameInfo.frame_bytes - DRMP3_HDR_SIZE);
 
@@ -3164,11 +3182,16 @@
             if (drmp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) {
                 drmp3_bool32 isXing = DRMP3_FALSE;
                 drmp3_bool32 isInfo = DRMP3_FALSE;
+                const drmp3_uint8* pTagData;
                 const drmp3_uint8* pTagDataBeg;
 
                 pTagDataBeg = pFirstFrameData + DRMP3_HDR_SIZE + (bs.pos/8);
                 pTagData    = pTagDataBeg;
 
+                if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 8) {
+                    goto done_xing_info;    /* Frame too small for a Xing/Info tag. */
+                }
+
                 /* Check for both "Xing" and "Info" identifiers. */
                 isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g');
                 isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o');
@@ -3180,42 +3203,60 @@
                     pTagData += 8;  /* Skip past the ID and flags. */
 
                     if (flags & 0x01) { /* FRAMES flag. */
+                        if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
+                            goto done_xing_info;    /* Invalid Xing/Info tag. */
+                        }
+
                         detectedMP3FrameCount = (drmp3_uint32)pTagData[0] << 24 | (drmp3_uint32)pTagData[1] << 16 | (drmp3_uint32)pTagData[2] << 8 | (drmp3_uint32)pTagData[3];
                         pTagData += 4;
                     }
 
                     if (flags & 0x02) { /* BYTES flag. */
+                        if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
+                            goto done_xing_info;    /* Invalid Xing/Info tag. */
+                        }
+
                         bytes  = (drmp3_uint32)pTagData[0] << 24 | (drmp3_uint32)pTagData[1] << 16 | (drmp3_uint32)pTagData[2] << 8 | (drmp3_uint32)pTagData[3];
                         (void)bytes;    /* <-- Just to silence a warning about `bytes` being assigned but unused. Want to leave this here in case I want to make use of it later. */
                         pTagData += 4;
                     }
 
                     if (flags & 0x04) { /* TOC flag. */
+                        if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 100) {
+                            goto done_xing_info;    /* Invalid Xing/Info tag. */
+                        }
+
                         /* TODO: Extract and bind seek points. */
                         pTagData += 100;
                     }
 
                     if (flags & 0x08) { /* SCALE flag. */
+                        if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 4) {
+                            goto done_xing_info;    /* Invalid Xing/Info tag. */
+                        }
+                        
                         pTagData += 4;
                     }
 
                     /* At this point we're done with the Xing/Info header. Now we can look at the LAME data. */
                     if (pTagData[0]) {
-                        pTagData += 21;
+                        int delayInPCMFrames;
+                        int paddingInPCMFrames;
 
-                        if (pTagData - pFirstFrameData + 14 < firstFrameInfo.frame_bytes) {
-                            int delayInPCMFrames;
-                            int paddingInPCMFrames;
+                        if (firstFrameInfo.frame_bytes - (size_t)(pTagData - pFirstFrameData) < 36) {
+                            goto done_xing_info;    /* Invalid Xing/Info tag. */
+                        }
 
-                            delayInPCMFrames   = (( (drmp3_uint32)pTagData[0]        << 4) | ((drmp3_uint32)pTagData[1] >> 4)) + (528 + 1);
-                            paddingInPCMFrames = ((((drmp3_uint32)pTagData[1] & 0xF) << 8) | ((drmp3_uint32)pTagData[2]     )) - (528 + 1);
-                            if (paddingInPCMFrames < 0) {
-                                paddingInPCMFrames = 0; /* Padding cannot be negative. Probably a malformed file. Ignore. */
-                            }
-                            
-                            pMP3->delayInPCMFrames   = (drmp3_uint32)delayInPCMFrames;
-                            pMP3->paddingInPCMFrames = (drmp3_uint32)paddingInPCMFrames;
+                        pTagData += 21;
+
+                        delayInPCMFrames   = (( (drmp3_uint32)pTagData[0]        << 4) | ((drmp3_uint32)pTagData[1] >> 4)) + (528 + 1);
+                        paddingInPCMFrames = ((((drmp3_uint32)pTagData[1] & 0xF) << 8) | ((drmp3_uint32)pTagData[2]     )) - (528 + 1);
+                        if (paddingInPCMFrames < 0) {
+                            paddingInPCMFrames = 0; /* Padding cannot be negative. Probably a malformed file. Ignore. */
                         }
+                        
+                        pMP3->delayInPCMFrames   = (drmp3_uint32)delayInPCMFrames;
+                        pMP3->paddingInPCMFrames = (drmp3_uint32)paddingInPCMFrames;
                     }
 
                     /*
@@ -3246,7 +3287,16 @@
                     /* The start offset needs to be moved to the end of this frame so it's not included in any audio processing after seeking. */
                     pMP3->streamStartOffset += (drmp3_uint32)(firstFrameInfo.frame_bytes);
                     pMP3->streamCursor = pMP3->streamStartOffset;
+
+                    /*
+                    The internal decoder needs to be reset to clear out any state. If we don't reset this state, it's possible for
+                    there to be inconsistencies in the number of samples read when reading to the end of the stream depending on
+                    whether or not the caller seeks to the start of the stream.
+                    */
+                    drmp3dec_init(&pMP3->decoder);
                 }
+
+                done_xing_info:;
             } else {
                 /* Failed to read the side info. */
             }
@@ -3259,7 +3309,7 @@
     }
 
     if (detectedMP3FrameCount != 0xFFFFFFFF) {
-        pMP3->totalPCMFrameCount = detectedMP3FrameCount * firstFramePCMFrameCount;
+        pMP3->totalPCMFrameCount = (drmp3_uint64)detectedMP3FrameCount * firstFramePCMFrameCount;
     }
 
     pMP3->channels   = pMP3->mp3FrameChannels;
@@ -3307,8 +3357,6 @@
 
     DRMP3_ASSERT(pMP3 != NULL);
 
-    newCursor = pMP3->memory.currentReadPos;
-
     if (origin == DRMP3_SEEK_SET) {
         newCursor = 0;
     } else if (origin == DRMP3_SEEK_CUR) {
@@ -3981,7 +4029,7 @@
     DRMP3_ASSERT(pFileStdio != NULL);
     DRMP3_ASSERT(pCursor    != NULL);
 
-#if defined(_WIN32)
+#if defined(_WIN32) && !defined(NXDK)
     #if defined(_MSC_VER) && _MSC_VER > 1200
         result = _ftelli64(pFileStdio);
     #else
@@ -4223,7 +4271,7 @@
 #else
     /* Slow path. Convert from s16 to f32. */
     {
-        drmp3_int16 pTempS16[8192];
+        drmp3_int16 pTempS16[1152*2];   /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
         drmp3_uint64 totalPCMFramesRead = 0;
 
         while (totalPCMFramesRead < framesToRead) {
@@ -4260,7 +4308,7 @@
 #else
     /* Slow path. Convert from f32 to s16. */
     {
-        float pTempF32[4096];
+        float pTempF32[1152*2];   /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
         drmp3_uint64 totalPCMFramesRead = 0;
 
         while (totalPCMFramesRead < framesToRead) {
@@ -4748,7 +4796,7 @@
     drmp3_uint64 totalFramesRead = 0;
     drmp3_uint64 framesCapacity = 0;
     float* pFrames = NULL;
-    float temp[4096];
+    float temp[1152*2];   /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
 
     DRMP3_ASSERT(pMP3 != NULL);
 
@@ -4780,6 +4828,8 @@
             pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
             if (pNewFrames == NULL) {
                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
+                pFrames = NULL;
+                totalFramesRead = 0;
                 break;
             }
 
@@ -4815,7 +4865,7 @@
     drmp3_uint64 totalFramesRead = 0;
     drmp3_uint64 framesCapacity = 0;
     drmp3_int16* pFrames = NULL;
-    drmp3_int16 temp[4096];
+    drmp3_int16 temp[1152*2];   /* MP3 frames have a maximum per-channel sample count of 1152. Times 2 to account for stereo. */
 
     DRMP3_ASSERT(pMP3 != NULL);
 
@@ -4847,6 +4897,8 @@
             pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
             if (pNewFrames == NULL) {
                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
+                pFrames = NULL;
+                totalFramesRead = 0;
                 break;
             }
 
@@ -4981,7 +5033,27 @@
 /*
 REVISION HISTORY
 ================
-v0.7.0 - TBD
+v0.7.4 - TBD
+  - Fix an overflow error with "Xing" and "Info" tag parsing.
+  - Add some validation checks for "Xing" and "Info" tag parsing.
+  - Reduce size of some stack allocations.
+  - Improvements to SIMD detection.
+
+v0.7.3 - 2026-01-17
+  - Fix an error in drmp3_open_and_read_pcm_frames_s16() and family when memory allocation fails.
+  - Fix some compilation warnings.
+
+v0.7.2 - 2025-12-02
+  - Reduce stack space to improve robustness on embedded systems.
+  - Fix a compilation error with MSVC Clang toolset relating to cpuid.
+  - Fix an error with APE tag parsing.
+
+v0.7.1 - 2025-09-10
+  - Silence a warning with GCC.
+  - Fix an error with the NXDK build.
+  - Fix a decoding inconsistency when seeking. Prior to this change, reading to the end of the stream immediately after initializing will result in a different number of samples read than if the stream is seeked to the start and read to the end.
+
+v0.7.0 - 2025-07-23
   - The old `DRMP3_IMPLEMENTATION` has been removed. Use `DR_MP3_IMPLEMENTATION` instead. The reason for this change is that in the future everything will eventually be using the underscored naming convention in the future, so `drmp3` will become `dr_mp3`.
   - API CHANGE: Seek origins have been renamed to match the naming convention used by dr_wav and my other libraries.
     - drmp3_seek_origin_start   -> DRMP3_SEEK_SET
diff --git a/raylib/src/external/dr_wav.h b/raylib/src/external/dr_wav.h
--- a/raylib/src/external/dr_wav.h
+++ b/raylib/src/external/dr_wav.h
@@ -1,6 +1,6 @@
 /*
 WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
-dr_wav - v0.14.0 - TBD
+dr_wav - v0.14.6 - TBD
 
 David Reid - mackron@gmail.com
 
@@ -147,7 +147,7 @@
 
 #define DRWAV_VERSION_MAJOR     0
 #define DRWAV_VERSION_MINOR     14
-#define DRWAV_VERSION_REVISION  0
+#define DRWAV_VERSION_REVISION  6
 #define DRWAV_VERSION_STRING    DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
 
 #include <stddef.h> /* For size_t. */
@@ -1971,7 +1971,15 @@
             return DRWAV_INVALID_FILE;
         }
 
-        pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24;    /* <-- Subtract 24 because w64 includes the size of the header. */
+        pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes);
+
+        /* Subtract 24 from the size because with w64 the reported chunk size includes the size of the header itself. */
+        if (pHeaderOut->sizeInBytes >= 24) {
+            pHeaderOut->sizeInBytes -= 24;
+        } else {
+            return DRWAV_INVALID_FILE;
+        }
+
         pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
         *pRunningBytesReadOut += 24;
     } else {
@@ -2189,7 +2197,23 @@
 
     if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) {
         drwav_uint32 iSampleLoop;
+        drwav_uint32 loopCount;
+        drwav_uint32 calculatedLoopCount;
 
+        /*
+        When we calcualted the amount of memory required for the "smpl" chunk we excluded the chunk entirely
+        if the loop count in the header did not match with the calculated count based on the size of the
+        chunk. When this happens, the second stage will still hit this path but the `pMetadata` will be
+        non-null, but will either be pointing at the very end of the allocation or at the start of another
+        chunk. We need to check the loop counts for consistency *before* dereferencing the pMetadata object
+        so it's consistent with how we do it in the first stage.
+        */
+        loopCount = drwav_bytes_to_u32(smplHeaderData + 28);
+        calculatedLoopCount = (drwav_uint32)((pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES);
+        if (loopCount != calculatedLoopCount) {
+            return totalBytesRead;
+        }
+
         pMetadata->type                                     = drwav_metadata_type_smpl;
         pMetadata->data.smpl.manufacturerId                 = drwav_bytes_to_u32(smplHeaderData + 0);
         pMetadata->data.smpl.productId                      = drwav_bytes_to_u32(smplHeaderData + 4);
@@ -2205,7 +2229,7 @@
         The loop count needs to be validated against the size of the chunk for safety so we don't
         attempt to read over the boundary of the chunk.
         */
-        if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) {
+        if (pMetadata->data.smpl.sampleLoopCount == calculatedLoopCount) {
             pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT);
 
             for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) {
@@ -2230,6 +2254,15 @@
 
                 drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
             }
+        } else {
+            /*
+            Getting here means the loop count in the header does not match up with the size of the
+            chunk. Clear out the data to zero just to be safe.
+
+            This should never actually get hit because we check for it above, but keeping this here
+            for added safety.
+            */
+            DRWAV_ZERO_OBJECT(&pMetadata->data.smpl);
         }
     }
 
@@ -2555,8 +2588,10 @@
                 pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1);
                 DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
 
-                bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
-                pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory);
+                pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
+                pMetadata->data.bext.pCodingHistory[pMetadata->data.bext.codingHistorySize] = '\0'; /* <-- Explicit null terminator in case of a badly formed file. */
+                
+                bytesRead += pMetadata->data.bext.codingHistorySize;
             } else {
                 pMetadata->data.bext.pCodingHistory    = NULL;
                 pMetadata->data.bext.codingHistorySize = 0;
@@ -2730,10 +2765,10 @@
                 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
                 if (bytesJustRead == sizeof(buffer)) {
                     drwav_uint32 loopCount = drwav_bytes_to_u32(buffer);
-                    drwav_uint64 calculatedLoopCount;
+                    drwav_uint32 calculatedLoopCount;
 
                     /* The loop count must be validated against the size of the chunk. */
-                    calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES;
+                    calculatedLoopCount = (drwav_uint32)((pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES);
                     if (calculatedLoopCount == loopCount) {
                         bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
                         if (bytesJustRead == sizeof(buffer)) {
@@ -2835,8 +2870,10 @@
                     return bytesRead;
                 }
                 allocSizeNeeded += drwav__strlen(buffer) + 1;
-                allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1; /* Coding history. */
 
+                /* Coding history. */
+                allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1;
+
                 drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
 
                 pParser->metadataCount += 1;
@@ -3296,6 +3333,10 @@
             ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
             drwav_uint8 fmtData[16];
 
+            if (header.sizeInBytes < sizeof(fmtData)) {
+                return DRWAV_FALSE; /* Invalid fmt chunk. */
+            }
+
             foundChunk_fmt = DRWAV_TRUE;
 
             if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) {
@@ -3605,7 +3646,7 @@
                     we'll need to abort because we can't be doing a backwards seek back to the SSND chunk in order to read the
                     data. For this reason, this configuration of AIFF files are not supported with sequential mode.
                     */
-                    return DRWAV_FALSE; 
+                    return DRWAV_FALSE;
                 }
             } else {
                 chunkSize += header.paddingSize;                /* <-- Make sure we seek past the padding. */
@@ -3808,6 +3849,11 @@
 
             /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
             totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
+            if (totalBlockHeaderSizeInBytes >= dataChunkSize) {  /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
+                drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
+                return DRWAV_FALSE; /* Invalid file. */
+            }
+
             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
         }
         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
@@ -3821,6 +3867,11 @@
 
             /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
             totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
+            if (totalBlockHeaderSizeInBytes >= dataChunkSize) {  /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
+                drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
+                return DRWAV_FALSE; /* Invalid file. */
+            }
+
             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
 
             /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
@@ -5285,7 +5336,7 @@
     DRWAV_ASSERT(pFileStdio != NULL);
     DRWAV_ASSERT(pCursor    != NULL);
 
-#if defined(_WIN32)
+#if defined(_WIN32) && !defined(NXDK)
     #if defined(_MSC_VER) && _MSC_VER > 1200
         result = _ftelli64(pFileStdio);
     #else
@@ -5492,8 +5543,6 @@
 
     DRWAV_ASSERT(pWav != NULL);
 
-    newCursor = pWav->memoryStream.currentReadPos;
-
     if (origin == DRWAV_SEEK_SET) {
         newCursor = 0;
     } else if (origin == DRWAV_SEEK_CUR) {
@@ -5566,8 +5615,6 @@
 
     DRWAV_ASSERT(pWav != NULL);
 
-    newCursor = pWav->memoryStreamWrite.currentWritePos;
-
     if (origin == DRWAV_SEEK_SET) {
         newCursor = 0;
     } else if (origin == DRWAV_SEEK_CUR) {
@@ -5576,7 +5623,7 @@
         newCursor = (drwav_int64)pWav->memoryStreamWrite.dataSize;
     } else {
         DRWAV_ASSERT(!"Invalid seek origin");
-        return DRWAV_INVALID_ARGS;
+        return DRWAV_FALSE;
     }
 
     newCursor += offset;
@@ -6258,12 +6305,12 @@
 {
     drwav_uint64 totalFramesRead = 0;
 
-    static drwav_int32 adaptationTable[] = {
+    static const drwav_int32 adaptationTable[] = {
         230, 230, 230, 230, 307, 409, 512, 614,
         768, 614, 512, 409, 307, 230, 230, 230
     };
-    static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
-    static drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
+    static const drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
+    static const drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
 
     DRWAV_ASSERT(pWav != NULL);
     DRWAV_ASSERT(framesToRead > 0);
@@ -6292,7 +6339,7 @@
                 pWav->msadpcm.cachedFrameCount = 2;
 
                 /* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
-                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table)) {
+                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
                     return totalFramesRead; /* Invalid file. */
                 }
             } else {
@@ -6319,7 +6366,8 @@
                 pWav->msadpcm.cachedFrameCount = 2;
 
                 /* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
-                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
+                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table) ||
+                    pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
                     return totalFramesRead; /* Invalid file. */
                 }
             }
@@ -6373,15 +6421,17 @@
                     drwav_int32 newSample0;
                     drwav_int32 newSample1;
 
+                    /* The predictor is read from the file and then indexed into a table. Check that it's in bounds. */
+                    if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
+                        return totalFramesRead;
+                    }
+
                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
 
-                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
-                    if (pWav->msadpcm.delta[0] < 16) {
-                        pWav->msadpcm.delta[0] = 16;
-                    }
-
+                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
+ 
                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
                     pWav->msadpcm.prevFrames[0][1] = newSample0;
 
@@ -6390,15 +6440,11 @@
                     newSample1 += nibble1 * pWav->msadpcm.delta[0];
                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
 
-                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
-                    if (pWav->msadpcm.delta[0] < 16) {
-                        pWav->msadpcm.delta[0] = 16;
-                    }
+                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
 
                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
                     pWav->msadpcm.prevFrames[0][1] = newSample1;
 
-
                     pWav->msadpcm.cachedFrames[2] = newSample0;
                     pWav->msadpcm.cachedFrames[3] = newSample1;
                     pWav->msadpcm.cachedFrameCount = 2;
@@ -6408,28 +6454,30 @@
                     drwav_int32 newSample1;
 
                     /* Left. */
+                    if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
+                        return totalFramesRead; /* Out of bounds. Invalid file. */
+                    }
+
                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
 
-                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
-                    if (pWav->msadpcm.delta[0] < 16) {
-                        pWav->msadpcm.delta[0] = 16;
-                    }
+                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
 
                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
                     pWav->msadpcm.prevFrames[0][1] = newSample0;
 
 
                     /* Right. */
+                    if (pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
+                        return totalFramesRead; /* Out of bounds. Invalid file. */
+                    }
+
                     newSample1  = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
                     newSample1 += nibble1 * pWav->msadpcm.delta[1];
                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
 
-                    pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
-                    if (pWav->msadpcm.delta[1] < 16) {
-                        pWav->msadpcm.delta[1] = 16;
-                    }
+                    pWav->msadpcm.delta[1] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8, 16, 0x7FFFFFFF);
 
                     pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
                     pWav->msadpcm.prevFrames[1][1] = newSample1;
@@ -6451,12 +6499,12 @@
     drwav_uint64 totalFramesRead = 0;
     drwav_uint32 iChannel;
 
-    static drwav_int32 indexTable[16] = {
+    static const drwav_int32 indexTable[16] = {
         -1, -1, -1, -1, 2, 4, 6, 8,
         -1, -1, -1, -1, 2, 4, 6, 8
     };
 
-    static drwav_int32 stepTable[89] = {
+    static const drwav_int32 stepTable[89] = {
         7,     8,     9,     10,    11,    12,    13,    14,    16,    17,
         19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
         50,    55,    60,    66,    73,    80,    88,    97,    107,   118,
@@ -6606,7 +6654,7 @@
 
 
 #ifndef DR_WAV_NO_CONVERSION_API
-static unsigned short g_drwavAlawTable[256] = {
+static const unsigned short g_drwavAlawTable[256] = {
     0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
     0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
     0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
@@ -6625,7 +6673,7 @@
     0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
 };
 
-static unsigned short g_drwavMulawTable[256] = {
+static const unsigned short g_drwavMulawTable[256] = {
     0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
     0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
     0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
@@ -6703,6 +6751,10 @@
             shift  += 8;
         }
 
+        if (!drwav__is_little_endian()) {
+            sample = drwav__bswap64(sample);
+        }
+
         pIn += j;
         *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
     }
@@ -7144,6 +7196,10 @@
             shift  += 8;
         }
 
+        if (!drwav__is_little_endian()) {
+            sample = drwav__bswap64(sample);
+        }
+
         pIn += j;
         *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
     }
@@ -7628,6 +7684,10 @@
             shift  += 8;
         }
 
+        if (!drwav__is_little_endian()) {
+            sample = drwav__bswap64(sample);
+        }
+
         pIn += j;
         *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
     }
@@ -8053,6 +8113,12 @@
 
     DRWAV_ASSERT(pWav != NULL);
 
+    /* Check for overflow before multiplication. */
+    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int16)) {
+        drwav_uninit(pWav);
+        return NULL;    /* Overflow or invalid channels. */
+    }
+
     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
     if (sampleDataSize > DRWAV_SIZE_MAX) {
         drwav_uninit(pWav);
@@ -8095,6 +8161,12 @@
 
     DRWAV_ASSERT(pWav != NULL);
 
+    /* Check for overflow before multiplication. */
+    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(float)) {
+        drwav_uninit(pWav);
+        return NULL;    /* Overflow or invalid channels. */
+    }
+
     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
     if (sampleDataSize > DRWAV_SIZE_MAX) {
         drwav_uninit(pWav);
@@ -8137,6 +8209,12 @@
 
     DRWAV_ASSERT(pWav != NULL);
 
+    /* Check for overflow before multiplication. */
+    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int32)) {
+        drwav_uninit(pWav);
+        return NULL;    /* Overflow or invalid channels. */
+    }
+
     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
     if (sampleDataSize > DRWAV_SIZE_MAX) {
         drwav_uninit(pWav);
@@ -8517,7 +8595,31 @@
 /*
 REVISION HISTORY
 ================
-v0.14.0 - TBD
+v0.14.6 - TBD
+  - Fix an error when loading files with a malformed "bext" chunk.
+  - Fix an error when loading files with a malformed "fmt" chunk.
+  - Fix an underflow error with badly formed ADPCM encoded files.
+  - Fix an underflow error with badly formed W64 files.
+  - Fix an error when converting from >32 bit samples to s16/f32/s32 on big-endian architectures.
+
+v0.14.5 - 2026-03-03
+  - Fix a crash when loading files with a malformed "smpl" chunk.
+  - Fix a signed overflow bug with the MS-ADPCM decoder.
+
+v0.14.4 - 2026-01-17
+  - Fix some compilation warnings.
+
+v0.14.3 - 2025-12-14
+  - Fix a possible out-of-bounds read when reading from MS-ADPCM encoded files.
+  - Fix a possible integer overflow error.
+
+v0.14.2 - 2025-12-02
+  - Fix a compilation warning.
+
+v0.14.1 - 2025-09-10
+  - Fix an error with the NXDK build.
+
+v0.14.0 - 2025-07-23
   - API CHANGE: Seek origin enums have been renamed to the following:
     - drwav_seek_origin_start   -> DRWAV_SEEK_SET
     - drwav_seek_origin_current -> DRWAV_SEEK_CUR
diff --git a/raylib/src/external/fix_win32_compatibility.h b/raylib/src/external/fix_win32_compatibility.h
--- a/raylib/src/external/fix_win32_compatibility.h
+++ b/raylib/src/external/fix_win32_compatibility.h
@@ -2,7 +2,7 @@
 *
 *   fix_win32_compatibility.h   Utility to help include windows.h with raylib projects
 *
-*   Useage: #include "fix_win32_compatibility.h" any library that uses windows.h
+*   Usage: #include "fix_win32_compatibility.h" any library that uses windows.h
 *                                     order is critical, this must be done before raylib
 *
 *   LICENSE: MIT
@@ -32,7 +32,7 @@
 #pragma once
 
 // move the windows functions to new names
-// note that you can't call these functions or structures from your code, but you should not neeed to
+// note that you can't call these functions or structures from your code, but you should not need to
 #define CloseWindow CloseWindowWin32
 #define Rectangle RectangleWin32
 #define ShowCursor ShowCursorWin32
@@ -46,8 +46,9 @@
 // include windows
 #define WIN32_LEAN_AND_MEAN 
 #include <windows.h>
+#include <playsoundapi.h>
 
-// remove all our redfintions so that raylib can define them properly
+// remove all our redefinitions so that raylib can define them properly
 #undef CloseWindow
 #undef Rectangle
 #undef ShowCursor
diff --git a/raylib/src/external/glfw/deps/getopt.c b/raylib/src/external/glfw/deps/getopt.c
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/getopt.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/* Copyright (c) 2012, Kim Gräsman
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *  * Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *  * Neither the name of Kim Gräsman nor the names of contributors may be used
- *    to endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "getopt.h"
-
-#include <stddef.h>
-#include <string.h>
-
-const int no_argument = 0;
-const int required_argument = 1;
-const int optional_argument = 2;
-
-char* optarg;
-int optopt;
-/* The variable optind [...] shall be initialized to 1 by the system. */
-int optind = 1;
-int opterr;
-
-static char* optcursor = NULL;
-
-/* Implemented based on [1] and [2] for optional arguments.
-   optopt is handled FreeBSD-style, per [3].
-   Other GNU and FreeBSD extensions are purely accidental.
-
-[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
-[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
-[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE
-*/
-int getopt(int argc, char* const argv[], const char* optstring) {
-  int optchar = -1;
-  const char* optdecl = NULL;
-
-  optarg = NULL;
-  opterr = 0;
-  optopt = 0;
-
-  /* Unspecified, but we need it to avoid overrunning the argv bounds. */
-  if (optind >= argc)
-    goto no_more_optchars;
-
-  /* If, when getopt() is called argv[optind] is a null pointer, getopt()
-     shall return -1 without changing optind. */
-  if (argv[optind] == NULL)
-    goto no_more_optchars;
-
-  /* If, when getopt() is called *argv[optind]  is not the character '-',
-     getopt() shall return -1 without changing optind. */
-  if (*argv[optind] != '-')
-    goto no_more_optchars;
-
-  /* If, when getopt() is called argv[optind] points to the string "-",
-     getopt() shall return -1 without changing optind. */
-  if (strcmp(argv[optind], "-") == 0)
-    goto no_more_optchars;
-
-  /* If, when getopt() is called argv[optind] points to the string "--",
-     getopt() shall return -1 after incrementing optind. */
-  if (strcmp(argv[optind], "--") == 0) {
-    ++optind;
-    goto no_more_optchars;
-  }
-
-  if (optcursor == NULL || *optcursor == '\0')
-    optcursor = argv[optind] + 1;
-
-  optchar = *optcursor;
-
-  /* FreeBSD: The variable optopt saves the last known option character
-     returned by getopt(). */
-  optopt = optchar;
-
-  /* The getopt() function shall return the next option character (if one is
-     found) from argv that matches a character in optstring, if there is
-     one that matches. */
-  optdecl = strchr(optstring, optchar);
-  if (optdecl) {
-    /* [I]f a character is followed by a colon, the option takes an
-       argument. */
-    if (optdecl[1] == ':') {
-      optarg = ++optcursor;
-      if (*optarg == '\0') {
-        /* GNU extension: Two colons mean an option takes an
-           optional arg; if there is text in the current argv-element
-           (i.e., in the same word as the option name itself, for example,
-           "-oarg"), then it is returned in optarg, otherwise optarg is set
-           to zero. */
-        if (optdecl[2] != ':') {
-          /* If the option was the last character in the string pointed to by
-             an element of argv, then optarg shall contain the next element
-             of argv, and optind shall be incremented by 2. If the resulting
-             value of optind is greater than argc, this indicates a missing
-             option-argument, and getopt() shall return an error indication.
-
-             Otherwise, optarg shall point to the string following the
-             option character in that element of argv, and optind shall be
-             incremented by 1.
-          */
-          if (++optind < argc) {
-            optarg = argv[optind];
-          } else {
-            /* If it detects a missing option-argument, it shall return the
-               colon character ( ':' ) if the first character of optstring
-               was a colon, or a question-mark character ( '?' ) otherwise.
-            */
-            optarg = NULL;
-            optchar = (optstring[0] == ':') ? ':' : '?';
-          }
-        } else {
-          optarg = NULL;
-        }
-      }
-
-      optcursor = NULL;
-    }
-  } else {
-    /* If getopt() encounters an option character that is not contained in
-       optstring, it shall return the question-mark ( '?' ) character. */
-    optchar = '?';
-  }
-
-  if (optcursor == NULL || *++optcursor == '\0')
-    ++optind;
-
-  return optchar;
-
-no_more_optchars:
-  optcursor = NULL;
-  return -1;
-}
-
-/* Implementation based on [1].
-
-[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
-*/
-int getopt_long(int argc, char* const argv[], const char* optstring,
-  const struct option* longopts, int* longindex) {
-  const struct option* o = longopts;
-  const struct option* match = NULL;
-  int num_matches = 0;
-  size_t argument_name_length = 0;
-  const char* current_argument = NULL;
-  int retval = -1;
-
-  optarg = NULL;
-  optopt = 0;
-
-  if (optind >= argc)
-    return -1;
-
-  if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0)
-    return getopt(argc, argv, optstring);
-
-  /* It's an option; starts with -- and is longer than two chars. */
-  current_argument = argv[optind] + 2;
-  argument_name_length = strcspn(current_argument, "=");
-  for (; o->name; ++o) {
-    if (strncmp(o->name, current_argument, argument_name_length) == 0) {
-      match = o;
-      ++num_matches;
-    }
-  }
-
-  if (num_matches == 1) {
-    /* If longindex is not NULL, it points to a variable which is set to the
-       index of the long option relative to longopts. */
-    if (longindex)
-      *longindex = (int) (match - longopts);
-
-    /* If flag is NULL, then getopt_long() shall return val.
-       Otherwise, getopt_long() returns 0, and flag shall point to a variable
-       which shall be set to val if the option is found, but left unchanged if
-       the option is not found. */
-    if (match->flag)
-      *(match->flag) = match->val;
-
-    retval = match->flag ? 0 : match->val;
-
-    if (match->has_arg != no_argument) {
-      optarg = strchr(argv[optind], '=');
-      if (optarg != NULL)
-        ++optarg;
-
-      if (match->has_arg == required_argument) {
-        /* Only scan the next argv for required arguments. Behavior is not
-           specified, but has been observed with Ubuntu and Mac OSX. */
-        if (optarg == NULL && ++optind < argc) {
-          optarg = argv[optind];
-        }
-
-        if (optarg == NULL)
-          retval = ':';
-      }
-    } else if (strchr(argv[optind], '=')) {
-      /* An argument was provided to a non-argument option.
-         I haven't seen this specified explicitly, but both GNU and BSD-based
-         implementations show this behavior.
-      */
-      retval = '?';
-    }
-  } else {
-    /* Unknown option or ambiguous match. */
-    retval = '?';
-  }
-
-  ++optind;
-  return retval;
-}
diff --git a/raylib/src/external/glfw/deps/getopt.h b/raylib/src/external/glfw/deps/getopt.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/getopt.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright (c) 2012, Kim Gräsman
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *  * Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *  * Neither the name of Kim Gräsman nor the names of contributors may be used
- *    to endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef INCLUDED_GETOPT_PORT_H
-#define INCLUDED_GETOPT_PORT_H
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-extern const int no_argument;
-extern const int required_argument;
-extern const int optional_argument;
-
-extern char* optarg;
-extern int optind, opterr, optopt;
-
-struct option {
-  const char* name;
-  int has_arg;
-  int* flag;
-  int val;
-};
-
-int getopt(int argc, char* const argv[], const char* optstring);
-
-int getopt_long(int argc, char* const argv[],
-  const char* optstring, const struct option* longopts, int* longindex);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif // INCLUDED_GETOPT_PORT_H
diff --git a/raylib/src/external/glfw/deps/glad/gl.h b/raylib/src/external/glfw/deps/glad/gl.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/glad/gl.h
+++ /dev/null
@@ -1,5996 +0,0 @@
-/**
- * Loader generated by glad 2.0.0-beta on Tue Aug 24 22:51:07 2021
- *
- * Generator: C/C++
- * Specification: gl
- * Extensions: 3
- *
- * APIs:
- *  - gl:compatibility=3.3
- *
- * Options:
- *  - ALIAS = False
- *  - DEBUG = False
- *  - HEADER_ONLY = True
- *  - LOADER = False
- *  - MX = False
- *  - MX_GLOBAL = False
- *  - ON_DEMAND = False
- *
- * Commandline:
- *    --api='gl:compatibility=3.3' --extensions='GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug' c --header-only
- *
- * Online:
- *    http://glad.sh/#api=gl%3Acompatibility%3D3.3&extensions=GL_ARB_multisample%2CGL_ARB_robustness%2CGL_KHR_debug&generator=c&options=HEADER_ONLY
- *
- */
-
-#ifndef GLAD_GL_H_
-#define GLAD_GL_H_
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wreserved-id-macro"
-#endif
-#ifdef __gl_h_
-  #error OpenGL (gl.h) header already included (API: gl), remove previous include!
-#endif
-#define __gl_h_ 1
-#ifdef __gl3_h_
-  #error OpenGL (gl3.h) header already included (API: gl), remove previous include!
-#endif
-#define __gl3_h_ 1
-#ifdef __glext_h_
-  #error OpenGL (glext.h) header already included (API: gl), remove previous include!
-#endif
-#define __glext_h_ 1
-#ifdef __gl3ext_h_
-  #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include!
-#endif
-#define __gl3ext_h_ 1
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#define GLAD_GL
-#define GLAD_OPTION_GL_HEADER_ONLY
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef GLAD_PLATFORM_H_
-#define GLAD_PLATFORM_H_
-
-#ifndef GLAD_PLATFORM_WIN32
-  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
-    #define GLAD_PLATFORM_WIN32 1
-  #else
-    #define GLAD_PLATFORM_WIN32 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_APPLE
-  #ifdef __APPLE__
-    #define GLAD_PLATFORM_APPLE 1
-  #else
-    #define GLAD_PLATFORM_APPLE 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_EMSCRIPTEN
-  #ifdef __EMSCRIPTEN__
-    #define GLAD_PLATFORM_EMSCRIPTEN 1
-  #else
-    #define GLAD_PLATFORM_EMSCRIPTEN 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_UWP
-  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
-    #ifdef __has_include
-      #if __has_include(<winapifamily.h>)
-        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-      #endif
-    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
-      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-    #endif
-  #endif
-
-  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
-    #include <winapifamily.h>
-    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-      #define GLAD_PLATFORM_UWP 1
-    #endif
-  #endif
-
-  #ifndef GLAD_PLATFORM_UWP
-    #define GLAD_PLATFORM_UWP 0
-  #endif
-#endif
-
-#ifdef __GNUC__
-  #define GLAD_GNUC_EXTENSION __extension__
-#else
-  #define GLAD_GNUC_EXTENSION
-#endif
-
-#ifndef GLAD_API_CALL
-  #if defined(GLAD_API_CALL_EXPORT)
-    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
-      #if defined(GLAD_API_CALL_EXPORT_BUILD)
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllexport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllexport) extern
-        #endif
-      #else
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllimport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllimport) extern
-        #endif
-      #endif
-    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
-      #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
-    #else
-      #define GLAD_API_CALL extern
-    #endif
-  #else
-    #define GLAD_API_CALL extern
-  #endif
-#endif
-
-#ifdef APIENTRY
-  #define GLAD_API_PTR APIENTRY
-#elif GLAD_PLATFORM_WIN32
-  #define GLAD_API_PTR __stdcall
-#else
-  #define GLAD_API_PTR
-#endif
-
-#ifndef GLAPI
-#define GLAPI GLAD_API_CALL
-#endif
-
-#ifndef GLAPIENTRY
-#define GLAPIENTRY GLAD_API_PTR
-#endif
-
-#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
-#define GLAD_VERSION_MAJOR(version) (version / 10000)
-#define GLAD_VERSION_MINOR(version) (version % 10000)
-
-#define GLAD_GENERATOR_VERSION "2.0.0-beta"
-
-typedef void (*GLADapiproc)(void);
-
-typedef GLADapiproc (*GLADloadfunc)(const char *name);
-typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
-
-typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
-typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
-
-#endif /* GLAD_PLATFORM_H_ */
-
-#define GL_2D 0x0600
-#define GL_2_BYTES 0x1407
-#define GL_3D 0x0601
-#define GL_3D_COLOR 0x0602
-#define GL_3D_COLOR_TEXTURE 0x0603
-#define GL_3_BYTES 0x1408
-#define GL_4D_COLOR_TEXTURE 0x0604
-#define GL_4_BYTES 0x1409
-#define GL_ACCUM 0x0100
-#define GL_ACCUM_ALPHA_BITS 0x0D5B
-#define GL_ACCUM_BLUE_BITS 0x0D5A
-#define GL_ACCUM_BUFFER_BIT 0x00000200
-#define GL_ACCUM_CLEAR_VALUE 0x0B80
-#define GL_ACCUM_GREEN_BITS 0x0D59
-#define GL_ACCUM_RED_BITS 0x0D58
-#define GL_ACTIVE_ATTRIBUTES 0x8B89
-#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
-#define GL_ACTIVE_TEXTURE 0x84E0
-#define GL_ACTIVE_UNIFORMS 0x8B86
-#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
-#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
-#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
-#define GL_ADD 0x0104
-#define GL_ADD_SIGNED 0x8574
-#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
-#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
-#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF
-#define GL_ALPHA 0x1906
-#define GL_ALPHA12 0x803D
-#define GL_ALPHA16 0x803E
-#define GL_ALPHA4 0x803B
-#define GL_ALPHA8 0x803C
-#define GL_ALPHA_BIAS 0x0D1D
-#define GL_ALPHA_BITS 0x0D55
-#define GL_ALPHA_INTEGER 0x8D97
-#define GL_ALPHA_SCALE 0x0D1C
-#define GL_ALPHA_TEST 0x0BC0
-#define GL_ALPHA_TEST_FUNC 0x0BC1
-#define GL_ALPHA_TEST_REF 0x0BC2
-#define GL_ALREADY_SIGNALED 0x911A
-#define GL_ALWAYS 0x0207
-#define GL_AMBIENT 0x1200
-#define GL_AMBIENT_AND_DIFFUSE 0x1602
-#define GL_AND 0x1501
-#define GL_AND_INVERTED 0x1504
-#define GL_AND_REVERSE 0x1502
-#define GL_ANY_SAMPLES_PASSED 0x8C2F
-#define GL_ARRAY_BUFFER 0x8892
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ATTACHED_SHADERS 0x8B85
-#define GL_ATTRIB_STACK_DEPTH 0x0BB0
-#define GL_AUTO_NORMAL 0x0D80
-#define GL_AUX0 0x0409
-#define GL_AUX1 0x040A
-#define GL_AUX2 0x040B
-#define GL_AUX3 0x040C
-#define GL_AUX_BUFFERS 0x0C00
-#define GL_BACK 0x0405
-#define GL_BACK_LEFT 0x0402
-#define GL_BACK_RIGHT 0x0403
-#define GL_BGR 0x80E0
-#define GL_BGRA 0x80E1
-#define GL_BGRA_INTEGER 0x8D9B
-#define GL_BGR_INTEGER 0x8D9A
-#define GL_BITMAP 0x1A00
-#define GL_BITMAP_TOKEN 0x0704
-#define GL_BLEND 0x0BE2
-#define GL_BLEND_COLOR 0x8005
-#define GL_BLEND_DST 0x0BE0
-#define GL_BLEND_DST_ALPHA 0x80CA
-#define GL_BLEND_DST_RGB 0x80C8
-#define GL_BLEND_EQUATION 0x8009
-#define GL_BLEND_EQUATION_ALPHA 0x883D
-#define GL_BLEND_EQUATION_RGB 0x8009
-#define GL_BLEND_SRC 0x0BE1
-#define GL_BLEND_SRC_ALPHA 0x80CB
-#define GL_BLEND_SRC_RGB 0x80C9
-#define GL_BLUE 0x1905
-#define GL_BLUE_BIAS 0x0D1B
-#define GL_BLUE_BITS 0x0D54
-#define GL_BLUE_INTEGER 0x8D96
-#define GL_BLUE_SCALE 0x0D1A
-#define GL_BOOL 0x8B56
-#define GL_BOOL_VEC2 0x8B57
-#define GL_BOOL_VEC3 0x8B58
-#define GL_BOOL_VEC4 0x8B59
-#define GL_BUFFER 0x82E0
-#define GL_BUFFER_ACCESS 0x88BB
-#define GL_BUFFER_ACCESS_FLAGS 0x911F
-#define GL_BUFFER_MAPPED 0x88BC
-#define GL_BUFFER_MAP_LENGTH 0x9120
-#define GL_BUFFER_MAP_OFFSET 0x9121
-#define GL_BUFFER_MAP_POINTER 0x88BD
-#define GL_BUFFER_SIZE 0x8764
-#define GL_BUFFER_USAGE 0x8765
-#define GL_BYTE 0x1400
-#define GL_C3F_V3F 0x2A24
-#define GL_C4F_N3F_V3F 0x2A26
-#define GL_C4UB_V2F 0x2A22
-#define GL_C4UB_V3F 0x2A23
-#define GL_CCW 0x0901
-#define GL_CLAMP 0x2900
-#define GL_CLAMP_FRAGMENT_COLOR 0x891B
-#define GL_CLAMP_READ_COLOR 0x891C
-#define GL_CLAMP_TO_BORDER 0x812D
-#define GL_CLAMP_TO_EDGE 0x812F
-#define GL_CLAMP_VERTEX_COLOR 0x891A
-#define GL_CLEAR 0x1500
-#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
-#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF
-#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
-#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001
-#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002
-#define GL_CLIP_DISTANCE0 0x3000
-#define GL_CLIP_DISTANCE1 0x3001
-#define GL_CLIP_DISTANCE2 0x3002
-#define GL_CLIP_DISTANCE3 0x3003
-#define GL_CLIP_DISTANCE4 0x3004
-#define GL_CLIP_DISTANCE5 0x3005
-#define GL_CLIP_DISTANCE6 0x3006
-#define GL_CLIP_DISTANCE7 0x3007
-#define GL_CLIP_PLANE0 0x3000
-#define GL_CLIP_PLANE1 0x3001
-#define GL_CLIP_PLANE2 0x3002
-#define GL_CLIP_PLANE3 0x3003
-#define GL_CLIP_PLANE4 0x3004
-#define GL_CLIP_PLANE5 0x3005
-#define GL_COEFF 0x0A00
-#define GL_COLOR 0x1800
-#define GL_COLOR_ARRAY 0x8076
-#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
-#define GL_COLOR_ARRAY_POINTER 0x8090
-#define GL_COLOR_ARRAY_SIZE 0x8081
-#define GL_COLOR_ARRAY_STRIDE 0x8083
-#define GL_COLOR_ARRAY_TYPE 0x8082
-#define GL_COLOR_ATTACHMENT0 0x8CE0
-#define GL_COLOR_ATTACHMENT1 0x8CE1
-#define GL_COLOR_ATTACHMENT10 0x8CEA
-#define GL_COLOR_ATTACHMENT11 0x8CEB
-#define GL_COLOR_ATTACHMENT12 0x8CEC
-#define GL_COLOR_ATTACHMENT13 0x8CED
-#define GL_COLOR_ATTACHMENT14 0x8CEE
-#define GL_COLOR_ATTACHMENT15 0x8CEF
-#define GL_COLOR_ATTACHMENT16 0x8CF0
-#define GL_COLOR_ATTACHMENT17 0x8CF1
-#define GL_COLOR_ATTACHMENT18 0x8CF2
-#define GL_COLOR_ATTACHMENT19 0x8CF3
-#define GL_COLOR_ATTACHMENT2 0x8CE2
-#define GL_COLOR_ATTACHMENT20 0x8CF4
-#define GL_COLOR_ATTACHMENT21 0x8CF5
-#define GL_COLOR_ATTACHMENT22 0x8CF6
-#define GL_COLOR_ATTACHMENT23 0x8CF7
-#define GL_COLOR_ATTACHMENT24 0x8CF8
-#define GL_COLOR_ATTACHMENT25 0x8CF9
-#define GL_COLOR_ATTACHMENT26 0x8CFA
-#define GL_COLOR_ATTACHMENT27 0x8CFB
-#define GL_COLOR_ATTACHMENT28 0x8CFC
-#define GL_COLOR_ATTACHMENT29 0x8CFD
-#define GL_COLOR_ATTACHMENT3 0x8CE3
-#define GL_COLOR_ATTACHMENT30 0x8CFE
-#define GL_COLOR_ATTACHMENT31 0x8CFF
-#define GL_COLOR_ATTACHMENT4 0x8CE4
-#define GL_COLOR_ATTACHMENT5 0x8CE5
-#define GL_COLOR_ATTACHMENT6 0x8CE6
-#define GL_COLOR_ATTACHMENT7 0x8CE7
-#define GL_COLOR_ATTACHMENT8 0x8CE8
-#define GL_COLOR_ATTACHMENT9 0x8CE9
-#define GL_COLOR_BUFFER_BIT 0x00004000
-#define GL_COLOR_CLEAR_VALUE 0x0C22
-#define GL_COLOR_INDEX 0x1900
-#define GL_COLOR_INDEXES 0x1603
-#define GL_COLOR_LOGIC_OP 0x0BF2
-#define GL_COLOR_MATERIAL 0x0B57
-#define GL_COLOR_MATERIAL_FACE 0x0B55
-#define GL_COLOR_MATERIAL_PARAMETER 0x0B56
-#define GL_COLOR_SUM 0x8458
-#define GL_COLOR_WRITEMASK 0x0C23
-#define GL_COMBINE 0x8570
-#define GL_COMBINE_ALPHA 0x8572
-#define GL_COMBINE_RGB 0x8571
-#define GL_COMPARE_REF_TO_TEXTURE 0x884E
-#define GL_COMPARE_R_TO_TEXTURE 0x884E
-#define GL_COMPILE 0x1300
-#define GL_COMPILE_AND_EXECUTE 0x1301
-#define GL_COMPILE_STATUS 0x8B81
-#define GL_COMPRESSED_ALPHA 0x84E9
-#define GL_COMPRESSED_INTENSITY 0x84EC
-#define GL_COMPRESSED_LUMINANCE 0x84EA
-#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
-#define GL_COMPRESSED_RED 0x8225
-#define GL_COMPRESSED_RED_RGTC1 0x8DBB
-#define GL_COMPRESSED_RG 0x8226
-#define GL_COMPRESSED_RGB 0x84ED
-#define GL_COMPRESSED_RGBA 0x84EE
-#define GL_COMPRESSED_RG_RGTC2 0x8DBD
-#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
-#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
-#define GL_COMPRESSED_SLUMINANCE 0x8C4A
-#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B
-#define GL_COMPRESSED_SRGB 0x8C48
-#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
-#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-#define GL_CONDITION_SATISFIED 0x911C
-#define GL_CONSTANT 0x8576
-#define GL_CONSTANT_ALPHA 0x8003
-#define GL_CONSTANT_ATTENUATION 0x1207
-#define GL_CONSTANT_COLOR 0x8001
-#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
-#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
-#define GL_CONTEXT_FLAGS 0x821E
-#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
-#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
-#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004
-#define GL_CONTEXT_PROFILE_MASK 0x9126
-#define GL_COORD_REPLACE 0x8862
-#define GL_COPY 0x1503
-#define GL_COPY_INVERTED 0x150C
-#define GL_COPY_PIXEL_TOKEN 0x0706
-#define GL_COPY_READ_BUFFER 0x8F36
-#define GL_COPY_WRITE_BUFFER 0x8F37
-#define GL_CULL_FACE 0x0B44
-#define GL_CULL_FACE_MODE 0x0B45
-#define GL_CURRENT_BIT 0x00000001
-#define GL_CURRENT_COLOR 0x0B00
-#define GL_CURRENT_FOG_COORD 0x8453
-#define GL_CURRENT_FOG_COORDINATE 0x8453
-#define GL_CURRENT_INDEX 0x0B01
-#define GL_CURRENT_NORMAL 0x0B02
-#define GL_CURRENT_PROGRAM 0x8B8D
-#define GL_CURRENT_QUERY 0x8865
-#define GL_CURRENT_RASTER_COLOR 0x0B04
-#define GL_CURRENT_RASTER_DISTANCE 0x0B09
-#define GL_CURRENT_RASTER_INDEX 0x0B05
-#define GL_CURRENT_RASTER_POSITION 0x0B07
-#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08
-#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F
-#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06
-#define GL_CURRENT_SECONDARY_COLOR 0x8459
-#define GL_CURRENT_TEXTURE_COORDS 0x0B03
-#define GL_CURRENT_VERTEX_ATTRIB 0x8626
-#define GL_CW 0x0900
-#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
-#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
-#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
-#define GL_DEBUG_LOGGED_MESSAGES 0x9145
-#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
-#define GL_DEBUG_OUTPUT 0x92E0
-#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
-#define GL_DEBUG_SEVERITY_HIGH 0x9146
-#define GL_DEBUG_SEVERITY_LOW 0x9148
-#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
-#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
-#define GL_DEBUG_SOURCE_API 0x8246
-#define GL_DEBUG_SOURCE_APPLICATION 0x824A
-#define GL_DEBUG_SOURCE_OTHER 0x824B
-#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
-#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
-#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
-#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
-#define GL_DEBUG_TYPE_ERROR 0x824C
-#define GL_DEBUG_TYPE_MARKER 0x8268
-#define GL_DEBUG_TYPE_OTHER 0x8251
-#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
-#define GL_DEBUG_TYPE_POP_GROUP 0x826A
-#define GL_DEBUG_TYPE_PORTABILITY 0x824F
-#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
-#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
-#define GL_DECAL 0x2101
-#define GL_DECR 0x1E03
-#define GL_DECR_WRAP 0x8508
-#define GL_DELETE_STATUS 0x8B80
-#define GL_DEPTH 0x1801
-#define GL_DEPTH24_STENCIL8 0x88F0
-#define GL_DEPTH32F_STENCIL8 0x8CAD
-#define GL_DEPTH_ATTACHMENT 0x8D00
-#define GL_DEPTH_BIAS 0x0D1F
-#define GL_DEPTH_BITS 0x0D56
-#define GL_DEPTH_BUFFER_BIT 0x00000100
-#define GL_DEPTH_CLAMP 0x864F
-#define GL_DEPTH_CLEAR_VALUE 0x0B73
-#define GL_DEPTH_COMPONENT 0x1902
-#define GL_DEPTH_COMPONENT16 0x81A5
-#define GL_DEPTH_COMPONENT24 0x81A6
-#define GL_DEPTH_COMPONENT32 0x81A7
-#define GL_DEPTH_COMPONENT32F 0x8CAC
-#define GL_DEPTH_FUNC 0x0B74
-#define GL_DEPTH_RANGE 0x0B70
-#define GL_DEPTH_SCALE 0x0D1E
-#define GL_DEPTH_STENCIL 0x84F9
-#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
-#define GL_DEPTH_TEST 0x0B71
-#define GL_DEPTH_TEXTURE_MODE 0x884B
-#define GL_DEPTH_WRITEMASK 0x0B72
-#define GL_DIFFUSE 0x1201
-#define GL_DISPLAY_LIST 0x82E7
-#define GL_DITHER 0x0BD0
-#define GL_DOMAIN 0x0A02
-#define GL_DONT_CARE 0x1100
-#define GL_DOT3_RGB 0x86AE
-#define GL_DOT3_RGBA 0x86AF
-#define GL_DOUBLE 0x140A
-#define GL_DOUBLEBUFFER 0x0C32
-#define GL_DRAW_BUFFER 0x0C01
-#define GL_DRAW_BUFFER0 0x8825
-#define GL_DRAW_BUFFER1 0x8826
-#define GL_DRAW_BUFFER10 0x882F
-#define GL_DRAW_BUFFER11 0x8830
-#define GL_DRAW_BUFFER12 0x8831
-#define GL_DRAW_BUFFER13 0x8832
-#define GL_DRAW_BUFFER14 0x8833
-#define GL_DRAW_BUFFER15 0x8834
-#define GL_DRAW_BUFFER2 0x8827
-#define GL_DRAW_BUFFER3 0x8828
-#define GL_DRAW_BUFFER4 0x8829
-#define GL_DRAW_BUFFER5 0x882A
-#define GL_DRAW_BUFFER6 0x882B
-#define GL_DRAW_BUFFER7 0x882C
-#define GL_DRAW_BUFFER8 0x882D
-#define GL_DRAW_BUFFER9 0x882E
-#define GL_DRAW_FRAMEBUFFER 0x8CA9
-#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
-#define GL_DRAW_PIXEL_TOKEN 0x0705
-#define GL_DST_ALPHA 0x0304
-#define GL_DST_COLOR 0x0306
-#define GL_DYNAMIC_COPY 0x88EA
-#define GL_DYNAMIC_DRAW 0x88E8
-#define GL_DYNAMIC_READ 0x88E9
-#define GL_EDGE_FLAG 0x0B43
-#define GL_EDGE_FLAG_ARRAY 0x8079
-#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
-#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093
-#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C
-#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-#define GL_EMISSION 0x1600
-#define GL_ENABLE_BIT 0x00002000
-#define GL_EQUAL 0x0202
-#define GL_EQUIV 0x1509
-#define GL_EVAL_BIT 0x00010000
-#define GL_EXP 0x0800
-#define GL_EXP2 0x0801
-#define GL_EXTENSIONS 0x1F03
-#define GL_EYE_LINEAR 0x2400
-#define GL_EYE_PLANE 0x2502
-#define GL_FALSE 0
-#define GL_FASTEST 0x1101
-#define GL_FEEDBACK 0x1C01
-#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0
-#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1
-#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2
-#define GL_FILL 0x1B02
-#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
-#define GL_FIXED_ONLY 0x891D
-#define GL_FLAT 0x1D00
-#define GL_FLOAT 0x1406
-#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
-#define GL_FLOAT_MAT2 0x8B5A
-#define GL_FLOAT_MAT2x3 0x8B65
-#define GL_FLOAT_MAT2x4 0x8B66
-#define GL_FLOAT_MAT3 0x8B5B
-#define GL_FLOAT_MAT3x2 0x8B67
-#define GL_FLOAT_MAT3x4 0x8B68
-#define GL_FLOAT_MAT4 0x8B5C
-#define GL_FLOAT_MAT4x2 0x8B69
-#define GL_FLOAT_MAT4x3 0x8B6A
-#define GL_FLOAT_VEC2 0x8B50
-#define GL_FLOAT_VEC3 0x8B51
-#define GL_FLOAT_VEC4 0x8B52
-#define GL_FOG 0x0B60
-#define GL_FOG_BIT 0x00000080
-#define GL_FOG_COLOR 0x0B66
-#define GL_FOG_COORD 0x8451
-#define GL_FOG_COORDINATE 0x8451
-#define GL_FOG_COORDINATE_ARRAY 0x8457
-#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
-#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456
-#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455
-#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454
-#define GL_FOG_COORDINATE_SOURCE 0x8450
-#define GL_FOG_COORD_ARRAY 0x8457
-#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D
-#define GL_FOG_COORD_ARRAY_POINTER 0x8456
-#define GL_FOG_COORD_ARRAY_STRIDE 0x8455
-#define GL_FOG_COORD_ARRAY_TYPE 0x8454
-#define GL_FOG_COORD_SRC 0x8450
-#define GL_FOG_DENSITY 0x0B62
-#define GL_FOG_END 0x0B64
-#define GL_FOG_HINT 0x0C54
-#define GL_FOG_INDEX 0x0B61
-#define GL_FOG_MODE 0x0B65
-#define GL_FOG_START 0x0B63
-#define GL_FRAGMENT_DEPTH 0x8452
-#define GL_FRAGMENT_SHADER 0x8B30
-#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
-#define GL_FRAMEBUFFER 0x8D40
-#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
-#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
-#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
-#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
-#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
-#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
-#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
-#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
-#define GL_FRAMEBUFFER_BINDING 0x8CA6
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#define GL_FRAMEBUFFER_DEFAULT 0x8218
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
-#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
-#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
-#define GL_FRAMEBUFFER_SRGB 0x8DB9
-#define GL_FRAMEBUFFER_UNDEFINED 0x8219
-#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
-#define GL_FRONT 0x0404
-#define GL_FRONT_AND_BACK 0x0408
-#define GL_FRONT_FACE 0x0B46
-#define GL_FRONT_LEFT 0x0400
-#define GL_FRONT_RIGHT 0x0401
-#define GL_FUNC_ADD 0x8006
-#define GL_FUNC_REVERSE_SUBTRACT 0x800B
-#define GL_FUNC_SUBTRACT 0x800A
-#define GL_GENERATE_MIPMAP 0x8191
-#define GL_GENERATE_MIPMAP_HINT 0x8192
-#define GL_GEOMETRY_INPUT_TYPE 0x8917
-#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
-#define GL_GEOMETRY_SHADER 0x8DD9
-#define GL_GEOMETRY_VERTICES_OUT 0x8916
-#define GL_GEQUAL 0x0206
-#define GL_GREATER 0x0204
-#define GL_GREEN 0x1904
-#define GL_GREEN_BIAS 0x0D19
-#define GL_GREEN_BITS 0x0D53
-#define GL_GREEN_INTEGER 0x8D95
-#define GL_GREEN_SCALE 0x0D18
-#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253
-#define GL_HALF_FLOAT 0x140B
-#define GL_HINT_BIT 0x00008000
-#define GL_INCR 0x1E02
-#define GL_INCR_WRAP 0x8507
-#define GL_INDEX 0x8222
-#define GL_INDEX_ARRAY 0x8077
-#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899
-#define GL_INDEX_ARRAY_POINTER 0x8091
-#define GL_INDEX_ARRAY_STRIDE 0x8086
-#define GL_INDEX_ARRAY_TYPE 0x8085
-#define GL_INDEX_BITS 0x0D51
-#define GL_INDEX_CLEAR_VALUE 0x0C20
-#define GL_INDEX_LOGIC_OP 0x0BF1
-#define GL_INDEX_MODE 0x0C30
-#define GL_INDEX_OFFSET 0x0D13
-#define GL_INDEX_SHIFT 0x0D12
-#define GL_INDEX_WRITEMASK 0x0C21
-#define GL_INFO_LOG_LENGTH 0x8B84
-#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254
-#define GL_INT 0x1404
-#define GL_INTENSITY 0x8049
-#define GL_INTENSITY12 0x804C
-#define GL_INTENSITY16 0x804D
-#define GL_INTENSITY4 0x804A
-#define GL_INTENSITY8 0x804B
-#define GL_INTERLEAVED_ATTRIBS 0x8C8C
-#define GL_INTERPOLATE 0x8575
-#define GL_INT_2_10_10_10_REV 0x8D9F
-#define GL_INT_SAMPLER_1D 0x8DC9
-#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
-#define GL_INT_SAMPLER_2D 0x8DCA
-#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
-#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
-#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
-#define GL_INT_SAMPLER_2D_RECT 0x8DCD
-#define GL_INT_SAMPLER_3D 0x8DCB
-#define GL_INT_SAMPLER_BUFFER 0x8DD0
-#define GL_INT_SAMPLER_CUBE 0x8DCC
-#define GL_INT_VEC2 0x8B53
-#define GL_INT_VEC3 0x8B54
-#define GL_INT_VEC4 0x8B55
-#define GL_INVALID_ENUM 0x0500
-#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
-#define GL_INVALID_INDEX 0xFFFFFFFF
-#define GL_INVALID_OPERATION 0x0502
-#define GL_INVALID_VALUE 0x0501
-#define GL_INVERT 0x150A
-#define GL_KEEP 0x1E00
-#define GL_LAST_VERTEX_CONVENTION 0x8E4E
-#define GL_LEFT 0x0406
-#define GL_LEQUAL 0x0203
-#define GL_LESS 0x0201
-#define GL_LIGHT0 0x4000
-#define GL_LIGHT1 0x4001
-#define GL_LIGHT2 0x4002
-#define GL_LIGHT3 0x4003
-#define GL_LIGHT4 0x4004
-#define GL_LIGHT5 0x4005
-#define GL_LIGHT6 0x4006
-#define GL_LIGHT7 0x4007
-#define GL_LIGHTING 0x0B50
-#define GL_LIGHTING_BIT 0x00000040
-#define GL_LIGHT_MODEL_AMBIENT 0x0B53
-#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8
-#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51
-#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
-#define GL_LINE 0x1B01
-#define GL_LINEAR 0x2601
-#define GL_LINEAR_ATTENUATION 0x1208
-#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-#define GL_LINEAR_MIPMAP_NEAREST 0x2701
-#define GL_LINES 0x0001
-#define GL_LINES_ADJACENCY 0x000A
-#define GL_LINE_BIT 0x00000004
-#define GL_LINE_LOOP 0x0002
-#define GL_LINE_RESET_TOKEN 0x0707
-#define GL_LINE_SMOOTH 0x0B20
-#define GL_LINE_SMOOTH_HINT 0x0C52
-#define GL_LINE_STIPPLE 0x0B24
-#define GL_LINE_STIPPLE_PATTERN 0x0B25
-#define GL_LINE_STIPPLE_REPEAT 0x0B26
-#define GL_LINE_STRIP 0x0003
-#define GL_LINE_STRIP_ADJACENCY 0x000B
-#define GL_LINE_TOKEN 0x0702
-#define GL_LINE_WIDTH 0x0B21
-#define GL_LINE_WIDTH_GRANULARITY 0x0B23
-#define GL_LINE_WIDTH_RANGE 0x0B22
-#define GL_LINK_STATUS 0x8B82
-#define GL_LIST_BASE 0x0B32
-#define GL_LIST_BIT 0x00020000
-#define GL_LIST_INDEX 0x0B33
-#define GL_LIST_MODE 0x0B30
-#define GL_LOAD 0x0101
-#define GL_LOGIC_OP 0x0BF1
-#define GL_LOGIC_OP_MODE 0x0BF0
-#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
-#define GL_LOWER_LEFT 0x8CA1
-#define GL_LUMINANCE 0x1909
-#define GL_LUMINANCE12 0x8041
-#define GL_LUMINANCE12_ALPHA12 0x8047
-#define GL_LUMINANCE12_ALPHA4 0x8046
-#define GL_LUMINANCE16 0x8042
-#define GL_LUMINANCE16_ALPHA16 0x8048
-#define GL_LUMINANCE4 0x803F
-#define GL_LUMINANCE4_ALPHA4 0x8043
-#define GL_LUMINANCE6_ALPHA2 0x8044
-#define GL_LUMINANCE8 0x8040
-#define GL_LUMINANCE8_ALPHA8 0x8045
-#define GL_LUMINANCE_ALPHA 0x190A
-#define GL_MAJOR_VERSION 0x821B
-#define GL_MAP1_COLOR_4 0x0D90
-#define GL_MAP1_GRID_DOMAIN 0x0DD0
-#define GL_MAP1_GRID_SEGMENTS 0x0DD1
-#define GL_MAP1_INDEX 0x0D91
-#define GL_MAP1_NORMAL 0x0D92
-#define GL_MAP1_TEXTURE_COORD_1 0x0D93
-#define GL_MAP1_TEXTURE_COORD_2 0x0D94
-#define GL_MAP1_TEXTURE_COORD_3 0x0D95
-#define GL_MAP1_TEXTURE_COORD_4 0x0D96
-#define GL_MAP1_VERTEX_3 0x0D97
-#define GL_MAP1_VERTEX_4 0x0D98
-#define GL_MAP2_COLOR_4 0x0DB0
-#define GL_MAP2_GRID_DOMAIN 0x0DD2
-#define GL_MAP2_GRID_SEGMENTS 0x0DD3
-#define GL_MAP2_INDEX 0x0DB1
-#define GL_MAP2_NORMAL 0x0DB2
-#define GL_MAP2_TEXTURE_COORD_1 0x0DB3
-#define GL_MAP2_TEXTURE_COORD_2 0x0DB4
-#define GL_MAP2_TEXTURE_COORD_3 0x0DB5
-#define GL_MAP2_TEXTURE_COORD_4 0x0DB6
-#define GL_MAP2_VERTEX_3 0x0DB7
-#define GL_MAP2_VERTEX_4 0x0DB8
-#define GL_MAP_COLOR 0x0D10
-#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
-#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
-#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
-#define GL_MAP_READ_BIT 0x0001
-#define GL_MAP_STENCIL 0x0D11
-#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
-#define GL_MAP_WRITE_BIT 0x0002
-#define GL_MATRIX_MODE 0x0BA0
-#define GL_MAX 0x8008
-#define GL_MAX_3D_TEXTURE_SIZE 0x8073
-#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
-#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35
-#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B
-#define GL_MAX_CLIP_DISTANCES 0x0D32
-#define GL_MAX_CLIP_PLANES 0x0D32
-#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
-#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
-#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
-#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
-#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
-#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
-#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
-#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
-#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
-#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
-#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
-#define GL_MAX_DRAW_BUFFERS 0x8824
-#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
-#define GL_MAX_ELEMENTS_INDICES 0x80E9
-#define GL_MAX_ELEMENTS_VERTICES 0x80E8
-#define GL_MAX_EVAL_ORDER 0x0D30
-#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
-#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
-#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
-#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
-#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
-#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
-#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
-#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
-#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
-#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
-#define GL_MAX_INTEGER_SAMPLES 0x9110
-#define GL_MAX_LABEL_LENGTH 0x82E8
-#define GL_MAX_LIGHTS 0x0D31
-#define GL_MAX_LIST_NESTING 0x0B31
-#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
-#define GL_MAX_NAME_STACK_DEPTH 0x0D37
-#define GL_MAX_PIXEL_MAP_TABLE 0x0D34
-#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
-#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
-#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
-#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
-#define GL_MAX_SAMPLES 0x8D57
-#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
-#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
-#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
-#define GL_MAX_TEXTURE_COORDS 0x8871
-#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
-#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
-#define GL_MAX_TEXTURE_SIZE 0x0D33
-#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
-#define GL_MAX_TEXTURE_UNITS 0x84E2
-#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
-#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
-#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
-#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
-#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
-#define GL_MAX_VARYING_COMPONENTS 0x8B4B
-#define GL_MAX_VARYING_FLOATS 0x8B4B
-#define GL_MAX_VERTEX_ATTRIBS 0x8869
-#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
-#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
-#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
-#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
-#define GL_MAX_VIEWPORT_DIMS 0x0D3A
-#define GL_MIN 0x8007
-#define GL_MINOR_VERSION 0x821C
-#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
-#define GL_MIRRORED_REPEAT 0x8370
-#define GL_MODELVIEW 0x1700
-#define GL_MODELVIEW_MATRIX 0x0BA6
-#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
-#define GL_MODULATE 0x2100
-#define GL_MULT 0x0103
-#define GL_MULTISAMPLE 0x809D
-#define GL_MULTISAMPLE_ARB 0x809D
-#define GL_MULTISAMPLE_BIT 0x20000000
-#define GL_MULTISAMPLE_BIT_ARB 0x20000000
-#define GL_N3F_V3F 0x2A25
-#define GL_NAME_STACK_DEPTH 0x0D70
-#define GL_NAND 0x150E
-#define GL_NEAREST 0x2600
-#define GL_NEAREST_MIPMAP_LINEAR 0x2702
-#define GL_NEAREST_MIPMAP_NEAREST 0x2700
-#define GL_NEVER 0x0200
-#define GL_NICEST 0x1102
-#define GL_NONE 0
-#define GL_NOOP 0x1505
-#define GL_NOR 0x1508
-#define GL_NORMALIZE 0x0BA1
-#define GL_NORMAL_ARRAY 0x8075
-#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
-#define GL_NORMAL_ARRAY_POINTER 0x808F
-#define GL_NORMAL_ARRAY_STRIDE 0x807F
-#define GL_NORMAL_ARRAY_TYPE 0x807E
-#define GL_NORMAL_MAP 0x8511
-#define GL_NOTEQUAL 0x0205
-#define GL_NO_ERROR 0
-#define GL_NO_RESET_NOTIFICATION_ARB 0x8261
-#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
-#define GL_NUM_EXTENSIONS 0x821D
-#define GL_OBJECT_LINEAR 0x2401
-#define GL_OBJECT_PLANE 0x2501
-#define GL_OBJECT_TYPE 0x9112
-#define GL_ONE 1
-#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
-#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
-#define GL_ONE_MINUS_DST_ALPHA 0x0305
-#define GL_ONE_MINUS_DST_COLOR 0x0307
-#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
-#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
-#define GL_ONE_MINUS_SRC_ALPHA 0x0303
-#define GL_ONE_MINUS_SRC_COLOR 0x0301
-#define GL_OPERAND0_ALPHA 0x8598
-#define GL_OPERAND0_RGB 0x8590
-#define GL_OPERAND1_ALPHA 0x8599
-#define GL_OPERAND1_RGB 0x8591
-#define GL_OPERAND2_ALPHA 0x859A
-#define GL_OPERAND2_RGB 0x8592
-#define GL_OR 0x1507
-#define GL_ORDER 0x0A01
-#define GL_OR_INVERTED 0x150D
-#define GL_OR_REVERSE 0x150B
-#define GL_OUT_OF_MEMORY 0x0505
-#define GL_PACK_ALIGNMENT 0x0D05
-#define GL_PACK_IMAGE_HEIGHT 0x806C
-#define GL_PACK_LSB_FIRST 0x0D01
-#define GL_PACK_ROW_LENGTH 0x0D02
-#define GL_PACK_SKIP_IMAGES 0x806B
-#define GL_PACK_SKIP_PIXELS 0x0D04
-#define GL_PACK_SKIP_ROWS 0x0D03
-#define GL_PACK_SWAP_BYTES 0x0D00
-#define GL_PASS_THROUGH_TOKEN 0x0700
-#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
-#define GL_PIXEL_MAP_A_TO_A 0x0C79
-#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9
-#define GL_PIXEL_MAP_B_TO_B 0x0C78
-#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8
-#define GL_PIXEL_MAP_G_TO_G 0x0C77
-#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7
-#define GL_PIXEL_MAP_I_TO_A 0x0C75
-#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5
-#define GL_PIXEL_MAP_I_TO_B 0x0C74
-#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4
-#define GL_PIXEL_MAP_I_TO_G 0x0C73
-#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3
-#define GL_PIXEL_MAP_I_TO_I 0x0C70
-#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0
-#define GL_PIXEL_MAP_I_TO_R 0x0C72
-#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2
-#define GL_PIXEL_MAP_R_TO_R 0x0C76
-#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6
-#define GL_PIXEL_MAP_S_TO_S 0x0C71
-#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1
-#define GL_PIXEL_MODE_BIT 0x00000020
-#define GL_PIXEL_PACK_BUFFER 0x88EB
-#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
-#define GL_PIXEL_UNPACK_BUFFER 0x88EC
-#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
-#define GL_POINT 0x1B00
-#define GL_POINTS 0x0000
-#define GL_POINT_BIT 0x00000002
-#define GL_POINT_DISTANCE_ATTENUATION 0x8129
-#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
-#define GL_POINT_SIZE 0x0B11
-#define GL_POINT_SIZE_GRANULARITY 0x0B13
-#define GL_POINT_SIZE_MAX 0x8127
-#define GL_POINT_SIZE_MIN 0x8126
-#define GL_POINT_SIZE_RANGE 0x0B12
-#define GL_POINT_SMOOTH 0x0B10
-#define GL_POINT_SMOOTH_HINT 0x0C51
-#define GL_POINT_SPRITE 0x8861
-#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
-#define GL_POINT_TOKEN 0x0701
-#define GL_POLYGON 0x0009
-#define GL_POLYGON_BIT 0x00000008
-#define GL_POLYGON_MODE 0x0B40
-#define GL_POLYGON_OFFSET_FACTOR 0x8038
-#define GL_POLYGON_OFFSET_FILL 0x8037
-#define GL_POLYGON_OFFSET_LINE 0x2A02
-#define GL_POLYGON_OFFSET_POINT 0x2A01
-#define GL_POLYGON_OFFSET_UNITS 0x2A00
-#define GL_POLYGON_SMOOTH 0x0B41
-#define GL_POLYGON_SMOOTH_HINT 0x0C53
-#define GL_POLYGON_STIPPLE 0x0B42
-#define GL_POLYGON_STIPPLE_BIT 0x00000010
-#define GL_POLYGON_TOKEN 0x0703
-#define GL_POSITION 0x1203
-#define GL_PREVIOUS 0x8578
-#define GL_PRIMARY_COLOR 0x8577
-#define GL_PRIMITIVES_GENERATED 0x8C87
-#define GL_PRIMITIVE_RESTART 0x8F9D
-#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
-#define GL_PROGRAM 0x82E2
-#define GL_PROGRAM_PIPELINE 0x82E4
-#define GL_PROGRAM_POINT_SIZE 0x8642
-#define GL_PROJECTION 0x1701
-#define GL_PROJECTION_MATRIX 0x0BA7
-#define GL_PROJECTION_STACK_DEPTH 0x0BA4
-#define GL_PROVOKING_VERTEX 0x8E4F
-#define GL_PROXY_TEXTURE_1D 0x8063
-#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
-#define GL_PROXY_TEXTURE_2D 0x8064
-#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
-#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
-#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
-#define GL_PROXY_TEXTURE_3D 0x8070
-#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
-#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
-#define GL_Q 0x2003
-#define GL_QUADRATIC_ATTENUATION 0x1209
-#define GL_QUADS 0x0007
-#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
-#define GL_QUAD_STRIP 0x0008
-#define GL_QUERY 0x82E3
-#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
-#define GL_QUERY_BY_REGION_WAIT 0x8E15
-#define GL_QUERY_COUNTER_BITS 0x8864
-#define GL_QUERY_NO_WAIT 0x8E14
-#define GL_QUERY_RESULT 0x8866
-#define GL_QUERY_RESULT_AVAILABLE 0x8867
-#define GL_QUERY_WAIT 0x8E13
-#define GL_R 0x2002
-#define GL_R11F_G11F_B10F 0x8C3A
-#define GL_R16 0x822A
-#define GL_R16F 0x822D
-#define GL_R16I 0x8233
-#define GL_R16UI 0x8234
-#define GL_R16_SNORM 0x8F98
-#define GL_R32F 0x822E
-#define GL_R32I 0x8235
-#define GL_R32UI 0x8236
-#define GL_R3_G3_B2 0x2A10
-#define GL_R8 0x8229
-#define GL_R8I 0x8231
-#define GL_R8UI 0x8232
-#define GL_R8_SNORM 0x8F94
-#define GL_RASTERIZER_DISCARD 0x8C89
-#define GL_READ_BUFFER 0x0C02
-#define GL_READ_FRAMEBUFFER 0x8CA8
-#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
-#define GL_READ_ONLY 0x88B8
-#define GL_READ_WRITE 0x88BA
-#define GL_RED 0x1903
-#define GL_RED_BIAS 0x0D15
-#define GL_RED_BITS 0x0D52
-#define GL_RED_INTEGER 0x8D94
-#define GL_RED_SCALE 0x0D14
-#define GL_REFLECTION_MAP 0x8512
-#define GL_RENDER 0x1C00
-#define GL_RENDERBUFFER 0x8D41
-#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
-#define GL_RENDERBUFFER_BINDING 0x8CA7
-#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
-#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
-#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
-#define GL_RENDERBUFFER_HEIGHT 0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
-#define GL_RENDERBUFFER_RED_SIZE 0x8D50
-#define GL_RENDERBUFFER_SAMPLES 0x8CAB
-#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
-#define GL_RENDERBUFFER_WIDTH 0x8D42
-#define GL_RENDERER 0x1F01
-#define GL_RENDER_MODE 0x0C40
-#define GL_REPEAT 0x2901
-#define GL_REPLACE 0x1E01
-#define GL_RESCALE_NORMAL 0x803A
-#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
-#define GL_RETURN 0x0102
-#define GL_RG 0x8227
-#define GL_RG16 0x822C
-#define GL_RG16F 0x822F
-#define GL_RG16I 0x8239
-#define GL_RG16UI 0x823A
-#define GL_RG16_SNORM 0x8F99
-#define GL_RG32F 0x8230
-#define GL_RG32I 0x823B
-#define GL_RG32UI 0x823C
-#define GL_RG8 0x822B
-#define GL_RG8I 0x8237
-#define GL_RG8UI 0x8238
-#define GL_RG8_SNORM 0x8F95
-#define GL_RGB 0x1907
-#define GL_RGB10 0x8052
-#define GL_RGB10_A2 0x8059
-#define GL_RGB10_A2UI 0x906F
-#define GL_RGB12 0x8053
-#define GL_RGB16 0x8054
-#define GL_RGB16F 0x881B
-#define GL_RGB16I 0x8D89
-#define GL_RGB16UI 0x8D77
-#define GL_RGB16_SNORM 0x8F9A
-#define GL_RGB32F 0x8815
-#define GL_RGB32I 0x8D83
-#define GL_RGB32UI 0x8D71
-#define GL_RGB4 0x804F
-#define GL_RGB5 0x8050
-#define GL_RGB5_A1 0x8057
-#define GL_RGB8 0x8051
-#define GL_RGB8I 0x8D8F
-#define GL_RGB8UI 0x8D7D
-#define GL_RGB8_SNORM 0x8F96
-#define GL_RGB9_E5 0x8C3D
-#define GL_RGBA 0x1908
-#define GL_RGBA12 0x805A
-#define GL_RGBA16 0x805B
-#define GL_RGBA16F 0x881A
-#define GL_RGBA16I 0x8D88
-#define GL_RGBA16UI 0x8D76
-#define GL_RGBA16_SNORM 0x8F9B
-#define GL_RGBA2 0x8055
-#define GL_RGBA32F 0x8814
-#define GL_RGBA32I 0x8D82
-#define GL_RGBA32UI 0x8D70
-#define GL_RGBA4 0x8056
-#define GL_RGBA8 0x8058
-#define GL_RGBA8I 0x8D8E
-#define GL_RGBA8UI 0x8D7C
-#define GL_RGBA8_SNORM 0x8F97
-#define GL_RGBA_INTEGER 0x8D99
-#define GL_RGBA_MODE 0x0C31
-#define GL_RGB_INTEGER 0x8D98
-#define GL_RGB_SCALE 0x8573
-#define GL_RG_INTEGER 0x8228
-#define GL_RIGHT 0x0407
-#define GL_S 0x2000
-#define GL_SAMPLER 0x82E6
-#define GL_SAMPLER_1D 0x8B5D
-#define GL_SAMPLER_1D_ARRAY 0x8DC0
-#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
-#define GL_SAMPLER_1D_SHADOW 0x8B61
-#define GL_SAMPLER_2D 0x8B5E
-#define GL_SAMPLER_2D_ARRAY 0x8DC1
-#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
-#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
-#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
-#define GL_SAMPLER_2D_RECT 0x8B63
-#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
-#define GL_SAMPLER_2D_SHADOW 0x8B62
-#define GL_SAMPLER_3D 0x8B5F
-#define GL_SAMPLER_BINDING 0x8919
-#define GL_SAMPLER_BUFFER 0x8DC2
-#define GL_SAMPLER_CUBE 0x8B60
-#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
-#define GL_SAMPLES 0x80A9
-#define GL_SAMPLES_ARB 0x80A9
-#define GL_SAMPLES_PASSED 0x8914
-#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
-#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
-#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
-#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
-#define GL_SAMPLE_BUFFERS 0x80A8
-#define GL_SAMPLE_BUFFERS_ARB 0x80A8
-#define GL_SAMPLE_COVERAGE 0x80A0
-#define GL_SAMPLE_COVERAGE_ARB 0x80A0
-#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
-#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB
-#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
-#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA
-#define GL_SAMPLE_MASK 0x8E51
-#define GL_SAMPLE_MASK_VALUE 0x8E52
-#define GL_SAMPLE_POSITION 0x8E50
-#define GL_SCISSOR_BIT 0x00080000
-#define GL_SCISSOR_BOX 0x0C10
-#define GL_SCISSOR_TEST 0x0C11
-#define GL_SECONDARY_COLOR_ARRAY 0x845E
-#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
-#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D
-#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A
-#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C
-#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B
-#define GL_SELECT 0x1C02
-#define GL_SELECTION_BUFFER_POINTER 0x0DF3
-#define GL_SELECTION_BUFFER_SIZE 0x0DF4
-#define GL_SEPARATE_ATTRIBS 0x8C8D
-#define GL_SEPARATE_SPECULAR_COLOR 0x81FA
-#define GL_SET 0x150F
-#define GL_SHADER 0x82E1
-#define GL_SHADER_SOURCE_LENGTH 0x8B88
-#define GL_SHADER_TYPE 0x8B4F
-#define GL_SHADE_MODEL 0x0B54
-#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
-#define GL_SHININESS 0x1601
-#define GL_SHORT 0x1402
-#define GL_SIGNALED 0x9119
-#define GL_SIGNED_NORMALIZED 0x8F9C
-#define GL_SINGLE_COLOR 0x81F9
-#define GL_SLUMINANCE 0x8C46
-#define GL_SLUMINANCE8 0x8C47
-#define GL_SLUMINANCE8_ALPHA8 0x8C45
-#define GL_SLUMINANCE_ALPHA 0x8C44
-#define GL_SMOOTH 0x1D01
-#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
-#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
-#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
-#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
-#define GL_SOURCE0_ALPHA 0x8588
-#define GL_SOURCE0_RGB 0x8580
-#define GL_SOURCE1_ALPHA 0x8589
-#define GL_SOURCE1_RGB 0x8581
-#define GL_SOURCE2_ALPHA 0x858A
-#define GL_SOURCE2_RGB 0x8582
-#define GL_SPECULAR 0x1202
-#define GL_SPHERE_MAP 0x2402
-#define GL_SPOT_CUTOFF 0x1206
-#define GL_SPOT_DIRECTION 0x1204
-#define GL_SPOT_EXPONENT 0x1205
-#define GL_SRC0_ALPHA 0x8588
-#define GL_SRC0_RGB 0x8580
-#define GL_SRC1_ALPHA 0x8589
-#define GL_SRC1_COLOR 0x88F9
-#define GL_SRC1_RGB 0x8581
-#define GL_SRC2_ALPHA 0x858A
-#define GL_SRC2_RGB 0x8582
-#define GL_SRC_ALPHA 0x0302
-#define GL_SRC_ALPHA_SATURATE 0x0308
-#define GL_SRC_COLOR 0x0300
-#define GL_SRGB 0x8C40
-#define GL_SRGB8 0x8C41
-#define GL_SRGB8_ALPHA8 0x8C43
-#define GL_SRGB_ALPHA 0x8C42
-#define GL_STACK_OVERFLOW 0x0503
-#define GL_STACK_UNDERFLOW 0x0504
-#define GL_STATIC_COPY 0x88E6
-#define GL_STATIC_DRAW 0x88E4
-#define GL_STATIC_READ 0x88E5
-#define GL_STENCIL 0x1802
-#define GL_STENCIL_ATTACHMENT 0x8D20
-#define GL_STENCIL_BACK_FAIL 0x8801
-#define GL_STENCIL_BACK_FUNC 0x8800
-#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
-#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
-#define GL_STENCIL_BACK_REF 0x8CA3
-#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
-#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
-#define GL_STENCIL_BITS 0x0D57
-#define GL_STENCIL_BUFFER_BIT 0x00000400
-#define GL_STENCIL_CLEAR_VALUE 0x0B91
-#define GL_STENCIL_FAIL 0x0B94
-#define GL_STENCIL_FUNC 0x0B92
-#define GL_STENCIL_INDEX 0x1901
-#define GL_STENCIL_INDEX1 0x8D46
-#define GL_STENCIL_INDEX16 0x8D49
-#define GL_STENCIL_INDEX4 0x8D47
-#define GL_STENCIL_INDEX8 0x8D48
-#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
-#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
-#define GL_STENCIL_REF 0x0B97
-#define GL_STENCIL_TEST 0x0B90
-#define GL_STENCIL_VALUE_MASK 0x0B93
-#define GL_STENCIL_WRITEMASK 0x0B98
-#define GL_STEREO 0x0C33
-#define GL_STREAM_COPY 0x88E2
-#define GL_STREAM_DRAW 0x88E0
-#define GL_STREAM_READ 0x88E1
-#define GL_SUBPIXEL_BITS 0x0D50
-#define GL_SUBTRACT 0x84E7
-#define GL_SYNC_CONDITION 0x9113
-#define GL_SYNC_FENCE 0x9116
-#define GL_SYNC_FLAGS 0x9115
-#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
-#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
-#define GL_SYNC_STATUS 0x9114
-#define GL_T 0x2001
-#define GL_T2F_C3F_V3F 0x2A2A
-#define GL_T2F_C4F_N3F_V3F 0x2A2C
-#define GL_T2F_C4UB_V3F 0x2A29
-#define GL_T2F_N3F_V3F 0x2A2B
-#define GL_T2F_V3F 0x2A27
-#define GL_T4F_C4F_N3F_V4F 0x2A2D
-#define GL_T4F_V4F 0x2A28
-#define GL_TEXTURE 0x1702
-#define GL_TEXTURE0 0x84C0
-#define GL_TEXTURE1 0x84C1
-#define GL_TEXTURE10 0x84CA
-#define GL_TEXTURE11 0x84CB
-#define GL_TEXTURE12 0x84CC
-#define GL_TEXTURE13 0x84CD
-#define GL_TEXTURE14 0x84CE
-#define GL_TEXTURE15 0x84CF
-#define GL_TEXTURE16 0x84D0
-#define GL_TEXTURE17 0x84D1
-#define GL_TEXTURE18 0x84D2
-#define GL_TEXTURE19 0x84D3
-#define GL_TEXTURE2 0x84C2
-#define GL_TEXTURE20 0x84D4
-#define GL_TEXTURE21 0x84D5
-#define GL_TEXTURE22 0x84D6
-#define GL_TEXTURE23 0x84D7
-#define GL_TEXTURE24 0x84D8
-#define GL_TEXTURE25 0x84D9
-#define GL_TEXTURE26 0x84DA
-#define GL_TEXTURE27 0x84DB
-#define GL_TEXTURE28 0x84DC
-#define GL_TEXTURE29 0x84DD
-#define GL_TEXTURE3 0x84C3
-#define GL_TEXTURE30 0x84DE
-#define GL_TEXTURE31 0x84DF
-#define GL_TEXTURE4 0x84C4
-#define GL_TEXTURE5 0x84C5
-#define GL_TEXTURE6 0x84C6
-#define GL_TEXTURE7 0x84C7
-#define GL_TEXTURE8 0x84C8
-#define GL_TEXTURE9 0x84C9
-#define GL_TEXTURE_1D 0x0DE0
-#define GL_TEXTURE_1D_ARRAY 0x8C18
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_TEXTURE_2D_ARRAY 0x8C1A
-#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
-#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
-#define GL_TEXTURE_3D 0x806F
-#define GL_TEXTURE_ALPHA_SIZE 0x805F
-#define GL_TEXTURE_ALPHA_TYPE 0x8C13
-#define GL_TEXTURE_BASE_LEVEL 0x813C
-#define GL_TEXTURE_BINDING_1D 0x8068
-#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
-#define GL_TEXTURE_BINDING_2D 0x8069
-#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
-#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
-#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
-#define GL_TEXTURE_BINDING_3D 0x806A
-#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
-#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
-#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
-#define GL_TEXTURE_BIT 0x00040000
-#define GL_TEXTURE_BLUE_SIZE 0x805E
-#define GL_TEXTURE_BLUE_TYPE 0x8C12
-#define GL_TEXTURE_BORDER 0x1005
-#define GL_TEXTURE_BORDER_COLOR 0x1004
-#define GL_TEXTURE_BUFFER 0x8C2A
-#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
-#define GL_TEXTURE_COMPARE_FUNC 0x884D
-#define GL_TEXTURE_COMPARE_MODE 0x884C
-#define GL_TEXTURE_COMPONENTS 0x1003
-#define GL_TEXTURE_COMPRESSED 0x86A1
-#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
-#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
-#define GL_TEXTURE_COORD_ARRAY 0x8078
-#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
-#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
-#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
-#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
-#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
-#define GL_TEXTURE_CUBE_MAP 0x8513
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
-#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
-#define GL_TEXTURE_DEPTH 0x8071
-#define GL_TEXTURE_DEPTH_SIZE 0x884A
-#define GL_TEXTURE_DEPTH_TYPE 0x8C16
-#define GL_TEXTURE_ENV 0x2300
-#define GL_TEXTURE_ENV_COLOR 0x2201
-#define GL_TEXTURE_ENV_MODE 0x2200
-#define GL_TEXTURE_FILTER_CONTROL 0x8500
-#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
-#define GL_TEXTURE_GEN_MODE 0x2500
-#define GL_TEXTURE_GEN_Q 0x0C63
-#define GL_TEXTURE_GEN_R 0x0C62
-#define GL_TEXTURE_GEN_S 0x0C60
-#define GL_TEXTURE_GEN_T 0x0C61
-#define GL_TEXTURE_GREEN_SIZE 0x805D
-#define GL_TEXTURE_GREEN_TYPE 0x8C11
-#define GL_TEXTURE_HEIGHT 0x1001
-#define GL_TEXTURE_INTENSITY_SIZE 0x8061
-#define GL_TEXTURE_INTENSITY_TYPE 0x8C15
-#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
-#define GL_TEXTURE_LOD_BIAS 0x8501
-#define GL_TEXTURE_LUMINANCE_SIZE 0x8060
-#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_MATRIX 0x0BA8
-#define GL_TEXTURE_MAX_LEVEL 0x813D
-#define GL_TEXTURE_MAX_LOD 0x813B
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_MIN_LOD 0x813A
-#define GL_TEXTURE_PRIORITY 0x8066
-#define GL_TEXTURE_RECTANGLE 0x84F5
-#define GL_TEXTURE_RED_SIZE 0x805C
-#define GL_TEXTURE_RED_TYPE 0x8C10
-#define GL_TEXTURE_RESIDENT 0x8067
-#define GL_TEXTURE_SAMPLES 0x9106
-#define GL_TEXTURE_SHARED_SIZE 0x8C3F
-#define GL_TEXTURE_STACK_DEPTH 0x0BA5
-#define GL_TEXTURE_STENCIL_SIZE 0x88F1
-#define GL_TEXTURE_SWIZZLE_A 0x8E45
-#define GL_TEXTURE_SWIZZLE_B 0x8E44
-#define GL_TEXTURE_SWIZZLE_G 0x8E43
-#define GL_TEXTURE_SWIZZLE_R 0x8E42
-#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
-#define GL_TEXTURE_WIDTH 0x1000
-#define GL_TEXTURE_WRAP_R 0x8072
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-#define GL_TIMEOUT_EXPIRED 0x911B
-#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
-#define GL_TIMESTAMP 0x8E28
-#define GL_TIME_ELAPSED 0x88BF
-#define GL_TRANSFORM_BIT 0x00001000
-#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
-#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
-#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
-#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
-#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
-#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
-#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
-#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
-#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6
-#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3
-#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4
-#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5
-#define GL_TRIANGLES 0x0004
-#define GL_TRIANGLES_ADJACENCY 0x000C
-#define GL_TRIANGLE_FAN 0x0006
-#define GL_TRIANGLE_STRIP 0x0005
-#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
-#define GL_TRUE 1
-#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
-#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
-#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
-#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
-#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
-#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
-#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
-#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
-#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
-#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
-#define GL_UNIFORM_BUFFER 0x8A11
-#define GL_UNIFORM_BUFFER_BINDING 0x8A28
-#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
-#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
-#define GL_UNIFORM_BUFFER_START 0x8A29
-#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
-#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
-#define GL_UNIFORM_NAME_LENGTH 0x8A39
-#define GL_UNIFORM_OFFSET 0x8A3B
-#define GL_UNIFORM_SIZE 0x8A38
-#define GL_UNIFORM_TYPE 0x8A37
-#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_UNPACK_IMAGE_HEIGHT 0x806E
-#define GL_UNPACK_LSB_FIRST 0x0CF1
-#define GL_UNPACK_ROW_LENGTH 0x0CF2
-#define GL_UNPACK_SKIP_IMAGES 0x806D
-#define GL_UNPACK_SKIP_PIXELS 0x0CF4
-#define GL_UNPACK_SKIP_ROWS 0x0CF3
-#define GL_UNPACK_SWAP_BYTES 0x0CF0
-#define GL_UNSIGNALED 0x9118
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
-#define GL_UNSIGNED_BYTE_3_3_2 0x8032
-#define GL_UNSIGNED_INT 0x1405
-#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
-#define GL_UNSIGNED_INT_10_10_10_2 0x8036
-#define GL_UNSIGNED_INT_24_8 0x84FA
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
-#define GL_UNSIGNED_INT_8_8_8_8 0x8035
-#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
-#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
-#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
-#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
-#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
-#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
-#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
-#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
-#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
-#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
-#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
-#define GL_UNSIGNED_INT_VEC2 0x8DC6
-#define GL_UNSIGNED_INT_VEC3 0x8DC7
-#define GL_UNSIGNED_INT_VEC4 0x8DC8
-#define GL_UNSIGNED_NORMALIZED 0x8C17
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
-#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
-#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
-#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
-#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
-#define GL_UPPER_LEFT 0x8CA2
-#define GL_V2F 0x2A20
-#define GL_V3F 0x2A21
-#define GL_VALIDATE_STATUS 0x8B83
-#define GL_VENDOR 0x1F00
-#define GL_VERSION 0x1F02
-#define GL_VERTEX_ARRAY 0x8074
-#define GL_VERTEX_ARRAY_BINDING 0x85B5
-#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
-#define GL_VERTEX_ARRAY_POINTER 0x808E
-#define GL_VERTEX_ARRAY_SIZE 0x807A
-#define GL_VERTEX_ARRAY_STRIDE 0x807C
-#define GL_VERTEX_ARRAY_TYPE 0x807B
-#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
-#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
-#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
-#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
-#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
-#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
-#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
-#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
-#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
-#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
-#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
-#define GL_VERTEX_SHADER 0x8B31
-#define GL_VIEWPORT 0x0BA2
-#define GL_VIEWPORT_BIT 0x00000800
-#define GL_WAIT_FAILED 0x911D
-#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E
-#define GL_WRITE_ONLY 0x88B9
-#define GL_XOR 0x1506
-#define GL_ZERO 0
-#define GL_ZOOM_X 0x0D16
-#define GL_ZOOM_Y 0x0D17
-
-
-#ifndef __khrplatform_h_
-#define __khrplatform_h_
-
-/*
-** Copyright (c) 2008-2018 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Khronos platform-specific types and definitions.
- *
- * The master copy of khrplatform.h is maintained in the Khronos EGL
- * Registry repository at https://github.com/KhronosGroup/EGL-Registry
- * The last semantic modification to khrplatform.h was at commit ID:
- *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
- *
- * Adopters may modify this file to suit their platform. Adopters are
- * encouraged to submit platform specific modifications to the Khronos
- * group so that they can be included in future versions of this file.
- * Please submit changes by filing pull requests or issues on
- * the EGL Registry repository linked above.
- *
- *
- * See the Implementer's Guidelines for information about where this file
- * should be located on your system and for more details of its use:
- *    http://www.khronos.org/registry/implementers_guide.pdf
- *
- * This file should be included as
- *        #include <KHR/khrplatform.h>
- * by Khronos client API header files that use its types and defines.
- *
- * The types in khrplatform.h should only be used to define API-specific types.
- *
- * Types defined in khrplatform.h:
- *    khronos_int8_t              signed   8  bit
- *    khronos_uint8_t             unsigned 8  bit
- *    khronos_int16_t             signed   16 bit
- *    khronos_uint16_t            unsigned 16 bit
- *    khronos_int32_t             signed   32 bit
- *    khronos_uint32_t            unsigned 32 bit
- *    khronos_int64_t             signed   64 bit
- *    khronos_uint64_t            unsigned 64 bit
- *    khronos_intptr_t            signed   same number of bits as a pointer
- *    khronos_uintptr_t           unsigned same number of bits as a pointer
- *    khronos_ssize_t             signed   size
- *    khronos_usize_t             unsigned size
- *    khronos_float_t             signed   32 bit floating point
- *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
- *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
- *                                         nanoseconds
- *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
- *    khronos_boolean_enum_t      enumerated boolean type. This should
- *      only be used as a base type when a client API's boolean type is
- *      an enum. Client APIs which use an integer or other type for
- *      booleans cannot use this as the base type for their boolean.
- *
- * Tokens defined in khrplatform.h:
- *
- *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
- *
- *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
- *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
- *
- * Calling convention macros defined in this file:
- *    KHRONOS_APICALL
- *    KHRONOS_GLAD_API_PTR
- *    KHRONOS_APIATTRIBUTES
- *
- * These may be used in function prototypes as:
- *
- *      KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname(
- *                                  int arg1,
- *                                  int arg2) KHRONOS_APIATTRIBUTES;
- */
-
-#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
-#   define KHRONOS_STATIC 1
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APICALL
- *-------------------------------------------------------------------------
- * This precedes the return type of the function in the function prototype.
- */
-#if defined(KHRONOS_STATIC)
-    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
-     * header compatible with static linking. */
-#   define KHRONOS_APICALL
-#elif defined(_WIN32)
-#   define KHRONOS_APICALL __declspec(dllimport)
-#elif defined (__SYMBIAN32__)
-#   define KHRONOS_APICALL IMPORT_C
-#elif defined(__ANDROID__)
-#   define KHRONOS_APICALL __attribute__((visibility("default")))
-#else
-#   define KHRONOS_APICALL
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_GLAD_API_PTR
- *-------------------------------------------------------------------------
- * This follows the return type of the function  and precedes the function
- * name in the function prototype.
- */
-#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
-    /* Win32 but not WinCE */
-#   define KHRONOS_GLAD_API_PTR __stdcall
-#else
-#   define KHRONOS_GLAD_API_PTR
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APIATTRIBUTES
- *-------------------------------------------------------------------------
- * This follows the closing parenthesis of the function prototype arguments.
- */
-#if defined (__ARMCC_2__)
-#define KHRONOS_APIATTRIBUTES __softfp
-#else
-#define KHRONOS_APIATTRIBUTES
-#endif
-
-/*-------------------------------------------------------------------------
- * basic type definitions
- *-----------------------------------------------------------------------*/
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
-
-
-/*
- * Using <stdint.h>
- */
-#include <stdint.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(__VMS ) || defined(__sgi)
-
-/*
- * Using <inttypes.h>
- */
-#include <inttypes.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
-
-/*
- * Win32
- */
-typedef __int32                 khronos_int32_t;
-typedef unsigned __int32        khronos_uint32_t;
-typedef __int64                 khronos_int64_t;
-typedef unsigned __int64        khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(__sun__) || defined(__digital__)
-
-/*
- * Sun or Digital
- */
-typedef int                     khronos_int32_t;
-typedef unsigned int            khronos_uint32_t;
-#if defined(__arch64__) || defined(_LP64)
-typedef long int                khronos_int64_t;
-typedef unsigned long int       khronos_uint64_t;
-#else
-typedef long long int           khronos_int64_t;
-typedef unsigned long long int  khronos_uint64_t;
-#endif /* __arch64__ */
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif 0
-
-/*
- * Hypothetical platform with no float or int64 support
- */
-typedef int                     khronos_int32_t;
-typedef unsigned int            khronos_uint32_t;
-#define KHRONOS_SUPPORT_INT64   0
-#define KHRONOS_SUPPORT_FLOAT   0
-
-#else
-
-/*
- * Generic fallback
- */
-#include <stdint.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#endif
-
-
-/*
- * Types that are (so far) the same on all platforms
- */
-typedef signed   char          khronos_int8_t;
-typedef unsigned char          khronos_uint8_t;
-typedef signed   short int     khronos_int16_t;
-typedef unsigned short int     khronos_uint16_t;
-
-/*
- * Types that differ between LLP64 and LP64 architectures - in LLP64,
- * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
- * to be the only LLP64 architecture in current use.
- */
-#ifdef _WIN64
-typedef signed   long long int khronos_intptr_t;
-typedef unsigned long long int khronos_uintptr_t;
-typedef signed   long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
-#else
-typedef signed   long  int     khronos_intptr_t;
-typedef unsigned long  int     khronos_uintptr_t;
-typedef signed   long  int     khronos_ssize_t;
-typedef unsigned long  int     khronos_usize_t;
-#endif
-
-#if KHRONOS_SUPPORT_FLOAT
-/*
- * Float type
- */
-typedef          float         khronos_float_t;
-#endif
-
-#if KHRONOS_SUPPORT_INT64
-/* Time types
- *
- * These types can be used to represent a time interval in nanoseconds or
- * an absolute Unadjusted System Time.  Unadjusted System Time is the number
- * of nanoseconds since some arbitrary system event (e.g. since the last
- * time the system booted).  The Unadjusted System Time is an unsigned
- * 64 bit value that wraps back to 0 every 584 years.  Time intervals
- * may be either signed or unsigned.
- */
-typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
-typedef khronos_int64_t        khronos_stime_nanoseconds_t;
-#endif
-
-/*
- * Dummy value used to pad enum types to 32 bits.
- */
-#ifndef KHRONOS_MAX_ENUM
-#define KHRONOS_MAX_ENUM 0x7FFFFFFF
-#endif
-
-/*
- * Enumerated boolean type
- *
- * Values other than zero should be considered to be true.  Therefore
- * comparisons should not be made against KHRONOS_TRUE.
- */
-typedef enum {
-    KHRONOS_FALSE = 0,
-    KHRONOS_TRUE  = 1,
-    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
-} khronos_boolean_enum_t;
-
-#endif /* __khrplatform_h_ */
-
-typedef unsigned int GLenum;
-
-typedef unsigned char GLboolean;
-
-typedef unsigned int GLbitfield;
-
-typedef void GLvoid;
-
-typedef khronos_int8_t GLbyte;
-
-typedef khronos_uint8_t GLubyte;
-
-typedef khronos_int16_t GLshort;
-
-typedef khronos_uint16_t GLushort;
-
-typedef int GLint;
-
-typedef unsigned int GLuint;
-
-typedef khronos_int32_t GLclampx;
-
-typedef int GLsizei;
-
-typedef khronos_float_t GLfloat;
-
-typedef khronos_float_t GLclampf;
-
-typedef double GLdouble;
-
-typedef double GLclampd;
-
-typedef void *GLeglClientBufferEXT;
-
-typedef void *GLeglImageOES;
-
-typedef char GLchar;
-
-typedef char GLcharARB;
-
-#ifdef __APPLE__
-typedef void *GLhandleARB;
-#else
-typedef unsigned int GLhandleARB;
-#endif
-
-typedef khronos_uint16_t GLhalf;
-
-typedef khronos_uint16_t GLhalfARB;
-
-typedef khronos_int32_t GLfixed;
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_intptr_t GLintptr;
-#else
-typedef khronos_intptr_t GLintptr;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_intptr_t GLintptrARB;
-#else
-typedef khronos_intptr_t GLintptrARB;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_ssize_t GLsizeiptr;
-#else
-typedef khronos_ssize_t GLsizeiptr;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_ssize_t GLsizeiptrARB;
-#else
-typedef khronos_ssize_t GLsizeiptrARB;
-#endif
-
-typedef khronos_int64_t GLint64;
-
-typedef khronos_int64_t GLint64EXT;
-
-typedef khronos_uint64_t GLuint64;
-
-typedef khronos_uint64_t GLuint64EXT;
-
-typedef struct __GLsync *GLsync;
-
-struct _cl_context;
-
-struct _cl_event;
-
-typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
-
-typedef unsigned short GLhalfNV;
-
-typedef GLintptr GLvdpauSurfaceNV;
-
-typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void);
-
-
-
-#define GL_VERSION_1_0 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_0;
-#define GL_VERSION_1_1 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_1;
-#define GL_VERSION_1_2 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_2;
-#define GL_VERSION_1_3 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_3;
-#define GL_VERSION_1_4 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_4;
-#define GL_VERSION_1_5 1
-GLAD_API_CALL int GLAD_GL_VERSION_1_5;
-#define GL_VERSION_2_0 1
-GLAD_API_CALL int GLAD_GL_VERSION_2_0;
-#define GL_VERSION_2_1 1
-GLAD_API_CALL int GLAD_GL_VERSION_2_1;
-#define GL_VERSION_3_0 1
-GLAD_API_CALL int GLAD_GL_VERSION_3_0;
-#define GL_VERSION_3_1 1
-GLAD_API_CALL int GLAD_GL_VERSION_3_1;
-#define GL_VERSION_3_2 1
-GLAD_API_CALL int GLAD_GL_VERSION_3_2;
-#define GL_VERSION_3_3 1
-GLAD_API_CALL int GLAD_GL_VERSION_3_3;
-#define GL_ARB_multisample 1
-GLAD_API_CALL int GLAD_GL_ARB_multisample;
-#define GL_ARB_robustness 1
-GLAD_API_CALL int GLAD_GL_ARB_robustness;
-#define GL_KHR_debug 1
-GLAD_API_CALL int GLAD_GL_KHR_debug;
-
-
-typedef void (GLAD_API_PTR *PFNGLACCUMPROC)(GLenum op, GLfloat value);
-typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture);
-typedef void (GLAD_API_PTR *PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref);
-typedef GLboolean (GLAD_API_PTR *PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint * textures, GLboolean * residences);
-typedef void (GLAD_API_PTR *PFNGLARRAYELEMENTPROC)(GLint i);
-typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLBEGINPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);
-typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);
-typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
-typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);
-typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
-typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
-typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
-typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);
-typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
-typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array);
-typedef void (GLAD_API_PTR *PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte * bitmap);
-typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
-typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
-typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
-typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);
-typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCALLLISTPROC)(GLuint list);
-typedef void (GLAD_API_PTR *PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void * lists);
-typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);
-typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask);
-typedef void (GLAD_API_PTR *PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
-typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth);
-typedef void (GLAD_API_PTR *PFNGLCLEARINDEXPROC)(GLfloat c);
-typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s);
-typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture);
-typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GLAD_API_PTR *PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble * equation);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3BVPROC)(const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3UBVPROC)(const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3UIVPROC)(const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue);
-typedef void (GLAD_API_PTR *PFNGLCOLOR3USVPROC)(const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4BVPROC)(const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4UBVPROC)(const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4UIVPROC)(const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLOR4USVPROC)(const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
-typedef void (GLAD_API_PTR *PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLCOLORP3UIPROC)(GLenum type, GLuint color);
-typedef void (GLAD_API_PTR *PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint * color);
-typedef void (GLAD_API_PTR *PFNGLCOLORP4UIPROC)(GLenum type, GLuint color);
-typedef void (GLAD_API_PTR *PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint * color);
-typedef void (GLAD_API_PTR *PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
-typedef void (GLAD_API_PTR *PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void);
-typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type);
-typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void * userParam);
-typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled);
-typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf);
-typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers);
-typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers);
-typedef void (GLAD_API_PTR *PFNGLDELETELISTSPROC)(GLuint list, GLsizei range);
-typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids);
-typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers);
-typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers);
-typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync);
-typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures);
-typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays);
-typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func);
-typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag);
-typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);
-typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap);
-typedef void (GLAD_API_PTR *PFNGLDISABLECLIENTSTATEPROC)(GLenum array);
-typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
-typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index);
-typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
-typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
-typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf);
-typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs);
-typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices);
-typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex);
-typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount);
-typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex);
-typedef void (GLAD_API_PTR *PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices);
-typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex);
-typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPROC)(GLboolean flag);
-typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLEDGEFLAGVPROC)(const GLboolean * flag);
-typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap);
-typedef void (GLAD_API_PTR *PFNGLENABLECLIENTSTATEPROC)(GLenum array);
-typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
-typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index);
-typedef void (GLAD_API_PTR *PFNGLENDPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLENDLISTPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DPROC)(GLdouble u);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DVPROC)(const GLdouble * u);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FPROC)(GLfloat u);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FVPROC)(const GLfloat * u);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DVPROC)(const GLdouble * u);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v);
-typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FVPROC)(const GLfloat * u);
-typedef void (GLAD_API_PTR *PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2);
-typedef void (GLAD_API_PTR *PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
-typedef void (GLAD_API_PTR *PFNGLEVALPOINT1PROC)(GLint i);
-typedef void (GLAD_API_PTR *PFNGLEVALPOINT2PROC)(GLint i, GLint j);
-typedef void (GLAD_API_PTR *PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat * buffer);
-typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
-typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);
-typedef void (GLAD_API_PTR *PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLFOGCOORDDPROC)(GLdouble coord);
-typedef void (GLAD_API_PTR *PFNGLFOGCOORDDVPROC)(const GLdouble * coord);
-typedef void (GLAD_API_PTR *PFNGLFOGCOORDFPROC)(GLfloat coord);
-typedef void (GLAD_API_PTR *PFNGLFOGCOORDFVPROC)(const GLfloat * coord);
-typedef void (GLAD_API_PTR *PFNGLFOGFPROC)(GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLFOGFVPROC)(GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLFOGIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLFOGIVPROC)(GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
-typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
-typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers);
-typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers);
-typedef GLuint (GLAD_API_PTR *PFNGLGENLISTSPROC)(GLsizei range);
-typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids);
-typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers);
-typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers);
-typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures);
-typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays);
-typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders);
-typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data);
-typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data);
-typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params);
-typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params);
-typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data);
-typedef void (GLAD_API_PTR *PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble * equation);
-typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img);
-typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog);
-typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data);
-typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data);
-typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name);
-typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params);
-typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSARBPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data);
-typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data);
-typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data);
-typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data);
-typedef void (GLAD_API_PTR *PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint * v);
-typedef void (GLAD_API_PTR *PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val);
-typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label);
-typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label);
-typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat * values);
-typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint * values);
-typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort * values);
-typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params);
-typedef void (GLAD_API_PTR *PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte * mask);
-typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
-typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params);
-typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params);
-typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params);
-typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name);
-typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
-typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values);
-typedef void (GLAD_API_PTR *PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels);
-typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name);
-typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices);
-typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETNCOLORTABLEARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void * table);
-typedef void (GLAD_API_PTR *PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC)(GLenum target, GLint lod, GLsizei bufSize, void * img);
-typedef void (GLAD_API_PTR *PFNGLGETNCONVOLUTIONFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void * image);
-typedef void (GLAD_API_PTR *PFNGLGETNHISTOGRAMARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void * values);
-typedef void (GLAD_API_PTR *PFNGLGETNMAPDVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLGETNMAPFVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLGETNMAPIVARBPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint * v);
-typedef void (GLAD_API_PTR *PFNGLGETNMINMAXARBPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void * values);
-typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPFVARBPROC)(GLenum map, GLsizei bufSize, GLfloat * values);
-typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPUIVARBPROC)(GLenum map, GLsizei bufSize, GLuint * values);
-typedef void (GLAD_API_PTR *PFNGLGETNPIXELMAPUSVARBPROC)(GLenum map, GLsizei bufSize, GLushort * values);
-typedef void (GLAD_API_PTR *PFNGLGETNPOLYGONSTIPPLEARBPROC)(GLsizei bufSize, GLubyte * pattern);
-typedef void (GLAD_API_PTR *PFNGLGETNSEPARABLEFILTERARBPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void * row, GLsizei columnBufSize, void * column, void * span);
-typedef void (GLAD_API_PTR *PFNGLGETNTEXIMAGEARBPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void * img);
-typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMDVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble * params);
-typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVARBPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLINDEXMASKPROC)(GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLINDEXDPROC)(GLdouble c);
-typedef void (GLAD_API_PTR *PFNGLINDEXDVPROC)(const GLdouble * c);
-typedef void (GLAD_API_PTR *PFNGLINDEXFPROC)(GLfloat c);
-typedef void (GLAD_API_PTR *PFNGLINDEXFVPROC)(const GLfloat * c);
-typedef void (GLAD_API_PTR *PFNGLINDEXIPROC)(GLint c);
-typedef void (GLAD_API_PTR *PFNGLINDEXIVPROC)(const GLint * c);
-typedef void (GLAD_API_PTR *PFNGLINDEXSPROC)(GLshort c);
-typedef void (GLAD_API_PTR *PFNGLINDEXSVPROC)(const GLshort * c);
-typedef void (GLAD_API_PTR *PFNGLINDEXUBPROC)(GLubyte c);
-typedef void (GLAD_API_PTR *PFNGLINDEXUBVPROC)(const GLubyte * c);
-typedef void (GLAD_API_PTR *PFNGLINITNAMESPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void * pointer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap);
-typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index);
-typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISLISTPROC)(GLuint list);
-typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program);
-typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id);
-typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler);
-typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader);
-typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync);
-typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture);
-typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array);
-typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern);
-typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width);
-typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLLISTBASEPROC)(GLuint base);
-typedef void (GLAD_API_PTR *PFNGLLOADIDENTITYPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLLOADMATRIXDPROC)(const GLdouble * m);
-typedef void (GLAD_API_PTR *PFNGLLOADMATRIXFPROC)(const GLfloat * m);
-typedef void (GLAD_API_PTR *PFNGLLOADNAMEPROC)(GLuint name);
-typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble * m);
-typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat * m);
-typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode);
-typedef void (GLAD_API_PTR *PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble * points);
-typedef void (GLAD_API_PTR *PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat * points);
-typedef void (GLAD_API_PTR *PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble * points);
-typedef void (GLAD_API_PTR *PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat * points);
-typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);
-typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-typedef void (GLAD_API_PTR *PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2);
-typedef void (GLAD_API_PTR *PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2);
-typedef void (GLAD_API_PTR *PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);
-typedef void (GLAD_API_PTR *PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);
-typedef void (GLAD_API_PTR *PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLMATRIXMODEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLMULTMATRIXDPROC)(const GLdouble * m);
-typedef void (GLAD_API_PTR *PFNGLMULTMATRIXFPROC)(const GLfloat * m);
-typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble * m);
-typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat * m);
-typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount);
-typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount);
-typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLNEWLISTPROC)(GLuint list, GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3BVPROC)(const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz);
-typedef void (GLAD_API_PTR *PFNGLNORMAL3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label);
-typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei length, const GLchar * label);
-typedef void (GLAD_API_PTR *PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
-typedef void (GLAD_API_PTR *PFNGLPASSTHROUGHPROC)(GLfloat token);
-typedef void (GLAD_API_PTR *PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat * values);
-typedef void (GLAD_API_PTR *PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint * values);
-typedef void (GLAD_API_PTR *PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort * values);
-typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor);
-typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size);
-typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
-typedef void (GLAD_API_PTR *PFNGLPOLYGONSTIPPLEPROC)(const GLubyte * mask);
-typedef void (GLAD_API_PTR *PFNGLPOPATTRIBPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPOPCLIENTATTRIBPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPOPMATRIXPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPOPNAMEPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);
-typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint * textures, const GLfloat * priorities);
-typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLPUSHATTRIBPROC)(GLbitfield mask);
-typedef void (GLAD_API_PTR *PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask);
-typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message);
-typedef void (GLAD_API_PTR *PFNGLPUSHMATRIXPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLPUSHNAMEPROC)(GLuint name);
-typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IPROC)(GLint x, GLint y);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w);
-typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src);
-typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);
-typedef void (GLAD_API_PTR *PFNGLREADNPIXELSARBPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data);
-typedef void (GLAD_API_PTR *PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
-typedef void (GLAD_API_PTR *PFNGLRECTDVPROC)(const GLdouble * v1, const GLdouble * v2);
-typedef void (GLAD_API_PTR *PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
-typedef void (GLAD_API_PTR *PFNGLRECTFVPROC)(const GLfloat * v1, const GLfloat * v2);
-typedef void (GLAD_API_PTR *PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2);
-typedef void (GLAD_API_PTR *PFNGLRECTIVPROC)(const GLint * v1, const GLint * v2);
-typedef void (GLAD_API_PTR *PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2);
-typedef void (GLAD_API_PTR *PFNGLRECTSVPROC)(const GLshort * v1, const GLshort * v2);
-typedef GLint (GLAD_API_PTR *PFNGLRENDERMODEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
-typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert);
-typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param);
-typedef void (GLAD_API_PTR *PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USVPROC)(const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint * color);
-typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint * buffer);
-typedef void (GLAD_API_PTR *PFNGLSHADEMODELPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
-typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
-typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
-typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DPROC)(GLdouble s);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FPROC)(GLfloat s);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IPROC)(GLint s);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SPROC)(GLshort s);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IPROC)(GLint s, GLint t);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint * coords);
-typedef void (GLAD_API_PTR *PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param);
-typedef void (GLAD_API_PTR *PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble * params);
-typedef void (GLAD_API_PTR *PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode);
-typedef void (GLAD_API_PTR *PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2IPROC)(GLint x, GLint y);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2SPROC)(GLshort x, GLshort y);
-typedef void (GLAD_API_PTR *PFNGLVERTEX2SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z);
-typedef void (GLAD_API_PTR *PFNGLVERTEX3SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w);
-typedef void (GLAD_API_PTR *PFNGLVERTEX4SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint * value);
-typedef void (GLAD_API_PTR *PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IPROC)(GLint x, GLint y);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SVPROC)(const GLshort * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DVPROC)(const GLdouble * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FVPROC)(const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IVPROC)(const GLint * v);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z);
-typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SVPROC)(const GLshort * v);
-
-GLAD_API_CALL PFNGLACCUMPROC glad_glAccum;
-#define glAccum glad_glAccum
-GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
-#define glActiveTexture glad_glActiveTexture
-GLAD_API_CALL PFNGLALPHAFUNCPROC glad_glAlphaFunc;
-#define glAlphaFunc glad_glAlphaFunc
-GLAD_API_CALL PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident;
-#define glAreTexturesResident glad_glAreTexturesResident
-GLAD_API_CALL PFNGLARRAYELEMENTPROC glad_glArrayElement;
-#define glArrayElement glad_glArrayElement
-GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader;
-#define glAttachShader glad_glAttachShader
-GLAD_API_CALL PFNGLBEGINPROC glad_glBegin;
-#define glBegin glad_glBegin
-GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
-#define glBeginConditionalRender glad_glBeginConditionalRender
-GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery;
-#define glBeginQuery glad_glBeginQuery
-GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
-#define glBeginTransformFeedback glad_glBeginTransformFeedback
-GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
-#define glBindAttribLocation glad_glBindAttribLocation
-GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer;
-#define glBindBuffer glad_glBindBuffer
-GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
-#define glBindBufferBase glad_glBindBufferBase
-GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
-#define glBindBufferRange glad_glBindBufferRange
-GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
-#define glBindFragDataLocation glad_glBindFragDataLocation
-GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
-#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
-GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
-#define glBindFramebuffer glad_glBindFramebuffer
-GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
-#define glBindRenderbuffer glad_glBindRenderbuffer
-GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler;
-#define glBindSampler glad_glBindSampler
-GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture;
-#define glBindTexture glad_glBindTexture
-GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
-#define glBindVertexArray glad_glBindVertexArray
-GLAD_API_CALL PFNGLBITMAPPROC glad_glBitmap;
-#define glBitmap glad_glBitmap
-GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor;
-#define glBlendColor glad_glBlendColor
-GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
-#define glBlendEquation glad_glBlendEquation
-GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
-#define glBlendEquationSeparate glad_glBlendEquationSeparate
-GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc;
-#define glBlendFunc glad_glBlendFunc
-GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
-#define glBlendFuncSeparate glad_glBlendFuncSeparate
-GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
-#define glBlitFramebuffer glad_glBlitFramebuffer
-GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData;
-#define glBufferData glad_glBufferData
-GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
-#define glBufferSubData glad_glBufferSubData
-GLAD_API_CALL PFNGLCALLLISTPROC glad_glCallList;
-#define glCallList glad_glCallList
-GLAD_API_CALL PFNGLCALLLISTSPROC glad_glCallLists;
-#define glCallLists glad_glCallLists
-GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
-#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
-GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor;
-#define glClampColor glad_glClampColor
-GLAD_API_CALL PFNGLCLEARPROC glad_glClear;
-#define glClear glad_glClear
-GLAD_API_CALL PFNGLCLEARACCUMPROC glad_glClearAccum;
-#define glClearAccum glad_glClearAccum
-GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
-#define glClearBufferfi glad_glClearBufferfi
-GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
-#define glClearBufferfv glad_glClearBufferfv
-GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
-#define glClearBufferiv glad_glClearBufferiv
-GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
-#define glClearBufferuiv glad_glClearBufferuiv
-GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor;
-#define glClearColor glad_glClearColor
-GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth;
-#define glClearDepth glad_glClearDepth
-GLAD_API_CALL PFNGLCLEARINDEXPROC glad_glClearIndex;
-#define glClearIndex glad_glClearIndex
-GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil;
-#define glClearStencil glad_glClearStencil
-GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture;
-#define glClientActiveTexture glad_glClientActiveTexture
-GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
-#define glClientWaitSync glad_glClientWaitSync
-GLAD_API_CALL PFNGLCLIPPLANEPROC glad_glClipPlane;
-#define glClipPlane glad_glClipPlane
-GLAD_API_CALL PFNGLCOLOR3BPROC glad_glColor3b;
-#define glColor3b glad_glColor3b
-GLAD_API_CALL PFNGLCOLOR3BVPROC glad_glColor3bv;
-#define glColor3bv glad_glColor3bv
-GLAD_API_CALL PFNGLCOLOR3DPROC glad_glColor3d;
-#define glColor3d glad_glColor3d
-GLAD_API_CALL PFNGLCOLOR3DVPROC glad_glColor3dv;
-#define glColor3dv glad_glColor3dv
-GLAD_API_CALL PFNGLCOLOR3FPROC glad_glColor3f;
-#define glColor3f glad_glColor3f
-GLAD_API_CALL PFNGLCOLOR3FVPROC glad_glColor3fv;
-#define glColor3fv glad_glColor3fv
-GLAD_API_CALL PFNGLCOLOR3IPROC glad_glColor3i;
-#define glColor3i glad_glColor3i
-GLAD_API_CALL PFNGLCOLOR3IVPROC glad_glColor3iv;
-#define glColor3iv glad_glColor3iv
-GLAD_API_CALL PFNGLCOLOR3SPROC glad_glColor3s;
-#define glColor3s glad_glColor3s
-GLAD_API_CALL PFNGLCOLOR3SVPROC glad_glColor3sv;
-#define glColor3sv glad_glColor3sv
-GLAD_API_CALL PFNGLCOLOR3UBPROC glad_glColor3ub;
-#define glColor3ub glad_glColor3ub
-GLAD_API_CALL PFNGLCOLOR3UBVPROC glad_glColor3ubv;
-#define glColor3ubv glad_glColor3ubv
-GLAD_API_CALL PFNGLCOLOR3UIPROC glad_glColor3ui;
-#define glColor3ui glad_glColor3ui
-GLAD_API_CALL PFNGLCOLOR3UIVPROC glad_glColor3uiv;
-#define glColor3uiv glad_glColor3uiv
-GLAD_API_CALL PFNGLCOLOR3USPROC glad_glColor3us;
-#define glColor3us glad_glColor3us
-GLAD_API_CALL PFNGLCOLOR3USVPROC glad_glColor3usv;
-#define glColor3usv glad_glColor3usv
-GLAD_API_CALL PFNGLCOLOR4BPROC glad_glColor4b;
-#define glColor4b glad_glColor4b
-GLAD_API_CALL PFNGLCOLOR4BVPROC glad_glColor4bv;
-#define glColor4bv glad_glColor4bv
-GLAD_API_CALL PFNGLCOLOR4DPROC glad_glColor4d;
-#define glColor4d glad_glColor4d
-GLAD_API_CALL PFNGLCOLOR4DVPROC glad_glColor4dv;
-#define glColor4dv glad_glColor4dv
-GLAD_API_CALL PFNGLCOLOR4FPROC glad_glColor4f;
-#define glColor4f glad_glColor4f
-GLAD_API_CALL PFNGLCOLOR4FVPROC glad_glColor4fv;
-#define glColor4fv glad_glColor4fv
-GLAD_API_CALL PFNGLCOLOR4IPROC glad_glColor4i;
-#define glColor4i glad_glColor4i
-GLAD_API_CALL PFNGLCOLOR4IVPROC glad_glColor4iv;
-#define glColor4iv glad_glColor4iv
-GLAD_API_CALL PFNGLCOLOR4SPROC glad_glColor4s;
-#define glColor4s glad_glColor4s
-GLAD_API_CALL PFNGLCOLOR4SVPROC glad_glColor4sv;
-#define glColor4sv glad_glColor4sv
-GLAD_API_CALL PFNGLCOLOR4UBPROC glad_glColor4ub;
-#define glColor4ub glad_glColor4ub
-GLAD_API_CALL PFNGLCOLOR4UBVPROC glad_glColor4ubv;
-#define glColor4ubv glad_glColor4ubv
-GLAD_API_CALL PFNGLCOLOR4UIPROC glad_glColor4ui;
-#define glColor4ui glad_glColor4ui
-GLAD_API_CALL PFNGLCOLOR4UIVPROC glad_glColor4uiv;
-#define glColor4uiv glad_glColor4uiv
-GLAD_API_CALL PFNGLCOLOR4USPROC glad_glColor4us;
-#define glColor4us glad_glColor4us
-GLAD_API_CALL PFNGLCOLOR4USVPROC glad_glColor4usv;
-#define glColor4usv glad_glColor4usv
-GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask;
-#define glColorMask glad_glColorMask
-GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski;
-#define glColorMaski glad_glColorMaski
-GLAD_API_CALL PFNGLCOLORMATERIALPROC glad_glColorMaterial;
-#define glColorMaterial glad_glColorMaterial
-GLAD_API_CALL PFNGLCOLORP3UIPROC glad_glColorP3ui;
-#define glColorP3ui glad_glColorP3ui
-GLAD_API_CALL PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
-#define glColorP3uiv glad_glColorP3uiv
-GLAD_API_CALL PFNGLCOLORP4UIPROC glad_glColorP4ui;
-#define glColorP4ui glad_glColorP4ui
-GLAD_API_CALL PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
-#define glColorP4uiv glad_glColorP4uiv
-GLAD_API_CALL PFNGLCOLORPOINTERPROC glad_glColorPointer;
-#define glColorPointer glad_glColorPointer
-GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader;
-#define glCompileShader glad_glCompileShader
-GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
-#define glCompressedTexImage1D glad_glCompressedTexImage1D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
-#define glCompressedTexImage2D glad_glCompressedTexImage2D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
-#define glCompressedTexImage3D glad_glCompressedTexImage3D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
-#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
-#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
-#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
-GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
-#define glCopyBufferSubData glad_glCopyBufferSubData
-GLAD_API_CALL PFNGLCOPYPIXELSPROC glad_glCopyPixels;
-#define glCopyPixels glad_glCopyPixels
-GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
-#define glCopyTexImage1D glad_glCopyTexImage1D
-GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
-#define glCopyTexImage2D glad_glCopyTexImage2D
-GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
-#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
-GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
-#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
-GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
-#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
-GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
-#define glCreateProgram glad_glCreateProgram
-GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader;
-#define glCreateShader glad_glCreateShader
-GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace;
-#define glCullFace glad_glCullFace
-GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
-#define glDebugMessageCallback glad_glDebugMessageCallback
-GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
-#define glDebugMessageControl glad_glDebugMessageControl
-GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
-#define glDebugMessageInsert glad_glDebugMessageInsert
-GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
-#define glDeleteBuffers glad_glDeleteBuffers
-GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
-#define glDeleteFramebuffers glad_glDeleteFramebuffers
-GLAD_API_CALL PFNGLDELETELISTSPROC glad_glDeleteLists;
-#define glDeleteLists glad_glDeleteLists
-GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
-#define glDeleteProgram glad_glDeleteProgram
-GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
-#define glDeleteQueries glad_glDeleteQueries
-GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
-#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
-GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
-#define glDeleteSamplers glad_glDeleteSamplers
-GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader;
-#define glDeleteShader glad_glDeleteShader
-GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync;
-#define glDeleteSync glad_glDeleteSync
-GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
-#define glDeleteTextures glad_glDeleteTextures
-GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
-#define glDeleteVertexArrays glad_glDeleteVertexArrays
-GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc;
-#define glDepthFunc glad_glDepthFunc
-GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask;
-#define glDepthMask glad_glDepthMask
-GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange;
-#define glDepthRange glad_glDepthRange
-GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader;
-#define glDetachShader glad_glDetachShader
-GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable;
-#define glDisable glad_glDisable
-GLAD_API_CALL PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState;
-#define glDisableClientState glad_glDisableClientState
-GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
-#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
-GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei;
-#define glDisablei glad_glDisablei
-GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays;
-#define glDrawArrays glad_glDrawArrays
-GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
-#define glDrawArraysInstanced glad_glDrawArraysInstanced
-GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
-#define glDrawBuffer glad_glDrawBuffer
-GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
-#define glDrawBuffers glad_glDrawBuffers
-GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements;
-#define glDrawElements glad_glDrawElements
-GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
-#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
-GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
-#define glDrawElementsInstanced glad_glDrawElementsInstanced
-GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
-#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
-GLAD_API_CALL PFNGLDRAWPIXELSPROC glad_glDrawPixels;
-#define glDrawPixels glad_glDrawPixels
-GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
-#define glDrawRangeElements glad_glDrawRangeElements
-GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
-#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
-GLAD_API_CALL PFNGLEDGEFLAGPROC glad_glEdgeFlag;
-#define glEdgeFlag glad_glEdgeFlag
-GLAD_API_CALL PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer;
-#define glEdgeFlagPointer glad_glEdgeFlagPointer
-GLAD_API_CALL PFNGLEDGEFLAGVPROC glad_glEdgeFlagv;
-#define glEdgeFlagv glad_glEdgeFlagv
-GLAD_API_CALL PFNGLENABLEPROC glad_glEnable;
-#define glEnable glad_glEnable
-GLAD_API_CALL PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState;
-#define glEnableClientState glad_glEnableClientState
-GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
-#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
-GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei;
-#define glEnablei glad_glEnablei
-GLAD_API_CALL PFNGLENDPROC glad_glEnd;
-#define glEnd glad_glEnd
-GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
-#define glEndConditionalRender glad_glEndConditionalRender
-GLAD_API_CALL PFNGLENDLISTPROC glad_glEndList;
-#define glEndList glad_glEndList
-GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery;
-#define glEndQuery glad_glEndQuery
-GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
-#define glEndTransformFeedback glad_glEndTransformFeedback
-GLAD_API_CALL PFNGLEVALCOORD1DPROC glad_glEvalCoord1d;
-#define glEvalCoord1d glad_glEvalCoord1d
-GLAD_API_CALL PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv;
-#define glEvalCoord1dv glad_glEvalCoord1dv
-GLAD_API_CALL PFNGLEVALCOORD1FPROC glad_glEvalCoord1f;
-#define glEvalCoord1f glad_glEvalCoord1f
-GLAD_API_CALL PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv;
-#define glEvalCoord1fv glad_glEvalCoord1fv
-GLAD_API_CALL PFNGLEVALCOORD2DPROC glad_glEvalCoord2d;
-#define glEvalCoord2d glad_glEvalCoord2d
-GLAD_API_CALL PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv;
-#define glEvalCoord2dv glad_glEvalCoord2dv
-GLAD_API_CALL PFNGLEVALCOORD2FPROC glad_glEvalCoord2f;
-#define glEvalCoord2f glad_glEvalCoord2f
-GLAD_API_CALL PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv;
-#define glEvalCoord2fv glad_glEvalCoord2fv
-GLAD_API_CALL PFNGLEVALMESH1PROC glad_glEvalMesh1;
-#define glEvalMesh1 glad_glEvalMesh1
-GLAD_API_CALL PFNGLEVALMESH2PROC glad_glEvalMesh2;
-#define glEvalMesh2 glad_glEvalMesh2
-GLAD_API_CALL PFNGLEVALPOINT1PROC glad_glEvalPoint1;
-#define glEvalPoint1 glad_glEvalPoint1
-GLAD_API_CALL PFNGLEVALPOINT2PROC glad_glEvalPoint2;
-#define glEvalPoint2 glad_glEvalPoint2
-GLAD_API_CALL PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer;
-#define glFeedbackBuffer glad_glFeedbackBuffer
-GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync;
-#define glFenceSync glad_glFenceSync
-GLAD_API_CALL PFNGLFINISHPROC glad_glFinish;
-#define glFinish glad_glFinish
-GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush;
-#define glFlush glad_glFlush
-GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
-#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
-GLAD_API_CALL PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer;
-#define glFogCoordPointer glad_glFogCoordPointer
-GLAD_API_CALL PFNGLFOGCOORDDPROC glad_glFogCoordd;
-#define glFogCoordd glad_glFogCoordd
-GLAD_API_CALL PFNGLFOGCOORDDVPROC glad_glFogCoorddv;
-#define glFogCoorddv glad_glFogCoorddv
-GLAD_API_CALL PFNGLFOGCOORDFPROC glad_glFogCoordf;
-#define glFogCoordf glad_glFogCoordf
-GLAD_API_CALL PFNGLFOGCOORDFVPROC glad_glFogCoordfv;
-#define glFogCoordfv glad_glFogCoordfv
-GLAD_API_CALL PFNGLFOGFPROC glad_glFogf;
-#define glFogf glad_glFogf
-GLAD_API_CALL PFNGLFOGFVPROC glad_glFogfv;
-#define glFogfv glad_glFogfv
-GLAD_API_CALL PFNGLFOGIPROC glad_glFogi;
-#define glFogi glad_glFogi
-GLAD_API_CALL PFNGLFOGIVPROC glad_glFogiv;
-#define glFogiv glad_glFogiv
-GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
-#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
-#define glFramebufferTexture glad_glFramebufferTexture
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
-#define glFramebufferTexture1D glad_glFramebufferTexture1D
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
-#define glFramebufferTexture2D glad_glFramebufferTexture2D
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
-#define glFramebufferTexture3D glad_glFramebufferTexture3D
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
-#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
-GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace;
-#define glFrontFace glad_glFrontFace
-GLAD_API_CALL PFNGLFRUSTUMPROC glad_glFrustum;
-#define glFrustum glad_glFrustum
-GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers;
-#define glGenBuffers glad_glGenBuffers
-GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
-#define glGenFramebuffers glad_glGenFramebuffers
-GLAD_API_CALL PFNGLGENLISTSPROC glad_glGenLists;
-#define glGenLists glad_glGenLists
-GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries;
-#define glGenQueries glad_glGenQueries
-GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
-#define glGenRenderbuffers glad_glGenRenderbuffers
-GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers;
-#define glGenSamplers glad_glGenSamplers
-GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures;
-#define glGenTextures glad_glGenTextures
-GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
-#define glGenVertexArrays glad_glGenVertexArrays
-GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
-#define glGenerateMipmap glad_glGenerateMipmap
-GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
-#define glGetActiveAttrib glad_glGetActiveAttrib
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
-#define glGetActiveUniform glad_glGetActiveUniform
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
-#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
-#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
-#define glGetActiveUniformName glad_glGetActiveUniformName
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
-#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
-GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
-#define glGetAttachedShaders glad_glGetAttachedShaders
-GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
-#define glGetAttribLocation glad_glGetAttribLocation
-GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
-#define glGetBooleani_v glad_glGetBooleani_v
-GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
-#define glGetBooleanv glad_glGetBooleanv
-GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
-#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
-GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
-#define glGetBufferParameteriv glad_glGetBufferParameteriv
-GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
-#define glGetBufferPointerv glad_glGetBufferPointerv
-GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
-#define glGetBufferSubData glad_glGetBufferSubData
-GLAD_API_CALL PFNGLGETCLIPPLANEPROC glad_glGetClipPlane;
-#define glGetClipPlane glad_glGetClipPlane
-GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
-#define glGetCompressedTexImage glad_glGetCompressedTexImage
-GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
-#define glGetDebugMessageLog glad_glGetDebugMessageLog
-GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev;
-#define glGetDoublev glad_glGetDoublev
-GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError;
-#define glGetError glad_glGetError
-GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv;
-#define glGetFloatv glad_glGetFloatv
-GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
-#define glGetFragDataIndex glad_glGetFragDataIndex
-GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
-#define glGetFragDataLocation glad_glGetFragDataLocation
-GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
-#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
-GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB;
-#define glGetGraphicsResetStatusARB glad_glGetGraphicsResetStatusARB
-GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
-#define glGetInteger64i_v glad_glGetInteger64i_v
-GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
-#define glGetInteger64v glad_glGetInteger64v
-GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
-#define glGetIntegeri_v glad_glGetIntegeri_v
-GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv;
-#define glGetIntegerv glad_glGetIntegerv
-GLAD_API_CALL PFNGLGETLIGHTFVPROC glad_glGetLightfv;
-#define glGetLightfv glad_glGetLightfv
-GLAD_API_CALL PFNGLGETLIGHTIVPROC glad_glGetLightiv;
-#define glGetLightiv glad_glGetLightiv
-GLAD_API_CALL PFNGLGETMAPDVPROC glad_glGetMapdv;
-#define glGetMapdv glad_glGetMapdv
-GLAD_API_CALL PFNGLGETMAPFVPROC glad_glGetMapfv;
-#define glGetMapfv glad_glGetMapfv
-GLAD_API_CALL PFNGLGETMAPIVPROC glad_glGetMapiv;
-#define glGetMapiv glad_glGetMapiv
-GLAD_API_CALL PFNGLGETMATERIALFVPROC glad_glGetMaterialfv;
-#define glGetMaterialfv glad_glGetMaterialfv
-GLAD_API_CALL PFNGLGETMATERIALIVPROC glad_glGetMaterialiv;
-#define glGetMaterialiv glad_glGetMaterialiv
-GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
-#define glGetMultisamplefv glad_glGetMultisamplefv
-GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
-#define glGetObjectLabel glad_glGetObjectLabel
-GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
-#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
-GLAD_API_CALL PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv;
-#define glGetPixelMapfv glad_glGetPixelMapfv
-GLAD_API_CALL PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv;
-#define glGetPixelMapuiv glad_glGetPixelMapuiv
-GLAD_API_CALL PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv;
-#define glGetPixelMapusv glad_glGetPixelMapusv
-GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv;
-#define glGetPointerv glad_glGetPointerv
-GLAD_API_CALL PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple;
-#define glGetPolygonStipple glad_glGetPolygonStipple
-GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
-#define glGetProgramInfoLog glad_glGetProgramInfoLog
-GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
-#define glGetProgramiv glad_glGetProgramiv
-GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
-#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
-GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
-#define glGetQueryObjectiv glad_glGetQueryObjectiv
-GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
-#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
-GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
-#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
-GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv;
-#define glGetQueryiv glad_glGetQueryiv
-GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
-#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
-GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
-#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
-GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
-#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
-GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
-#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
-GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
-#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
-GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
-#define glGetShaderInfoLog glad_glGetShaderInfoLog
-GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
-#define glGetShaderSource glad_glGetShaderSource
-GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv;
-#define glGetShaderiv glad_glGetShaderiv
-GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString;
-#define glGetString glad_glGetString
-GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi;
-#define glGetStringi glad_glGetStringi
-GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv;
-#define glGetSynciv glad_glGetSynciv
-GLAD_API_CALL PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv;
-#define glGetTexEnvfv glad_glGetTexEnvfv
-GLAD_API_CALL PFNGLGETTEXENVIVPROC glad_glGetTexEnviv;
-#define glGetTexEnviv glad_glGetTexEnviv
-GLAD_API_CALL PFNGLGETTEXGENDVPROC glad_glGetTexGendv;
-#define glGetTexGendv glad_glGetTexGendv
-GLAD_API_CALL PFNGLGETTEXGENFVPROC glad_glGetTexGenfv;
-#define glGetTexGenfv glad_glGetTexGenfv
-GLAD_API_CALL PFNGLGETTEXGENIVPROC glad_glGetTexGeniv;
-#define glGetTexGeniv glad_glGetTexGeniv
-GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
-#define glGetTexImage glad_glGetTexImage
-GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
-#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
-GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
-#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
-GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
-#define glGetTexParameterIiv glad_glGetTexParameterIiv
-GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
-#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
-GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
-#define glGetTexParameterfv glad_glGetTexParameterfv
-GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
-#define glGetTexParameteriv glad_glGetTexParameteriv
-GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
-#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
-GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
-#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
-GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
-#define glGetUniformIndices glad_glGetUniformIndices
-GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
-#define glGetUniformLocation glad_glGetUniformLocation
-GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
-#define glGetUniformfv glad_glGetUniformfv
-GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
-#define glGetUniformiv glad_glGetUniformiv
-GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
-#define glGetUniformuiv glad_glGetUniformuiv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
-#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
-#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
-#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
-#define glGetVertexAttribdv glad_glGetVertexAttribdv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
-#define glGetVertexAttribfv glad_glGetVertexAttribfv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
-#define glGetVertexAttribiv glad_glGetVertexAttribiv
-GLAD_API_CALL PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB;
-#define glGetnColorTableARB glad_glGetnColorTableARB
-GLAD_API_CALL PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB;
-#define glGetnCompressedTexImageARB glad_glGetnCompressedTexImageARB
-GLAD_API_CALL PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB;
-#define glGetnConvolutionFilterARB glad_glGetnConvolutionFilterARB
-GLAD_API_CALL PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB;
-#define glGetnHistogramARB glad_glGetnHistogramARB
-GLAD_API_CALL PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB;
-#define glGetnMapdvARB glad_glGetnMapdvARB
-GLAD_API_CALL PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB;
-#define glGetnMapfvARB glad_glGetnMapfvARB
-GLAD_API_CALL PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB;
-#define glGetnMapivARB glad_glGetnMapivARB
-GLAD_API_CALL PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB;
-#define glGetnMinmaxARB glad_glGetnMinmaxARB
-GLAD_API_CALL PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB;
-#define glGetnPixelMapfvARB glad_glGetnPixelMapfvARB
-GLAD_API_CALL PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB;
-#define glGetnPixelMapuivARB glad_glGetnPixelMapuivARB
-GLAD_API_CALL PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB;
-#define glGetnPixelMapusvARB glad_glGetnPixelMapusvARB
-GLAD_API_CALL PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB;
-#define glGetnPolygonStippleARB glad_glGetnPolygonStippleARB
-GLAD_API_CALL PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB;
-#define glGetnSeparableFilterARB glad_glGetnSeparableFilterARB
-GLAD_API_CALL PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB;
-#define glGetnTexImageARB glad_glGetnTexImageARB
-GLAD_API_CALL PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB;
-#define glGetnUniformdvARB glad_glGetnUniformdvARB
-GLAD_API_CALL PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB;
-#define glGetnUniformfvARB glad_glGetnUniformfvARB
-GLAD_API_CALL PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB;
-#define glGetnUniformivARB glad_glGetnUniformivARB
-GLAD_API_CALL PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB;
-#define glGetnUniformuivARB glad_glGetnUniformuivARB
-GLAD_API_CALL PFNGLHINTPROC glad_glHint;
-#define glHint glad_glHint
-GLAD_API_CALL PFNGLINDEXMASKPROC glad_glIndexMask;
-#define glIndexMask glad_glIndexMask
-GLAD_API_CALL PFNGLINDEXPOINTERPROC glad_glIndexPointer;
-#define glIndexPointer glad_glIndexPointer
-GLAD_API_CALL PFNGLINDEXDPROC glad_glIndexd;
-#define glIndexd glad_glIndexd
-GLAD_API_CALL PFNGLINDEXDVPROC glad_glIndexdv;
-#define glIndexdv glad_glIndexdv
-GLAD_API_CALL PFNGLINDEXFPROC glad_glIndexf;
-#define glIndexf glad_glIndexf
-GLAD_API_CALL PFNGLINDEXFVPROC glad_glIndexfv;
-#define glIndexfv glad_glIndexfv
-GLAD_API_CALL PFNGLINDEXIPROC glad_glIndexi;
-#define glIndexi glad_glIndexi
-GLAD_API_CALL PFNGLINDEXIVPROC glad_glIndexiv;
-#define glIndexiv glad_glIndexiv
-GLAD_API_CALL PFNGLINDEXSPROC glad_glIndexs;
-#define glIndexs glad_glIndexs
-GLAD_API_CALL PFNGLINDEXSVPROC glad_glIndexsv;
-#define glIndexsv glad_glIndexsv
-GLAD_API_CALL PFNGLINDEXUBPROC glad_glIndexub;
-#define glIndexub glad_glIndexub
-GLAD_API_CALL PFNGLINDEXUBVPROC glad_glIndexubv;
-#define glIndexubv glad_glIndexubv
-GLAD_API_CALL PFNGLINITNAMESPROC glad_glInitNames;
-#define glInitNames glad_glInitNames
-GLAD_API_CALL PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays;
-#define glInterleavedArrays glad_glInterleavedArrays
-GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer;
-#define glIsBuffer glad_glIsBuffer
-GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled;
-#define glIsEnabled glad_glIsEnabled
-GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi;
-#define glIsEnabledi glad_glIsEnabledi
-GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
-#define glIsFramebuffer glad_glIsFramebuffer
-GLAD_API_CALL PFNGLISLISTPROC glad_glIsList;
-#define glIsList glad_glIsList
-GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram;
-#define glIsProgram glad_glIsProgram
-GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery;
-#define glIsQuery glad_glIsQuery
-GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
-#define glIsRenderbuffer glad_glIsRenderbuffer
-GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler;
-#define glIsSampler glad_glIsSampler
-GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader;
-#define glIsShader glad_glIsShader
-GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync;
-#define glIsSync glad_glIsSync
-GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture;
-#define glIsTexture glad_glIsTexture
-GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
-#define glIsVertexArray glad_glIsVertexArray
-GLAD_API_CALL PFNGLLIGHTMODELFPROC glad_glLightModelf;
-#define glLightModelf glad_glLightModelf
-GLAD_API_CALL PFNGLLIGHTMODELFVPROC glad_glLightModelfv;
-#define glLightModelfv glad_glLightModelfv
-GLAD_API_CALL PFNGLLIGHTMODELIPROC glad_glLightModeli;
-#define glLightModeli glad_glLightModeli
-GLAD_API_CALL PFNGLLIGHTMODELIVPROC glad_glLightModeliv;
-#define glLightModeliv glad_glLightModeliv
-GLAD_API_CALL PFNGLLIGHTFPROC glad_glLightf;
-#define glLightf glad_glLightf
-GLAD_API_CALL PFNGLLIGHTFVPROC glad_glLightfv;
-#define glLightfv glad_glLightfv
-GLAD_API_CALL PFNGLLIGHTIPROC glad_glLighti;
-#define glLighti glad_glLighti
-GLAD_API_CALL PFNGLLIGHTIVPROC glad_glLightiv;
-#define glLightiv glad_glLightiv
-GLAD_API_CALL PFNGLLINESTIPPLEPROC glad_glLineStipple;
-#define glLineStipple glad_glLineStipple
-GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth;
-#define glLineWidth glad_glLineWidth
-GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram;
-#define glLinkProgram glad_glLinkProgram
-GLAD_API_CALL PFNGLLISTBASEPROC glad_glListBase;
-#define glListBase glad_glListBase
-GLAD_API_CALL PFNGLLOADIDENTITYPROC glad_glLoadIdentity;
-#define glLoadIdentity glad_glLoadIdentity
-GLAD_API_CALL PFNGLLOADMATRIXDPROC glad_glLoadMatrixd;
-#define glLoadMatrixd glad_glLoadMatrixd
-GLAD_API_CALL PFNGLLOADMATRIXFPROC glad_glLoadMatrixf;
-#define glLoadMatrixf glad_glLoadMatrixf
-GLAD_API_CALL PFNGLLOADNAMEPROC glad_glLoadName;
-#define glLoadName glad_glLoadName
-GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd;
-#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd
-GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf;
-#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf
-GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp;
-#define glLogicOp glad_glLogicOp
-GLAD_API_CALL PFNGLMAP1DPROC glad_glMap1d;
-#define glMap1d glad_glMap1d
-GLAD_API_CALL PFNGLMAP1FPROC glad_glMap1f;
-#define glMap1f glad_glMap1f
-GLAD_API_CALL PFNGLMAP2DPROC glad_glMap2d;
-#define glMap2d glad_glMap2d
-GLAD_API_CALL PFNGLMAP2FPROC glad_glMap2f;
-#define glMap2f glad_glMap2f
-GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer;
-#define glMapBuffer glad_glMapBuffer
-GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
-#define glMapBufferRange glad_glMapBufferRange
-GLAD_API_CALL PFNGLMAPGRID1DPROC glad_glMapGrid1d;
-#define glMapGrid1d glad_glMapGrid1d
-GLAD_API_CALL PFNGLMAPGRID1FPROC glad_glMapGrid1f;
-#define glMapGrid1f glad_glMapGrid1f
-GLAD_API_CALL PFNGLMAPGRID2DPROC glad_glMapGrid2d;
-#define glMapGrid2d glad_glMapGrid2d
-GLAD_API_CALL PFNGLMAPGRID2FPROC glad_glMapGrid2f;
-#define glMapGrid2f glad_glMapGrid2f
-GLAD_API_CALL PFNGLMATERIALFPROC glad_glMaterialf;
-#define glMaterialf glad_glMaterialf
-GLAD_API_CALL PFNGLMATERIALFVPROC glad_glMaterialfv;
-#define glMaterialfv glad_glMaterialfv
-GLAD_API_CALL PFNGLMATERIALIPROC glad_glMateriali;
-#define glMateriali glad_glMateriali
-GLAD_API_CALL PFNGLMATERIALIVPROC glad_glMaterialiv;
-#define glMaterialiv glad_glMaterialiv
-GLAD_API_CALL PFNGLMATRIXMODEPROC glad_glMatrixMode;
-#define glMatrixMode glad_glMatrixMode
-GLAD_API_CALL PFNGLMULTMATRIXDPROC glad_glMultMatrixd;
-#define glMultMatrixd glad_glMultMatrixd
-GLAD_API_CALL PFNGLMULTMATRIXFPROC glad_glMultMatrixf;
-#define glMultMatrixf glad_glMultMatrixf
-GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd;
-#define glMultTransposeMatrixd glad_glMultTransposeMatrixd
-GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf;
-#define glMultTransposeMatrixf glad_glMultTransposeMatrixf
-GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
-#define glMultiDrawArrays glad_glMultiDrawArrays
-GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
-#define glMultiDrawElements glad_glMultiDrawElements
-GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
-#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
-GLAD_API_CALL PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d;
-#define glMultiTexCoord1d glad_glMultiTexCoord1d
-GLAD_API_CALL PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv;
-#define glMultiTexCoord1dv glad_glMultiTexCoord1dv
-GLAD_API_CALL PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f;
-#define glMultiTexCoord1f glad_glMultiTexCoord1f
-GLAD_API_CALL PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv;
-#define glMultiTexCoord1fv glad_glMultiTexCoord1fv
-GLAD_API_CALL PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i;
-#define glMultiTexCoord1i glad_glMultiTexCoord1i
-GLAD_API_CALL PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv;
-#define glMultiTexCoord1iv glad_glMultiTexCoord1iv
-GLAD_API_CALL PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s;
-#define glMultiTexCoord1s glad_glMultiTexCoord1s
-GLAD_API_CALL PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv;
-#define glMultiTexCoord1sv glad_glMultiTexCoord1sv
-GLAD_API_CALL PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d;
-#define glMultiTexCoord2d glad_glMultiTexCoord2d
-GLAD_API_CALL PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv;
-#define glMultiTexCoord2dv glad_glMultiTexCoord2dv
-GLAD_API_CALL PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f;
-#define glMultiTexCoord2f glad_glMultiTexCoord2f
-GLAD_API_CALL PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv;
-#define glMultiTexCoord2fv glad_glMultiTexCoord2fv
-GLAD_API_CALL PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i;
-#define glMultiTexCoord2i glad_glMultiTexCoord2i
-GLAD_API_CALL PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv;
-#define glMultiTexCoord2iv glad_glMultiTexCoord2iv
-GLAD_API_CALL PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s;
-#define glMultiTexCoord2s glad_glMultiTexCoord2s
-GLAD_API_CALL PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv;
-#define glMultiTexCoord2sv glad_glMultiTexCoord2sv
-GLAD_API_CALL PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d;
-#define glMultiTexCoord3d glad_glMultiTexCoord3d
-GLAD_API_CALL PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv;
-#define glMultiTexCoord3dv glad_glMultiTexCoord3dv
-GLAD_API_CALL PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f;
-#define glMultiTexCoord3f glad_glMultiTexCoord3f
-GLAD_API_CALL PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv;
-#define glMultiTexCoord3fv glad_glMultiTexCoord3fv
-GLAD_API_CALL PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i;
-#define glMultiTexCoord3i glad_glMultiTexCoord3i
-GLAD_API_CALL PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv;
-#define glMultiTexCoord3iv glad_glMultiTexCoord3iv
-GLAD_API_CALL PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s;
-#define glMultiTexCoord3s glad_glMultiTexCoord3s
-GLAD_API_CALL PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv;
-#define glMultiTexCoord3sv glad_glMultiTexCoord3sv
-GLAD_API_CALL PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d;
-#define glMultiTexCoord4d glad_glMultiTexCoord4d
-GLAD_API_CALL PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv;
-#define glMultiTexCoord4dv glad_glMultiTexCoord4dv
-GLAD_API_CALL PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f;
-#define glMultiTexCoord4f glad_glMultiTexCoord4f
-GLAD_API_CALL PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv;
-#define glMultiTexCoord4fv glad_glMultiTexCoord4fv
-GLAD_API_CALL PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i;
-#define glMultiTexCoord4i glad_glMultiTexCoord4i
-GLAD_API_CALL PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv;
-#define glMultiTexCoord4iv glad_glMultiTexCoord4iv
-GLAD_API_CALL PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s;
-#define glMultiTexCoord4s glad_glMultiTexCoord4s
-GLAD_API_CALL PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv;
-#define glMultiTexCoord4sv glad_glMultiTexCoord4sv
-GLAD_API_CALL PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
-#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui
-GLAD_API_CALL PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
-#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv
-GLAD_API_CALL PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
-#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui
-GLAD_API_CALL PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
-#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv
-GLAD_API_CALL PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
-#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui
-GLAD_API_CALL PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
-#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv
-GLAD_API_CALL PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
-#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui
-GLAD_API_CALL PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
-#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv
-GLAD_API_CALL PFNGLNEWLISTPROC glad_glNewList;
-#define glNewList glad_glNewList
-GLAD_API_CALL PFNGLNORMAL3BPROC glad_glNormal3b;
-#define glNormal3b glad_glNormal3b
-GLAD_API_CALL PFNGLNORMAL3BVPROC glad_glNormal3bv;
-#define glNormal3bv glad_glNormal3bv
-GLAD_API_CALL PFNGLNORMAL3DPROC glad_glNormal3d;
-#define glNormal3d glad_glNormal3d
-GLAD_API_CALL PFNGLNORMAL3DVPROC glad_glNormal3dv;
-#define glNormal3dv glad_glNormal3dv
-GLAD_API_CALL PFNGLNORMAL3FPROC glad_glNormal3f;
-#define glNormal3f glad_glNormal3f
-GLAD_API_CALL PFNGLNORMAL3FVPROC glad_glNormal3fv;
-#define glNormal3fv glad_glNormal3fv
-GLAD_API_CALL PFNGLNORMAL3IPROC glad_glNormal3i;
-#define glNormal3i glad_glNormal3i
-GLAD_API_CALL PFNGLNORMAL3IVPROC glad_glNormal3iv;
-#define glNormal3iv glad_glNormal3iv
-GLAD_API_CALL PFNGLNORMAL3SPROC glad_glNormal3s;
-#define glNormal3s glad_glNormal3s
-GLAD_API_CALL PFNGLNORMAL3SVPROC glad_glNormal3sv;
-#define glNormal3sv glad_glNormal3sv
-GLAD_API_CALL PFNGLNORMALP3UIPROC glad_glNormalP3ui;
-#define glNormalP3ui glad_glNormalP3ui
-GLAD_API_CALL PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
-#define glNormalP3uiv glad_glNormalP3uiv
-GLAD_API_CALL PFNGLNORMALPOINTERPROC glad_glNormalPointer;
-#define glNormalPointer glad_glNormalPointer
-GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel;
-#define glObjectLabel glad_glObjectLabel
-GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
-#define glObjectPtrLabel glad_glObjectPtrLabel
-GLAD_API_CALL PFNGLORTHOPROC glad_glOrtho;
-#define glOrtho glad_glOrtho
-GLAD_API_CALL PFNGLPASSTHROUGHPROC glad_glPassThrough;
-#define glPassThrough glad_glPassThrough
-GLAD_API_CALL PFNGLPIXELMAPFVPROC glad_glPixelMapfv;
-#define glPixelMapfv glad_glPixelMapfv
-GLAD_API_CALL PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv;
-#define glPixelMapuiv glad_glPixelMapuiv
-GLAD_API_CALL PFNGLPIXELMAPUSVPROC glad_glPixelMapusv;
-#define glPixelMapusv glad_glPixelMapusv
-GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref;
-#define glPixelStoref glad_glPixelStoref
-GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei;
-#define glPixelStorei glad_glPixelStorei
-GLAD_API_CALL PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf;
-#define glPixelTransferf glad_glPixelTransferf
-GLAD_API_CALL PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi;
-#define glPixelTransferi glad_glPixelTransferi
-GLAD_API_CALL PFNGLPIXELZOOMPROC glad_glPixelZoom;
-#define glPixelZoom glad_glPixelZoom
-GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
-#define glPointParameterf glad_glPointParameterf
-GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
-#define glPointParameterfv glad_glPointParameterfv
-GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
-#define glPointParameteri glad_glPointParameteri
-GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
-#define glPointParameteriv glad_glPointParameteriv
-GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize;
-#define glPointSize glad_glPointSize
-GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode;
-#define glPolygonMode glad_glPolygonMode
-GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
-#define glPolygonOffset glad_glPolygonOffset
-GLAD_API_CALL PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple;
-#define glPolygonStipple glad_glPolygonStipple
-GLAD_API_CALL PFNGLPOPATTRIBPROC glad_glPopAttrib;
-#define glPopAttrib glad_glPopAttrib
-GLAD_API_CALL PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib;
-#define glPopClientAttrib glad_glPopClientAttrib
-GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
-#define glPopDebugGroup glad_glPopDebugGroup
-GLAD_API_CALL PFNGLPOPMATRIXPROC glad_glPopMatrix;
-#define glPopMatrix glad_glPopMatrix
-GLAD_API_CALL PFNGLPOPNAMEPROC glad_glPopName;
-#define glPopName glad_glPopName
-GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
-#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
-GLAD_API_CALL PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures;
-#define glPrioritizeTextures glad_glPrioritizeTextures
-GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
-#define glProvokingVertex glad_glProvokingVertex
-GLAD_API_CALL PFNGLPUSHATTRIBPROC glad_glPushAttrib;
-#define glPushAttrib glad_glPushAttrib
-GLAD_API_CALL PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib;
-#define glPushClientAttrib glad_glPushClientAttrib
-GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
-#define glPushDebugGroup glad_glPushDebugGroup
-GLAD_API_CALL PFNGLPUSHMATRIXPROC glad_glPushMatrix;
-#define glPushMatrix glad_glPushMatrix
-GLAD_API_CALL PFNGLPUSHNAMEPROC glad_glPushName;
-#define glPushName glad_glPushName
-GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
-#define glQueryCounter glad_glQueryCounter
-GLAD_API_CALL PFNGLRASTERPOS2DPROC glad_glRasterPos2d;
-#define glRasterPos2d glad_glRasterPos2d
-GLAD_API_CALL PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv;
-#define glRasterPos2dv glad_glRasterPos2dv
-GLAD_API_CALL PFNGLRASTERPOS2FPROC glad_glRasterPos2f;
-#define glRasterPos2f glad_glRasterPos2f
-GLAD_API_CALL PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv;
-#define glRasterPos2fv glad_glRasterPos2fv
-GLAD_API_CALL PFNGLRASTERPOS2IPROC glad_glRasterPos2i;
-#define glRasterPos2i glad_glRasterPos2i
-GLAD_API_CALL PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv;
-#define glRasterPos2iv glad_glRasterPos2iv
-GLAD_API_CALL PFNGLRASTERPOS2SPROC glad_glRasterPos2s;
-#define glRasterPos2s glad_glRasterPos2s
-GLAD_API_CALL PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv;
-#define glRasterPos2sv glad_glRasterPos2sv
-GLAD_API_CALL PFNGLRASTERPOS3DPROC glad_glRasterPos3d;
-#define glRasterPos3d glad_glRasterPos3d
-GLAD_API_CALL PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv;
-#define glRasterPos3dv glad_glRasterPos3dv
-GLAD_API_CALL PFNGLRASTERPOS3FPROC glad_glRasterPos3f;
-#define glRasterPos3f glad_glRasterPos3f
-GLAD_API_CALL PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv;
-#define glRasterPos3fv glad_glRasterPos3fv
-GLAD_API_CALL PFNGLRASTERPOS3IPROC glad_glRasterPos3i;
-#define glRasterPos3i glad_glRasterPos3i
-GLAD_API_CALL PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv;
-#define glRasterPos3iv glad_glRasterPos3iv
-GLAD_API_CALL PFNGLRASTERPOS3SPROC glad_glRasterPos3s;
-#define glRasterPos3s glad_glRasterPos3s
-GLAD_API_CALL PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv;
-#define glRasterPos3sv glad_glRasterPos3sv
-GLAD_API_CALL PFNGLRASTERPOS4DPROC glad_glRasterPos4d;
-#define glRasterPos4d glad_glRasterPos4d
-GLAD_API_CALL PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv;
-#define glRasterPos4dv glad_glRasterPos4dv
-GLAD_API_CALL PFNGLRASTERPOS4FPROC glad_glRasterPos4f;
-#define glRasterPos4f glad_glRasterPos4f
-GLAD_API_CALL PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv;
-#define glRasterPos4fv glad_glRasterPos4fv
-GLAD_API_CALL PFNGLRASTERPOS4IPROC glad_glRasterPos4i;
-#define glRasterPos4i glad_glRasterPos4i
-GLAD_API_CALL PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv;
-#define glRasterPos4iv glad_glRasterPos4iv
-GLAD_API_CALL PFNGLRASTERPOS4SPROC glad_glRasterPos4s;
-#define glRasterPos4s glad_glRasterPos4s
-GLAD_API_CALL PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv;
-#define glRasterPos4sv glad_glRasterPos4sv
-GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer;
-#define glReadBuffer glad_glReadBuffer
-GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels;
-#define glReadPixels glad_glReadPixels
-GLAD_API_CALL PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB;
-#define glReadnPixelsARB glad_glReadnPixelsARB
-GLAD_API_CALL PFNGLRECTDPROC glad_glRectd;
-#define glRectd glad_glRectd
-GLAD_API_CALL PFNGLRECTDVPROC glad_glRectdv;
-#define glRectdv glad_glRectdv
-GLAD_API_CALL PFNGLRECTFPROC glad_glRectf;
-#define glRectf glad_glRectf
-GLAD_API_CALL PFNGLRECTFVPROC glad_glRectfv;
-#define glRectfv glad_glRectfv
-GLAD_API_CALL PFNGLRECTIPROC glad_glRecti;
-#define glRecti glad_glRecti
-GLAD_API_CALL PFNGLRECTIVPROC glad_glRectiv;
-#define glRectiv glad_glRectiv
-GLAD_API_CALL PFNGLRECTSPROC glad_glRects;
-#define glRects glad_glRects
-GLAD_API_CALL PFNGLRECTSVPROC glad_glRectsv;
-#define glRectsv glad_glRectsv
-GLAD_API_CALL PFNGLRENDERMODEPROC glad_glRenderMode;
-#define glRenderMode glad_glRenderMode
-GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
-#define glRenderbufferStorage glad_glRenderbufferStorage
-GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
-#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
-GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated;
-#define glRotated glad_glRotated
-GLAD_API_CALL PFNGLROTATEFPROC glad_glRotatef;
-#define glRotatef glad_glRotatef
-GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
-#define glSampleCoverage glad_glSampleCoverage
-GLAD_API_CALL PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB;
-#define glSampleCoverageARB glad_glSampleCoverageARB
-GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
-#define glSampleMaski glad_glSampleMaski
-GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
-#define glSamplerParameterIiv glad_glSamplerParameterIiv
-GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
-#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
-GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
-#define glSamplerParameterf glad_glSamplerParameterf
-GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
-#define glSamplerParameterfv glad_glSamplerParameterfv
-GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
-#define glSamplerParameteri glad_glSamplerParameteri
-GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
-#define glSamplerParameteriv glad_glSamplerParameteriv
-GLAD_API_CALL PFNGLSCALEDPROC glad_glScaled;
-#define glScaled glad_glScaled
-GLAD_API_CALL PFNGLSCALEFPROC glad_glScalef;
-#define glScalef glad_glScalef
-GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor;
-#define glScissor glad_glScissor
-GLAD_API_CALL PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b;
-#define glSecondaryColor3b glad_glSecondaryColor3b
-GLAD_API_CALL PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv;
-#define glSecondaryColor3bv glad_glSecondaryColor3bv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d;
-#define glSecondaryColor3d glad_glSecondaryColor3d
-GLAD_API_CALL PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv;
-#define glSecondaryColor3dv glad_glSecondaryColor3dv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f;
-#define glSecondaryColor3f glad_glSecondaryColor3f
-GLAD_API_CALL PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv;
-#define glSecondaryColor3fv glad_glSecondaryColor3fv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i;
-#define glSecondaryColor3i glad_glSecondaryColor3i
-GLAD_API_CALL PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv;
-#define glSecondaryColor3iv glad_glSecondaryColor3iv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s;
-#define glSecondaryColor3s glad_glSecondaryColor3s
-GLAD_API_CALL PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv;
-#define glSecondaryColor3sv glad_glSecondaryColor3sv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub;
-#define glSecondaryColor3ub glad_glSecondaryColor3ub
-GLAD_API_CALL PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv;
-#define glSecondaryColor3ubv glad_glSecondaryColor3ubv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui;
-#define glSecondaryColor3ui glad_glSecondaryColor3ui
-GLAD_API_CALL PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv;
-#define glSecondaryColor3uiv glad_glSecondaryColor3uiv
-GLAD_API_CALL PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us;
-#define glSecondaryColor3us glad_glSecondaryColor3us
-GLAD_API_CALL PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv;
-#define glSecondaryColor3usv glad_glSecondaryColor3usv
-GLAD_API_CALL PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
-#define glSecondaryColorP3ui glad_glSecondaryColorP3ui
-GLAD_API_CALL PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
-#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
-GLAD_API_CALL PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer;
-#define glSecondaryColorPointer glad_glSecondaryColorPointer
-GLAD_API_CALL PFNGLSELECTBUFFERPROC glad_glSelectBuffer;
-#define glSelectBuffer glad_glSelectBuffer
-GLAD_API_CALL PFNGLSHADEMODELPROC glad_glShadeModel;
-#define glShadeModel glad_glShadeModel
-GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource;
-#define glShaderSource glad_glShaderSource
-GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc;
-#define glStencilFunc glad_glStencilFunc
-GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
-#define glStencilFuncSeparate glad_glStencilFuncSeparate
-GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask;
-#define glStencilMask glad_glStencilMask
-GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
-#define glStencilMaskSeparate glad_glStencilMaskSeparate
-GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp;
-#define glStencilOp glad_glStencilOp
-GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
-#define glStencilOpSeparate glad_glStencilOpSeparate
-GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer;
-#define glTexBuffer glad_glTexBuffer
-GLAD_API_CALL PFNGLTEXCOORD1DPROC glad_glTexCoord1d;
-#define glTexCoord1d glad_glTexCoord1d
-GLAD_API_CALL PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv;
-#define glTexCoord1dv glad_glTexCoord1dv
-GLAD_API_CALL PFNGLTEXCOORD1FPROC glad_glTexCoord1f;
-#define glTexCoord1f glad_glTexCoord1f
-GLAD_API_CALL PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv;
-#define glTexCoord1fv glad_glTexCoord1fv
-GLAD_API_CALL PFNGLTEXCOORD1IPROC glad_glTexCoord1i;
-#define glTexCoord1i glad_glTexCoord1i
-GLAD_API_CALL PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv;
-#define glTexCoord1iv glad_glTexCoord1iv
-GLAD_API_CALL PFNGLTEXCOORD1SPROC glad_glTexCoord1s;
-#define glTexCoord1s glad_glTexCoord1s
-GLAD_API_CALL PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv;
-#define glTexCoord1sv glad_glTexCoord1sv
-GLAD_API_CALL PFNGLTEXCOORD2DPROC glad_glTexCoord2d;
-#define glTexCoord2d glad_glTexCoord2d
-GLAD_API_CALL PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv;
-#define glTexCoord2dv glad_glTexCoord2dv
-GLAD_API_CALL PFNGLTEXCOORD2FPROC glad_glTexCoord2f;
-#define glTexCoord2f glad_glTexCoord2f
-GLAD_API_CALL PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv;
-#define glTexCoord2fv glad_glTexCoord2fv
-GLAD_API_CALL PFNGLTEXCOORD2IPROC glad_glTexCoord2i;
-#define glTexCoord2i glad_glTexCoord2i
-GLAD_API_CALL PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv;
-#define glTexCoord2iv glad_glTexCoord2iv
-GLAD_API_CALL PFNGLTEXCOORD2SPROC glad_glTexCoord2s;
-#define glTexCoord2s glad_glTexCoord2s
-GLAD_API_CALL PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv;
-#define glTexCoord2sv glad_glTexCoord2sv
-GLAD_API_CALL PFNGLTEXCOORD3DPROC glad_glTexCoord3d;
-#define glTexCoord3d glad_glTexCoord3d
-GLAD_API_CALL PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv;
-#define glTexCoord3dv glad_glTexCoord3dv
-GLAD_API_CALL PFNGLTEXCOORD3FPROC glad_glTexCoord3f;
-#define glTexCoord3f glad_glTexCoord3f
-GLAD_API_CALL PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv;
-#define glTexCoord3fv glad_glTexCoord3fv
-GLAD_API_CALL PFNGLTEXCOORD3IPROC glad_glTexCoord3i;
-#define glTexCoord3i glad_glTexCoord3i
-GLAD_API_CALL PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv;
-#define glTexCoord3iv glad_glTexCoord3iv
-GLAD_API_CALL PFNGLTEXCOORD3SPROC glad_glTexCoord3s;
-#define glTexCoord3s glad_glTexCoord3s
-GLAD_API_CALL PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv;
-#define glTexCoord3sv glad_glTexCoord3sv
-GLAD_API_CALL PFNGLTEXCOORD4DPROC glad_glTexCoord4d;
-#define glTexCoord4d glad_glTexCoord4d
-GLAD_API_CALL PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv;
-#define glTexCoord4dv glad_glTexCoord4dv
-GLAD_API_CALL PFNGLTEXCOORD4FPROC glad_glTexCoord4f;
-#define glTexCoord4f glad_glTexCoord4f
-GLAD_API_CALL PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv;
-#define glTexCoord4fv glad_glTexCoord4fv
-GLAD_API_CALL PFNGLTEXCOORD4IPROC glad_glTexCoord4i;
-#define glTexCoord4i glad_glTexCoord4i
-GLAD_API_CALL PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv;
-#define glTexCoord4iv glad_glTexCoord4iv
-GLAD_API_CALL PFNGLTEXCOORD4SPROC glad_glTexCoord4s;
-#define glTexCoord4s glad_glTexCoord4s
-GLAD_API_CALL PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv;
-#define glTexCoord4sv glad_glTexCoord4sv
-GLAD_API_CALL PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
-#define glTexCoordP1ui glad_glTexCoordP1ui
-GLAD_API_CALL PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
-#define glTexCoordP1uiv glad_glTexCoordP1uiv
-GLAD_API_CALL PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
-#define glTexCoordP2ui glad_glTexCoordP2ui
-GLAD_API_CALL PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
-#define glTexCoordP2uiv glad_glTexCoordP2uiv
-GLAD_API_CALL PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
-#define glTexCoordP3ui glad_glTexCoordP3ui
-GLAD_API_CALL PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
-#define glTexCoordP3uiv glad_glTexCoordP3uiv
-GLAD_API_CALL PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
-#define glTexCoordP4ui glad_glTexCoordP4ui
-GLAD_API_CALL PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
-#define glTexCoordP4uiv glad_glTexCoordP4uiv
-GLAD_API_CALL PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer;
-#define glTexCoordPointer glad_glTexCoordPointer
-GLAD_API_CALL PFNGLTEXENVFPROC glad_glTexEnvf;
-#define glTexEnvf glad_glTexEnvf
-GLAD_API_CALL PFNGLTEXENVFVPROC glad_glTexEnvfv;
-#define glTexEnvfv glad_glTexEnvfv
-GLAD_API_CALL PFNGLTEXENVIPROC glad_glTexEnvi;
-#define glTexEnvi glad_glTexEnvi
-GLAD_API_CALL PFNGLTEXENVIVPROC glad_glTexEnviv;
-#define glTexEnviv glad_glTexEnviv
-GLAD_API_CALL PFNGLTEXGENDPROC glad_glTexGend;
-#define glTexGend glad_glTexGend
-GLAD_API_CALL PFNGLTEXGENDVPROC glad_glTexGendv;
-#define glTexGendv glad_glTexGendv
-GLAD_API_CALL PFNGLTEXGENFPROC glad_glTexGenf;
-#define glTexGenf glad_glTexGenf
-GLAD_API_CALL PFNGLTEXGENFVPROC glad_glTexGenfv;
-#define glTexGenfv glad_glTexGenfv
-GLAD_API_CALL PFNGLTEXGENIPROC glad_glTexGeni;
-#define glTexGeni glad_glTexGeni
-GLAD_API_CALL PFNGLTEXGENIVPROC glad_glTexGeniv;
-#define glTexGeniv glad_glTexGeniv
-GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
-#define glTexImage1D glad_glTexImage1D
-GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
-#define glTexImage2D glad_glTexImage2D
-GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
-#define glTexImage2DMultisample glad_glTexImage2DMultisample
-GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
-#define glTexImage3D glad_glTexImage3D
-GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
-#define glTexImage3DMultisample glad_glTexImage3DMultisample
-GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
-#define glTexParameterIiv glad_glTexParameterIiv
-GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
-#define glTexParameterIuiv glad_glTexParameterIuiv
-GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
-#define glTexParameterf glad_glTexParameterf
-GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
-#define glTexParameterfv glad_glTexParameterfv
-GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
-#define glTexParameteri glad_glTexParameteri
-GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
-#define glTexParameteriv glad_glTexParameteriv
-GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
-#define glTexSubImage1D glad_glTexSubImage1D
-GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
-#define glTexSubImage2D glad_glTexSubImage2D
-GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
-#define glTexSubImage3D glad_glTexSubImage3D
-GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
-#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
-GLAD_API_CALL PFNGLTRANSLATEDPROC glad_glTranslated;
-#define glTranslated glad_glTranslated
-GLAD_API_CALL PFNGLTRANSLATEFPROC glad_glTranslatef;
-#define glTranslatef glad_glTranslatef
-GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f;
-#define glUniform1f glad_glUniform1f
-GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv;
-#define glUniform1fv glad_glUniform1fv
-GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i;
-#define glUniform1i glad_glUniform1i
-GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv;
-#define glUniform1iv glad_glUniform1iv
-GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui;
-#define glUniform1ui glad_glUniform1ui
-GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
-#define glUniform1uiv glad_glUniform1uiv
-GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f;
-#define glUniform2f glad_glUniform2f
-GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv;
-#define glUniform2fv glad_glUniform2fv
-GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i;
-#define glUniform2i glad_glUniform2i
-GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv;
-#define glUniform2iv glad_glUniform2iv
-GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui;
-#define glUniform2ui glad_glUniform2ui
-GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
-#define glUniform2uiv glad_glUniform2uiv
-GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f;
-#define glUniform3f glad_glUniform3f
-GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv;
-#define glUniform3fv glad_glUniform3fv
-GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i;
-#define glUniform3i glad_glUniform3i
-GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv;
-#define glUniform3iv glad_glUniform3iv
-GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui;
-#define glUniform3ui glad_glUniform3ui
-GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
-#define glUniform3uiv glad_glUniform3uiv
-GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f;
-#define glUniform4f glad_glUniform4f
-GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv;
-#define glUniform4fv glad_glUniform4fv
-GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i;
-#define glUniform4i glad_glUniform4i
-GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv;
-#define glUniform4iv glad_glUniform4iv
-GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui;
-#define glUniform4ui glad_glUniform4ui
-GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
-#define glUniform4uiv glad_glUniform4uiv
-GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
-#define glUniformBlockBinding glad_glUniformBlockBinding
-GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
-#define glUniformMatrix2fv glad_glUniformMatrix2fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
-#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
-#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
-#define glUniformMatrix3fv glad_glUniformMatrix3fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
-#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
-#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
-#define glUniformMatrix4fv glad_glUniformMatrix4fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
-#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
-#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
-GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
-#define glUnmapBuffer glad_glUnmapBuffer
-GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram;
-#define glUseProgram glad_glUseProgram
-GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
-#define glValidateProgram glad_glValidateProgram
-GLAD_API_CALL PFNGLVERTEX2DPROC glad_glVertex2d;
-#define glVertex2d glad_glVertex2d
-GLAD_API_CALL PFNGLVERTEX2DVPROC glad_glVertex2dv;
-#define glVertex2dv glad_glVertex2dv
-GLAD_API_CALL PFNGLVERTEX2FPROC glad_glVertex2f;
-#define glVertex2f glad_glVertex2f
-GLAD_API_CALL PFNGLVERTEX2FVPROC glad_glVertex2fv;
-#define glVertex2fv glad_glVertex2fv
-GLAD_API_CALL PFNGLVERTEX2IPROC glad_glVertex2i;
-#define glVertex2i glad_glVertex2i
-GLAD_API_CALL PFNGLVERTEX2IVPROC glad_glVertex2iv;
-#define glVertex2iv glad_glVertex2iv
-GLAD_API_CALL PFNGLVERTEX2SPROC glad_glVertex2s;
-#define glVertex2s glad_glVertex2s
-GLAD_API_CALL PFNGLVERTEX2SVPROC glad_glVertex2sv;
-#define glVertex2sv glad_glVertex2sv
-GLAD_API_CALL PFNGLVERTEX3DPROC glad_glVertex3d;
-#define glVertex3d glad_glVertex3d
-GLAD_API_CALL PFNGLVERTEX3DVPROC glad_glVertex3dv;
-#define glVertex3dv glad_glVertex3dv
-GLAD_API_CALL PFNGLVERTEX3FPROC glad_glVertex3f;
-#define glVertex3f glad_glVertex3f
-GLAD_API_CALL PFNGLVERTEX3FVPROC glad_glVertex3fv;
-#define glVertex3fv glad_glVertex3fv
-GLAD_API_CALL PFNGLVERTEX3IPROC glad_glVertex3i;
-#define glVertex3i glad_glVertex3i
-GLAD_API_CALL PFNGLVERTEX3IVPROC glad_glVertex3iv;
-#define glVertex3iv glad_glVertex3iv
-GLAD_API_CALL PFNGLVERTEX3SPROC glad_glVertex3s;
-#define glVertex3s glad_glVertex3s
-GLAD_API_CALL PFNGLVERTEX3SVPROC glad_glVertex3sv;
-#define glVertex3sv glad_glVertex3sv
-GLAD_API_CALL PFNGLVERTEX4DPROC glad_glVertex4d;
-#define glVertex4d glad_glVertex4d
-GLAD_API_CALL PFNGLVERTEX4DVPROC glad_glVertex4dv;
-#define glVertex4dv glad_glVertex4dv
-GLAD_API_CALL PFNGLVERTEX4FPROC glad_glVertex4f;
-#define glVertex4f glad_glVertex4f
-GLAD_API_CALL PFNGLVERTEX4FVPROC glad_glVertex4fv;
-#define glVertex4fv glad_glVertex4fv
-GLAD_API_CALL PFNGLVERTEX4IPROC glad_glVertex4i;
-#define glVertex4i glad_glVertex4i
-GLAD_API_CALL PFNGLVERTEX4IVPROC glad_glVertex4iv;
-#define glVertex4iv glad_glVertex4iv
-GLAD_API_CALL PFNGLVERTEX4SPROC glad_glVertex4s;
-#define glVertex4s glad_glVertex4s
-GLAD_API_CALL PFNGLVERTEX4SVPROC glad_glVertex4sv;
-#define glVertex4sv glad_glVertex4sv
-GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
-#define glVertexAttrib1d glad_glVertexAttrib1d
-GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
-#define glVertexAttrib1dv glad_glVertexAttrib1dv
-GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
-#define glVertexAttrib1f glad_glVertexAttrib1f
-GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
-#define glVertexAttrib1fv glad_glVertexAttrib1fv
-GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
-#define glVertexAttrib1s glad_glVertexAttrib1s
-GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
-#define glVertexAttrib1sv glad_glVertexAttrib1sv
-GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
-#define glVertexAttrib2d glad_glVertexAttrib2d
-GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
-#define glVertexAttrib2dv glad_glVertexAttrib2dv
-GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
-#define glVertexAttrib2f glad_glVertexAttrib2f
-GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
-#define glVertexAttrib2fv glad_glVertexAttrib2fv
-GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
-#define glVertexAttrib2s glad_glVertexAttrib2s
-GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
-#define glVertexAttrib2sv glad_glVertexAttrib2sv
-GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
-#define glVertexAttrib3d glad_glVertexAttrib3d
-GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
-#define glVertexAttrib3dv glad_glVertexAttrib3dv
-GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
-#define glVertexAttrib3f glad_glVertexAttrib3f
-GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
-#define glVertexAttrib3fv glad_glVertexAttrib3fv
-GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
-#define glVertexAttrib3s glad_glVertexAttrib3s
-GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
-#define glVertexAttrib3sv glad_glVertexAttrib3sv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
-#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
-#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
-#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
-#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
-GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
-#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
-#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
-GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
-#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
-GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
-#define glVertexAttrib4bv glad_glVertexAttrib4bv
-GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
-#define glVertexAttrib4d glad_glVertexAttrib4d
-GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
-#define glVertexAttrib4dv glad_glVertexAttrib4dv
-GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
-#define glVertexAttrib4f glad_glVertexAttrib4f
-GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
-#define glVertexAttrib4fv glad_glVertexAttrib4fv
-GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
-#define glVertexAttrib4iv glad_glVertexAttrib4iv
-GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
-#define glVertexAttrib4s glad_glVertexAttrib4s
-GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
-#define glVertexAttrib4sv glad_glVertexAttrib4sv
-GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
-#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
-GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
-#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
-GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
-#define glVertexAttrib4usv glad_glVertexAttrib4usv
-GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
-#define glVertexAttribDivisor glad_glVertexAttribDivisor
-GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
-#define glVertexAttribI1i glad_glVertexAttribI1i
-GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
-#define glVertexAttribI1iv glad_glVertexAttribI1iv
-GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
-#define glVertexAttribI1ui glad_glVertexAttribI1ui
-GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
-#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
-#define glVertexAttribI2i glad_glVertexAttribI2i
-GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
-#define glVertexAttribI2iv glad_glVertexAttribI2iv
-GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
-#define glVertexAttribI2ui glad_glVertexAttribI2ui
-GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
-#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
-#define glVertexAttribI3i glad_glVertexAttribI3i
-GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
-#define glVertexAttribI3iv glad_glVertexAttribI3iv
-GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
-#define glVertexAttribI3ui glad_glVertexAttribI3ui
-GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
-#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
-#define glVertexAttribI4bv glad_glVertexAttribI4bv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
-#define glVertexAttribI4i glad_glVertexAttribI4i
-GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
-#define glVertexAttribI4iv glad_glVertexAttribI4iv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
-#define glVertexAttribI4sv glad_glVertexAttribI4sv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
-#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
-#define glVertexAttribI4ui glad_glVertexAttribI4ui
-GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
-#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
-#define glVertexAttribI4usv glad_glVertexAttribI4usv
-GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
-#define glVertexAttribIPointer glad_glVertexAttribIPointer
-GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
-#define glVertexAttribP1ui glad_glVertexAttribP1ui
-GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
-#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
-#define glVertexAttribP2ui glad_glVertexAttribP2ui
-GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
-#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
-#define glVertexAttribP3ui glad_glVertexAttribP3ui
-GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
-#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
-#define glVertexAttribP4ui glad_glVertexAttribP4ui
-GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
-#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
-GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
-#define glVertexAttribPointer glad_glVertexAttribPointer
-GLAD_API_CALL PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
-#define glVertexP2ui glad_glVertexP2ui
-GLAD_API_CALL PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
-#define glVertexP2uiv glad_glVertexP2uiv
-GLAD_API_CALL PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
-#define glVertexP3ui glad_glVertexP3ui
-GLAD_API_CALL PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
-#define glVertexP3uiv glad_glVertexP3uiv
-GLAD_API_CALL PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
-#define glVertexP4ui glad_glVertexP4ui
-GLAD_API_CALL PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
-#define glVertexP4uiv glad_glVertexP4uiv
-GLAD_API_CALL PFNGLVERTEXPOINTERPROC glad_glVertexPointer;
-#define glVertexPointer glad_glVertexPointer
-GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport;
-#define glViewport glad_glViewport
-GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync;
-#define glWaitSync glad_glWaitSync
-GLAD_API_CALL PFNGLWINDOWPOS2DPROC glad_glWindowPos2d;
-#define glWindowPos2d glad_glWindowPos2d
-GLAD_API_CALL PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv;
-#define glWindowPos2dv glad_glWindowPos2dv
-GLAD_API_CALL PFNGLWINDOWPOS2FPROC glad_glWindowPos2f;
-#define glWindowPos2f glad_glWindowPos2f
-GLAD_API_CALL PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv;
-#define glWindowPos2fv glad_glWindowPos2fv
-GLAD_API_CALL PFNGLWINDOWPOS2IPROC glad_glWindowPos2i;
-#define glWindowPos2i glad_glWindowPos2i
-GLAD_API_CALL PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv;
-#define glWindowPos2iv glad_glWindowPos2iv
-GLAD_API_CALL PFNGLWINDOWPOS2SPROC glad_glWindowPos2s;
-#define glWindowPos2s glad_glWindowPos2s
-GLAD_API_CALL PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv;
-#define glWindowPos2sv glad_glWindowPos2sv
-GLAD_API_CALL PFNGLWINDOWPOS3DPROC glad_glWindowPos3d;
-#define glWindowPos3d glad_glWindowPos3d
-GLAD_API_CALL PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv;
-#define glWindowPos3dv glad_glWindowPos3dv
-GLAD_API_CALL PFNGLWINDOWPOS3FPROC glad_glWindowPos3f;
-#define glWindowPos3f glad_glWindowPos3f
-GLAD_API_CALL PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv;
-#define glWindowPos3fv glad_glWindowPos3fv
-GLAD_API_CALL PFNGLWINDOWPOS3IPROC glad_glWindowPos3i;
-#define glWindowPos3i glad_glWindowPos3i
-GLAD_API_CALL PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv;
-#define glWindowPos3iv glad_glWindowPos3iv
-GLAD_API_CALL PFNGLWINDOWPOS3SPROC glad_glWindowPos3s;
-#define glWindowPos3s glad_glWindowPos3s
-GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv;
-#define glWindowPos3sv glad_glWindowPos3sv
-
-
-
-
-
-GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr);
-GLAD_API_CALL int gladLoadGL( GLADloadfunc load);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-/* Source */
-#ifdef GLAD_GL_IMPLEMENTATION
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef GLAD_IMPL_UTIL_C_
-#define GLAD_IMPL_UTIL_C_
-
-#ifdef _MSC_VER
-#define GLAD_IMPL_UTIL_SSCANF sscanf_s
-#else
-#define GLAD_IMPL_UTIL_SSCANF sscanf
-#endif
-
-#endif /* GLAD_IMPL_UTIL_C_ */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-
-int GLAD_GL_VERSION_1_0 = 0;
-int GLAD_GL_VERSION_1_1 = 0;
-int GLAD_GL_VERSION_1_2 = 0;
-int GLAD_GL_VERSION_1_3 = 0;
-int GLAD_GL_VERSION_1_4 = 0;
-int GLAD_GL_VERSION_1_5 = 0;
-int GLAD_GL_VERSION_2_0 = 0;
-int GLAD_GL_VERSION_2_1 = 0;
-int GLAD_GL_VERSION_3_0 = 0;
-int GLAD_GL_VERSION_3_1 = 0;
-int GLAD_GL_VERSION_3_2 = 0;
-int GLAD_GL_VERSION_3_3 = 0;
-int GLAD_GL_ARB_multisample = 0;
-int GLAD_GL_ARB_robustness = 0;
-int GLAD_GL_KHR_debug = 0;
-
-
-
-PFNGLACCUMPROC glad_glAccum = NULL;
-PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
-PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL;
-PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL;
-PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL;
-PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
-PFNGLBEGINPROC glad_glBegin = NULL;
-PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
-PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
-PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
-PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
-PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
-PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
-PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
-PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
-PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
-PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
-PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
-PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
-PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
-PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
-PFNGLBITMAPPROC glad_glBitmap = NULL;
-PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
-PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
-PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
-PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
-PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
-PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
-PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
-PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
-PFNGLCALLLISTPROC glad_glCallList = NULL;
-PFNGLCALLLISTSPROC glad_glCallLists = NULL;
-PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
-PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
-PFNGLCLEARPROC glad_glClear = NULL;
-PFNGLCLEARACCUMPROC glad_glClearAccum = NULL;
-PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
-PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
-PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
-PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
-PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
-PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
-PFNGLCLEARINDEXPROC glad_glClearIndex = NULL;
-PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
-PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL;
-PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
-PFNGLCLIPPLANEPROC glad_glClipPlane = NULL;
-PFNGLCOLOR3BPROC glad_glColor3b = NULL;
-PFNGLCOLOR3BVPROC glad_glColor3bv = NULL;
-PFNGLCOLOR3DPROC glad_glColor3d = NULL;
-PFNGLCOLOR3DVPROC glad_glColor3dv = NULL;
-PFNGLCOLOR3FPROC glad_glColor3f = NULL;
-PFNGLCOLOR3FVPROC glad_glColor3fv = NULL;
-PFNGLCOLOR3IPROC glad_glColor3i = NULL;
-PFNGLCOLOR3IVPROC glad_glColor3iv = NULL;
-PFNGLCOLOR3SPROC glad_glColor3s = NULL;
-PFNGLCOLOR3SVPROC glad_glColor3sv = NULL;
-PFNGLCOLOR3UBPROC glad_glColor3ub = NULL;
-PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL;
-PFNGLCOLOR3UIPROC glad_glColor3ui = NULL;
-PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL;
-PFNGLCOLOR3USPROC glad_glColor3us = NULL;
-PFNGLCOLOR3USVPROC glad_glColor3usv = NULL;
-PFNGLCOLOR4BPROC glad_glColor4b = NULL;
-PFNGLCOLOR4BVPROC glad_glColor4bv = NULL;
-PFNGLCOLOR4DPROC glad_glColor4d = NULL;
-PFNGLCOLOR4DVPROC glad_glColor4dv = NULL;
-PFNGLCOLOR4FPROC glad_glColor4f = NULL;
-PFNGLCOLOR4FVPROC glad_glColor4fv = NULL;
-PFNGLCOLOR4IPROC glad_glColor4i = NULL;
-PFNGLCOLOR4IVPROC glad_glColor4iv = NULL;
-PFNGLCOLOR4SPROC glad_glColor4s = NULL;
-PFNGLCOLOR4SVPROC glad_glColor4sv = NULL;
-PFNGLCOLOR4UBPROC glad_glColor4ub = NULL;
-PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL;
-PFNGLCOLOR4UIPROC glad_glColor4ui = NULL;
-PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL;
-PFNGLCOLOR4USPROC glad_glColor4us = NULL;
-PFNGLCOLOR4USVPROC glad_glColor4usv = NULL;
-PFNGLCOLORMASKPROC glad_glColorMask = NULL;
-PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
-PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL;
-PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
-PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
-PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
-PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
-PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL;
-PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
-PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
-PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
-PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
-PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
-PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
-PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
-PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
-PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL;
-PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
-PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
-PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
-PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
-PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
-PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
-PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
-PFNGLCULLFACEPROC glad_glCullFace = NULL;
-PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
-PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
-PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
-PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
-PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
-PFNGLDELETELISTSPROC glad_glDeleteLists = NULL;
-PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
-PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
-PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
-PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
-PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
-PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
-PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
-PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
-PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
-PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
-PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
-PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
-PFNGLDISABLEPROC glad_glDisable = NULL;
-PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL;
-PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
-PFNGLDISABLEIPROC glad_glDisablei = NULL;
-PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
-PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
-PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
-PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
-PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
-PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
-PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
-PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
-PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL;
-PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
-PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
-PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL;
-PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL;
-PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL;
-PFNGLENABLEPROC glad_glEnable = NULL;
-PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL;
-PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
-PFNGLENABLEIPROC glad_glEnablei = NULL;
-PFNGLENDPROC glad_glEnd = NULL;
-PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
-PFNGLENDLISTPROC glad_glEndList = NULL;
-PFNGLENDQUERYPROC glad_glEndQuery = NULL;
-PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
-PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL;
-PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL;
-PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL;
-PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL;
-PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL;
-PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL;
-PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL;
-PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL;
-PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL;
-PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL;
-PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL;
-PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL;
-PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL;
-PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
-PFNGLFINISHPROC glad_glFinish = NULL;
-PFNGLFLUSHPROC glad_glFlush = NULL;
-PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
-PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL;
-PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL;
-PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL;
-PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL;
-PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL;
-PFNGLFOGFPROC glad_glFogf = NULL;
-PFNGLFOGFVPROC glad_glFogfv = NULL;
-PFNGLFOGIPROC glad_glFogi = NULL;
-PFNGLFOGIVPROC glad_glFogiv = NULL;
-PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
-PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
-PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
-PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
-PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
-PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
-PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
-PFNGLFRUSTUMPROC glad_glFrustum = NULL;
-PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
-PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
-PFNGLGENLISTSPROC glad_glGenLists = NULL;
-PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
-PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
-PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
-PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
-PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
-PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
-PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
-PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
-PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
-PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
-PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
-PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
-PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
-PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
-PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
-PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
-PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
-PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
-PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
-PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
-PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL;
-PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
-PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
-PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
-PFNGLGETERRORPROC glad_glGetError = NULL;
-PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
-PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
-PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
-PFNGLGETGRAPHICSRESETSTATUSARBPROC glad_glGetGraphicsResetStatusARB = NULL;
-PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
-PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
-PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
-PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
-PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL;
-PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL;
-PFNGLGETMAPDVPROC glad_glGetMapdv = NULL;
-PFNGLGETMAPFVPROC glad_glGetMapfv = NULL;
-PFNGLGETMAPIVPROC glad_glGetMapiv = NULL;
-PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL;
-PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL;
-PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
-PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
-PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
-PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL;
-PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL;
-PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL;
-PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
-PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL;
-PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
-PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
-PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
-PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
-PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
-PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
-PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
-PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
-PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
-PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
-PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
-PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
-PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
-PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
-PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
-PFNGLGETSTRINGPROC glad_glGetString = NULL;
-PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
-PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
-PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL;
-PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL;
-PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL;
-PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL;
-PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL;
-PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
-PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
-PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
-PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
-PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
-PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
-PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
-PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
-PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
-PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
-PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
-PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
-PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
-PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
-PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
-PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
-PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
-PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
-PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
-PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
-PFNGLGETNCOLORTABLEARBPROC glad_glGetnColorTableARB = NULL;
-PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC glad_glGetnCompressedTexImageARB = NULL;
-PFNGLGETNCONVOLUTIONFILTERARBPROC glad_glGetnConvolutionFilterARB = NULL;
-PFNGLGETNHISTOGRAMARBPROC glad_glGetnHistogramARB = NULL;
-PFNGLGETNMAPDVARBPROC glad_glGetnMapdvARB = NULL;
-PFNGLGETNMAPFVARBPROC glad_glGetnMapfvARB = NULL;
-PFNGLGETNMAPIVARBPROC glad_glGetnMapivARB = NULL;
-PFNGLGETNMINMAXARBPROC glad_glGetnMinmaxARB = NULL;
-PFNGLGETNPIXELMAPFVARBPROC glad_glGetnPixelMapfvARB = NULL;
-PFNGLGETNPIXELMAPUIVARBPROC glad_glGetnPixelMapuivARB = NULL;
-PFNGLGETNPIXELMAPUSVARBPROC glad_glGetnPixelMapusvARB = NULL;
-PFNGLGETNPOLYGONSTIPPLEARBPROC glad_glGetnPolygonStippleARB = NULL;
-PFNGLGETNSEPARABLEFILTERARBPROC glad_glGetnSeparableFilterARB = NULL;
-PFNGLGETNTEXIMAGEARBPROC glad_glGetnTexImageARB = NULL;
-PFNGLGETNUNIFORMDVARBPROC glad_glGetnUniformdvARB = NULL;
-PFNGLGETNUNIFORMFVARBPROC glad_glGetnUniformfvARB = NULL;
-PFNGLGETNUNIFORMIVARBPROC glad_glGetnUniformivARB = NULL;
-PFNGLGETNUNIFORMUIVARBPROC glad_glGetnUniformuivARB = NULL;
-PFNGLHINTPROC glad_glHint = NULL;
-PFNGLINDEXMASKPROC glad_glIndexMask = NULL;
-PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL;
-PFNGLINDEXDPROC glad_glIndexd = NULL;
-PFNGLINDEXDVPROC glad_glIndexdv = NULL;
-PFNGLINDEXFPROC glad_glIndexf = NULL;
-PFNGLINDEXFVPROC glad_glIndexfv = NULL;
-PFNGLINDEXIPROC glad_glIndexi = NULL;
-PFNGLINDEXIVPROC glad_glIndexiv = NULL;
-PFNGLINDEXSPROC glad_glIndexs = NULL;
-PFNGLINDEXSVPROC glad_glIndexsv = NULL;
-PFNGLINDEXUBPROC glad_glIndexub = NULL;
-PFNGLINDEXUBVPROC glad_glIndexubv = NULL;
-PFNGLINITNAMESPROC glad_glInitNames = NULL;
-PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL;
-PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
-PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
-PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
-PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
-PFNGLISLISTPROC glad_glIsList = NULL;
-PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
-PFNGLISQUERYPROC glad_glIsQuery = NULL;
-PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
-PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
-PFNGLISSHADERPROC glad_glIsShader = NULL;
-PFNGLISSYNCPROC glad_glIsSync = NULL;
-PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
-PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
-PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL;
-PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL;
-PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL;
-PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL;
-PFNGLLIGHTFPROC glad_glLightf = NULL;
-PFNGLLIGHTFVPROC glad_glLightfv = NULL;
-PFNGLLIGHTIPROC glad_glLighti = NULL;
-PFNGLLIGHTIVPROC glad_glLightiv = NULL;
-PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL;
-PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
-PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
-PFNGLLISTBASEPROC glad_glListBase = NULL;
-PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL;
-PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL;
-PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL;
-PFNGLLOADNAMEPROC glad_glLoadName = NULL;
-PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL;
-PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL;
-PFNGLLOGICOPPROC glad_glLogicOp = NULL;
-PFNGLMAP1DPROC glad_glMap1d = NULL;
-PFNGLMAP1FPROC glad_glMap1f = NULL;
-PFNGLMAP2DPROC glad_glMap2d = NULL;
-PFNGLMAP2FPROC glad_glMap2f = NULL;
-PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
-PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
-PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL;
-PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL;
-PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL;
-PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL;
-PFNGLMATERIALFPROC glad_glMaterialf = NULL;
-PFNGLMATERIALFVPROC glad_glMaterialfv = NULL;
-PFNGLMATERIALIPROC glad_glMateriali = NULL;
-PFNGLMATERIALIVPROC glad_glMaterialiv = NULL;
-PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL;
-PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL;
-PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL;
-PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL;
-PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL;
-PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
-PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
-PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
-PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL;
-PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL;
-PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL;
-PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL;
-PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL;
-PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL;
-PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL;
-PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL;
-PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL;
-PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL;
-PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL;
-PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL;
-PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL;
-PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL;
-PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL;
-PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL;
-PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL;
-PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL;
-PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL;
-PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL;
-PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL;
-PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL;
-PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL;
-PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL;
-PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL;
-PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL;
-PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL;
-PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL;
-PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL;
-PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL;
-PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL;
-PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL;
-PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
-PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
-PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
-PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
-PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
-PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
-PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
-PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
-PFNGLNEWLISTPROC glad_glNewList = NULL;
-PFNGLNORMAL3BPROC glad_glNormal3b = NULL;
-PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL;
-PFNGLNORMAL3DPROC glad_glNormal3d = NULL;
-PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL;
-PFNGLNORMAL3FPROC glad_glNormal3f = NULL;
-PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL;
-PFNGLNORMAL3IPROC glad_glNormal3i = NULL;
-PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL;
-PFNGLNORMAL3SPROC glad_glNormal3s = NULL;
-PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL;
-PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
-PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
-PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL;
-PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
-PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
-PFNGLORTHOPROC glad_glOrtho = NULL;
-PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL;
-PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL;
-PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL;
-PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL;
-PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
-PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
-PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL;
-PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL;
-PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL;
-PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
-PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
-PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
-PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
-PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
-PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
-PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
-PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL;
-PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL;
-PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL;
-PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
-PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL;
-PFNGLPOPNAMEPROC glad_glPopName = NULL;
-PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
-PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL;
-PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
-PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL;
-PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL;
-PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
-PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL;
-PFNGLPUSHNAMEPROC glad_glPushName = NULL;
-PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
-PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL;
-PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL;
-PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL;
-PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL;
-PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL;
-PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL;
-PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL;
-PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL;
-PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL;
-PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL;
-PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL;
-PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL;
-PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL;
-PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL;
-PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL;
-PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL;
-PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL;
-PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL;
-PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL;
-PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL;
-PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL;
-PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL;
-PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL;
-PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL;
-PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
-PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
-PFNGLREADNPIXELSARBPROC glad_glReadnPixelsARB = NULL;
-PFNGLRECTDPROC glad_glRectd = NULL;
-PFNGLRECTDVPROC glad_glRectdv = NULL;
-PFNGLRECTFPROC glad_glRectf = NULL;
-PFNGLRECTFVPROC glad_glRectfv = NULL;
-PFNGLRECTIPROC glad_glRecti = NULL;
-PFNGLRECTIVPROC glad_glRectiv = NULL;
-PFNGLRECTSPROC glad_glRects = NULL;
-PFNGLRECTSVPROC glad_glRectsv = NULL;
-PFNGLRENDERMODEPROC glad_glRenderMode = NULL;
-PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
-PFNGLROTATEDPROC glad_glRotated = NULL;
-PFNGLROTATEFPROC glad_glRotatef = NULL;
-PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
-PFNGLSAMPLECOVERAGEARBPROC glad_glSampleCoverageARB = NULL;
-PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
-PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
-PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
-PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
-PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
-PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
-PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
-PFNGLSCALEDPROC glad_glScaled = NULL;
-PFNGLSCALEFPROC glad_glScalef = NULL;
-PFNGLSCISSORPROC glad_glScissor = NULL;
-PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL;
-PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL;
-PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL;
-PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL;
-PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL;
-PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL;
-PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL;
-PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL;
-PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL;
-PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL;
-PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL;
-PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL;
-PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL;
-PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL;
-PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL;
-PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL;
-PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
-PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
-PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL;
-PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL;
-PFNGLSHADEMODELPROC glad_glShadeModel = NULL;
-PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
-PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
-PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
-PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
-PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
-PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
-PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
-PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
-PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL;
-PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL;
-PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL;
-PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL;
-PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL;
-PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL;
-PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL;
-PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL;
-PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL;
-PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL;
-PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL;
-PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL;
-PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL;
-PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL;
-PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL;
-PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL;
-PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL;
-PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL;
-PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL;
-PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL;
-PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL;
-PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL;
-PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL;
-PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL;
-PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL;
-PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL;
-PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL;
-PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL;
-PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL;
-PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL;
-PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL;
-PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL;
-PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
-PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
-PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
-PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
-PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
-PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
-PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
-PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
-PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL;
-PFNGLTEXENVFPROC glad_glTexEnvf = NULL;
-PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL;
-PFNGLTEXENVIPROC glad_glTexEnvi = NULL;
-PFNGLTEXENVIVPROC glad_glTexEnviv = NULL;
-PFNGLTEXGENDPROC glad_glTexGend = NULL;
-PFNGLTEXGENDVPROC glad_glTexGendv = NULL;
-PFNGLTEXGENFPROC glad_glTexGenf = NULL;
-PFNGLTEXGENFVPROC glad_glTexGenfv = NULL;
-PFNGLTEXGENIPROC glad_glTexGeni = NULL;
-PFNGLTEXGENIVPROC glad_glTexGeniv = NULL;
-PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
-PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
-PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
-PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
-PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
-PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
-PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
-PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
-PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
-PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
-PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
-PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
-PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
-PFNGLTRANSLATEDPROC glad_glTranslated = NULL;
-PFNGLTRANSLATEFPROC glad_glTranslatef = NULL;
-PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
-PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
-PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
-PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
-PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
-PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
-PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
-PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
-PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
-PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
-PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
-PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
-PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
-PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
-PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
-PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
-PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
-PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
-PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
-PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
-PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
-PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
-PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
-PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
-PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
-PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
-PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
-PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
-PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
-PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
-PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
-PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
-PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
-PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
-PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
-PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
-PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
-PFNGLVERTEX2DPROC glad_glVertex2d = NULL;
-PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL;
-PFNGLVERTEX2FPROC glad_glVertex2f = NULL;
-PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL;
-PFNGLVERTEX2IPROC glad_glVertex2i = NULL;
-PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL;
-PFNGLVERTEX2SPROC glad_glVertex2s = NULL;
-PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL;
-PFNGLVERTEX3DPROC glad_glVertex3d = NULL;
-PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL;
-PFNGLVERTEX3FPROC glad_glVertex3f = NULL;
-PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL;
-PFNGLVERTEX3IPROC glad_glVertex3i = NULL;
-PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL;
-PFNGLVERTEX3SPROC glad_glVertex3s = NULL;
-PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL;
-PFNGLVERTEX4DPROC glad_glVertex4d = NULL;
-PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL;
-PFNGLVERTEX4FPROC glad_glVertex4f = NULL;
-PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL;
-PFNGLVERTEX4IPROC glad_glVertex4i = NULL;
-PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL;
-PFNGLVERTEX4SPROC glad_glVertex4s = NULL;
-PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL;
-PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
-PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
-PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
-PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
-PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
-PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
-PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
-PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
-PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
-PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
-PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
-PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
-PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
-PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
-PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
-PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
-PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
-PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
-PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
-PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
-PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
-PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
-PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
-PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
-PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
-PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
-PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
-PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
-PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
-PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
-PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
-PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
-PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
-PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
-PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
-PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
-PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
-PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
-PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
-PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
-PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
-PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
-PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
-PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
-PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
-PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
-PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
-PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
-PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
-PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
-PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
-PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
-PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
-PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
-PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
-PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
-PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
-PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
-PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
-PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
-PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
-PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
-PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
-PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
-PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
-PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
-PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
-PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
-PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
-PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
-PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
-PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
-PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
-PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL;
-PFNGLVIEWPORTPROC glad_glViewport = NULL;
-PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
-PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL;
-PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL;
-PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL;
-PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL;
-PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL;
-PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL;
-PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL;
-PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL;
-PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL;
-PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL;
-PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL;
-PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL;
-PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL;
-PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL;
-PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;
-PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;
-
-
-static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_0) return;
-    glad_glAccum = (PFNGLACCUMPROC) load(userptr, "glAccum");
-    glad_glAlphaFunc = (PFNGLALPHAFUNCPROC) load(userptr, "glAlphaFunc");
-    glad_glBegin = (PFNGLBEGINPROC) load(userptr, "glBegin");
-    glad_glBitmap = (PFNGLBITMAPPROC) load(userptr, "glBitmap");
-    glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc");
-    glad_glCallList = (PFNGLCALLLISTPROC) load(userptr, "glCallList");
-    glad_glCallLists = (PFNGLCALLLISTSPROC) load(userptr, "glCallLists");
-    glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear");
-    glad_glClearAccum = (PFNGLCLEARACCUMPROC) load(userptr, "glClearAccum");
-    glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor");
-    glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth");
-    glad_glClearIndex = (PFNGLCLEARINDEXPROC) load(userptr, "glClearIndex");
-    glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil");
-    glad_glClipPlane = (PFNGLCLIPPLANEPROC) load(userptr, "glClipPlane");
-    glad_glColor3b = (PFNGLCOLOR3BPROC) load(userptr, "glColor3b");
-    glad_glColor3bv = (PFNGLCOLOR3BVPROC) load(userptr, "glColor3bv");
-    glad_glColor3d = (PFNGLCOLOR3DPROC) load(userptr, "glColor3d");
-    glad_glColor3dv = (PFNGLCOLOR3DVPROC) load(userptr, "glColor3dv");
-    glad_glColor3f = (PFNGLCOLOR3FPROC) load(userptr, "glColor3f");
-    glad_glColor3fv = (PFNGLCOLOR3FVPROC) load(userptr, "glColor3fv");
-    glad_glColor3i = (PFNGLCOLOR3IPROC) load(userptr, "glColor3i");
-    glad_glColor3iv = (PFNGLCOLOR3IVPROC) load(userptr, "glColor3iv");
-    glad_glColor3s = (PFNGLCOLOR3SPROC) load(userptr, "glColor3s");
-    glad_glColor3sv = (PFNGLCOLOR3SVPROC) load(userptr, "glColor3sv");
-    glad_glColor3ub = (PFNGLCOLOR3UBPROC) load(userptr, "glColor3ub");
-    glad_glColor3ubv = (PFNGLCOLOR3UBVPROC) load(userptr, "glColor3ubv");
-    glad_glColor3ui = (PFNGLCOLOR3UIPROC) load(userptr, "glColor3ui");
-    glad_glColor3uiv = (PFNGLCOLOR3UIVPROC) load(userptr, "glColor3uiv");
-    glad_glColor3us = (PFNGLCOLOR3USPROC) load(userptr, "glColor3us");
-    glad_glColor3usv = (PFNGLCOLOR3USVPROC) load(userptr, "glColor3usv");
-    glad_glColor4b = (PFNGLCOLOR4BPROC) load(userptr, "glColor4b");
-    glad_glColor4bv = (PFNGLCOLOR4BVPROC) load(userptr, "glColor4bv");
-    glad_glColor4d = (PFNGLCOLOR4DPROC) load(userptr, "glColor4d");
-    glad_glColor4dv = (PFNGLCOLOR4DVPROC) load(userptr, "glColor4dv");
-    glad_glColor4f = (PFNGLCOLOR4FPROC) load(userptr, "glColor4f");
-    glad_glColor4fv = (PFNGLCOLOR4FVPROC) load(userptr, "glColor4fv");
-    glad_glColor4i = (PFNGLCOLOR4IPROC) load(userptr, "glColor4i");
-    glad_glColor4iv = (PFNGLCOLOR4IVPROC) load(userptr, "glColor4iv");
-    glad_glColor4s = (PFNGLCOLOR4SPROC) load(userptr, "glColor4s");
-    glad_glColor4sv = (PFNGLCOLOR4SVPROC) load(userptr, "glColor4sv");
-    glad_glColor4ub = (PFNGLCOLOR4UBPROC) load(userptr, "glColor4ub");
-    glad_glColor4ubv = (PFNGLCOLOR4UBVPROC) load(userptr, "glColor4ubv");
-    glad_glColor4ui = (PFNGLCOLOR4UIPROC) load(userptr, "glColor4ui");
-    glad_glColor4uiv = (PFNGLCOLOR4UIVPROC) load(userptr, "glColor4uiv");
-    glad_glColor4us = (PFNGLCOLOR4USPROC) load(userptr, "glColor4us");
-    glad_glColor4usv = (PFNGLCOLOR4USVPROC) load(userptr, "glColor4usv");
-    glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask");
-    glad_glColorMaterial = (PFNGLCOLORMATERIALPROC) load(userptr, "glColorMaterial");
-    glad_glCopyPixels = (PFNGLCOPYPIXELSPROC) load(userptr, "glCopyPixels");
-    glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace");
-    glad_glDeleteLists = (PFNGLDELETELISTSPROC) load(userptr, "glDeleteLists");
-    glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc");
-    glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask");
-    glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange");
-    glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable");
-    glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer");
-    glad_glDrawPixels = (PFNGLDRAWPIXELSPROC) load(userptr, "glDrawPixels");
-    glad_glEdgeFlag = (PFNGLEDGEFLAGPROC) load(userptr, "glEdgeFlag");
-    glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC) load(userptr, "glEdgeFlagv");
-    glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable");
-    glad_glEnd = (PFNGLENDPROC) load(userptr, "glEnd");
-    glad_glEndList = (PFNGLENDLISTPROC) load(userptr, "glEndList");
-    glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC) load(userptr, "glEvalCoord1d");
-    glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC) load(userptr, "glEvalCoord1dv");
-    glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC) load(userptr, "glEvalCoord1f");
-    glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC) load(userptr, "glEvalCoord1fv");
-    glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC) load(userptr, "glEvalCoord2d");
-    glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC) load(userptr, "glEvalCoord2dv");
-    glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC) load(userptr, "glEvalCoord2f");
-    glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC) load(userptr, "glEvalCoord2fv");
-    glad_glEvalMesh1 = (PFNGLEVALMESH1PROC) load(userptr, "glEvalMesh1");
-    glad_glEvalMesh2 = (PFNGLEVALMESH2PROC) load(userptr, "glEvalMesh2");
-    glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC) load(userptr, "glEvalPoint1");
-    glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC) load(userptr, "glEvalPoint2");
-    glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC) load(userptr, "glFeedbackBuffer");
-    glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish");
-    glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush");
-    glad_glFogf = (PFNGLFOGFPROC) load(userptr, "glFogf");
-    glad_glFogfv = (PFNGLFOGFVPROC) load(userptr, "glFogfv");
-    glad_glFogi = (PFNGLFOGIPROC) load(userptr, "glFogi");
-    glad_glFogiv = (PFNGLFOGIVPROC) load(userptr, "glFogiv");
-    glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace");
-    glad_glFrustum = (PFNGLFRUSTUMPROC) load(userptr, "glFrustum");
-    glad_glGenLists = (PFNGLGENLISTSPROC) load(userptr, "glGenLists");
-    glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv");
-    glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC) load(userptr, "glGetClipPlane");
-    glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev");
-    glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError");
-    glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv");
-    glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv");
-    glad_glGetLightfv = (PFNGLGETLIGHTFVPROC) load(userptr, "glGetLightfv");
-    glad_glGetLightiv = (PFNGLGETLIGHTIVPROC) load(userptr, "glGetLightiv");
-    glad_glGetMapdv = (PFNGLGETMAPDVPROC) load(userptr, "glGetMapdv");
-    glad_glGetMapfv = (PFNGLGETMAPFVPROC) load(userptr, "glGetMapfv");
-    glad_glGetMapiv = (PFNGLGETMAPIVPROC) load(userptr, "glGetMapiv");
-    glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC) load(userptr, "glGetMaterialfv");
-    glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC) load(userptr, "glGetMaterialiv");
-    glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC) load(userptr, "glGetPixelMapfv");
-    glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC) load(userptr, "glGetPixelMapuiv");
-    glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC) load(userptr, "glGetPixelMapusv");
-    glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC) load(userptr, "glGetPolygonStipple");
-    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
-    glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC) load(userptr, "glGetTexEnvfv");
-    glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC) load(userptr, "glGetTexEnviv");
-    glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC) load(userptr, "glGetTexGendv");
-    glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC) load(userptr, "glGetTexGenfv");
-    glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC) load(userptr, "glGetTexGeniv");
-    glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage");
-    glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv");
-    glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv");
-    glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv");
-    glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv");
-    glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint");
-    glad_glIndexMask = (PFNGLINDEXMASKPROC) load(userptr, "glIndexMask");
-    glad_glIndexd = (PFNGLINDEXDPROC) load(userptr, "glIndexd");
-    glad_glIndexdv = (PFNGLINDEXDVPROC) load(userptr, "glIndexdv");
-    glad_glIndexf = (PFNGLINDEXFPROC) load(userptr, "glIndexf");
-    glad_glIndexfv = (PFNGLINDEXFVPROC) load(userptr, "glIndexfv");
-    glad_glIndexi = (PFNGLINDEXIPROC) load(userptr, "glIndexi");
-    glad_glIndexiv = (PFNGLINDEXIVPROC) load(userptr, "glIndexiv");
-    glad_glIndexs = (PFNGLINDEXSPROC) load(userptr, "glIndexs");
-    glad_glIndexsv = (PFNGLINDEXSVPROC) load(userptr, "glIndexsv");
-    glad_glInitNames = (PFNGLINITNAMESPROC) load(userptr, "glInitNames");
-    glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled");
-    glad_glIsList = (PFNGLISLISTPROC) load(userptr, "glIsList");
-    glad_glLightModelf = (PFNGLLIGHTMODELFPROC) load(userptr, "glLightModelf");
-    glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC) load(userptr, "glLightModelfv");
-    glad_glLightModeli = (PFNGLLIGHTMODELIPROC) load(userptr, "glLightModeli");
-    glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC) load(userptr, "glLightModeliv");
-    glad_glLightf = (PFNGLLIGHTFPROC) load(userptr, "glLightf");
-    glad_glLightfv = (PFNGLLIGHTFVPROC) load(userptr, "glLightfv");
-    glad_glLighti = (PFNGLLIGHTIPROC) load(userptr, "glLighti");
-    glad_glLightiv = (PFNGLLIGHTIVPROC) load(userptr, "glLightiv");
-    glad_glLineStipple = (PFNGLLINESTIPPLEPROC) load(userptr, "glLineStipple");
-    glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth");
-    glad_glListBase = (PFNGLLISTBASEPROC) load(userptr, "glListBase");
-    glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC) load(userptr, "glLoadIdentity");
-    glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC) load(userptr, "glLoadMatrixd");
-    glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC) load(userptr, "glLoadMatrixf");
-    glad_glLoadName = (PFNGLLOADNAMEPROC) load(userptr, "glLoadName");
-    glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp");
-    glad_glMap1d = (PFNGLMAP1DPROC) load(userptr, "glMap1d");
-    glad_glMap1f = (PFNGLMAP1FPROC) load(userptr, "glMap1f");
-    glad_glMap2d = (PFNGLMAP2DPROC) load(userptr, "glMap2d");
-    glad_glMap2f = (PFNGLMAP2FPROC) load(userptr, "glMap2f");
-    glad_glMapGrid1d = (PFNGLMAPGRID1DPROC) load(userptr, "glMapGrid1d");
-    glad_glMapGrid1f = (PFNGLMAPGRID1FPROC) load(userptr, "glMapGrid1f");
-    glad_glMapGrid2d = (PFNGLMAPGRID2DPROC) load(userptr, "glMapGrid2d");
-    glad_glMapGrid2f = (PFNGLMAPGRID2FPROC) load(userptr, "glMapGrid2f");
-    glad_glMaterialf = (PFNGLMATERIALFPROC) load(userptr, "glMaterialf");
-    glad_glMaterialfv = (PFNGLMATERIALFVPROC) load(userptr, "glMaterialfv");
-    glad_glMateriali = (PFNGLMATERIALIPROC) load(userptr, "glMateriali");
-    glad_glMaterialiv = (PFNGLMATERIALIVPROC) load(userptr, "glMaterialiv");
-    glad_glMatrixMode = (PFNGLMATRIXMODEPROC) load(userptr, "glMatrixMode");
-    glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC) load(userptr, "glMultMatrixd");
-    glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC) load(userptr, "glMultMatrixf");
-    glad_glNewList = (PFNGLNEWLISTPROC) load(userptr, "glNewList");
-    glad_glNormal3b = (PFNGLNORMAL3BPROC) load(userptr, "glNormal3b");
-    glad_glNormal3bv = (PFNGLNORMAL3BVPROC) load(userptr, "glNormal3bv");
-    glad_glNormal3d = (PFNGLNORMAL3DPROC) load(userptr, "glNormal3d");
-    glad_glNormal3dv = (PFNGLNORMAL3DVPROC) load(userptr, "glNormal3dv");
-    glad_glNormal3f = (PFNGLNORMAL3FPROC) load(userptr, "glNormal3f");
-    glad_glNormal3fv = (PFNGLNORMAL3FVPROC) load(userptr, "glNormal3fv");
-    glad_glNormal3i = (PFNGLNORMAL3IPROC) load(userptr, "glNormal3i");
-    glad_glNormal3iv = (PFNGLNORMAL3IVPROC) load(userptr, "glNormal3iv");
-    glad_glNormal3s = (PFNGLNORMAL3SPROC) load(userptr, "glNormal3s");
-    glad_glNormal3sv = (PFNGLNORMAL3SVPROC) load(userptr, "glNormal3sv");
-    glad_glOrtho = (PFNGLORTHOPROC) load(userptr, "glOrtho");
-    glad_glPassThrough = (PFNGLPASSTHROUGHPROC) load(userptr, "glPassThrough");
-    glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC) load(userptr, "glPixelMapfv");
-    glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC) load(userptr, "glPixelMapuiv");
-    glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC) load(userptr, "glPixelMapusv");
-    glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref");
-    glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei");
-    glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC) load(userptr, "glPixelTransferf");
-    glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC) load(userptr, "glPixelTransferi");
-    glad_glPixelZoom = (PFNGLPIXELZOOMPROC) load(userptr, "glPixelZoom");
-    glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize");
-    glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode");
-    glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC) load(userptr, "glPolygonStipple");
-    glad_glPopAttrib = (PFNGLPOPATTRIBPROC) load(userptr, "glPopAttrib");
-    glad_glPopMatrix = (PFNGLPOPMATRIXPROC) load(userptr, "glPopMatrix");
-    glad_glPopName = (PFNGLPOPNAMEPROC) load(userptr, "glPopName");
-    glad_glPushAttrib = (PFNGLPUSHATTRIBPROC) load(userptr, "glPushAttrib");
-    glad_glPushMatrix = (PFNGLPUSHMATRIXPROC) load(userptr, "glPushMatrix");
-    glad_glPushName = (PFNGLPUSHNAMEPROC) load(userptr, "glPushName");
-    glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC) load(userptr, "glRasterPos2d");
-    glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC) load(userptr, "glRasterPos2dv");
-    glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC) load(userptr, "glRasterPos2f");
-    glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC) load(userptr, "glRasterPos2fv");
-    glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC) load(userptr, "glRasterPos2i");
-    glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC) load(userptr, "glRasterPos2iv");
-    glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC) load(userptr, "glRasterPos2s");
-    glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC) load(userptr, "glRasterPos2sv");
-    glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC) load(userptr, "glRasterPos3d");
-    glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC) load(userptr, "glRasterPos3dv");
-    glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC) load(userptr, "glRasterPos3f");
-    glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC) load(userptr, "glRasterPos3fv");
-    glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC) load(userptr, "glRasterPos3i");
-    glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC) load(userptr, "glRasterPos3iv");
-    glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC) load(userptr, "glRasterPos3s");
-    glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC) load(userptr, "glRasterPos3sv");
-    glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC) load(userptr, "glRasterPos4d");
-    glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC) load(userptr, "glRasterPos4dv");
-    glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC) load(userptr, "glRasterPos4f");
-    glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC) load(userptr, "glRasterPos4fv");
-    glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC) load(userptr, "glRasterPos4i");
-    glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC) load(userptr, "glRasterPos4iv");
-    glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC) load(userptr, "glRasterPos4s");
-    glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC) load(userptr, "glRasterPos4sv");
-    glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer");
-    glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels");
-    glad_glRectd = (PFNGLRECTDPROC) load(userptr, "glRectd");
-    glad_glRectdv = (PFNGLRECTDVPROC) load(userptr, "glRectdv");
-    glad_glRectf = (PFNGLRECTFPROC) load(userptr, "glRectf");
-    glad_glRectfv = (PFNGLRECTFVPROC) load(userptr, "glRectfv");
-    glad_glRecti = (PFNGLRECTIPROC) load(userptr, "glRecti");
-    glad_glRectiv = (PFNGLRECTIVPROC) load(userptr, "glRectiv");
-    glad_glRects = (PFNGLRECTSPROC) load(userptr, "glRects");
-    glad_glRectsv = (PFNGLRECTSVPROC) load(userptr, "glRectsv");
-    glad_glRenderMode = (PFNGLRENDERMODEPROC) load(userptr, "glRenderMode");
-    glad_glRotated = (PFNGLROTATEDPROC) load(userptr, "glRotated");
-    glad_glRotatef = (PFNGLROTATEFPROC) load(userptr, "glRotatef");
-    glad_glScaled = (PFNGLSCALEDPROC) load(userptr, "glScaled");
-    glad_glScalef = (PFNGLSCALEFPROC) load(userptr, "glScalef");
-    glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor");
-    glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC) load(userptr, "glSelectBuffer");
-    glad_glShadeModel = (PFNGLSHADEMODELPROC) load(userptr, "glShadeModel");
-    glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc");
-    glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask");
-    glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp");
-    glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC) load(userptr, "glTexCoord1d");
-    glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC) load(userptr, "glTexCoord1dv");
-    glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC) load(userptr, "glTexCoord1f");
-    glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC) load(userptr, "glTexCoord1fv");
-    glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC) load(userptr, "glTexCoord1i");
-    glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC) load(userptr, "glTexCoord1iv");
-    glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC) load(userptr, "glTexCoord1s");
-    glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC) load(userptr, "glTexCoord1sv");
-    glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC) load(userptr, "glTexCoord2d");
-    glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC) load(userptr, "glTexCoord2dv");
-    glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC) load(userptr, "glTexCoord2f");
-    glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC) load(userptr, "glTexCoord2fv");
-    glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC) load(userptr, "glTexCoord2i");
-    glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC) load(userptr, "glTexCoord2iv");
-    glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC) load(userptr, "glTexCoord2s");
-    glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC) load(userptr, "glTexCoord2sv");
-    glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC) load(userptr, "glTexCoord3d");
-    glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC) load(userptr, "glTexCoord3dv");
-    glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC) load(userptr, "glTexCoord3f");
-    glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC) load(userptr, "glTexCoord3fv");
-    glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC) load(userptr, "glTexCoord3i");
-    glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC) load(userptr, "glTexCoord3iv");
-    glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC) load(userptr, "glTexCoord3s");
-    glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC) load(userptr, "glTexCoord3sv");
-    glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC) load(userptr, "glTexCoord4d");
-    glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC) load(userptr, "glTexCoord4dv");
-    glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC) load(userptr, "glTexCoord4f");
-    glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC) load(userptr, "glTexCoord4fv");
-    glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC) load(userptr, "glTexCoord4i");
-    glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC) load(userptr, "glTexCoord4iv");
-    glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC) load(userptr, "glTexCoord4s");
-    glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC) load(userptr, "glTexCoord4sv");
-    glad_glTexEnvf = (PFNGLTEXENVFPROC) load(userptr, "glTexEnvf");
-    glad_glTexEnvfv = (PFNGLTEXENVFVPROC) load(userptr, "glTexEnvfv");
-    glad_glTexEnvi = (PFNGLTEXENVIPROC) load(userptr, "glTexEnvi");
-    glad_glTexEnviv = (PFNGLTEXENVIVPROC) load(userptr, "glTexEnviv");
-    glad_glTexGend = (PFNGLTEXGENDPROC) load(userptr, "glTexGend");
-    glad_glTexGendv = (PFNGLTEXGENDVPROC) load(userptr, "glTexGendv");
-    glad_glTexGenf = (PFNGLTEXGENFPROC) load(userptr, "glTexGenf");
-    glad_glTexGenfv = (PFNGLTEXGENFVPROC) load(userptr, "glTexGenfv");
-    glad_glTexGeni = (PFNGLTEXGENIPROC) load(userptr, "glTexGeni");
-    glad_glTexGeniv = (PFNGLTEXGENIVPROC) load(userptr, "glTexGeniv");
-    glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D");
-    glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D");
-    glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf");
-    glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv");
-    glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri");
-    glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv");
-    glad_glTranslated = (PFNGLTRANSLATEDPROC) load(userptr, "glTranslated");
-    glad_glTranslatef = (PFNGLTRANSLATEFPROC) load(userptr, "glTranslatef");
-    glad_glVertex2d = (PFNGLVERTEX2DPROC) load(userptr, "glVertex2d");
-    glad_glVertex2dv = (PFNGLVERTEX2DVPROC) load(userptr, "glVertex2dv");
-    glad_glVertex2f = (PFNGLVERTEX2FPROC) load(userptr, "glVertex2f");
-    glad_glVertex2fv = (PFNGLVERTEX2FVPROC) load(userptr, "glVertex2fv");
-    glad_glVertex2i = (PFNGLVERTEX2IPROC) load(userptr, "glVertex2i");
-    glad_glVertex2iv = (PFNGLVERTEX2IVPROC) load(userptr, "glVertex2iv");
-    glad_glVertex2s = (PFNGLVERTEX2SPROC) load(userptr, "glVertex2s");
-    glad_glVertex2sv = (PFNGLVERTEX2SVPROC) load(userptr, "glVertex2sv");
-    glad_glVertex3d = (PFNGLVERTEX3DPROC) load(userptr, "glVertex3d");
-    glad_glVertex3dv = (PFNGLVERTEX3DVPROC) load(userptr, "glVertex3dv");
-    glad_glVertex3f = (PFNGLVERTEX3FPROC) load(userptr, "glVertex3f");
-    glad_glVertex3fv = (PFNGLVERTEX3FVPROC) load(userptr, "glVertex3fv");
-    glad_glVertex3i = (PFNGLVERTEX3IPROC) load(userptr, "glVertex3i");
-    glad_glVertex3iv = (PFNGLVERTEX3IVPROC) load(userptr, "glVertex3iv");
-    glad_glVertex3s = (PFNGLVERTEX3SPROC) load(userptr, "glVertex3s");
-    glad_glVertex3sv = (PFNGLVERTEX3SVPROC) load(userptr, "glVertex3sv");
-    glad_glVertex4d = (PFNGLVERTEX4DPROC) load(userptr, "glVertex4d");
-    glad_glVertex4dv = (PFNGLVERTEX4DVPROC) load(userptr, "glVertex4dv");
-    glad_glVertex4f = (PFNGLVERTEX4FPROC) load(userptr, "glVertex4f");
-    glad_glVertex4fv = (PFNGLVERTEX4FVPROC) load(userptr, "glVertex4fv");
-    glad_glVertex4i = (PFNGLVERTEX4IPROC) load(userptr, "glVertex4i");
-    glad_glVertex4iv = (PFNGLVERTEX4IVPROC) load(userptr, "glVertex4iv");
-    glad_glVertex4s = (PFNGLVERTEX4SPROC) load(userptr, "glVertex4s");
-    glad_glVertex4sv = (PFNGLVERTEX4SVPROC) load(userptr, "glVertex4sv");
-    glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport");
-}
-static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_1) return;
-    glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC) load(userptr, "glAreTexturesResident");
-    glad_glArrayElement = (PFNGLARRAYELEMENTPROC) load(userptr, "glArrayElement");
-    glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture");
-    glad_glColorPointer = (PFNGLCOLORPOINTERPROC) load(userptr, "glColorPointer");
-    glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D");
-    glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D");
-    glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D");
-    glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D");
-    glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures");
-    glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC) load(userptr, "glDisableClientState");
-    glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays");
-    glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements");
-    glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC) load(userptr, "glEdgeFlagPointer");
-    glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC) load(userptr, "glEnableClientState");
-    glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures");
-    glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv");
-    glad_glIndexPointer = (PFNGLINDEXPOINTERPROC) load(userptr, "glIndexPointer");
-    glad_glIndexub = (PFNGLINDEXUBPROC) load(userptr, "glIndexub");
-    glad_glIndexubv = (PFNGLINDEXUBVPROC) load(userptr, "glIndexubv");
-    glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC) load(userptr, "glInterleavedArrays");
-    glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture");
-    glad_glNormalPointer = (PFNGLNORMALPOINTERPROC) load(userptr, "glNormalPointer");
-    glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset");
-    glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC) load(userptr, "glPopClientAttrib");
-    glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC) load(userptr, "glPrioritizeTextures");
-    glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC) load(userptr, "glPushClientAttrib");
-    glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC) load(userptr, "glTexCoordPointer");
-    glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D");
-    glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D");
-    glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC) load(userptr, "glVertexPointer");
-}
-static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_2) return;
-    glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D");
-    glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements");
-    glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D");
-    glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D");
-}
-static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_3) return;
-    glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture");
-    glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) load(userptr, "glClientActiveTexture");
-    glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D");
-    glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D");
-    glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D");
-    glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D");
-    glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D");
-    glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D");
-    glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage");
-    glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC) load(userptr, "glLoadTransposeMatrixd");
-    glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC) load(userptr, "glLoadTransposeMatrixf");
-    glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC) load(userptr, "glMultTransposeMatrixd");
-    glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC) load(userptr, "glMultTransposeMatrixf");
-    glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC) load(userptr, "glMultiTexCoord1d");
-    glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC) load(userptr, "glMultiTexCoord1dv");
-    glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC) load(userptr, "glMultiTexCoord1f");
-    glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC) load(userptr, "glMultiTexCoord1fv");
-    glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC) load(userptr, "glMultiTexCoord1i");
-    glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC) load(userptr, "glMultiTexCoord1iv");
-    glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC) load(userptr, "glMultiTexCoord1s");
-    glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC) load(userptr, "glMultiTexCoord1sv");
-    glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC) load(userptr, "glMultiTexCoord2d");
-    glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC) load(userptr, "glMultiTexCoord2dv");
-    glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) load(userptr, "glMultiTexCoord2f");
-    glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC) load(userptr, "glMultiTexCoord2fv");
-    glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC) load(userptr, "glMultiTexCoord2i");
-    glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC) load(userptr, "glMultiTexCoord2iv");
-    glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC) load(userptr, "glMultiTexCoord2s");
-    glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC) load(userptr, "glMultiTexCoord2sv");
-    glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC) load(userptr, "glMultiTexCoord3d");
-    glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC) load(userptr, "glMultiTexCoord3dv");
-    glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC) load(userptr, "glMultiTexCoord3f");
-    glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC) load(userptr, "glMultiTexCoord3fv");
-    glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC) load(userptr, "glMultiTexCoord3i");
-    glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC) load(userptr, "glMultiTexCoord3iv");
-    glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC) load(userptr, "glMultiTexCoord3s");
-    glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC) load(userptr, "glMultiTexCoord3sv");
-    glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC) load(userptr, "glMultiTexCoord4d");
-    glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC) load(userptr, "glMultiTexCoord4dv");
-    glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC) load(userptr, "glMultiTexCoord4f");
-    glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC) load(userptr, "glMultiTexCoord4fv");
-    glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC) load(userptr, "glMultiTexCoord4i");
-    glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC) load(userptr, "glMultiTexCoord4iv");
-    glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC) load(userptr, "glMultiTexCoord4s");
-    glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC) load(userptr, "glMultiTexCoord4sv");
-    glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage");
-}
-static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_4) return;
-    glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor");
-    glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation");
-    glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate");
-    glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC) load(userptr, "glFogCoordPointer");
-    glad_glFogCoordd = (PFNGLFOGCOORDDPROC) load(userptr, "glFogCoordd");
-    glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC) load(userptr, "glFogCoorddv");
-    glad_glFogCoordf = (PFNGLFOGCOORDFPROC) load(userptr, "glFogCoordf");
-    glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC) load(userptr, "glFogCoordfv");
-    glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays");
-    glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements");
-    glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf");
-    glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv");
-    glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri");
-    glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv");
-    glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC) load(userptr, "glSecondaryColor3b");
-    glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC) load(userptr, "glSecondaryColor3bv");
-    glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC) load(userptr, "glSecondaryColor3d");
-    glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC) load(userptr, "glSecondaryColor3dv");
-    glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC) load(userptr, "glSecondaryColor3f");
-    glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC) load(userptr, "glSecondaryColor3fv");
-    glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC) load(userptr, "glSecondaryColor3i");
-    glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC) load(userptr, "glSecondaryColor3iv");
-    glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC) load(userptr, "glSecondaryColor3s");
-    glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC) load(userptr, "glSecondaryColor3sv");
-    glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC) load(userptr, "glSecondaryColor3ub");
-    glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC) load(userptr, "glSecondaryColor3ubv");
-    glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC) load(userptr, "glSecondaryColor3ui");
-    glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC) load(userptr, "glSecondaryColor3uiv");
-    glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC) load(userptr, "glSecondaryColor3us");
-    glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC) load(userptr, "glSecondaryColor3usv");
-    glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC) load(userptr, "glSecondaryColorPointer");
-    glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC) load(userptr, "glWindowPos2d");
-    glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC) load(userptr, "glWindowPos2dv");
-    glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC) load(userptr, "glWindowPos2f");
-    glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC) load(userptr, "glWindowPos2fv");
-    glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC) load(userptr, "glWindowPos2i");
-    glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC) load(userptr, "glWindowPos2iv");
-    glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC) load(userptr, "glWindowPos2s");
-    glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC) load(userptr, "glWindowPos2sv");
-    glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC) load(userptr, "glWindowPos3d");
-    glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC) load(userptr, "glWindowPos3dv");
-    glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC) load(userptr, "glWindowPos3f");
-    glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC) load(userptr, "glWindowPos3fv");
-    glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC) load(userptr, "glWindowPos3i");
-    glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC) load(userptr, "glWindowPos3iv");
-    glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC) load(userptr, "glWindowPos3s");
-    glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC) load(userptr, "glWindowPos3sv");
-}
-static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_1_5) return;
-    glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery");
-    glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer");
-    glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData");
-    glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData");
-    glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers");
-    glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries");
-    glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery");
-    glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers");
-    glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries");
-    glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv");
-    glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv");
-    glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData");
-    glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv");
-    glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv");
-    glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv");
-    glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer");
-    glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery");
-    glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer");
-    glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer");
-}
-static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_2_0) return;
-    glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader");
-    glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation");
-    glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate");
-    glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader");
-    glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram");
-    glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader");
-    glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram");
-    glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader");
-    glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader");
-    glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray");
-    glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers");
-    glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray");
-    glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib");
-    glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform");
-    glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders");
-    glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation");
-    glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog");
-    glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv");
-    glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog");
-    glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource");
-    glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv");
-    glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation");
-    glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv");
-    glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv");
-    glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv");
-    glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv");
-    glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv");
-    glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv");
-    glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram");
-    glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader");
-    glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram");
-    glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource");
-    glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate");
-    glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate");
-    glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate");
-    glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f");
-    glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv");
-    glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i");
-    glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv");
-    glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f");
-    glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv");
-    glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i");
-    glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv");
-    glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f");
-    glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv");
-    glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i");
-    glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv");
-    glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f");
-    glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv");
-    glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i");
-    glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv");
-    glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv");
-    glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv");
-    glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv");
-    glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram");
-    glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram");
-    glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d");
-    glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv");
-    glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f");
-    glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv");
-    glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s");
-    glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv");
-    glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d");
-    glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv");
-    glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f");
-    glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv");
-    glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s");
-    glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv");
-    glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d");
-    glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv");
-    glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f");
-    glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv");
-    glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s");
-    glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv");
-    glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv");
-    glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv");
-    glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv");
-    glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub");
-    glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv");
-    glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv");
-    glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv");
-    glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv");
-    glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d");
-    glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv");
-    glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f");
-    glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv");
-    glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv");
-    glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s");
-    glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv");
-    glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv");
-    glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv");
-    glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv");
-    glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer");
-}
-static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_2_1) return;
-    glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv");
-    glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv");
-    glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv");
-    glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv");
-    glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv");
-    glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv");
-}
-static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_3_0) return;
-    glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, "glBeginConditionalRender");
-    glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback");
-    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
-    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
-    glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, "glBindFragDataLocation");
-    glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer");
-    glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer");
-    glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray");
-    glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer");
-    glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus");
-    glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, "glClampColor");
-    glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi");
-    glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv");
-    glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv");
-    glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv");
-    glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski");
-    glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers");
-    glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers");
-    glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays");
-    glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei");
-    glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei");
-    glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, "glEndConditionalRender");
-    glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback");
-    glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange");
-    glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer");
-    glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D");
-    glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D");
-    glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D");
-    glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer");
-    glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers");
-    glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers");
-    glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays");
-    glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap");
-    glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v");
-    glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation");
-    glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv");
-    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
-    glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv");
-    glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi");
-    glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv");
-    glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv");
-    glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying");
-    glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv");
-    glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv");
-    glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv");
-    glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi");
-    glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer");
-    glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer");
-    glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray");
-    glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange");
-    glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage");
-    glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample");
-    glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv");
-    glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv");
-    glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings");
-    glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui");
-    glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv");
-    glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui");
-    glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv");
-    glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui");
-    glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv");
-    glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui");
-    glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv");
-    glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, "glVertexAttribI1i");
-    glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, "glVertexAttribI1iv");
-    glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, "glVertexAttribI1ui");
-    glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, "glVertexAttribI1uiv");
-    glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, "glVertexAttribI2i");
-    glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, "glVertexAttribI2iv");
-    glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, "glVertexAttribI2ui");
-    glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, "glVertexAttribI2uiv");
-    glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, "glVertexAttribI3i");
-    glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, "glVertexAttribI3iv");
-    glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, "glVertexAttribI3ui");
-    glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, "glVertexAttribI3uiv");
-    glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, "glVertexAttribI4bv");
-    glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i");
-    glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv");
-    glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, "glVertexAttribI4sv");
-    glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, "glVertexAttribI4ubv");
-    glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui");
-    glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv");
-    glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, "glVertexAttribI4usv");
-    glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer");
-}
-static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_3_1) return;
-    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
-    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
-    glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData");
-    glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced");
-    glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced");
-    glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName");
-    glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv");
-    glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, "glGetActiveUniformName");
-    glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv");
-    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
-    glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex");
-    glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices");
-    glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load(userptr, "glPrimitiveRestartIndex");
-    glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, "glTexBuffer");
-    glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding");
-}
-static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_3_2) return;
-    glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync");
-    glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync");
-    glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex");
-    glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex");
-    glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex");
-    glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync");
-    glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, "glFramebufferTexture");
-    glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v");
-    glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v");
-    glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v");
-    glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv");
-    glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv");
-    glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync");
-    glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glMultiDrawElementsBaseVertex");
-    glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load(userptr, "glProvokingVertex");
-    glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski");
-    glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample");
-    glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample");
-    glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync");
-}
-static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_VERSION_3_3) return;
-    glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, "glBindFragDataLocationIndexed");
-    glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler");
-    glad_glColorP3ui = (PFNGLCOLORP3UIPROC) load(userptr, "glColorP3ui");
-    glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC) load(userptr, "glColorP3uiv");
-    glad_glColorP4ui = (PFNGLCOLORP4UIPROC) load(userptr, "glColorP4ui");
-    glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC) load(userptr, "glColorP4uiv");
-    glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers");
-    glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers");
-    glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, "glGetFragDataIndex");
-    glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v");
-    glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v");
-    glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, "glGetSamplerParameterIiv");
-    glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, "glGetSamplerParameterIuiv");
-    glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv");
-    glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv");
-    glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler");
-    glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC) load(userptr, "glMultiTexCoordP1ui");
-    glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC) load(userptr, "glMultiTexCoordP1uiv");
-    glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC) load(userptr, "glMultiTexCoordP2ui");
-    glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC) load(userptr, "glMultiTexCoordP2uiv");
-    glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC) load(userptr, "glMultiTexCoordP3ui");
-    glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC) load(userptr, "glMultiTexCoordP3uiv");
-    glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC) load(userptr, "glMultiTexCoordP4ui");
-    glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC) load(userptr, "glMultiTexCoordP4uiv");
-    glad_glNormalP3ui = (PFNGLNORMALP3UIPROC) load(userptr, "glNormalP3ui");
-    glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC) load(userptr, "glNormalP3uiv");
-    glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter");
-    glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, "glSamplerParameterIiv");
-    glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, "glSamplerParameterIuiv");
-    glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf");
-    glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv");
-    glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri");
-    glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv");
-    glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC) load(userptr, "glSecondaryColorP3ui");
-    glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC) load(userptr, "glSecondaryColorP3uiv");
-    glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC) load(userptr, "glTexCoordP1ui");
-    glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC) load(userptr, "glTexCoordP1uiv");
-    glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC) load(userptr, "glTexCoordP2ui");
-    glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC) load(userptr, "glTexCoordP2uiv");
-    glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC) load(userptr, "glTexCoordP3ui");
-    glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC) load(userptr, "glTexCoordP3uiv");
-    glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC) load(userptr, "glTexCoordP4ui");
-    glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC) load(userptr, "glTexCoordP4uiv");
-    glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor");
-    glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load(userptr, "glVertexAttribP1ui");
-    glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load(userptr, "glVertexAttribP1uiv");
-    glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load(userptr, "glVertexAttribP2ui");
-    glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load(userptr, "glVertexAttribP2uiv");
-    glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load(userptr, "glVertexAttribP3ui");
-    glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load(userptr, "glVertexAttribP3uiv");
-    glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load(userptr, "glVertexAttribP4ui");
-    glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load(userptr, "glVertexAttribP4uiv");
-    glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC) load(userptr, "glVertexP2ui");
-    glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC) load(userptr, "glVertexP2uiv");
-    glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC) load(userptr, "glVertexP3ui");
-    glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC) load(userptr, "glVertexP3uiv");
-    glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC) load(userptr, "glVertexP4ui");
-    glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC) load(userptr, "glVertexP4uiv");
-}
-static void glad_gl_load_GL_ARB_multisample( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_ARB_multisample) return;
-    glad_glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC) load(userptr, "glSampleCoverageARB");
-}
-static void glad_gl_load_GL_ARB_robustness( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_ARB_robustness) return;
-    glad_glGetGraphicsResetStatusARB = (PFNGLGETGRAPHICSRESETSTATUSARBPROC) load(userptr, "glGetGraphicsResetStatusARB");
-    glad_glGetnColorTableARB = (PFNGLGETNCOLORTABLEARBPROC) load(userptr, "glGetnColorTableARB");
-    glad_glGetnCompressedTexImageARB = (PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) load(userptr, "glGetnCompressedTexImageARB");
-    glad_glGetnConvolutionFilterARB = (PFNGLGETNCONVOLUTIONFILTERARBPROC) load(userptr, "glGetnConvolutionFilterARB");
-    glad_glGetnHistogramARB = (PFNGLGETNHISTOGRAMARBPROC) load(userptr, "glGetnHistogramARB");
-    glad_glGetnMapdvARB = (PFNGLGETNMAPDVARBPROC) load(userptr, "glGetnMapdvARB");
-    glad_glGetnMapfvARB = (PFNGLGETNMAPFVARBPROC) load(userptr, "glGetnMapfvARB");
-    glad_glGetnMapivARB = (PFNGLGETNMAPIVARBPROC) load(userptr, "glGetnMapivARB");
-    glad_glGetnMinmaxARB = (PFNGLGETNMINMAXARBPROC) load(userptr, "glGetnMinmaxARB");
-    glad_glGetnPixelMapfvARB = (PFNGLGETNPIXELMAPFVARBPROC) load(userptr, "glGetnPixelMapfvARB");
-    glad_glGetnPixelMapuivARB = (PFNGLGETNPIXELMAPUIVARBPROC) load(userptr, "glGetnPixelMapuivARB");
-    glad_glGetnPixelMapusvARB = (PFNGLGETNPIXELMAPUSVARBPROC) load(userptr, "glGetnPixelMapusvARB");
-    glad_glGetnPolygonStippleARB = (PFNGLGETNPOLYGONSTIPPLEARBPROC) load(userptr, "glGetnPolygonStippleARB");
-    glad_glGetnSeparableFilterARB = (PFNGLGETNSEPARABLEFILTERARBPROC) load(userptr, "glGetnSeparableFilterARB");
-    glad_glGetnTexImageARB = (PFNGLGETNTEXIMAGEARBPROC) load(userptr, "glGetnTexImageARB");
-    glad_glGetnUniformdvARB = (PFNGLGETNUNIFORMDVARBPROC) load(userptr, "glGetnUniformdvARB");
-    glad_glGetnUniformfvARB = (PFNGLGETNUNIFORMFVARBPROC) load(userptr, "glGetnUniformfvARB");
-    glad_glGetnUniformivARB = (PFNGLGETNUNIFORMIVARBPROC) load(userptr, "glGetnUniformivARB");
-    glad_glGetnUniformuivARB = (PFNGLGETNUNIFORMUIVARBPROC) load(userptr, "glGetnUniformuivARB");
-    glad_glReadnPixelsARB = (PFNGLREADNPIXELSARBPROC) load(userptr, "glReadnPixelsARB");
-}
-static void glad_gl_load_GL_KHR_debug( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_KHR_debug) return;
-    glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load(userptr, "glDebugMessageCallback");
-    glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load(userptr, "glDebugMessageControl");
-    glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load(userptr, "glDebugMessageInsert");
-    glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load(userptr, "glGetDebugMessageLog");
-    glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load(userptr, "glGetObjectLabel");
-    glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load(userptr, "glGetObjectPtrLabel");
-    glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv");
-    glad_glObjectLabel = (PFNGLOBJECTLABELPROC) load(userptr, "glObjectLabel");
-    glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load(userptr, "glObjectPtrLabel");
-    glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load(userptr, "glPopDebugGroup");
-    glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load(userptr, "glPushDebugGroup");
-}
-
-
-
-#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
-#define GLAD_GL_IS_SOME_NEW_VERSION 1
-#else
-#define GLAD_GL_IS_SOME_NEW_VERSION 0
-#endif
-
-static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) {
-#if GLAD_GL_IS_SOME_NEW_VERSION
-    if(GLAD_VERSION_MAJOR(version) < 3) {
-#else
-    (void) version;
-    (void) out_num_exts_i;
-    (void) out_exts_i;
-#endif
-        if (glad_glGetString == NULL) {
-            return 0;
-        }
-        *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS);
-#if GLAD_GL_IS_SOME_NEW_VERSION
-    } else {
-        unsigned int index = 0;
-        unsigned int num_exts_i = 0;
-        char **exts_i = NULL;
-        if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) {
-            return 0;
-        }
-        glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);
-        if (num_exts_i > 0) {
-            exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i));
-        }
-        if (exts_i == NULL) {
-            return 0;
-        }
-        for(index = 0; index < num_exts_i; index++) {
-            const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index);
-            size_t len = strlen(gl_str_tmp) + 1;
-
-            char *local_str = (char*) malloc(len * sizeof(char));
-            if(local_str != NULL) {
-                memcpy(local_str, gl_str_tmp, len * sizeof(char));
-            }
-
-            exts_i[index] = local_str;
-        }
-
-        *out_num_exts_i = num_exts_i;
-        *out_exts_i = exts_i;
-    }
-#endif
-    return 1;
-}
-static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) {
-    if (exts_i != NULL) {
-        unsigned int index;
-        for(index = 0; index < num_exts_i; index++) {
-            free((void *) (exts_i[index]));
-        }
-        free((void *)exts_i);
-        exts_i = NULL;
-    }
-}
-static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) {
-    if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) {
-        const char *extensions;
-        const char *loc;
-        const char *terminator;
-        extensions = exts;
-        if(extensions == NULL || ext == NULL) {
-            return 0;
-        }
-        while(1) {
-            loc = strstr(extensions, ext);
-            if(loc == NULL) {
-                return 0;
-            }
-            terminator = loc + strlen(ext);
-            if((loc == extensions || *(loc - 1) == ' ') &&
-                (*terminator == ' ' || *terminator == '\0')) {
-                return 1;
-            }
-            extensions = terminator;
-        }
-    } else {
-        unsigned int index;
-        for(index = 0; index < num_exts_i; index++) {
-            const char *e = exts_i[index];
-            if(strcmp(e, ext) == 0) {
-                return 1;
-            }
-        }
-    }
-    return 0;
-}
-
-static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) {
-    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
-}
-
-static int glad_gl_find_extensions_gl( int version) {
-    const char *exts = NULL;
-    unsigned int num_exts_i = 0;
-    char **exts_i = NULL;
-    if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;
-
-    GLAD_GL_ARB_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_multisample");
-    GLAD_GL_ARB_robustness = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_robustness");
-    GLAD_GL_KHR_debug = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_KHR_debug");
-
-    glad_gl_free_extensions(exts_i, num_exts_i);
-
-    return 1;
-}
-
-static int glad_gl_find_core_gl(void) {
-    int i;
-    const char* version;
-    const char* prefixes[] = {
-        "OpenGL ES-CM ",
-        "OpenGL ES-CL ",
-        "OpenGL ES ",
-        "OpenGL SC ",
-        NULL
-    };
-    int major = 0;
-    int minor = 0;
-    version = (const char*) glad_glGetString(GL_VERSION);
-    if (!version) return 0;
-    for (i = 0;  prefixes[i];  i++) {
-        const size_t length = strlen(prefixes[i]);
-        if (strncmp(version, prefixes[i], length) == 0) {
-            version += length;
-            break;
-        }
-    }
-
-    GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
-
-    GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
-    GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
-    GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
-    GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
-    GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
-    GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
-    GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
-    GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
-    GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
-    GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
-    GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
-    GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
-
-    return GLAD_MAKE_VERSION(major, minor);
-}
-
-int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {
-    int version;
-
-    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
-    if(glad_glGetString == NULL) return 0;
-    if(glad_glGetString(GL_VERSION) == NULL) return 0;
-    version = glad_gl_find_core_gl();
-
-    glad_gl_load_GL_VERSION_1_0(load, userptr);
-    glad_gl_load_GL_VERSION_1_1(load, userptr);
-    glad_gl_load_GL_VERSION_1_2(load, userptr);
-    glad_gl_load_GL_VERSION_1_3(load, userptr);
-    glad_gl_load_GL_VERSION_1_4(load, userptr);
-    glad_gl_load_GL_VERSION_1_5(load, userptr);
-    glad_gl_load_GL_VERSION_2_0(load, userptr);
-    glad_gl_load_GL_VERSION_2_1(load, userptr);
-    glad_gl_load_GL_VERSION_3_0(load, userptr);
-    glad_gl_load_GL_VERSION_3_1(load, userptr);
-    glad_gl_load_GL_VERSION_3_2(load, userptr);
-    glad_gl_load_GL_VERSION_3_3(load, userptr);
-
-    if (!glad_gl_find_extensions_gl(version)) return 0;
-    glad_gl_load_GL_ARB_multisample(load, userptr);
-    glad_gl_load_GL_ARB_robustness(load, userptr);
-    glad_gl_load_GL_KHR_debug(load, userptr);
-
-
-
-    return version;
-}
-
-
-int gladLoadGL( GLADloadfunc load) {
-    return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
-}
-
-
-
- 
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLAD_GL_IMPLEMENTATION */
-
diff --git a/raylib/src/external/glfw/deps/glad/gles2.h b/raylib/src/external/glfw/deps/glad/gles2.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/glad/gles2.h
+++ /dev/null
@@ -1,1805 +0,0 @@
-/**
- * Loader generated by glad 2.0.0-beta on Tue Aug 24 22:51:42 2021
- *
- * Generator: C/C++
- * Specification: gl
- * Extensions: 0
- *
- * APIs:
- *  - gles2=2.0
- *
- * Options:
- *  - ALIAS = False
- *  - DEBUG = False
- *  - HEADER_ONLY = True
- *  - LOADER = False
- *  - MX = False
- *  - MX_GLOBAL = False
- *  - ON_DEMAND = False
- *
- * Commandline:
- *    --api='gles2=2.0' --extensions='' c --header-only
- *
- * Online:
- *    http://glad.sh/#api=gles2%3D2.0&extensions=&generator=c&options=HEADER_ONLY
- *
- */
-
-#ifndef GLAD_GLES2_H_
-#define GLAD_GLES2_H_
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wreserved-id-macro"
-#endif
-#ifdef __gl2_h_
-  #error OpenGL ES 2 header already included (API: gles2), remove previous include!
-#endif
-#define __gl2_h_ 1
-#ifdef __gl3_h_
-  #error OpenGL ES 3 header already included (API: gles2), remove previous include!
-#endif
-#define __gl3_h_ 1
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#define GLAD_GLES2
-#define GLAD_OPTION_GLES2_HEADER_ONLY
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef GLAD_PLATFORM_H_
-#define GLAD_PLATFORM_H_
-
-#ifndef GLAD_PLATFORM_WIN32
-  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
-    #define GLAD_PLATFORM_WIN32 1
-  #else
-    #define GLAD_PLATFORM_WIN32 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_APPLE
-  #ifdef __APPLE__
-    #define GLAD_PLATFORM_APPLE 1
-  #else
-    #define GLAD_PLATFORM_APPLE 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_EMSCRIPTEN
-  #ifdef __EMSCRIPTEN__
-    #define GLAD_PLATFORM_EMSCRIPTEN 1
-  #else
-    #define GLAD_PLATFORM_EMSCRIPTEN 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_UWP
-  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
-    #ifdef __has_include
-      #if __has_include(<winapifamily.h>)
-        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-      #endif
-    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
-      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-    #endif
-  #endif
-
-  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
-    #include <winapifamily.h>
-    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-      #define GLAD_PLATFORM_UWP 1
-    #endif
-  #endif
-
-  #ifndef GLAD_PLATFORM_UWP
-    #define GLAD_PLATFORM_UWP 0
-  #endif
-#endif
-
-#ifdef __GNUC__
-  #define GLAD_GNUC_EXTENSION __extension__
-#else
-  #define GLAD_GNUC_EXTENSION
-#endif
-
-#ifndef GLAD_API_CALL
-  #if defined(GLAD_API_CALL_EXPORT)
-    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
-      #if defined(GLAD_API_CALL_EXPORT_BUILD)
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllexport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllexport) extern
-        #endif
-      #else
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllimport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllimport) extern
-        #endif
-      #endif
-    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
-      #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
-    #else
-      #define GLAD_API_CALL extern
-    #endif
-  #else
-    #define GLAD_API_CALL extern
-  #endif
-#endif
-
-#ifdef APIENTRY
-  #define GLAD_API_PTR APIENTRY
-#elif GLAD_PLATFORM_WIN32
-  #define GLAD_API_PTR __stdcall
-#else
-  #define GLAD_API_PTR
-#endif
-
-#ifndef GLAPI
-#define GLAPI GLAD_API_CALL
-#endif
-
-#ifndef GLAPIENTRY
-#define GLAPIENTRY GLAD_API_PTR
-#endif
-
-#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
-#define GLAD_VERSION_MAJOR(version) (version / 10000)
-#define GLAD_VERSION_MINOR(version) (version % 10000)
-
-#define GLAD_GENERATOR_VERSION "2.0.0-beta"
-
-typedef void (*GLADapiproc)(void);
-
-typedef GLADapiproc (*GLADloadfunc)(const char *name);
-typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
-
-typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
-typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
-
-#endif /* GLAD_PLATFORM_H_ */
-
-#define GL_ACTIVE_ATTRIBUTES 0x8B89
-#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
-#define GL_ACTIVE_TEXTURE 0x84E0
-#define GL_ACTIVE_UNIFORMS 0x8B86
-#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
-#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
-#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
-#define GL_ALPHA 0x1906
-#define GL_ALPHA_BITS 0x0D55
-#define GL_ALWAYS 0x0207
-#define GL_ARRAY_BUFFER 0x8892
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ATTACHED_SHADERS 0x8B85
-#define GL_BACK 0x0405
-#define GL_BLEND 0x0BE2
-#define GL_BLEND_COLOR 0x8005
-#define GL_BLEND_DST_ALPHA 0x80CA
-#define GL_BLEND_DST_RGB 0x80C8
-#define GL_BLEND_EQUATION 0x8009
-#define GL_BLEND_EQUATION_ALPHA 0x883D
-#define GL_BLEND_EQUATION_RGB 0x8009
-#define GL_BLEND_SRC_ALPHA 0x80CB
-#define GL_BLEND_SRC_RGB 0x80C9
-#define GL_BLUE_BITS 0x0D54
-#define GL_BOOL 0x8B56
-#define GL_BOOL_VEC2 0x8B57
-#define GL_BOOL_VEC3 0x8B58
-#define GL_BOOL_VEC4 0x8B59
-#define GL_BUFFER_SIZE 0x8764
-#define GL_BUFFER_USAGE 0x8765
-#define GL_BYTE 0x1400
-#define GL_CCW 0x0901
-#define GL_CLAMP_TO_EDGE 0x812F
-#define GL_COLOR_ATTACHMENT0 0x8CE0
-#define GL_COLOR_BUFFER_BIT 0x00004000
-#define GL_COLOR_CLEAR_VALUE 0x0C22
-#define GL_COLOR_WRITEMASK 0x0C23
-#define GL_COMPILE_STATUS 0x8B81
-#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-#define GL_CONSTANT_ALPHA 0x8003
-#define GL_CONSTANT_COLOR 0x8001
-#define GL_CULL_FACE 0x0B44
-#define GL_CULL_FACE_MODE 0x0B45
-#define GL_CURRENT_PROGRAM 0x8B8D
-#define GL_CURRENT_VERTEX_ATTRIB 0x8626
-#define GL_CW 0x0900
-#define GL_DECR 0x1E03
-#define GL_DECR_WRAP 0x8508
-#define GL_DELETE_STATUS 0x8B80
-#define GL_DEPTH_ATTACHMENT 0x8D00
-#define GL_DEPTH_BITS 0x0D56
-#define GL_DEPTH_BUFFER_BIT 0x00000100
-#define GL_DEPTH_CLEAR_VALUE 0x0B73
-#define GL_DEPTH_COMPONENT 0x1902
-#define GL_DEPTH_COMPONENT16 0x81A5
-#define GL_DEPTH_FUNC 0x0B74
-#define GL_DEPTH_RANGE 0x0B70
-#define GL_DEPTH_TEST 0x0B71
-#define GL_DEPTH_WRITEMASK 0x0B72
-#define GL_DITHER 0x0BD0
-#define GL_DONT_CARE 0x1100
-#define GL_DST_ALPHA 0x0304
-#define GL_DST_COLOR 0x0306
-#define GL_DYNAMIC_DRAW 0x88E8
-#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-#define GL_EQUAL 0x0202
-#define GL_EXTENSIONS 0x1F03
-#define GL_FALSE 0
-#define GL_FASTEST 0x1101
-#define GL_FIXED 0x140C
-#define GL_FLOAT 0x1406
-#define GL_FLOAT_MAT2 0x8B5A
-#define GL_FLOAT_MAT3 0x8B5B
-#define GL_FLOAT_MAT4 0x8B5C
-#define GL_FLOAT_VEC2 0x8B50
-#define GL_FLOAT_VEC3 0x8B51
-#define GL_FLOAT_VEC4 0x8B52
-#define GL_FRAGMENT_SHADER 0x8B30
-#define GL_FRAMEBUFFER 0x8D40
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
-#define GL_FRAMEBUFFER_BINDING 0x8CA6
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
-#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
-#define GL_FRONT 0x0404
-#define GL_FRONT_AND_BACK 0x0408
-#define GL_FRONT_FACE 0x0B46
-#define GL_FUNC_ADD 0x8006
-#define GL_FUNC_REVERSE_SUBTRACT 0x800B
-#define GL_FUNC_SUBTRACT 0x800A
-#define GL_GENERATE_MIPMAP_HINT 0x8192
-#define GL_GEQUAL 0x0206
-#define GL_GREATER 0x0204
-#define GL_GREEN_BITS 0x0D53
-#define GL_HIGH_FLOAT 0x8DF2
-#define GL_HIGH_INT 0x8DF5
-#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
-#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
-#define GL_INCR 0x1E02
-#define GL_INCR_WRAP 0x8507
-#define GL_INFO_LOG_LENGTH 0x8B84
-#define GL_INT 0x1404
-#define GL_INT_VEC2 0x8B53
-#define GL_INT_VEC3 0x8B54
-#define GL_INT_VEC4 0x8B55
-#define GL_INVALID_ENUM 0x0500
-#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
-#define GL_INVALID_OPERATION 0x0502
-#define GL_INVALID_VALUE 0x0501
-#define GL_INVERT 0x150A
-#define GL_KEEP 0x1E00
-#define GL_LEQUAL 0x0203
-#define GL_LESS 0x0201
-#define GL_LINEAR 0x2601
-#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-#define GL_LINEAR_MIPMAP_NEAREST 0x2701
-#define GL_LINES 0x0001
-#define GL_LINE_LOOP 0x0002
-#define GL_LINE_STRIP 0x0003
-#define GL_LINE_WIDTH 0x0B21
-#define GL_LINK_STATUS 0x8B82
-#define GL_LOW_FLOAT 0x8DF0
-#define GL_LOW_INT 0x8DF3
-#define GL_LUMINANCE 0x1909
-#define GL_LUMINANCE_ALPHA 0x190A
-#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
-#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
-#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
-#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
-#define GL_MAX_TEXTURE_SIZE 0x0D33
-#define GL_MAX_VARYING_VECTORS 0x8DFC
-#define GL_MAX_VERTEX_ATTRIBS 0x8869
-#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
-#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
-#define GL_MAX_VIEWPORT_DIMS 0x0D3A
-#define GL_MEDIUM_FLOAT 0x8DF1
-#define GL_MEDIUM_INT 0x8DF4
-#define GL_MIRRORED_REPEAT 0x8370
-#define GL_NEAREST 0x2600
-#define GL_NEAREST_MIPMAP_LINEAR 0x2702
-#define GL_NEAREST_MIPMAP_NEAREST 0x2700
-#define GL_NEVER 0x0200
-#define GL_NICEST 0x1102
-#define GL_NONE 0
-#define GL_NOTEQUAL 0x0205
-#define GL_NO_ERROR 0
-#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
-#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
-#define GL_ONE 1
-#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
-#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
-#define GL_ONE_MINUS_DST_ALPHA 0x0305
-#define GL_ONE_MINUS_DST_COLOR 0x0307
-#define GL_ONE_MINUS_SRC_ALPHA 0x0303
-#define GL_ONE_MINUS_SRC_COLOR 0x0301
-#define GL_OUT_OF_MEMORY 0x0505
-#define GL_PACK_ALIGNMENT 0x0D05
-#define GL_POINTS 0x0000
-#define GL_POLYGON_OFFSET_FACTOR 0x8038
-#define GL_POLYGON_OFFSET_FILL 0x8037
-#define GL_POLYGON_OFFSET_UNITS 0x2A00
-#define GL_RED_BITS 0x0D52
-#define GL_RENDERBUFFER 0x8D41
-#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
-#define GL_RENDERBUFFER_BINDING 0x8CA7
-#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
-#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
-#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
-#define GL_RENDERBUFFER_HEIGHT 0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
-#define GL_RENDERBUFFER_RED_SIZE 0x8D50
-#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
-#define GL_RENDERBUFFER_WIDTH 0x8D42
-#define GL_RENDERER 0x1F01
-#define GL_REPEAT 0x2901
-#define GL_REPLACE 0x1E01
-#define GL_RGB 0x1907
-#define GL_RGB565 0x8D62
-#define GL_RGB5_A1 0x8057
-#define GL_RGBA 0x1908
-#define GL_RGBA4 0x8056
-#define GL_SAMPLER_2D 0x8B5E
-#define GL_SAMPLER_CUBE 0x8B60
-#define GL_SAMPLES 0x80A9
-#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
-#define GL_SAMPLE_BUFFERS 0x80A8
-#define GL_SAMPLE_COVERAGE 0x80A0
-#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
-#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
-#define GL_SCISSOR_BOX 0x0C10
-#define GL_SCISSOR_TEST 0x0C11
-#define GL_SHADER_BINARY_FORMATS 0x8DF8
-#define GL_SHADER_COMPILER 0x8DFA
-#define GL_SHADER_SOURCE_LENGTH 0x8B88
-#define GL_SHADER_TYPE 0x8B4F
-#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
-#define GL_SHORT 0x1402
-#define GL_SRC_ALPHA 0x0302
-#define GL_SRC_ALPHA_SATURATE 0x0308
-#define GL_SRC_COLOR 0x0300
-#define GL_STATIC_DRAW 0x88E4
-#define GL_STENCIL_ATTACHMENT 0x8D20
-#define GL_STENCIL_BACK_FAIL 0x8801
-#define GL_STENCIL_BACK_FUNC 0x8800
-#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
-#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
-#define GL_STENCIL_BACK_REF 0x8CA3
-#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
-#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
-#define GL_STENCIL_BITS 0x0D57
-#define GL_STENCIL_BUFFER_BIT 0x00000400
-#define GL_STENCIL_CLEAR_VALUE 0x0B91
-#define GL_STENCIL_FAIL 0x0B94
-#define GL_STENCIL_FUNC 0x0B92
-#define GL_STENCIL_INDEX8 0x8D48
-#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
-#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
-#define GL_STENCIL_REF 0x0B97
-#define GL_STENCIL_TEST 0x0B90
-#define GL_STENCIL_VALUE_MASK 0x0B93
-#define GL_STENCIL_WRITEMASK 0x0B98
-#define GL_STREAM_DRAW 0x88E0
-#define GL_SUBPIXEL_BITS 0x0D50
-#define GL_TEXTURE 0x1702
-#define GL_TEXTURE0 0x84C0
-#define GL_TEXTURE1 0x84C1
-#define GL_TEXTURE10 0x84CA
-#define GL_TEXTURE11 0x84CB
-#define GL_TEXTURE12 0x84CC
-#define GL_TEXTURE13 0x84CD
-#define GL_TEXTURE14 0x84CE
-#define GL_TEXTURE15 0x84CF
-#define GL_TEXTURE16 0x84D0
-#define GL_TEXTURE17 0x84D1
-#define GL_TEXTURE18 0x84D2
-#define GL_TEXTURE19 0x84D3
-#define GL_TEXTURE2 0x84C2
-#define GL_TEXTURE20 0x84D4
-#define GL_TEXTURE21 0x84D5
-#define GL_TEXTURE22 0x84D6
-#define GL_TEXTURE23 0x84D7
-#define GL_TEXTURE24 0x84D8
-#define GL_TEXTURE25 0x84D9
-#define GL_TEXTURE26 0x84DA
-#define GL_TEXTURE27 0x84DB
-#define GL_TEXTURE28 0x84DC
-#define GL_TEXTURE29 0x84DD
-#define GL_TEXTURE3 0x84C3
-#define GL_TEXTURE30 0x84DE
-#define GL_TEXTURE31 0x84DF
-#define GL_TEXTURE4 0x84C4
-#define GL_TEXTURE5 0x84C5
-#define GL_TEXTURE6 0x84C6
-#define GL_TEXTURE7 0x84C7
-#define GL_TEXTURE8 0x84C8
-#define GL_TEXTURE9 0x84C9
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_TEXTURE_BINDING_2D 0x8069
-#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
-#define GL_TEXTURE_CUBE_MAP 0x8513
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-#define GL_TRIANGLES 0x0004
-#define GL_TRIANGLE_FAN 0x0006
-#define GL_TRIANGLE_STRIP 0x0005
-#define GL_TRUE 1
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_UNSIGNED_INT 0x1405
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
-#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
-#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-#define GL_VALIDATE_STATUS 0x8B83
-#define GL_VENDOR 0x1F00
-#define GL_VERSION 0x1F02
-#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
-#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
-#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
-#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
-#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
-#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
-#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
-#define GL_VERTEX_SHADER 0x8B31
-#define GL_VIEWPORT 0x0BA2
-#define GL_ZERO 0
-
-
-#ifndef __khrplatform_h_
-#define __khrplatform_h_
-
-/*
-** Copyright (c) 2008-2018 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Khronos platform-specific types and definitions.
- *
- * The master copy of khrplatform.h is maintained in the Khronos EGL
- * Registry repository at https://github.com/KhronosGroup/EGL-Registry
- * The last semantic modification to khrplatform.h was at commit ID:
- *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
- *
- * Adopters may modify this file to suit their platform. Adopters are
- * encouraged to submit platform specific modifications to the Khronos
- * group so that they can be included in future versions of this file.
- * Please submit changes by filing pull requests or issues on
- * the EGL Registry repository linked above.
- *
- *
- * See the Implementer's Guidelines for information about where this file
- * should be located on your system and for more details of its use:
- *    http://www.khronos.org/registry/implementers_guide.pdf
- *
- * This file should be included as
- *        #include <KHR/khrplatform.h>
- * by Khronos client API header files that use its types and defines.
- *
- * The types in khrplatform.h should only be used to define API-specific types.
- *
- * Types defined in khrplatform.h:
- *    khronos_int8_t              signed   8  bit
- *    khronos_uint8_t             unsigned 8  bit
- *    khronos_int16_t             signed   16 bit
- *    khronos_uint16_t            unsigned 16 bit
- *    khronos_int32_t             signed   32 bit
- *    khronos_uint32_t            unsigned 32 bit
- *    khronos_int64_t             signed   64 bit
- *    khronos_uint64_t            unsigned 64 bit
- *    khronos_intptr_t            signed   same number of bits as a pointer
- *    khronos_uintptr_t           unsigned same number of bits as a pointer
- *    khronos_ssize_t             signed   size
- *    khronos_usize_t             unsigned size
- *    khronos_float_t             signed   32 bit floating point
- *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
- *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
- *                                         nanoseconds
- *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
- *    khronos_boolean_enum_t      enumerated boolean type. This should
- *      only be used as a base type when a client API's boolean type is
- *      an enum. Client APIs which use an integer or other type for
- *      booleans cannot use this as the base type for their boolean.
- *
- * Tokens defined in khrplatform.h:
- *
- *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
- *
- *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
- *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
- *
- * Calling convention macros defined in this file:
- *    KHRONOS_APICALL
- *    KHRONOS_GLAD_API_PTR
- *    KHRONOS_APIATTRIBUTES
- *
- * These may be used in function prototypes as:
- *
- *      KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname(
- *                                  int arg1,
- *                                  int arg2) KHRONOS_APIATTRIBUTES;
- */
-
-#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
-#   define KHRONOS_STATIC 1
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APICALL
- *-------------------------------------------------------------------------
- * This precedes the return type of the function in the function prototype.
- */
-#if defined(KHRONOS_STATIC)
-    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
-     * header compatible with static linking. */
-#   define KHRONOS_APICALL
-#elif defined(_WIN32)
-#   define KHRONOS_APICALL __declspec(dllimport)
-#elif defined (__SYMBIAN32__)
-#   define KHRONOS_APICALL IMPORT_C
-#elif defined(__ANDROID__)
-#   define KHRONOS_APICALL __attribute__((visibility("default")))
-#else
-#   define KHRONOS_APICALL
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_GLAD_API_PTR
- *-------------------------------------------------------------------------
- * This follows the return type of the function  and precedes the function
- * name in the function prototype.
- */
-#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
-    /* Win32 but not WinCE */
-#   define KHRONOS_GLAD_API_PTR __stdcall
-#else
-#   define KHRONOS_GLAD_API_PTR
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APIATTRIBUTES
- *-------------------------------------------------------------------------
- * This follows the closing parenthesis of the function prototype arguments.
- */
-#if defined (__ARMCC_2__)
-#define KHRONOS_APIATTRIBUTES __softfp
-#else
-#define KHRONOS_APIATTRIBUTES
-#endif
-
-/*-------------------------------------------------------------------------
- * basic type definitions
- *-----------------------------------------------------------------------*/
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
-
-
-/*
- * Using <stdint.h>
- */
-#include <stdint.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(__VMS ) || defined(__sgi)
-
-/*
- * Using <inttypes.h>
- */
-#include <inttypes.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
-
-/*
- * Win32
- */
-typedef __int32                 khronos_int32_t;
-typedef unsigned __int32        khronos_uint32_t;
-typedef __int64                 khronos_int64_t;
-typedef unsigned __int64        khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif defined(__sun__) || defined(__digital__)
-
-/*
- * Sun or Digital
- */
-typedef int                     khronos_int32_t;
-typedef unsigned int            khronos_uint32_t;
-#if defined(__arch64__) || defined(_LP64)
-typedef long int                khronos_int64_t;
-typedef unsigned long int       khronos_uint64_t;
-#else
-typedef long long int           khronos_int64_t;
-typedef unsigned long long int  khronos_uint64_t;
-#endif /* __arch64__ */
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#elif 0
-
-/*
- * Hypothetical platform with no float or int64 support
- */
-typedef int                     khronos_int32_t;
-typedef unsigned int            khronos_uint32_t;
-#define KHRONOS_SUPPORT_INT64   0
-#define KHRONOS_SUPPORT_FLOAT   0
-
-#else
-
-/*
- * Generic fallback
- */
-#include <stdint.h>
-typedef int32_t                 khronos_int32_t;
-typedef uint32_t                khronos_uint32_t;
-typedef int64_t                 khronos_int64_t;
-typedef uint64_t                khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64   1
-#define KHRONOS_SUPPORT_FLOAT   1
-
-#endif
-
-
-/*
- * Types that are (so far) the same on all platforms
- */
-typedef signed   char          khronos_int8_t;
-typedef unsigned char          khronos_uint8_t;
-typedef signed   short int     khronos_int16_t;
-typedef unsigned short int     khronos_uint16_t;
-
-/*
- * Types that differ between LLP64 and LP64 architectures - in LLP64,
- * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
- * to be the only LLP64 architecture in current use.
- */
-#ifdef _WIN64
-typedef signed   long long int khronos_intptr_t;
-typedef unsigned long long int khronos_uintptr_t;
-typedef signed   long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
-#else
-typedef signed   long  int     khronos_intptr_t;
-typedef unsigned long  int     khronos_uintptr_t;
-typedef signed   long  int     khronos_ssize_t;
-typedef unsigned long  int     khronos_usize_t;
-#endif
-
-#if KHRONOS_SUPPORT_FLOAT
-/*
- * Float type
- */
-typedef          float         khronos_float_t;
-#endif
-
-#if KHRONOS_SUPPORT_INT64
-/* Time types
- *
- * These types can be used to represent a time interval in nanoseconds or
- * an absolute Unadjusted System Time.  Unadjusted System Time is the number
- * of nanoseconds since some arbitrary system event (e.g. since the last
- * time the system booted).  The Unadjusted System Time is an unsigned
- * 64 bit value that wraps back to 0 every 584 years.  Time intervals
- * may be either signed or unsigned.
- */
-typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
-typedef khronos_int64_t        khronos_stime_nanoseconds_t;
-#endif
-
-/*
- * Dummy value used to pad enum types to 32 bits.
- */
-#ifndef KHRONOS_MAX_ENUM
-#define KHRONOS_MAX_ENUM 0x7FFFFFFF
-#endif
-
-/*
- * Enumerated boolean type
- *
- * Values other than zero should be considered to be true.  Therefore
- * comparisons should not be made against KHRONOS_TRUE.
- */
-typedef enum {
-    KHRONOS_FALSE = 0,
-    KHRONOS_TRUE  = 1,
-    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
-} khronos_boolean_enum_t;
-
-#endif /* __khrplatform_h_ */
-
-typedef unsigned int GLenum;
-
-typedef unsigned char GLboolean;
-
-typedef unsigned int GLbitfield;
-
-typedef void GLvoid;
-
-typedef khronos_int8_t GLbyte;
-
-typedef khronos_uint8_t GLubyte;
-
-typedef khronos_int16_t GLshort;
-
-typedef khronos_uint16_t GLushort;
-
-typedef int GLint;
-
-typedef unsigned int GLuint;
-
-typedef khronos_int32_t GLclampx;
-
-typedef int GLsizei;
-
-typedef khronos_float_t GLfloat;
-
-typedef khronos_float_t GLclampf;
-
-typedef double GLdouble;
-
-typedef double GLclampd;
-
-typedef void *GLeglClientBufferEXT;
-
-typedef void *GLeglImageOES;
-
-typedef char GLchar;
-
-typedef char GLcharARB;
-
-#ifdef __APPLE__
-typedef void *GLhandleARB;
-#else
-typedef unsigned int GLhandleARB;
-#endif
-
-typedef khronos_uint16_t GLhalf;
-
-typedef khronos_uint16_t GLhalfARB;
-
-typedef khronos_int32_t GLfixed;
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_intptr_t GLintptr;
-#else
-typedef khronos_intptr_t GLintptr;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_intptr_t GLintptrARB;
-#else
-typedef khronos_intptr_t GLintptrARB;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_ssize_t GLsizeiptr;
-#else
-typedef khronos_ssize_t GLsizeiptr;
-#endif
-
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
-typedef khronos_ssize_t GLsizeiptrARB;
-#else
-typedef khronos_ssize_t GLsizeiptrARB;
-#endif
-
-typedef khronos_int64_t GLint64;
-
-typedef khronos_int64_t GLint64EXT;
-
-typedef khronos_uint64_t GLuint64;
-
-typedef khronos_uint64_t GLuint64EXT;
-
-typedef struct __GLsync *GLsync;
-
-struct _cl_context;
-
-struct _cl_event;
-
-typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
-
-typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
-
-typedef unsigned short GLhalfNV;
-
-typedef GLintptr GLvdpauSurfaceNV;
-
-typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void);
-
-
-
-#define GL_ES_VERSION_2_0 1
-GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0;
-
-
-typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture);
-typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
-typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
-typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
-typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
-typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
-typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
-typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
-typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);
-typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);
-typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask);
-typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d);
-typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s);
-typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void);
-typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type);
-typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers);
-typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers);
-typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers);
-typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures);
-typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func);
-typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag);
-typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
-typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
-typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap);
-typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
-typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
-typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices);
-typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap);
-typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
-typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode);
-typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers);
-typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers);
-typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers);
-typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures);
-typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders);
-typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data);
-typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data);
-typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data);
-typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
-typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source);
-typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params);
-typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
-typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params);
-typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode);
-typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap);
-typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program);
-typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
-typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader);
-typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture);
-typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width);
-typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
-typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);
-typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void);
-typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
-typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length);
-typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
-typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
-typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
-typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
-typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
-typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params);
-typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
-typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
-typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v);
-typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);
-typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
-
-GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
-#define glActiveTexture glad_glActiveTexture
-GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader;
-#define glAttachShader glad_glAttachShader
-GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
-#define glBindAttribLocation glad_glBindAttribLocation
-GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer;
-#define glBindBuffer glad_glBindBuffer
-GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
-#define glBindFramebuffer glad_glBindFramebuffer
-GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
-#define glBindRenderbuffer glad_glBindRenderbuffer
-GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture;
-#define glBindTexture glad_glBindTexture
-GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor;
-#define glBlendColor glad_glBlendColor
-GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
-#define glBlendEquation glad_glBlendEquation
-GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
-#define glBlendEquationSeparate glad_glBlendEquationSeparate
-GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc;
-#define glBlendFunc glad_glBlendFunc
-GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
-#define glBlendFuncSeparate glad_glBlendFuncSeparate
-GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData;
-#define glBufferData glad_glBufferData
-GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
-#define glBufferSubData glad_glBufferSubData
-GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
-#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
-GLAD_API_CALL PFNGLCLEARPROC glad_glClear;
-#define glClear glad_glClear
-GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor;
-#define glClearColor glad_glClearColor
-GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
-#define glClearDepthf glad_glClearDepthf
-GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil;
-#define glClearStencil glad_glClearStencil
-GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask;
-#define glColorMask glad_glColorMask
-GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader;
-#define glCompileShader glad_glCompileShader
-GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
-#define glCompressedTexImage2D glad_glCompressedTexImage2D
-GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
-#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
-GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
-#define glCopyTexImage2D glad_glCopyTexImage2D
-GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
-#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
-GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
-#define glCreateProgram glad_glCreateProgram
-GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader;
-#define glCreateShader glad_glCreateShader
-GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace;
-#define glCullFace glad_glCullFace
-GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
-#define glDeleteBuffers glad_glDeleteBuffers
-GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
-#define glDeleteFramebuffers glad_glDeleteFramebuffers
-GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
-#define glDeleteProgram glad_glDeleteProgram
-GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
-#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
-GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader;
-#define glDeleteShader glad_glDeleteShader
-GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
-#define glDeleteTextures glad_glDeleteTextures
-GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc;
-#define glDepthFunc glad_glDepthFunc
-GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask;
-#define glDepthMask glad_glDepthMask
-GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
-#define glDepthRangef glad_glDepthRangef
-GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader;
-#define glDetachShader glad_glDetachShader
-GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable;
-#define glDisable glad_glDisable
-GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
-#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
-GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays;
-#define glDrawArrays glad_glDrawArrays
-GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements;
-#define glDrawElements glad_glDrawElements
-GLAD_API_CALL PFNGLENABLEPROC glad_glEnable;
-#define glEnable glad_glEnable
-GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
-#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
-GLAD_API_CALL PFNGLFINISHPROC glad_glFinish;
-#define glFinish glad_glFinish
-GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush;
-#define glFlush glad_glFlush
-GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
-#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
-GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
-#define glFramebufferTexture2D glad_glFramebufferTexture2D
-GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace;
-#define glFrontFace glad_glFrontFace
-GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers;
-#define glGenBuffers glad_glGenBuffers
-GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
-#define glGenFramebuffers glad_glGenFramebuffers
-GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
-#define glGenRenderbuffers glad_glGenRenderbuffers
-GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures;
-#define glGenTextures glad_glGenTextures
-GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
-#define glGenerateMipmap glad_glGenerateMipmap
-GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
-#define glGetActiveAttrib glad_glGetActiveAttrib
-GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
-#define glGetActiveUniform glad_glGetActiveUniform
-GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
-#define glGetAttachedShaders glad_glGetAttachedShaders
-GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
-#define glGetAttribLocation glad_glGetAttribLocation
-GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
-#define glGetBooleanv glad_glGetBooleanv
-GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
-#define glGetBufferParameteriv glad_glGetBufferParameteriv
-GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError;
-#define glGetError glad_glGetError
-GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv;
-#define glGetFloatv glad_glGetFloatv
-GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
-#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
-GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv;
-#define glGetIntegerv glad_glGetIntegerv
-GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
-#define glGetProgramInfoLog glad_glGetProgramInfoLog
-GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
-#define glGetProgramiv glad_glGetProgramiv
-GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
-#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
-GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
-#define glGetShaderInfoLog glad_glGetShaderInfoLog
-GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
-#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
-GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
-#define glGetShaderSource glad_glGetShaderSource
-GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv;
-#define glGetShaderiv glad_glGetShaderiv
-GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString;
-#define glGetString glad_glGetString
-GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
-#define glGetTexParameterfv glad_glGetTexParameterfv
-GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
-#define glGetTexParameteriv glad_glGetTexParameteriv
-GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
-#define glGetUniformLocation glad_glGetUniformLocation
-GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
-#define glGetUniformfv glad_glGetUniformfv
-GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
-#define glGetUniformiv glad_glGetUniformiv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
-#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
-#define glGetVertexAttribfv glad_glGetVertexAttribfv
-GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
-#define glGetVertexAttribiv glad_glGetVertexAttribiv
-GLAD_API_CALL PFNGLHINTPROC glad_glHint;
-#define glHint glad_glHint
-GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer;
-#define glIsBuffer glad_glIsBuffer
-GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled;
-#define glIsEnabled glad_glIsEnabled
-GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
-#define glIsFramebuffer glad_glIsFramebuffer
-GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram;
-#define glIsProgram glad_glIsProgram
-GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
-#define glIsRenderbuffer glad_glIsRenderbuffer
-GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader;
-#define glIsShader glad_glIsShader
-GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture;
-#define glIsTexture glad_glIsTexture
-GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth;
-#define glLineWidth glad_glLineWidth
-GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram;
-#define glLinkProgram glad_glLinkProgram
-GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei;
-#define glPixelStorei glad_glPixelStorei
-GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
-#define glPolygonOffset glad_glPolygonOffset
-GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels;
-#define glReadPixels glad_glReadPixels
-GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
-#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
-GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
-#define glRenderbufferStorage glad_glRenderbufferStorage
-GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
-#define glSampleCoverage glad_glSampleCoverage
-GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor;
-#define glScissor glad_glScissor
-GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary;
-#define glShaderBinary glad_glShaderBinary
-GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource;
-#define glShaderSource glad_glShaderSource
-GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc;
-#define glStencilFunc glad_glStencilFunc
-GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
-#define glStencilFuncSeparate glad_glStencilFuncSeparate
-GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask;
-#define glStencilMask glad_glStencilMask
-GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
-#define glStencilMaskSeparate glad_glStencilMaskSeparate
-GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp;
-#define glStencilOp glad_glStencilOp
-GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
-#define glStencilOpSeparate glad_glStencilOpSeparate
-GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
-#define glTexImage2D glad_glTexImage2D
-GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
-#define glTexParameterf glad_glTexParameterf
-GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
-#define glTexParameterfv glad_glTexParameterfv
-GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
-#define glTexParameteri glad_glTexParameteri
-GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
-#define glTexParameteriv glad_glTexParameteriv
-GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
-#define glTexSubImage2D glad_glTexSubImage2D
-GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f;
-#define glUniform1f glad_glUniform1f
-GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv;
-#define glUniform1fv glad_glUniform1fv
-GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i;
-#define glUniform1i glad_glUniform1i
-GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv;
-#define glUniform1iv glad_glUniform1iv
-GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f;
-#define glUniform2f glad_glUniform2f
-GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv;
-#define glUniform2fv glad_glUniform2fv
-GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i;
-#define glUniform2i glad_glUniform2i
-GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv;
-#define glUniform2iv glad_glUniform2iv
-GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f;
-#define glUniform3f glad_glUniform3f
-GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv;
-#define glUniform3fv glad_glUniform3fv
-GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i;
-#define glUniform3i glad_glUniform3i
-GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv;
-#define glUniform3iv glad_glUniform3iv
-GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f;
-#define glUniform4f glad_glUniform4f
-GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv;
-#define glUniform4fv glad_glUniform4fv
-GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i;
-#define glUniform4i glad_glUniform4i
-GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv;
-#define glUniform4iv glad_glUniform4iv
-GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
-#define glUniformMatrix2fv glad_glUniformMatrix2fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
-#define glUniformMatrix3fv glad_glUniformMatrix3fv
-GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
-#define glUniformMatrix4fv glad_glUniformMatrix4fv
-GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram;
-#define glUseProgram glad_glUseProgram
-GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
-#define glValidateProgram glad_glValidateProgram
-GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
-#define glVertexAttrib1f glad_glVertexAttrib1f
-GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
-#define glVertexAttrib1fv glad_glVertexAttrib1fv
-GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
-#define glVertexAttrib2f glad_glVertexAttrib2f
-GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
-#define glVertexAttrib2fv glad_glVertexAttrib2fv
-GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
-#define glVertexAttrib3f glad_glVertexAttrib3f
-GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
-#define glVertexAttrib3fv glad_glVertexAttrib3fv
-GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
-#define glVertexAttrib4f glad_glVertexAttrib4f
-GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
-#define glVertexAttrib4fv glad_glVertexAttrib4fv
-GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
-#define glVertexAttribPointer glad_glVertexAttribPointer
-GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport;
-#define glViewport glad_glViewport
-
-
-
-
-
-GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr);
-GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-/* Source */
-#ifdef GLAD_GLES2_IMPLEMENTATION
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef GLAD_IMPL_UTIL_C_
-#define GLAD_IMPL_UTIL_C_
-
-#ifdef _MSC_VER
-#define GLAD_IMPL_UTIL_SSCANF sscanf_s
-#else
-#define GLAD_IMPL_UTIL_SSCANF sscanf
-#endif
-
-#endif /* GLAD_IMPL_UTIL_C_ */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-
-int GLAD_GL_ES_VERSION_2_0 = 0;
-
-
-
-PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
-PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
-PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
-PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
-PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
-PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
-PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
-PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
-PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
-PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
-PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
-PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
-PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
-PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
-PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
-PFNGLCLEARPROC glad_glClear = NULL;
-PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
-PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
-PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
-PFNGLCOLORMASKPROC glad_glColorMask = NULL;
-PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
-PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
-PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
-PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
-PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
-PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
-PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
-PFNGLCULLFACEPROC glad_glCullFace = NULL;
-PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
-PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
-PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
-PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
-PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
-PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
-PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
-PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
-PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
-PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
-PFNGLDISABLEPROC glad_glDisable = NULL;
-PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
-PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
-PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
-PFNGLENABLEPROC glad_glEnable = NULL;
-PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
-PFNGLFINISHPROC glad_glFinish = NULL;
-PFNGLFLUSHPROC glad_glFlush = NULL;
-PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
-PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
-PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
-PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
-PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
-PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
-PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
-PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
-PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
-PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
-PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
-PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
-PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
-PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
-PFNGLGETERRORPROC glad_glGetError = NULL;
-PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
-PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
-PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
-PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
-PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
-PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
-PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
-PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
-PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
-PFNGLGETSTRINGPROC glad_glGetString = NULL;
-PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
-PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
-PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
-PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
-PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
-PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
-PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
-PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
-PFNGLHINTPROC glad_glHint = NULL;
-PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
-PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
-PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
-PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
-PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
-PFNGLISSHADERPROC glad_glIsShader = NULL;
-PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
-PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
-PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
-PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
-PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
-PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
-PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
-PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
-PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
-PFNGLSCISSORPROC glad_glScissor = NULL;
-PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
-PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
-PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
-PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
-PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
-PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
-PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
-PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
-PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
-PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
-PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
-PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
-PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
-PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
-PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
-PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
-PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
-PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
-PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
-PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
-PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
-PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
-PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
-PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
-PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
-PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
-PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
-PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
-PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
-PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
-PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
-PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
-PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
-PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
-PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
-PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
-PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
-PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
-PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
-PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
-PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
-PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
-PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
-PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
-PFNGLVIEWPORTPROC glad_glViewport = NULL;
-
-
-static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_GL_ES_VERSION_2_0) return;
-    glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture");
-    glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader");
-    glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation");
-    glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer");
-    glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer");
-    glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer");
-    glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture");
-    glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor");
-    glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation");
-    glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate");
-    glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc");
-    glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate");
-    glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData");
-    glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData");
-    glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus");
-    glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear");
-    glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor");
-    glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf");
-    glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil");
-    glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask");
-    glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader");
-    glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D");
-    glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D");
-    glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D");
-    glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D");
-    glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram");
-    glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader");
-    glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace");
-    glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers");
-    glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers");
-    glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram");
-    glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers");
-    glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader");
-    glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures");
-    glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc");
-    glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask");
-    glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef");
-    glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader");
-    glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable");
-    glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray");
-    glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays");
-    glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements");
-    glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable");
-    glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray");
-    glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish");
-    glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush");
-    glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer");
-    glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D");
-    glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace");
-    glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers");
-    glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers");
-    glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers");
-    glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures");
-    glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap");
-    glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib");
-    glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform");
-    glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders");
-    glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation");
-    glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv");
-    glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv");
-    glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError");
-    glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv");
-    glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv");
-    glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv");
-    glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog");
-    glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv");
-    glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv");
-    glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog");
-    glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat");
-    glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource");
-    glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv");
-    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
-    glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv");
-    glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv");
-    glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation");
-    glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv");
-    glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv");
-    glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv");
-    glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv");
-    glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv");
-    glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint");
-    glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer");
-    glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled");
-    glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer");
-    glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram");
-    glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer");
-    glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader");
-    glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture");
-    glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth");
-    glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram");
-    glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei");
-    glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset");
-    glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels");
-    glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler");
-    glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage");
-    glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage");
-    glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor");
-    glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary");
-    glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource");
-    glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc");
-    glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate");
-    glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask");
-    glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate");
-    glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp");
-    glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate");
-    glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D");
-    glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf");
-    glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv");
-    glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri");
-    glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv");
-    glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D");
-    glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f");
-    glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv");
-    glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i");
-    glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv");
-    glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f");
-    glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv");
-    glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i");
-    glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv");
-    glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f");
-    glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv");
-    glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i");
-    glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv");
-    glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f");
-    glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv");
-    glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i");
-    glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv");
-    glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv");
-    glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv");
-    glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv");
-    glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram");
-    glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram");
-    glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f");
-    glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv");
-    glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f");
-    glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv");
-    glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f");
-    glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv");
-    glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f");
-    glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv");
-    glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer");
-    glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport");
-}
-
-
-
-#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
-#define GLAD_GL_IS_SOME_NEW_VERSION 1
-#else
-#define GLAD_GL_IS_SOME_NEW_VERSION 0
-#endif
-
-static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) {
-#if GLAD_GL_IS_SOME_NEW_VERSION
-    if(GLAD_VERSION_MAJOR(version) < 3) {
-#else
-    (void) version;
-    (void) out_num_exts_i;
-    (void) out_exts_i;
-#endif
-        if (glad_glGetString == NULL) {
-            return 0;
-        }
-        *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS);
-#if GLAD_GL_IS_SOME_NEW_VERSION
-    } else {
-        unsigned int index = 0;
-        unsigned int num_exts_i = 0;
-        char **exts_i = NULL;
-        if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) {
-            return 0;
-        }
-        glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);
-        if (num_exts_i > 0) {
-            exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i));
-        }
-        if (exts_i == NULL) {
-            return 0;
-        }
-        for(index = 0; index < num_exts_i; index++) {
-            const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index);
-            size_t len = strlen(gl_str_tmp) + 1;
-
-            char *local_str = (char*) malloc(len * sizeof(char));
-            if(local_str != NULL) {
-                memcpy(local_str, gl_str_tmp, len * sizeof(char));
-            }
-
-            exts_i[index] = local_str;
-        }
-
-        *out_num_exts_i = num_exts_i;
-        *out_exts_i = exts_i;
-    }
-#endif
-    return 1;
-}
-static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) {
-    if (exts_i != NULL) {
-        unsigned int index;
-        for(index = 0; index < num_exts_i; index++) {
-            free((void *) (exts_i[index]));
-        }
-        free((void *)exts_i);
-        exts_i = NULL;
-    }
-}
-static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) {
-    if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) {
-        const char *extensions;
-        const char *loc;
-        const char *terminator;
-        extensions = exts;
-        if(extensions == NULL || ext == NULL) {
-            return 0;
-        }
-        while(1) {
-            loc = strstr(extensions, ext);
-            if(loc == NULL) {
-                return 0;
-            }
-            terminator = loc + strlen(ext);
-            if((loc == extensions || *(loc - 1) == ' ') &&
-                (*terminator == ' ' || *terminator == '\0')) {
-                return 1;
-            }
-            extensions = terminator;
-        }
-    } else {
-        unsigned int index;
-        for(index = 0; index < num_exts_i; index++) {
-            const char *e = exts_i[index];
-            if(strcmp(e, ext) == 0) {
-                return 1;
-            }
-        }
-    }
-    return 0;
-}
-
-static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) {
-    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
-}
-
-static int glad_gl_find_extensions_gles2( int version) {
-    const char *exts = NULL;
-    unsigned int num_exts_i = 0;
-    char **exts_i = NULL;
-    if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;
-
-    (void) glad_gl_has_extension;
-
-    glad_gl_free_extensions(exts_i, num_exts_i);
-
-    return 1;
-}
-
-static int glad_gl_find_core_gles2(void) {
-    int i;
-    const char* version;
-    const char* prefixes[] = {
-        "OpenGL ES-CM ",
-        "OpenGL ES-CL ",
-        "OpenGL ES ",
-        "OpenGL SC ",
-        NULL
-    };
-    int major = 0;
-    int minor = 0;
-    version = (const char*) glad_glGetString(GL_VERSION);
-    if (!version) return 0;
-    for (i = 0;  prefixes[i];  i++) {
-        const size_t length = strlen(prefixes[i]);
-        if (strncmp(version, prefixes[i], length) == 0) {
-            version += length;
-            break;
-        }
-    }
-
-    GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
-
-    GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
-
-    return GLAD_MAKE_VERSION(major, minor);
-}
-
-int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) {
-    int version;
-
-    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
-    if(glad_glGetString == NULL) return 0;
-    if(glad_glGetString(GL_VERSION) == NULL) return 0;
-    version = glad_gl_find_core_gles2();
-
-    glad_gl_load_GL_ES_VERSION_2_0(load, userptr);
-
-    if (!glad_gl_find_extensions_gles2(version)) return 0;
-
-
-
-    return version;
-}
-
-
-int gladLoadGLES2( GLADloadfunc load) {
-    return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
-}
-
-
-
- 
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLAD_GLES2_IMPLEMENTATION */
-
diff --git a/raylib/src/external/glfw/deps/glad/vulkan.h b/raylib/src/external/glfw/deps/glad/vulkan.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/glad/vulkan.h
+++ /dev/null
@@ -1,6330 +0,0 @@
-/**
- * Loader generated by glad 2.0.0-beta on Thu Jul  7 20:52:04 2022
- *
- * Generator: C/C++
- * Specification: vk
- * Extensions: 4
- *
- * APIs:
- *  - vulkan=1.3
- *
- * Options:
- *  - ALIAS = False
- *  - DEBUG = False
- *  - HEADER_ONLY = True
- *  - LOADER = False
- *  - MX = False
- *  - MX_GLOBAL = False
- *  - ON_DEMAND = False
- *
- * Commandline:
- *    --api='vulkan=1.3' --extensions='VK_EXT_debug_report,VK_KHR_portability_enumeration,VK_KHR_surface,VK_KHR_swapchain' c --header-only
- *
- * Online:
- *    http://glad.sh/#api=vulkan%3D1.3&extensions=VK_EXT_debug_report%2CVK_KHR_portability_enumeration%2CVK_KHR_surface%2CVK_KHR_swapchain&generator=c&options=HEADER_ONLY
- *
- */
-
-#ifndef GLAD_VULKAN_H_
-#define GLAD_VULKAN_H_
-
-#ifdef VULKAN_H_
-  #error  header already included (API: vulkan), remove previous include!
-#endif
-#define VULKAN_H_ 1
-
-#ifdef VULKAN_CORE_H_
-  #error  header already included (API: vulkan), remove previous include!
-#endif
-#define VULKAN_CORE_H_ 1
-
-
-#define GLAD_VULKAN
-#define GLAD_OPTION_VULKAN_HEADER_ONLY
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef GLAD_PLATFORM_H_
-#define GLAD_PLATFORM_H_
-
-#ifndef GLAD_PLATFORM_WIN32
-  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
-    #define GLAD_PLATFORM_WIN32 1
-  #else
-    #define GLAD_PLATFORM_WIN32 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_APPLE
-  #ifdef __APPLE__
-    #define GLAD_PLATFORM_APPLE 1
-  #else
-    #define GLAD_PLATFORM_APPLE 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_EMSCRIPTEN
-  #ifdef __EMSCRIPTEN__
-    #define GLAD_PLATFORM_EMSCRIPTEN 1
-  #else
-    #define GLAD_PLATFORM_EMSCRIPTEN 0
-  #endif
-#endif
-
-#ifndef GLAD_PLATFORM_UWP
-  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
-    #ifdef __has_include
-      #if __has_include(<winapifamily.h>)
-        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-      #endif
-    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
-      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
-    #endif
-  #endif
-
-  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
-    #include <winapifamily.h>
-    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-      #define GLAD_PLATFORM_UWP 1
-    #endif
-  #endif
-
-  #ifndef GLAD_PLATFORM_UWP
-    #define GLAD_PLATFORM_UWP 0
-  #endif
-#endif
-
-#ifdef __GNUC__
-  #define GLAD_GNUC_EXTENSION __extension__
-#else
-  #define GLAD_GNUC_EXTENSION
-#endif
-
-#ifndef GLAD_API_CALL
-  #if defined(GLAD_API_CALL_EXPORT)
-    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
-      #if defined(GLAD_API_CALL_EXPORT_BUILD)
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllexport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllexport) extern
-        #endif
-      #else
-        #if defined(__GNUC__)
-          #define GLAD_API_CALL __attribute__ ((dllimport)) extern
-        #else
-          #define GLAD_API_CALL __declspec(dllimport) extern
-        #endif
-      #endif
-    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
-      #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
-    #else
-      #define GLAD_API_CALL extern
-    #endif
-  #else
-    #define GLAD_API_CALL extern
-  #endif
-#endif
-
-#ifdef APIENTRY
-  #define GLAD_API_PTR APIENTRY
-#elif GLAD_PLATFORM_WIN32
-  #define GLAD_API_PTR __stdcall
-#else
-  #define GLAD_API_PTR
-#endif
-
-#ifndef GLAPI
-#define GLAPI GLAD_API_CALL
-#endif
-
-#ifndef GLAPIENTRY
-#define GLAPIENTRY GLAD_API_PTR
-#endif
-
-#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
-#define GLAD_VERSION_MAJOR(version) (version / 10000)
-#define GLAD_VERSION_MINOR(version) (version % 10000)
-
-#define GLAD_GENERATOR_VERSION "2.0.0-beta"
-
-typedef void (*GLADapiproc)(void);
-
-typedef GLADapiproc (*GLADloadfunc)(const char *name);
-typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
-
-typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
-typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
-
-#endif /* GLAD_PLATFORM_H_ */
-
-#define VK_ATTACHMENT_UNUSED (~0U)
-#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10
-#define VK_FALSE 0
-#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration"
-#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1
-#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
-#define VK_KHR_SURFACE_SPEC_VERSION 25
-#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
-#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70
-#define VK_LOD_CLAMP_NONE 1000.0F
-#define VK_LUID_SIZE 8
-#define VK_MAX_DESCRIPTION_SIZE 256
-#define VK_MAX_DEVICE_GROUP_SIZE 32
-#define VK_MAX_DRIVER_INFO_SIZE 256
-#define VK_MAX_DRIVER_NAME_SIZE 256
-#define VK_MAX_EXTENSION_NAME_SIZE 256
-#define VK_MAX_MEMORY_HEAPS 16
-#define VK_MAX_MEMORY_TYPES 32
-#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
-#define VK_QUEUE_FAMILY_EXTERNAL (~1U)
-#define VK_QUEUE_FAMILY_IGNORED (~0U)
-#define VK_REMAINING_ARRAY_LAYERS (~0U)
-#define VK_REMAINING_MIP_LEVELS (~0U)
-#define VK_SUBPASS_EXTERNAL (~0U)
-#define VK_TRUE 1
-#define VK_UUID_SIZE 16
-#define VK_WHOLE_SIZE (~0ULL)
-
-
-/* */
-/* File: vk_platform.h */
-/* */
-/*
-** Copyright 2014-2022 The Khronos Group Inc.
-**
-** SPDX-License-Identifier: Apache-2.0
-*/
-
-
-#ifndef VK_PLATFORM_H_
-#define VK_PLATFORM_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/*
-***************************************************************************************************
-*   Platform-specific directives and type declarations
-***************************************************************************************************
-*/
-
-/* Platform-specific calling convention macros.
- *
- * Platforms should define these so that Vulkan clients call Vulkan commands
- * with the same calling conventions that the Vulkan implementation expects.
- *
- * VKAPI_ATTR - Placed before the return type in function declarations.
- *              Useful for C++11 and GCC/Clang-style function attribute syntax.
- * VKAPI_CALL - Placed after the return type in function declarations.
- *              Useful for MSVC-style calling convention syntax.
- * VKAPI_PTR  - Placed between the '(' and '*' in function pointer types.
- *
- * Function declaration:  VKAPI_ATTR void VKAPI_CALL vkCommand(void);
- * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
- */
-#if defined(_WIN32)
-    /* On Windows, Vulkan commands use the stdcall convention */
-    #define VKAPI_ATTR
-    #define VKAPI_CALL __stdcall
-    #define VKAPI_PTR  VKAPI_CALL
-#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
-    #error "Vulkan is not supported for the 'armeabi' NDK ABI"
-#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
-    /* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */
-    /* calling convention, i.e. float parameters are passed in registers. This */
-    /* is true even if the rest of the application passes floats on the stack, */
-    /* as it does by default when compiling for the armeabi-v7a NDK ABI. */
-    #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
-    #define VKAPI_CALL
-    #define VKAPI_PTR  VKAPI_ATTR
-#else
-    /* On other platforms, use the default calling convention */
-    #define VKAPI_ATTR
-    #define VKAPI_CALL
-    #define VKAPI_PTR
-#endif
-
-#if !defined(VK_NO_STDDEF_H)
-    #include <stddef.h>
-#endif /* !defined(VK_NO_STDDEF_H) */
-
-#if !defined(VK_NO_STDINT_H)
-    #if defined(_MSC_VER) && (_MSC_VER < 1600)
-        typedef signed   __int8  int8_t;
-        typedef unsigned __int8  uint8_t;
-        typedef signed   __int16 int16_t;
-        typedef unsigned __int16 uint16_t;
-        typedef signed   __int32 int32_t;
-        typedef unsigned __int32 uint32_t;
-        typedef signed   __int64 int64_t;
-        typedef unsigned __int64 uint64_t;
-    #else
-        #include <stdint.h>
-    #endif
-#endif /* !defined(VK_NO_STDINT_H) */
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#endif
-/* DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. */
-#define VK_MAKE_VERSION(major, minor, patch) \
-    ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))
-/* DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. */
-#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
-/* DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. */
-#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)
-/* DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. */
-#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)
-#define VK_MAKE_API_VERSION(variant, major, minor, patch) \
-    ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))
-#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29)
-#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU)
-#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)
-#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)
-/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */
-/*#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 */
-/* Vulkan 1.0 version number */
-#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)/* Patch version should always be set to 0 */
-/* Vulkan 1.1 version number */
-#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)/* Patch version should always be set to 0 */
-/* Vulkan 1.2 version number */
-#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)/* Patch version should always be set to 0 */
-/* Vulkan 1.3 version number */
-#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)/* Patch version should always be set to 0 */
-/* Version of this file */
-#define VK_HEADER_VERSION 220
-/* Complete version of this file */
-#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION)
-#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
-#ifndef VK_USE_64_BIT_PTR_DEFINES
-    #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
-        #define VK_USE_64_BIT_PTR_DEFINES 1
-    #else
-        #define VK_USE_64_BIT_PTR_DEFINES 0
-    #endif
-#endif
-#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE
-    #if (VK_USE_64_BIT_PTR_DEFINES==1)
-        #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))
-            #define VK_NULL_HANDLE nullptr
-        #else
-            #define VK_NULL_HANDLE ((void*)0)
-        #endif
-    #else
-        #define VK_NULL_HANDLE 0ULL
-    #endif
-#endif
-#ifndef VK_NULL_HANDLE
-    #define VK_NULL_HANDLE 0
-#endif
-#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE
-    #if (VK_USE_64_BIT_PTR_DEFINES==1)
-        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
-    #else
-        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
-    #endif
-#endif
-
-
-
-
-
-
-
-
-VK_DEFINE_HANDLE(VkInstance)
-VK_DEFINE_HANDLE(VkPhysicalDevice)
-VK_DEFINE_HANDLE(VkDevice)
-VK_DEFINE_HANDLE(VkQueue)
-VK_DEFINE_HANDLE(VkCommandBuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-typedef enum VkAttachmentLoadOp {
-    VK_ATTACHMENT_LOAD_OP_LOAD = 0,
-    VK_ATTACHMENT_LOAD_OP_CLEAR = 1,
-    VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2,
-    VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentLoadOp;
-typedef enum VkAttachmentStoreOp {
-    VK_ATTACHMENT_STORE_OP_STORE = 0,
-    VK_ATTACHMENT_STORE_OP_DONT_CARE = 1,
-    VK_ATTACHMENT_STORE_OP_NONE = 1000301000,
-    VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentStoreOp;
-typedef enum VkBlendFactor {
-    VK_BLEND_FACTOR_ZERO = 0,
-    VK_BLEND_FACTOR_ONE = 1,
-    VK_BLEND_FACTOR_SRC_COLOR = 2,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
-    VK_BLEND_FACTOR_DST_COLOR = 4,
-    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
-    VK_BLEND_FACTOR_SRC_ALPHA = 6,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
-    VK_BLEND_FACTOR_DST_ALPHA = 8,
-    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
-    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
-    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
-    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
-    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
-    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
-    VK_BLEND_FACTOR_SRC1_COLOR = 15,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
-    VK_BLEND_FACTOR_SRC1_ALPHA = 17,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
-    VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF
-} VkBlendFactor;
-typedef enum VkBlendOp {
-    VK_BLEND_OP_ADD = 0,
-    VK_BLEND_OP_SUBTRACT = 1,
-    VK_BLEND_OP_REVERSE_SUBTRACT = 2,
-    VK_BLEND_OP_MIN = 3,
-    VK_BLEND_OP_MAX = 4,
-    VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF
-} VkBlendOp;
-typedef enum VkBorderColor {
-    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,
-    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,
-    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,
-    VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3,
-    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,
-    VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5,
-    VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF
-} VkBorderColor;
-typedef enum VkFramebufferCreateFlagBits {
-    VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 1,
-    VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFramebufferCreateFlagBits;
-typedef enum VkPipelineCacheHeaderVersion {
-    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
-    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCacheHeaderVersion;
-typedef enum VkPipelineCacheCreateFlagBits {
-    VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 1,
-    VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCacheCreateFlagBits;
-typedef enum VkPipelineShaderStageCreateFlagBits {
-    VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 1,
-    VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 2,
-    VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineShaderStageCreateFlagBits;
-typedef enum VkDescriptorSetLayoutCreateFlagBits {
-    VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 2,
-    VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorSetLayoutCreateFlagBits;
-typedef enum VkInstanceCreateFlagBits {
-    VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 1,
-    VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkInstanceCreateFlagBits;
-typedef enum VkDeviceQueueCreateFlagBits {
-    VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1,
-    VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDeviceQueueCreateFlagBits;
-typedef enum VkBufferCreateFlagBits {
-    VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 1,
-    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 2,
-    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 4,
-    VK_BUFFER_CREATE_PROTECTED_BIT = 8,
-    VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 16,
-    VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkBufferCreateFlagBits;
-typedef enum VkBufferUsageFlagBits {
-    VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 1,
-    VK_BUFFER_USAGE_TRANSFER_DST_BIT = 2,
-    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 4,
-    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 8,
-    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 16,
-    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 32,
-    VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 64,
-    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 128,
-    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 256,
-    VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 131072,
-    VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkBufferUsageFlagBits;
-typedef enum VkColorComponentFlagBits {
-    VK_COLOR_COMPONENT_R_BIT = 1,
-    VK_COLOR_COMPONENT_G_BIT = 2,
-    VK_COLOR_COMPONENT_B_BIT = 4,
-    VK_COLOR_COMPONENT_A_BIT = 8,
-    VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkColorComponentFlagBits;
-typedef enum VkComponentSwizzle {
-    VK_COMPONENT_SWIZZLE_IDENTITY = 0,
-    VK_COMPONENT_SWIZZLE_ZERO = 1,
-    VK_COMPONENT_SWIZZLE_ONE = 2,
-    VK_COMPONENT_SWIZZLE_R = 3,
-    VK_COMPONENT_SWIZZLE_G = 4,
-    VK_COMPONENT_SWIZZLE_B = 5,
-    VK_COMPONENT_SWIZZLE_A = 6,
-    VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF
-} VkComponentSwizzle;
-typedef enum VkCommandPoolCreateFlagBits {
-    VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 1,
-    VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 2,
-    VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4,
-    VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandPoolCreateFlagBits;
-typedef enum VkCommandPoolResetFlagBits {
-    VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1,
-    VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandPoolResetFlagBits;
-typedef enum VkCommandBufferResetFlagBits {
-    VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1,
-    VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferResetFlagBits;
-typedef enum VkCommandBufferLevel {
-    VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0,
-    VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1,
-    VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferLevel;
-typedef enum VkCommandBufferUsageFlagBits {
-    VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 1,
-    VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 2,
-    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4,
-    VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferUsageFlagBits;
-typedef enum VkCompareOp {
-    VK_COMPARE_OP_NEVER = 0,
-    VK_COMPARE_OP_LESS = 1,
-    VK_COMPARE_OP_EQUAL = 2,
-    VK_COMPARE_OP_LESS_OR_EQUAL = 3,
-    VK_COMPARE_OP_GREATER = 4,
-    VK_COMPARE_OP_NOT_EQUAL = 5,
-    VK_COMPARE_OP_GREATER_OR_EQUAL = 6,
-    VK_COMPARE_OP_ALWAYS = 7,
-    VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF
-} VkCompareOp;
-typedef enum VkCullModeFlagBits {
-    VK_CULL_MODE_NONE = 0,
-    VK_CULL_MODE_FRONT_BIT = 1,
-    VK_CULL_MODE_BACK_BIT = 2,
-    VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
-    VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCullModeFlagBits;
-typedef enum VkDescriptorType {
-    VK_DESCRIPTOR_TYPE_SAMPLER = 0,
-    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1,
-    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2,
-    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3,
-    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4,
-    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5,
-    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6,
-    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7,
-    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
-    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
-    VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
-    VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000,
-    VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorType;
-typedef enum VkDynamicState {
-    VK_DYNAMIC_STATE_VIEWPORT = 0,
-    VK_DYNAMIC_STATE_SCISSOR = 1,
-    VK_DYNAMIC_STATE_LINE_WIDTH = 2,
-    VK_DYNAMIC_STATE_DEPTH_BIAS = 3,
-    VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,
-    VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5,
-    VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,
-    VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,
-    VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
-    VK_DYNAMIC_STATE_CULL_MODE = 1000267000,
-    VK_DYNAMIC_STATE_FRONT_FACE = 1000267001,
-    VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002,
-    VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003,
-    VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004,
-    VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005,
-    VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006,
-    VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007,
-    VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008,
-    VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009,
-    VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010,
-    VK_DYNAMIC_STATE_STENCIL_OP = 1000267011,
-    VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001,
-    VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002,
-    VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004,
-    VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF
-} VkDynamicState;
-typedef enum VkFenceCreateFlagBits {
-    VK_FENCE_CREATE_SIGNALED_BIT = 1,
-    VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFenceCreateFlagBits;
-typedef enum VkPolygonMode {
-    VK_POLYGON_MODE_FILL = 0,
-    VK_POLYGON_MODE_LINE = 1,
-    VK_POLYGON_MODE_POINT = 2,
-    VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkPolygonMode;
-typedef enum VkFormat {
-    VK_FORMAT_UNDEFINED = 0,
-    VK_FORMAT_R4G4_UNORM_PACK8 = 1,
-    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
-    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
-    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
-    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
-    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
-    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
-    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
-    VK_FORMAT_R8_UNORM = 9,
-    VK_FORMAT_R8_SNORM = 10,
-    VK_FORMAT_R8_USCALED = 11,
-    VK_FORMAT_R8_SSCALED = 12,
-    VK_FORMAT_R8_UINT = 13,
-    VK_FORMAT_R8_SINT = 14,
-    VK_FORMAT_R8_SRGB = 15,
-    VK_FORMAT_R8G8_UNORM = 16,
-    VK_FORMAT_R8G8_SNORM = 17,
-    VK_FORMAT_R8G8_USCALED = 18,
-    VK_FORMAT_R8G8_SSCALED = 19,
-    VK_FORMAT_R8G8_UINT = 20,
-    VK_FORMAT_R8G8_SINT = 21,
-    VK_FORMAT_R8G8_SRGB = 22,
-    VK_FORMAT_R8G8B8_UNORM = 23,
-    VK_FORMAT_R8G8B8_SNORM = 24,
-    VK_FORMAT_R8G8B8_USCALED = 25,
-    VK_FORMAT_R8G8B8_SSCALED = 26,
-    VK_FORMAT_R8G8B8_UINT = 27,
-    VK_FORMAT_R8G8B8_SINT = 28,
-    VK_FORMAT_R8G8B8_SRGB = 29,
-    VK_FORMAT_B8G8R8_UNORM = 30,
-    VK_FORMAT_B8G8R8_SNORM = 31,
-    VK_FORMAT_B8G8R8_USCALED = 32,
-    VK_FORMAT_B8G8R8_SSCALED = 33,
-    VK_FORMAT_B8G8R8_UINT = 34,
-    VK_FORMAT_B8G8R8_SINT = 35,
-    VK_FORMAT_B8G8R8_SRGB = 36,
-    VK_FORMAT_R8G8B8A8_UNORM = 37,
-    VK_FORMAT_R8G8B8A8_SNORM = 38,
-    VK_FORMAT_R8G8B8A8_USCALED = 39,
-    VK_FORMAT_R8G8B8A8_SSCALED = 40,
-    VK_FORMAT_R8G8B8A8_UINT = 41,
-    VK_FORMAT_R8G8B8A8_SINT = 42,
-    VK_FORMAT_R8G8B8A8_SRGB = 43,
-    VK_FORMAT_B8G8R8A8_UNORM = 44,
-    VK_FORMAT_B8G8R8A8_SNORM = 45,
-    VK_FORMAT_B8G8R8A8_USCALED = 46,
-    VK_FORMAT_B8G8R8A8_SSCALED = 47,
-    VK_FORMAT_B8G8R8A8_UINT = 48,
-    VK_FORMAT_B8G8R8A8_SINT = 49,
-    VK_FORMAT_B8G8R8A8_SRGB = 50,
-    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
-    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
-    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
-    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
-    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
-    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
-    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
-    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
-    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
-    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
-    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
-    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
-    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
-    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
-    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
-    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
-    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
-    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
-    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
-    VK_FORMAT_R16_UNORM = 70,
-    VK_FORMAT_R16_SNORM = 71,
-    VK_FORMAT_R16_USCALED = 72,
-    VK_FORMAT_R16_SSCALED = 73,
-    VK_FORMAT_R16_UINT = 74,
-    VK_FORMAT_R16_SINT = 75,
-    VK_FORMAT_R16_SFLOAT = 76,
-    VK_FORMAT_R16G16_UNORM = 77,
-    VK_FORMAT_R16G16_SNORM = 78,
-    VK_FORMAT_R16G16_USCALED = 79,
-    VK_FORMAT_R16G16_SSCALED = 80,
-    VK_FORMAT_R16G16_UINT = 81,
-    VK_FORMAT_R16G16_SINT = 82,
-    VK_FORMAT_R16G16_SFLOAT = 83,
-    VK_FORMAT_R16G16B16_UNORM = 84,
-    VK_FORMAT_R16G16B16_SNORM = 85,
-    VK_FORMAT_R16G16B16_USCALED = 86,
-    VK_FORMAT_R16G16B16_SSCALED = 87,
-    VK_FORMAT_R16G16B16_UINT = 88,
-    VK_FORMAT_R16G16B16_SINT = 89,
-    VK_FORMAT_R16G16B16_SFLOAT = 90,
-    VK_FORMAT_R16G16B16A16_UNORM = 91,
-    VK_FORMAT_R16G16B16A16_SNORM = 92,
-    VK_FORMAT_R16G16B16A16_USCALED = 93,
-    VK_FORMAT_R16G16B16A16_SSCALED = 94,
-    VK_FORMAT_R16G16B16A16_UINT = 95,
-    VK_FORMAT_R16G16B16A16_SINT = 96,
-    VK_FORMAT_R16G16B16A16_SFLOAT = 97,
-    VK_FORMAT_R32_UINT = 98,
-    VK_FORMAT_R32_SINT = 99,
-    VK_FORMAT_R32_SFLOAT = 100,
-    VK_FORMAT_R32G32_UINT = 101,
-    VK_FORMAT_R32G32_SINT = 102,
-    VK_FORMAT_R32G32_SFLOAT = 103,
-    VK_FORMAT_R32G32B32_UINT = 104,
-    VK_FORMAT_R32G32B32_SINT = 105,
-    VK_FORMAT_R32G32B32_SFLOAT = 106,
-    VK_FORMAT_R32G32B32A32_UINT = 107,
-    VK_FORMAT_R32G32B32A32_SINT = 108,
-    VK_FORMAT_R32G32B32A32_SFLOAT = 109,
-    VK_FORMAT_R64_UINT = 110,
-    VK_FORMAT_R64_SINT = 111,
-    VK_FORMAT_R64_SFLOAT = 112,
-    VK_FORMAT_R64G64_UINT = 113,
-    VK_FORMAT_R64G64_SINT = 114,
-    VK_FORMAT_R64G64_SFLOAT = 115,
-    VK_FORMAT_R64G64B64_UINT = 116,
-    VK_FORMAT_R64G64B64_SINT = 117,
-    VK_FORMAT_R64G64B64_SFLOAT = 118,
-    VK_FORMAT_R64G64B64A64_UINT = 119,
-    VK_FORMAT_R64G64B64A64_SINT = 120,
-    VK_FORMAT_R64G64B64A64_SFLOAT = 121,
-    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
-    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
-    VK_FORMAT_D16_UNORM = 124,
-    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
-    VK_FORMAT_D32_SFLOAT = 126,
-    VK_FORMAT_S8_UINT = 127,
-    VK_FORMAT_D16_UNORM_S8_UINT = 128,
-    VK_FORMAT_D24_UNORM_S8_UINT = 129,
-    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
-    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
-    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
-    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
-    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
-    VK_FORMAT_BC2_UNORM_BLOCK = 135,
-    VK_FORMAT_BC2_SRGB_BLOCK = 136,
-    VK_FORMAT_BC3_UNORM_BLOCK = 137,
-    VK_FORMAT_BC3_SRGB_BLOCK = 138,
-    VK_FORMAT_BC4_UNORM_BLOCK = 139,
-    VK_FORMAT_BC4_SNORM_BLOCK = 140,
-    VK_FORMAT_BC5_UNORM_BLOCK = 141,
-    VK_FORMAT_BC5_SNORM_BLOCK = 142,
-    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
-    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
-    VK_FORMAT_BC7_UNORM_BLOCK = 145,
-    VK_FORMAT_BC7_SRGB_BLOCK = 146,
-    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
-    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
-    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
-    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
-    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
-    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
-    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
-    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
-    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
-    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
-    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
-    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
-    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
-    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
-    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
-    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
-    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
-    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
-    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
-    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
-    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
-    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
-    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
-    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
-    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
-    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
-    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
-    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
-    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
-    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
-    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
-    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
-    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
-    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
-    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
-    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
-    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
-    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
-    VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
-    VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
-    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
-    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
-    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
-    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
-    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
-    VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
-    VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
-    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
-    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
-    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
-    VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
-    VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
-    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
-    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
-    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
-    VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
-    VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
-    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
-    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
-    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
-    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
-    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
-    VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000,
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001,
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002,
-    VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003,
-    VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000,
-    VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001,
-    VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000,
-    VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001,
-    VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002,
-    VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003,
-    VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004,
-    VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005,
-    VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006,
-    VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007,
-    VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008,
-    VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009,
-    VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010,
-    VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011,
-    VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012,
-    VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013,
-    VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
-} VkFormat;
-typedef enum VkFormatFeatureFlagBits {
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 1,
-    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 2,
-    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 4,
-    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 8,
-    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 16,
-    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 32,
-    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 64,
-    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 128,
-    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 256,
-    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 512,
-    VK_FORMAT_FEATURE_BLIT_SRC_BIT = 1024,
-    VK_FORMAT_FEATURE_BLIT_DST_BIT = 2048,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 4096,
-    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 16384,
-    VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 32768,
-    VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 131072,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 262144,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 524288,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 1048576,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 2097152,
-    VK_FORMAT_FEATURE_DISJOINT_BIT = 4194304,
-    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 8388608,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 65536,
-    VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFormatFeatureFlagBits;
-typedef enum VkFrontFace {
-    VK_FRONT_FACE_COUNTER_CLOCKWISE = 0,
-    VK_FRONT_FACE_CLOCKWISE = 1,
-    VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF
-} VkFrontFace;
-typedef enum VkImageAspectFlagBits {
-    VK_IMAGE_ASPECT_COLOR_BIT = 1,
-    VK_IMAGE_ASPECT_DEPTH_BIT = 2,
-    VK_IMAGE_ASPECT_STENCIL_BIT = 4,
-    VK_IMAGE_ASPECT_METADATA_BIT = 8,
-    VK_IMAGE_ASPECT_PLANE_0_BIT = 16,
-    VK_IMAGE_ASPECT_PLANE_1_BIT = 32,
-    VK_IMAGE_ASPECT_PLANE_2_BIT = 64,
-    VK_IMAGE_ASPECT_NONE = 0,
-    VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageAspectFlagBits;
-typedef enum VkImageCreateFlagBits {
-    VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 1,
-    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 2,
-    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 4,
-    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 8,
-    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 16,
-    VK_IMAGE_CREATE_ALIAS_BIT = 1024,
-    VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 64,
-    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 32,
-    VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 128,
-    VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 256,
-    VK_IMAGE_CREATE_PROTECTED_BIT = 2048,
-    VK_IMAGE_CREATE_DISJOINT_BIT = 512,
-    VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageCreateFlagBits;
-typedef enum VkImageLayout {
-    VK_IMAGE_LAYOUT_UNDEFINED = 0,
-    VK_IMAGE_LAYOUT_GENERAL = 1,
-    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2,
-    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3,
-    VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4,
-    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5,
-    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,
-    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,
-    VK_IMAGE_LAYOUT_PREINITIALIZED = 8,
-    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
-    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
-    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000,
-    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001,
-    VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002,
-    VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003,
-    VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000,
-    VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001,
-    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
-    VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF
-} VkImageLayout;
-typedef enum VkImageTiling {
-    VK_IMAGE_TILING_OPTIMAL = 0,
-    VK_IMAGE_TILING_LINEAR = 1,
-    VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF
-} VkImageTiling;
-typedef enum VkImageType {
-    VK_IMAGE_TYPE_1D = 0,
-    VK_IMAGE_TYPE_2D = 1,
-    VK_IMAGE_TYPE_3D = 2,
-    VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkImageType;
-typedef enum VkImageUsageFlagBits {
-    VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 1,
-    VK_IMAGE_USAGE_TRANSFER_DST_BIT = 2,
-    VK_IMAGE_USAGE_SAMPLED_BIT = 4,
-    VK_IMAGE_USAGE_STORAGE_BIT = 8,
-    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 16,
-    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 32,
-    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 64,
-    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 128,
-    VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageUsageFlagBits;
-typedef enum VkImageViewType {
-    VK_IMAGE_VIEW_TYPE_1D = 0,
-    VK_IMAGE_VIEW_TYPE_2D = 1,
-    VK_IMAGE_VIEW_TYPE_3D = 2,
-    VK_IMAGE_VIEW_TYPE_CUBE = 3,
-    VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4,
-    VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5,
-    VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6,
-    VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkImageViewType;
-typedef enum VkSharingMode {
-    VK_SHARING_MODE_EXCLUSIVE = 0,
-    VK_SHARING_MODE_CONCURRENT = 1,
-    VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSharingMode;
-typedef enum VkIndexType {
-    VK_INDEX_TYPE_UINT16 = 0,
-    VK_INDEX_TYPE_UINT32 = 1,
-    VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkIndexType;
-typedef enum VkLogicOp {
-    VK_LOGIC_OP_CLEAR = 0,
-    VK_LOGIC_OP_AND = 1,
-    VK_LOGIC_OP_AND_REVERSE = 2,
-    VK_LOGIC_OP_COPY = 3,
-    VK_LOGIC_OP_AND_INVERTED = 4,
-    VK_LOGIC_OP_NO_OP = 5,
-    VK_LOGIC_OP_XOR = 6,
-    VK_LOGIC_OP_OR = 7,
-    VK_LOGIC_OP_NOR = 8,
-    VK_LOGIC_OP_EQUIVALENT = 9,
-    VK_LOGIC_OP_INVERT = 10,
-    VK_LOGIC_OP_OR_REVERSE = 11,
-    VK_LOGIC_OP_COPY_INVERTED = 12,
-    VK_LOGIC_OP_OR_INVERTED = 13,
-    VK_LOGIC_OP_NAND = 14,
-    VK_LOGIC_OP_SET = 15,
-    VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF
-} VkLogicOp;
-typedef enum VkMemoryHeapFlagBits {
-    VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 1,
-    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 2,
-    VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkMemoryHeapFlagBits;
-typedef enum VkAccessFlagBits {
-    VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 1,
-    VK_ACCESS_INDEX_READ_BIT = 2,
-    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 4,
-    VK_ACCESS_UNIFORM_READ_BIT = 8,
-    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 16,
-    VK_ACCESS_SHADER_READ_BIT = 32,
-    VK_ACCESS_SHADER_WRITE_BIT = 64,
-    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 128,
-    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 256,
-    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 512,
-    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 1024,
-    VK_ACCESS_TRANSFER_READ_BIT = 2048,
-    VK_ACCESS_TRANSFER_WRITE_BIT = 4096,
-    VK_ACCESS_HOST_READ_BIT = 8192,
-    VK_ACCESS_HOST_WRITE_BIT = 16384,
-    VK_ACCESS_MEMORY_READ_BIT = 32768,
-    VK_ACCESS_MEMORY_WRITE_BIT = 65536,
-    VK_ACCESS_NONE = 0,
-    VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkAccessFlagBits;
-typedef enum VkMemoryPropertyFlagBits {
-    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 1,
-    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 2,
-    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 4,
-    VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 8,
-    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 16,
-    VK_MEMORY_PROPERTY_PROTECTED_BIT = 32,
-    VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkMemoryPropertyFlagBits;
-typedef enum VkPhysicalDeviceType {
-    VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
-    VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
-    VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
-    VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
-    VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
-    VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkPhysicalDeviceType;
-typedef enum VkPipelineBindPoint {
-    VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
-    VK_PIPELINE_BIND_POINT_COMPUTE = 1,
-    VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineBindPoint;
-typedef enum VkPipelineCreateFlagBits {
-    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 1,
-    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 2,
-    VK_PIPELINE_CREATE_DERIVATIVE_BIT = 4,
-    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8,
-    VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 16,
-    VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT,
-    VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 256,
-    VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 512,
-    VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCreateFlagBits;
-typedef enum VkPrimitiveTopology {
-    VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,
-    VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,
-    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,
-    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,
-    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,
-    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,
-    VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF
-} VkPrimitiveTopology;
-typedef enum VkQueryControlFlagBits {
-    VK_QUERY_CONTROL_PRECISE_BIT = 1,
-    VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryControlFlagBits;
-typedef enum VkQueryPipelineStatisticFlagBits {
-    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 1,
-    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 2,
-    VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 4,
-    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 8,
-    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 16,
-    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 32,
-    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 64,
-    VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 128,
-    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 256,
-    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 512,
-    VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024,
-    VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryPipelineStatisticFlagBits;
-typedef enum VkQueryResultFlagBits {
-    VK_QUERY_RESULT_64_BIT = 1,
-    VK_QUERY_RESULT_WAIT_BIT = 2,
-    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 4,
-    VK_QUERY_RESULT_PARTIAL_BIT = 8,
-    VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryResultFlagBits;
-typedef enum VkQueryType {
-    VK_QUERY_TYPE_OCCLUSION = 0,
-    VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
-    VK_QUERY_TYPE_TIMESTAMP = 2,
-    VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkQueryType;
-typedef enum VkQueueFlagBits {
-    VK_QUEUE_GRAPHICS_BIT = 1,
-    VK_QUEUE_COMPUTE_BIT = 2,
-    VK_QUEUE_TRANSFER_BIT = 4,
-    VK_QUEUE_SPARSE_BINDING_BIT = 8,
-    VK_QUEUE_PROTECTED_BIT = 16,
-    VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueueFlagBits;
-typedef enum VkSubpassContents {
-    VK_SUBPASS_CONTENTS_INLINE = 0,
-    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1,
-    VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
-} VkSubpassContents;
-typedef enum VkResult {
-    VK_SUCCESS = 0,
-    VK_NOT_READY = 1,
-    VK_TIMEOUT = 2,
-    VK_EVENT_SET = 3,
-    VK_EVENT_RESET = 4,
-    VK_INCOMPLETE = 5,
-    VK_ERROR_OUT_OF_HOST_MEMORY = -1,
-    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
-    VK_ERROR_INITIALIZATION_FAILED = -3,
-    VK_ERROR_DEVICE_LOST = -4,
-    VK_ERROR_MEMORY_MAP_FAILED = -5,
-    VK_ERROR_LAYER_NOT_PRESENT = -6,
-    VK_ERROR_EXTENSION_NOT_PRESENT = -7,
-    VK_ERROR_FEATURE_NOT_PRESENT = -8,
-    VK_ERROR_INCOMPATIBLE_DRIVER = -9,
-    VK_ERROR_TOO_MANY_OBJECTS = -10,
-    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
-    VK_ERROR_FRAGMENTED_POOL = -12,
-    VK_ERROR_UNKNOWN = -13,
-    VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000,
-    VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003,
-    VK_ERROR_FRAGMENTATION = -1000161000,
-    VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000,
-    VK_PIPELINE_COMPILE_REQUIRED = 1000297000,
-    VK_ERROR_SURFACE_LOST_KHR = -1000000000,
-    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
-    VK_SUBOPTIMAL_KHR = 1000001003,
-    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
-    VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
-    VK_RESULT_MAX_ENUM = 0x7FFFFFFF
-} VkResult;
-typedef enum VkShaderStageFlagBits {
-    VK_SHADER_STAGE_VERTEX_BIT = 1,
-    VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 2,
-    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 4,
-    VK_SHADER_STAGE_GEOMETRY_BIT = 8,
-    VK_SHADER_STAGE_FRAGMENT_BIT = 16,
-    VK_SHADER_STAGE_COMPUTE_BIT = 32,
-    VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
-    VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
-    VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkShaderStageFlagBits;
-typedef enum VkSparseMemoryBindFlagBits {
-    VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1,
-    VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSparseMemoryBindFlagBits;
-typedef enum VkStencilFaceFlagBits {
-    VK_STENCIL_FACE_FRONT_BIT = 1,
-    VK_STENCIL_FACE_BACK_BIT = 2,
-    VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003,
-    VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK,
-    VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkStencilFaceFlagBits;
-typedef enum VkStencilOp {
-    VK_STENCIL_OP_KEEP = 0,
-    VK_STENCIL_OP_ZERO = 1,
-    VK_STENCIL_OP_REPLACE = 2,
-    VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3,
-    VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4,
-    VK_STENCIL_OP_INVERT = 5,
-    VK_STENCIL_OP_INCREMENT_AND_WRAP = 6,
-    VK_STENCIL_OP_DECREMENT_AND_WRAP = 7,
-    VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF
-} VkStencilOp;
-typedef enum VkStructureType {
-    VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
-    VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
-    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
-    VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
-    VK_STRUCTURE_TYPE_SUBMIT_INFO = 4,
-    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5,
-    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6,
-    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7,
-    VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8,
-    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9,
-    VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10,
-    VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11,
-    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12,
-    VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13,
-    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14,
-    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15,
-    VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16,
-    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17,
-    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18,
-    VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19,
-    VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,
-    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21,
-    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22,
-    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23,
-    VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24,
-    VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25,
-    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26,
-    VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27,
-    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28,
-    VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29,
-    VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30,
-    VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34,
-    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35,
-    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36,
-    VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37,
-    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38,
-    VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42,
-    VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43,
-    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44,
-    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45,
-    VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,
-    VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
-    VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000,
-    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000,
-    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000,
-    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001,
-    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006,
-    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001,
-    VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000,
-    VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001,
-    VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002,
-    VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003,
-    VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001,
-    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002,
-    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004,
-    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006,
-    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000,
-    VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001,
-    VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002,
-    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
-    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,
-    VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002,
-    VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003,
-    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000,
-    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002,
-    VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
-    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000,
-    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002,
-    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004,
-    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000,
-    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001,
-    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000,
-    VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001,
-    VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000,
-    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000,
-    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52,
-    VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000,
-    VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000,
-    VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001,
-    VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002,
-    VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003,
-    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004,
-    VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005,
-    VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000,
-    VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000,
-    VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000,
-    VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000,
-    VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001,
-    VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002,
-    VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000,
-    VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001,
-    VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001,
-    VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002,
-    VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003,
-    VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004,
-    VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000,
-    VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001,
-    VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002,
-    VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003,
-    VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54,
-    VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000,
-    VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001,
-    VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000,
-    VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000,
-    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001,
-    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002,
-    VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003,
-    VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004,
-    VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000,
-    VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000,
-    VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001,
-    VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002,
-    VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003,
-    VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004,
-    VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005,
-    VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006,
-    VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007,
-    VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008,
-    VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009,
-    VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000,
-    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001,
-    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000,
-    VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000,
-    VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001,
-    VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001,
-    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001,
-    VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002,
-    VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003,
-    VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
-    VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
-    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009,
-    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012,
-    VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
-    VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
-    VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkStructureType;
-typedef enum VkSystemAllocationScope {
-    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0,
-    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1,
-    VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2,
-    VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3,
-    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4,
-    VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF
-} VkSystemAllocationScope;
-typedef enum VkInternalAllocationType {
-    VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,
-    VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkInternalAllocationType;
-typedef enum VkSamplerAddressMode {
-    VK_SAMPLER_ADDRESS_MODE_REPEAT = 0,
-    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1,
-    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2,
-    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3,
-    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4,
-    VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerAddressMode;
-typedef enum VkFilter {
-    VK_FILTER_NEAREST = 0,
-    VK_FILTER_LINEAR = 1,
-    VK_FILTER_MAX_ENUM = 0x7FFFFFFF
-} VkFilter;
-typedef enum VkSamplerMipmapMode {
-    VK_SAMPLER_MIPMAP_MODE_NEAREST = 0,
-    VK_SAMPLER_MIPMAP_MODE_LINEAR = 1,
-    VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerMipmapMode;
-typedef enum VkVertexInputRate {
-    VK_VERTEX_INPUT_RATE_VERTEX = 0,
-    VK_VERTEX_INPUT_RATE_INSTANCE = 1,
-    VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF
-} VkVertexInputRate;
-typedef enum VkPipelineStageFlagBits {
-    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 1,
-    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 2,
-    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 4,
-    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 8,
-    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 16,
-    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 32,
-    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 64,
-    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 128,
-    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 256,
-    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 512,
-    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 1024,
-    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 2048,
-    VK_PIPELINE_STAGE_TRANSFER_BIT = 4096,
-    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 8192,
-    VK_PIPELINE_STAGE_HOST_BIT = 16384,
-    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 32768,
-    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 65536,
-    VK_PIPELINE_STAGE_NONE = 0,
-    VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineStageFlagBits;
-typedef enum VkSparseImageFormatFlagBits {
-    VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 1,
-    VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 2,
-    VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4,
-    VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSparseImageFormatFlagBits;
-typedef enum VkSampleCountFlagBits {
-    VK_SAMPLE_COUNT_1_BIT = 1,
-    VK_SAMPLE_COUNT_2_BIT = 2,
-    VK_SAMPLE_COUNT_4_BIT = 4,
-    VK_SAMPLE_COUNT_8_BIT = 8,
-    VK_SAMPLE_COUNT_16_BIT = 16,
-    VK_SAMPLE_COUNT_32_BIT = 32,
-    VK_SAMPLE_COUNT_64_BIT = 64,
-    VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSampleCountFlagBits;
-typedef enum VkAttachmentDescriptionFlagBits {
-    VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1,
-    VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentDescriptionFlagBits;
-typedef enum VkDescriptorPoolCreateFlagBits {
-    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 1,
-    VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 2,
-    VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorPoolCreateFlagBits;
-typedef enum VkDependencyFlagBits {
-    VK_DEPENDENCY_BY_REGION_BIT = 1,
-    VK_DEPENDENCY_DEVICE_GROUP_BIT = 4,
-    VK_DEPENDENCY_VIEW_LOCAL_BIT = 2,
-    VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDependencyFlagBits;
-typedef enum VkObjectType {
-    VK_OBJECT_TYPE_UNKNOWN = 0,
-    VK_OBJECT_TYPE_INSTANCE = 1,
-    VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
-    VK_OBJECT_TYPE_DEVICE = 3,
-    VK_OBJECT_TYPE_QUEUE = 4,
-    VK_OBJECT_TYPE_SEMAPHORE = 5,
-    VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
-    VK_OBJECT_TYPE_FENCE = 7,
-    VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
-    VK_OBJECT_TYPE_BUFFER = 9,
-    VK_OBJECT_TYPE_IMAGE = 10,
-    VK_OBJECT_TYPE_EVENT = 11,
-    VK_OBJECT_TYPE_QUERY_POOL = 12,
-    VK_OBJECT_TYPE_BUFFER_VIEW = 13,
-    VK_OBJECT_TYPE_IMAGE_VIEW = 14,
-    VK_OBJECT_TYPE_SHADER_MODULE = 15,
-    VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
-    VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
-    VK_OBJECT_TYPE_RENDER_PASS = 18,
-    VK_OBJECT_TYPE_PIPELINE = 19,
-    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
-    VK_OBJECT_TYPE_SAMPLER = 21,
-    VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
-    VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
-    VK_OBJECT_TYPE_FRAMEBUFFER = 24,
-    VK_OBJECT_TYPE_COMMAND_POOL = 25,
-    VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
-    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
-    VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000,
-    VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
-    VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
-    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
-    VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkObjectType;
-typedef enum VkEventCreateFlagBits {
-    VK_EVENT_CREATE_DEVICE_ONLY_BIT = 1,
-    VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkEventCreateFlagBits;
-typedef enum VkDescriptorUpdateTemplateType {
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorUpdateTemplateType;
-typedef enum VkPointClippingBehavior {
-    VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
-    VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
-    VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF
-} VkPointClippingBehavior;
-typedef enum VkResolveModeFlagBits {
-    VK_RESOLVE_MODE_NONE = 0,
-    VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 1,
-    VK_RESOLVE_MODE_AVERAGE_BIT = 2,
-    VK_RESOLVE_MODE_MIN_BIT = 4,
-    VK_RESOLVE_MODE_MAX_BIT = 8,
-    VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkResolveModeFlagBits;
-typedef enum VkDescriptorBindingFlagBits {
-    VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 1,
-    VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 2,
-    VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 4,
-    VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 8,
-    VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorBindingFlagBits;
-typedef enum VkSemaphoreType {
-    VK_SEMAPHORE_TYPE_BINARY = 0,
-    VK_SEMAPHORE_TYPE_TIMELINE = 1,
-    VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkSemaphoreType;
-typedef enum VkPipelineCreationFeedbackFlagBits {
-    VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 1,
-    VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT,
-    VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 2,
-    VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT,
-    VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 4,
-    VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT,
-    VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCreationFeedbackFlagBits;
-typedef enum VkSemaphoreWaitFlagBits {
-    VK_SEMAPHORE_WAIT_ANY_BIT = 1,
-    VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSemaphoreWaitFlagBits;
-typedef enum VkToolPurposeFlagBits {
-    VK_TOOL_PURPOSE_VALIDATION_BIT = 1,
-    VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT,
-    VK_TOOL_PURPOSE_PROFILING_BIT = 2,
-    VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT,
-    VK_TOOL_PURPOSE_TRACING_BIT = 4,
-    VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT,
-    VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 8,
-    VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT,
-    VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 16,
-    VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT,
-    VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkToolPurposeFlagBits;
-typedef uint64_t VkAccessFlagBits2;
-static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0;
-static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0;
-static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 1;
-static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 1;
-static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 2;
-static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 2;
-static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 4;
-static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 4;
-static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 8;
-static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 8;
-static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 16;
-static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 16;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 32;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 32;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 64;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 64;
-static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 128;
-static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 128;
-static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 256;
-static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 256;
-static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 512;
-static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 512;
-static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 1024;
-static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 1024;
-static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 2048;
-static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 2048;
-static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 4096;
-static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 4096;
-static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 8192;
-static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 8192;
-static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 16384;
-static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 16384;
-static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 32768;
-static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 32768;
-static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 65536;
-static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 65536;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 4294967296;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 4294967296;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 8589934592;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 8589934592;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 17179869184;
-static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 17179869184;
-
-typedef uint64_t VkPipelineStageFlagBits2;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 1;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 1;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 2;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 2;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 4;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 4;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 8;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 8;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 16;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 16;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 32;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 32;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 64;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 64;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 128;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 128;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 256;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 256;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 512;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 512;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 1024;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 1024;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 2048;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 2048;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 4096;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 4096;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 4096;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 4096;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 8192;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 8192;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 16384;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 16384;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 32768;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 32768;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 65536;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 65536;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 4294967296;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 4294967296;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 8589934592;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 8589934592;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 17179869184;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 17179869184;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 34359738368;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 34359738368;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 68719476736;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 68719476736;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 137438953472;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 137438953472;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 274877906944;
-static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 274877906944;
-
-typedef uint64_t VkFormatFeatureFlagBits2;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 1;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 1;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 2;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 2;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 4;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 4;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 8;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 8;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 16;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 16;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 32;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 32;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 64;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 64;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 128;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 128;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 256;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 256;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 512;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 512;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 1024;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 1024;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 2048;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 2048;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 4096;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 4096;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 8192;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 8192;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 16384;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 16384;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 32768;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 32768;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 65536;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 65536;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 131072;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 131072;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 262144;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 262144;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 524288;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 524288;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 1048576;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 1048576;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 2097152;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 2097152;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 4194304;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 4194304;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 8388608;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 8388608;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 2147483648;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 2147483648;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 4294967296;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 4294967296;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 8589934592;
-static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 8589934592;
-
-typedef enum VkRenderingFlagBits {
-    VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 1,
-    VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT,
-    VK_RENDERING_SUSPENDING_BIT = 2,
-    VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT,
-    VK_RENDERING_RESUMING_BIT = 4,
-    VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT,
-    VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkRenderingFlagBits;
-typedef enum VkColorSpaceKHR {
-    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
-    VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
-    VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkColorSpaceKHR;
-typedef enum VkCompositeAlphaFlagBitsKHR {
-    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 1,
-    VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 2,
-    VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 4,
-    VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8,
-    VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkCompositeAlphaFlagBitsKHR;
-typedef enum VkPresentModeKHR {
-    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,
-    VK_PRESENT_MODE_MAILBOX_KHR = 1,
-    VK_PRESENT_MODE_FIFO_KHR = 2,
-    VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,
-    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkPresentModeKHR;
-typedef enum VkSurfaceTransformFlagBitsKHR {
-    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 1,
-    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 2,
-    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 4,
-    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 8,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 16,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 32,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 64,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 128,
-    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256,
-    VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkSurfaceTransformFlagBitsKHR;
-typedef enum VkDebugReportFlagBitsEXT {
-    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 1,
-    VK_DEBUG_REPORT_WARNING_BIT_EXT = 2,
-    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 4,
-    VK_DEBUG_REPORT_ERROR_BIT_EXT = 8,
-    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16,
-    VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDebugReportFlagBitsEXT;
-typedef enum VkDebugReportObjectTypeEXT {
-    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
-    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
-    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
-    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
-    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
-    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
-    VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDebugReportObjectTypeEXT;
-typedef enum VkExternalMemoryHandleTypeFlagBits {
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 1,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 8,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 16,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 32,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 64,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalMemoryHandleTypeFlagBits;
-typedef enum VkExternalMemoryFeatureFlagBits {
-    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 1,
-    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 2,
-    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 4,
-    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalMemoryFeatureFlagBits;
-typedef enum VkExternalSemaphoreHandleTypeFlagBits {
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 1,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 8,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 16,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalSemaphoreHandleTypeFlagBits;
-typedef enum VkExternalSemaphoreFeatureFlagBits {
-    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 1,
-    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 2,
-    VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalSemaphoreFeatureFlagBits;
-typedef enum VkSemaphoreImportFlagBits {
-    VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 1,
-    VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSemaphoreImportFlagBits;
-typedef enum VkExternalFenceHandleTypeFlagBits {
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 1,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 4,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 8,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalFenceHandleTypeFlagBits;
-typedef enum VkExternalFenceFeatureFlagBits {
-    VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 1,
-    VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 2,
-    VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkExternalFenceFeatureFlagBits;
-typedef enum VkFenceImportFlagBits {
-    VK_FENCE_IMPORT_TEMPORARY_BIT = 1,
-    VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFenceImportFlagBits;
-typedef enum VkPeerMemoryFeatureFlagBits {
-    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 1,
-    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 2,
-    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 4,
-    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 8,
-    VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPeerMemoryFeatureFlagBits;
-typedef enum VkMemoryAllocateFlagBits {
-    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 1,
-    VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 2,
-    VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 4,
-    VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkMemoryAllocateFlagBits;
-typedef enum VkDeviceGroupPresentModeFlagBitsKHR {
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 1,
-    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 2,
-    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 4,
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8,
-    VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkDeviceGroupPresentModeFlagBitsKHR;
-typedef enum VkSwapchainCreateFlagBitsKHR {
-    VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 1,
-    VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 2,
-    VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkSwapchainCreateFlagBitsKHR;
-typedef enum VkSubgroupFeatureFlagBits {
-    VK_SUBGROUP_FEATURE_BASIC_BIT = 1,
-    VK_SUBGROUP_FEATURE_VOTE_BIT = 2,
-    VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 4,
-    VK_SUBGROUP_FEATURE_BALLOT_BIT = 8,
-    VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 16,
-    VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 32,
-    VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 64,
-    VK_SUBGROUP_FEATURE_QUAD_BIT = 128,
-    VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSubgroupFeatureFlagBits;
-typedef enum VkTessellationDomainOrigin {
-    VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0,
-    VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1,
-    VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF
-} VkTessellationDomainOrigin;
-typedef enum VkSamplerYcbcrModelConversion {
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0,
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1,
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2,
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3,
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4,
-    VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerYcbcrModelConversion;
-typedef enum VkSamplerYcbcrRange {
-    VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
-    VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
-    VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerYcbcrRange;
-typedef enum VkChromaLocation {
-    VK_CHROMA_LOCATION_COSITED_EVEN = 0,
-    VK_CHROMA_LOCATION_MIDPOINT = 1,
-    VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF
-} VkChromaLocation;
-typedef enum VkSamplerReductionMode {
-    VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0,
-    VK_SAMPLER_REDUCTION_MODE_MIN = 1,
-    VK_SAMPLER_REDUCTION_MODE_MAX = 2,
-    VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerReductionMode;
-typedef enum VkShaderFloatControlsIndependence {
-    VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0,
-    VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1,
-    VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2,
-    VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF
-} VkShaderFloatControlsIndependence;
-typedef enum VkSubmitFlagBits {
-    VK_SUBMIT_PROTECTED_BIT = 1,
-    VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT,
-    VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSubmitFlagBits;
-typedef enum VkVendorId {
-    VK_VENDOR_ID_VIV = 0x10001,
-    VK_VENDOR_ID_VSI = 0x10002,
-    VK_VENDOR_ID_KAZAN = 0x10003,
-    VK_VENDOR_ID_CODEPLAY = 0x10004,
-    VK_VENDOR_ID_MESA = 0x10005,
-    VK_VENDOR_ID_POCL = 0x10006,
-    VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF
-} VkVendorId;
-typedef enum VkDriverId {
-    VK_DRIVER_ID_AMD_PROPRIETARY = 1,
-    VK_DRIVER_ID_AMD_OPEN_SOURCE = 2,
-    VK_DRIVER_ID_MESA_RADV = 3,
-    VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4,
-    VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5,
-    VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6,
-    VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7,
-    VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8,
-    VK_DRIVER_ID_ARM_PROPRIETARY = 9,
-    VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10,
-    VK_DRIVER_ID_GGP_PROPRIETARY = 11,
-    VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12,
-    VK_DRIVER_ID_MESA_LLVMPIPE = 13,
-    VK_DRIVER_ID_MOLTENVK = 14,
-    VK_DRIVER_ID_COREAVI_PROPRIETARY = 15,
-    VK_DRIVER_ID_JUICE_PROPRIETARY = 16,
-    VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17,
-    VK_DRIVER_ID_MESA_TURNIP = 18,
-    VK_DRIVER_ID_MESA_V3DV = 19,
-    VK_DRIVER_ID_MESA_PANVK = 20,
-    VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21,
-    VK_DRIVER_ID_MESA_VENUS = 22,
-    VK_DRIVER_ID_MESA_DOZEN = 23,
-    VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF
-} VkDriverId;
-typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(
-    void*                                       pUserData,
-    size_t                                      size,
-    VkInternalAllocationType                    allocationType,
-    VkSystemAllocationScope                     allocationScope);
-typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(
-    void*                                       pUserData,
-    size_t                                      size,
-    VkInternalAllocationType                    allocationType,
-    VkSystemAllocationScope                     allocationScope);
-typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)(
-    void*                                       pUserData,
-    void*                                       pOriginal,
-    size_t                                      size,
-    size_t                                      alignment,
-    VkSystemAllocationScope                     allocationScope);
-typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(
-    void*                                       pUserData,
-    size_t                                      size,
-    size_t                                      alignment,
-    VkSystemAllocationScope                     allocationScope);
-typedef void (VKAPI_PTR *PFN_vkFreeFunction)(
-    void*                                       pUserData,
-    void*                                       pMemory);
-typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
-typedef struct VkBaseOutStructure {
-    VkStructureType   sType;
-    struct  VkBaseOutStructure *  pNext;
-} VkBaseOutStructure;
-
-typedef struct VkBaseInStructure {
-    VkStructureType   sType;
-    const struct  VkBaseInStructure *  pNext;
-} VkBaseInStructure;
-
-typedef struct VkOffset2D {
-    int32_t          x;
-    int32_t          y;
-} VkOffset2D;
-
-typedef struct VkOffset3D {
-    int32_t          x;
-    int32_t          y;
-    int32_t          z;
-} VkOffset3D;
-
-typedef struct VkExtent2D {
-    uint32_t          width;
-    uint32_t          height;
-} VkExtent2D;
-
-typedef struct VkExtent3D {
-    uint32_t          width;
-    uint32_t          height;
-    uint32_t          depth;
-} VkExtent3D;
-
-typedef struct VkViewport {
-    float   x;
-    float   y;
-    float   width;
-    float   height;
-    float                         minDepth;
-    float                         maxDepth;
-} VkViewport;
-
-typedef struct VkRect2D {
-    VkOffset2D       offset;
-    VkExtent2D       extent;
-} VkRect2D;
-
-typedef struct VkClearRect {
-    VkRect2D         rect;
-    uint32_t         baseArrayLayer;
-    uint32_t         layerCount;
-} VkClearRect;
-
-typedef struct VkComponentMapping {
-    VkComponentSwizzle   r;
-    VkComponentSwizzle   g;
-    VkComponentSwizzle   b;
-    VkComponentSwizzle   a;
-} VkComponentMapping;
-
-typedef struct VkExtensionProperties {
-    char              extensionName [ VK_MAX_EXTENSION_NAME_SIZE ];
-    uint32_t          specVersion;
-} VkExtensionProperties;
-
-typedef struct VkLayerProperties {
-    char              layerName [ VK_MAX_EXTENSION_NAME_SIZE ];
-    uint32_t          specVersion;
-    uint32_t          implementationVersion;
-    char              description [ VK_MAX_DESCRIPTION_SIZE ];
-} VkLayerProperties;
-
-typedef struct VkApplicationInfo {
-    VkStructureType   sType;
-    const  void *      pNext;
-    const  char *      pApplicationName;
-    uint32_t          applicationVersion;
-    const  char *      pEngineName;
-    uint32_t          engineVersion;
-    uint32_t          apiVersion;
-} VkApplicationInfo;
-
-typedef struct VkAllocationCallbacks {
-    void *            pUserData;
-    PFN_vkAllocationFunction     pfnAllocation;
-    PFN_vkReallocationFunction   pfnReallocation;
-    PFN_vkFreeFunction      pfnFree;
-    PFN_vkInternalAllocationNotification   pfnInternalAllocation;
-    PFN_vkInternalFreeNotification   pfnInternalFree;
-} VkAllocationCallbacks;
-
-typedef struct VkDescriptorImageInfo {
-    VkSampler         sampler;
-    VkImageView       imageView;
-    VkImageLayout     imageLayout;
-} VkDescriptorImageInfo;
-
-typedef struct VkCopyDescriptorSet {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDescriptorSet          srcSet;
-    uint32_t                 srcBinding;
-    uint32_t                 srcArrayElement;
-    VkDescriptorSet          dstSet;
-    uint32_t                 dstBinding;
-    uint32_t                 dstArrayElement;
-    uint32_t                 descriptorCount;
-} VkCopyDescriptorSet;
-
-typedef struct VkDescriptorPoolSize {
-    VkDescriptorType         type;
-    uint32_t                 descriptorCount;
-} VkDescriptorPoolSize;
-
-typedef struct VkDescriptorSetAllocateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDescriptorPool         descriptorPool;
-    uint32_t                 descriptorSetCount;
-    const  VkDescriptorSetLayout *  pSetLayouts;
-} VkDescriptorSetAllocateInfo;
-
-typedef struct VkSpecializationMapEntry {
-    uint32_t                       constantID;
-    uint32_t                       offset;
-    size_t   size;
-} VkSpecializationMapEntry;
-
-typedef struct VkSpecializationInfo {
-    uint32_t                 mapEntryCount;
-    const  VkSpecializationMapEntry *  pMapEntries;
-    size_t                   dataSize;
-    const  void *             pData;
-} VkSpecializationInfo;
-
-typedef struct VkVertexInputBindingDescription {
-    uint32_t                 binding;
-    uint32_t                 stride;
-    VkVertexInputRate        inputRate;
-} VkVertexInputBindingDescription;
-
-typedef struct VkVertexInputAttributeDescription {
-    uint32_t                 location;
-    uint32_t                 binding;
-    VkFormat                 format;
-    uint32_t                 offset;
-} VkVertexInputAttributeDescription;
-
-typedef struct VkStencilOpState {
-    VkStencilOp              failOp;
-    VkStencilOp              passOp;
-    VkStencilOp              depthFailOp;
-    VkCompareOp              compareOp;
-    uint32_t                 compareMask;
-    uint32_t                 writeMask;
-    uint32_t                 reference;
-} VkStencilOpState;
-
-typedef struct VkPipelineCacheHeaderVersionOne {
-    uint32_t                 headerSize;
-    VkPipelineCacheHeaderVersion   headerVersion;
-    uint32_t                 vendorID;
-    uint32_t                 deviceID;
-    uint8_t                  pipelineCacheUUID [ VK_UUID_SIZE ];
-} VkPipelineCacheHeaderVersionOne;
-
-typedef struct VkCommandBufferAllocateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkCommandPool            commandPool;
-    VkCommandBufferLevel     level;
-    uint32_t                 commandBufferCount;
-} VkCommandBufferAllocateInfo;
-
-typedef union VkClearColorValue {
-    float                    float32 [4];
-    int32_t                  int32 [4];
-    uint32_t                 uint32 [4];
-} VkClearColorValue;
-
-typedef struct VkClearDepthStencilValue {
-    float                    depth;
-    uint32_t                 stencil;
-} VkClearDepthStencilValue;
-
-typedef union VkClearValue {
-    VkClearColorValue        color;
-    VkClearDepthStencilValue   depthStencil;
-} VkClearValue;
-
-typedef struct VkAttachmentReference {
-    uint32_t                 attachment;
-    VkImageLayout            layout;
-} VkAttachmentReference;
-
-typedef struct VkDrawIndirectCommand {
-    uint32_t                         vertexCount;
-    uint32_t                         instanceCount;
-    uint32_t                         firstVertex;
-    uint32_t   firstInstance;
-} VkDrawIndirectCommand;
-
-typedef struct VkDrawIndexedIndirectCommand {
-    uint32_t                         indexCount;
-    uint32_t                         instanceCount;
-    uint32_t                         firstIndex;
-    int32_t                          vertexOffset;
-    uint32_t   firstInstance;
-} VkDrawIndexedIndirectCommand;
-
-typedef struct VkDispatchIndirectCommand {
-    uint32_t   x;
-    uint32_t   y;
-    uint32_t   z;
-} VkDispatchIndirectCommand;
-
-typedef struct VkSurfaceFormatKHR {
-    VkFormat                           format;
-    VkColorSpaceKHR                    colorSpace;
-} VkSurfaceFormatKHR;
-
-typedef struct VkPresentInfoKHR {
-    VkStructureType   sType;
-    const  void *   pNext;
-    uint32_t           waitSemaphoreCount;
-    const  VkSemaphore *  pWaitSemaphores;
-    uint32_t                           swapchainCount;
-    const  VkSwapchainKHR *  pSwapchains;
-    const  uint32_t *  pImageIndices;
-    VkResult *  pResults;
-} VkPresentInfoKHR;
-
-typedef struct VkDevicePrivateDataCreateInfo {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    uint32_t                                 privateDataSlotRequestCount;
-} VkDevicePrivateDataCreateInfo;
-
-typedef struct VkConformanceVersion {
-    uint8_t                            major;
-    uint8_t                            minor;
-    uint8_t                            subminor;
-    uint8_t                            patch;
-} VkConformanceVersion;
-
-typedef struct VkPhysicalDeviceDriverProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkDriverId                    driverID;
-    char                          driverName [ VK_MAX_DRIVER_NAME_SIZE ];
-    char                          driverInfo [ VK_MAX_DRIVER_INFO_SIZE ];
-    VkConformanceVersion          conformanceVersion;
-} VkPhysicalDeviceDriverProperties;
-
-typedef struct VkPhysicalDeviceExternalImageFormatInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalMemoryHandleTypeFlagBits   handleType;
-} VkPhysicalDeviceExternalImageFormatInfo;
-
-typedef struct VkPhysicalDeviceExternalSemaphoreInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalSemaphoreHandleTypeFlagBits   handleType;
-} VkPhysicalDeviceExternalSemaphoreInfo;
-
-typedef struct VkPhysicalDeviceExternalFenceInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalFenceHandleTypeFlagBits   handleType;
-} VkPhysicalDeviceExternalFenceInfo;
-
-typedef struct VkPhysicalDeviceMultiviewProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    uint32_t                           maxMultiviewViewCount;
-    uint32_t                           maxMultiviewInstanceIndex;
-} VkPhysicalDeviceMultiviewProperties;
-
-typedef struct VkRenderPassMultiviewCreateInfo {
-    VkStructureType          sType;
-    const  void *             pNext;
-    uint32_t                 subpassCount;
-    const  uint32_t *      pViewMasks;
-    uint32_t                 dependencyCount;
-    const  int32_t *    pViewOffsets;
-    uint32_t                 correlationMaskCount;
-    const  uint32_t *  pCorrelationMasks;
-} VkRenderPassMultiviewCreateInfo;
-
-typedef struct VkBindBufferMemoryDeviceGroupInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t           deviceIndexCount;
-    const  uint32_t *   pDeviceIndices;
-} VkBindBufferMemoryDeviceGroupInfo;
-
-typedef struct VkBindImageMemoryDeviceGroupInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t           deviceIndexCount;
-    const  uint32_t *   pDeviceIndices;
-    uint32_t           splitInstanceBindRegionCount;
-    const  VkRect2D *   pSplitInstanceBindRegions;
-} VkBindImageMemoryDeviceGroupInfo;
-
-typedef struct VkDeviceGroupRenderPassBeginInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t                           deviceMask;
-    uint32_t           deviceRenderAreaCount;
-    const  VkRect2D *   pDeviceRenderAreas;
-} VkDeviceGroupRenderPassBeginInfo;
-
-typedef struct VkDeviceGroupCommandBufferBeginInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t                           deviceMask;
-} VkDeviceGroupCommandBufferBeginInfo;
-
-typedef struct VkDeviceGroupSubmitInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t           waitSemaphoreCount;
-    const  uint32_t *     pWaitSemaphoreDeviceIndices;
-    uint32_t           commandBufferCount;
-    const  uint32_t *     pCommandBufferDeviceMasks;
-    uint32_t           signalSemaphoreCount;
-    const  uint32_t *   pSignalSemaphoreDeviceIndices;
-} VkDeviceGroupSubmitInfo;
-
-typedef struct VkDeviceGroupBindSparseInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t                           resourceDeviceIndex;
-    uint32_t                           memoryDeviceIndex;
-} VkDeviceGroupBindSparseInfo;
-
-typedef struct VkImageSwapchainCreateInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSwapchainKHR     swapchain;
-} VkImageSwapchainCreateInfoKHR;
-
-typedef struct VkBindImageMemorySwapchainInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSwapchainKHR   swapchain;
-    uint32_t                           imageIndex;
-} VkBindImageMemorySwapchainInfoKHR;
-
-typedef struct VkAcquireNextImageInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSwapchainKHR   swapchain;
-    uint64_t                           timeout;
-    VkSemaphore   semaphore;
-    VkFence   fence;
-    uint32_t                           deviceMask;
-} VkAcquireNextImageInfoKHR;
-
-typedef struct VkDeviceGroupPresentInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t           swapchainCount;
-    const  uint32_t *  pDeviceMasks;
-    VkDeviceGroupPresentModeFlagBitsKHR   mode;
-} VkDeviceGroupPresentInfoKHR;
-
-typedef struct VkDeviceGroupDeviceCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t                           physicalDeviceCount;
-    const  VkPhysicalDevice *   pPhysicalDevices;
-} VkDeviceGroupDeviceCreateInfo;
-
-typedef struct VkDescriptorUpdateTemplateEntry {
-    uint32_t                           dstBinding;
-    uint32_t                           dstArrayElement;
-    uint32_t                           descriptorCount;
-    VkDescriptorType                   descriptorType;
-    size_t                             offset;
-    size_t                             stride;
-} VkDescriptorUpdateTemplateEntry;
-
-typedef struct VkBufferMemoryRequirementsInfo2 {
-    VkStructureType   sType;
-    const  void *                                                           pNext;
-    VkBuffer                                                               buffer;
-} VkBufferMemoryRequirementsInfo2;
-
-typedef struct VkImageMemoryRequirementsInfo2 {
-    VkStructureType   sType;
-    const  void *                                                           pNext;
-    VkImage                                                                image;
-} VkImageMemoryRequirementsInfo2;
-
-typedef struct VkImageSparseMemoryRequirementsInfo2 {
-    VkStructureType   sType;
-    const  void *                                                           pNext;
-    VkImage                                                                image;
-} VkImageSparseMemoryRequirementsInfo2;
-
-typedef struct VkPhysicalDevicePointClippingProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkPointClippingBehavior       pointClippingBehavior;
-} VkPhysicalDevicePointClippingProperties;
-
-typedef struct VkMemoryDedicatedAllocateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkImage            image;
-    VkBuffer           buffer;
-} VkMemoryDedicatedAllocateInfo;
-
-typedef struct VkPipelineTessellationDomainOriginStateCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkTessellationDomainOrigin      domainOrigin;
-} VkPipelineTessellationDomainOriginStateCreateInfo;
-
-typedef struct VkSamplerYcbcrConversionInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSamplerYcbcrConversion        conversion;
-} VkSamplerYcbcrConversionInfo;
-
-typedef struct VkBindImagePlaneMemoryInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkImageAspectFlagBits              planeAspect;
-} VkBindImagePlaneMemoryInfo;
-
-typedef struct VkImagePlaneMemoryRequirementsInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkImageAspectFlagBits              planeAspect;
-} VkImagePlaneMemoryRequirementsInfo;
-
-typedef struct VkSamplerYcbcrConversionImageFormatProperties {
-    VkStructureType   sType;
-    void *       pNext;
-    uint32_t                           combinedImageSamplerDescriptorCount;
-} VkSamplerYcbcrConversionImageFormatProperties;
-
-typedef struct VkSamplerReductionModeCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSamplerReductionMode             reductionMode;
-} VkSamplerReductionModeCreateInfo;
-
-typedef struct VkPhysicalDeviceInlineUniformBlockProperties {
-    VkStructureType   sType;
-    void *                   pNext;
-    uint32_t                 maxInlineUniformBlockSize;
-    uint32_t                 maxPerStageDescriptorInlineUniformBlocks;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
-    uint32_t                 maxDescriptorSetInlineUniformBlocks;
-    uint32_t                 maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
-} VkPhysicalDeviceInlineUniformBlockProperties;
-
-typedef struct VkWriteDescriptorSetInlineUniformBlock {
-    VkStructureType   sType;
-    const  void *  pNext;
-    uint32_t                      dataSize;
-    const  void *   pData;
-} VkWriteDescriptorSetInlineUniformBlock;
-
-typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo {
-    VkStructureType   sType;
-    const  void *  pNext;
-    uint32_t                      maxInlineUniformBlockBindings;
-} VkDescriptorPoolInlineUniformBlockCreateInfo;
-
-typedef struct VkImageFormatListCreateInfo {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    uint32_t                 viewFormatCount;
-    const  VkFormat *   pViewFormats;
-} VkImageFormatListCreateInfo;
-
-typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    uint32_t                 descriptorSetCount;
-    const  uint32_t *  pDescriptorCounts;
-} VkDescriptorSetVariableDescriptorCountAllocateInfo;
-
-typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport {
-    VkStructureType   sType;
-    void *             pNext;
-    uint32_t           maxVariableDescriptorCount;
-} VkDescriptorSetVariableDescriptorCountLayoutSupport;
-
-typedef struct VkSubpassBeginInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSubpassContents        contents;
-} VkSubpassBeginInfo;
-
-typedef struct VkSubpassEndInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-} VkSubpassEndInfo;
-
-typedef struct VkPhysicalDeviceTimelineSemaphoreProperties {
-    VkStructureType   sType;
-    void *                   pNext;
-    uint64_t                 maxTimelineSemaphoreValueDifference;
-} VkPhysicalDeviceTimelineSemaphoreProperties;
-
-typedef struct VkSemaphoreTypeCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSemaphoreType          semaphoreType;
-    uint64_t                 initialValue;
-} VkSemaphoreTypeCreateInfo;
-
-typedef struct VkTimelineSemaphoreSubmitInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint32_t           waitSemaphoreValueCount;
-    const  uint64_t *  pWaitSemaphoreValues;
-    uint32_t           signalSemaphoreValueCount;
-    const  uint64_t *  pSignalSemaphoreValues;
-} VkTimelineSemaphoreSubmitInfo;
-
-typedef struct VkSemaphoreSignalInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSemaphore              semaphore;
-    uint64_t                 value;
-} VkSemaphoreSignalInfo;
-
-typedef struct VkBufferDeviceAddressInfo {
-    VkStructureType   sType;
-    const  void *                                             pNext;
-    VkBuffer                                                 buffer;
-} VkBufferDeviceAddressInfo;
-
-typedef struct VkBufferOpaqueCaptureAddressCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    uint64_t                           opaqueCaptureAddress;
-} VkBufferOpaqueCaptureAddressCreateInfo;
-
-typedef struct VkRenderPassAttachmentBeginInfo {
-    VkStructureType   sType;
-    const  void *                               pNext;
-    uint32_t                   attachmentCount;
-    const  VkImageView *  pAttachments;
-} VkRenderPassAttachmentBeginInfo;
-
-typedef struct VkAttachmentReferenceStencilLayout {
-    VkStructureType sType;
-    void *     pNext;
-    VkImageLayout                    stencilLayout;
-} VkAttachmentReferenceStencilLayout;
-
-typedef struct VkAttachmentDescriptionStencilLayout {
-    VkStructureType sType;
-    void *     pNext;
-    VkImageLayout                    stencilInitialLayout;
-    VkImageLayout                    stencilFinalLayout;
-} VkAttachmentDescriptionStencilLayout;
-
-typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo {
-    VkStructureType   sType;
-    void *   pNext;
-    uint32_t                 requiredSubgroupSize;
-} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo;
-
-typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo {
-    VkStructureType   sType;
-    const  void *                    pNext;
-    uint64_t                        opaqueCaptureAddress;
-} VkMemoryOpaqueCaptureAddressAllocateInfo;
-
-typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkDeviceMemory                     memory;
-} VkDeviceMemoryOpaqueCaptureAddressInfo;
-
-typedef struct VkCommandBufferSubmitInfo {
-    VkStructureType        sType;
-    const  void *                                                                 pNext;
-    VkCommandBuffer                                                              commandBuffer;
-    uint32_t                                                                     deviceMask;
-} VkCommandBufferSubmitInfo;
-
-typedef struct VkPipelineRenderingCreateInfo {
-    VkStructureType   sType;
-    const  void *                                                 pNext;
-    uint32_t                                                                     viewMask;
-    uint32_t                                                     colorAttachmentCount;
-    const  VkFormat *            pColorAttachmentFormats;
-    VkFormat                                               depthAttachmentFormat;
-    VkFormat                                               stencilAttachmentFormat;
-} VkPipelineRenderingCreateInfo;
-
-typedef struct VkRenderingAttachmentInfo {
-    VkStructureType         sType;
-    const  void *                                                 pNext;
-    VkImageView                                                  imageView;
-    VkImageLayout                                                                imageLayout;
-    VkResolveModeFlagBits                                        resolveMode;
-    VkImageView                                                  resolveImageView;
-    VkImageLayout                                                                resolveImageLayout;
-    VkAttachmentLoadOp                                                           loadOp;
-    VkAttachmentStoreOp                                                          storeOp;
-    VkClearValue                                                                 clearValue;
-} VkRenderingAttachmentInfo;
-
-typedef uint32_t VkSampleMask;
-typedef uint32_t VkBool32;
-typedef uint32_t VkFlags;
-typedef uint64_t VkFlags64;
-typedef uint64_t VkDeviceSize;
-typedef uint64_t VkDeviceAddress;
-typedef VkFlags VkFramebufferCreateFlags;
-typedef VkFlags VkQueryPoolCreateFlags;
-typedef VkFlags VkRenderPassCreateFlags;
-typedef VkFlags VkSamplerCreateFlags;
-typedef VkFlags VkPipelineLayoutCreateFlags;
-typedef VkFlags VkPipelineCacheCreateFlags;
-typedef VkFlags VkPipelineDepthStencilStateCreateFlags;
-typedef VkFlags VkPipelineDynamicStateCreateFlags;
-typedef VkFlags VkPipelineColorBlendStateCreateFlags;
-typedef VkFlags VkPipelineMultisampleStateCreateFlags;
-typedef VkFlags VkPipelineRasterizationStateCreateFlags;
-typedef VkFlags VkPipelineViewportStateCreateFlags;
-typedef VkFlags VkPipelineTessellationStateCreateFlags;
-typedef VkFlags VkPipelineInputAssemblyStateCreateFlags;
-typedef VkFlags VkPipelineVertexInputStateCreateFlags;
-typedef VkFlags VkPipelineShaderStageCreateFlags;
-typedef VkFlags VkDescriptorSetLayoutCreateFlags;
-typedef VkFlags VkBufferViewCreateFlags;
-typedef VkFlags VkInstanceCreateFlags;
-typedef VkFlags VkDeviceCreateFlags;
-typedef VkFlags VkDeviceQueueCreateFlags;
-typedef VkFlags VkQueueFlags;
-typedef VkFlags VkMemoryPropertyFlags;
-typedef VkFlags VkMemoryHeapFlags;
-typedef VkFlags VkAccessFlags;
-typedef VkFlags VkBufferUsageFlags;
-typedef VkFlags VkBufferCreateFlags;
-typedef VkFlags VkShaderStageFlags;
-typedef VkFlags VkImageUsageFlags;
-typedef VkFlags VkImageCreateFlags;
-typedef VkFlags VkImageViewCreateFlags;
-typedef VkFlags VkPipelineCreateFlags;
-typedef VkFlags VkColorComponentFlags;
-typedef VkFlags VkFenceCreateFlags;
-typedef VkFlags VkSemaphoreCreateFlags;
-typedef VkFlags VkFormatFeatureFlags;
-typedef VkFlags VkQueryControlFlags;
-typedef VkFlags VkQueryResultFlags;
-typedef VkFlags VkShaderModuleCreateFlags;
-typedef VkFlags VkEventCreateFlags;
-typedef VkFlags VkCommandPoolCreateFlags;
-typedef VkFlags VkCommandPoolResetFlags;
-typedef VkFlags VkCommandBufferResetFlags;
-typedef VkFlags VkCommandBufferUsageFlags;
-typedef VkFlags VkQueryPipelineStatisticFlags;
-typedef VkFlags VkMemoryMapFlags;
-typedef VkFlags VkImageAspectFlags;
-typedef VkFlags VkSparseMemoryBindFlags;
-typedef VkFlags VkSparseImageFormatFlags;
-typedef VkFlags VkSubpassDescriptionFlags;
-typedef VkFlags VkPipelineStageFlags;
-typedef VkFlags VkSampleCountFlags;
-typedef VkFlags VkAttachmentDescriptionFlags;
-typedef VkFlags VkStencilFaceFlags;
-typedef VkFlags VkCullModeFlags;
-typedef VkFlags VkDescriptorPoolCreateFlags;
-typedef VkFlags VkDescriptorPoolResetFlags;
-typedef VkFlags VkDependencyFlags;
-typedef VkFlags VkSubgroupFeatureFlags;
-typedef VkFlags VkPrivateDataSlotCreateFlags;
-typedef VkFlags VkDescriptorUpdateTemplateCreateFlags;
-typedef VkFlags VkPipelineCreationFeedbackFlags;
-typedef VkFlags VkSemaphoreWaitFlags;
-typedef VkFlags64 VkAccessFlags2;
-typedef VkFlags64 VkPipelineStageFlags2;
-typedef VkFlags64 VkFormatFeatureFlags2;
-typedef VkFlags VkRenderingFlags;
-typedef VkFlags VkCompositeAlphaFlagsKHR;
-typedef VkFlags VkSurfaceTransformFlagsKHR;
-typedef VkFlags VkSwapchainCreateFlagsKHR;
-typedef VkFlags VkPeerMemoryFeatureFlags;
-typedef VkFlags VkMemoryAllocateFlags;
-typedef VkFlags VkDeviceGroupPresentModeFlagsKHR;
-typedef VkFlags VkDebugReportFlagsEXT;
-typedef VkFlags VkCommandPoolTrimFlags;
-typedef VkFlags VkExternalMemoryHandleTypeFlags;
-typedef VkFlags VkExternalMemoryFeatureFlags;
-typedef VkFlags VkExternalSemaphoreHandleTypeFlags;
-typedef VkFlags VkExternalSemaphoreFeatureFlags;
-typedef VkFlags VkSemaphoreImportFlags;
-typedef VkFlags VkExternalFenceHandleTypeFlags;
-typedef VkFlags VkExternalFenceFeatureFlags;
-typedef VkFlags VkFenceImportFlags;
-typedef VkFlags VkDescriptorBindingFlags;
-typedef VkFlags VkResolveModeFlags;
-typedef VkFlags VkToolPurposeFlags;
-typedef VkFlags VkSubmitFlags;
-typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
-    VkDebugReportFlagsEXT                       flags,
-    VkDebugReportObjectTypeEXT                  objectType,
-    uint64_t                                    object,
-    size_t                                      location,
-    int32_t                                     messageCode,
-    const char*                                 pLayerPrefix,
-    const char*                                 pMessage,
-    void*                                       pUserData);
-typedef struct VkDeviceQueueCreateInfo {
-    VkStructureType   sType;
-    const  void *      pNext;
-    VkDeviceQueueCreateFlags      flags;
-    uint32_t          queueFamilyIndex;
-    uint32_t          queueCount;
-    const  float *     pQueuePriorities;
-} VkDeviceQueueCreateInfo;
-
-typedef struct VkInstanceCreateInfo {
-    VkStructureType   sType;
-    const  void *      pNext;
-    VkInstanceCreateFlags    flags;
-    const  VkApplicationInfo *  pApplicationInfo;
-    uint32_t                 enabledLayerCount;
-    const  char * const*       ppEnabledLayerNames;
-    uint32_t                 enabledExtensionCount;
-    const  char * const*       ppEnabledExtensionNames;
-} VkInstanceCreateInfo;
-
-typedef struct VkQueueFamilyProperties {
-    VkQueueFlags             queueFlags;
-    uint32_t                 queueCount;
-    uint32_t                 timestampValidBits;
-    VkExtent3D               minImageTransferGranularity;
-} VkQueueFamilyProperties;
-
-typedef struct VkMemoryAllocateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDeviceSize             allocationSize;
-    uint32_t                 memoryTypeIndex;
-} VkMemoryAllocateInfo;
-
-typedef struct VkMemoryRequirements {
-    VkDeviceSize             size;
-    VkDeviceSize             alignment;
-    uint32_t                 memoryTypeBits;
-} VkMemoryRequirements;
-
-typedef struct VkSparseImageFormatProperties {
-    VkImageAspectFlags         aspectMask;
-    VkExtent3D                                  imageGranularity;
-    VkSparseImageFormatFlags   flags;
-} VkSparseImageFormatProperties;
-
-typedef struct VkSparseImageMemoryRequirements {
-    VkSparseImageFormatProperties   formatProperties;
-    uint32_t                 imageMipTailFirstLod;
-    VkDeviceSize             imageMipTailSize;
-    VkDeviceSize             imageMipTailOffset;
-    VkDeviceSize             imageMipTailStride;
-} VkSparseImageMemoryRequirements;
-
-typedef struct VkMemoryType {
-    VkMemoryPropertyFlags    propertyFlags;
-    uint32_t                 heapIndex;
-} VkMemoryType;
-
-typedef struct VkMemoryHeap {
-    VkDeviceSize             size;
-    VkMemoryHeapFlags        flags;
-} VkMemoryHeap;
-
-typedef struct VkMappedMemoryRange {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDeviceMemory           memory;
-    VkDeviceSize             offset;
-    VkDeviceSize             size;
-} VkMappedMemoryRange;
-
-typedef struct VkFormatProperties {
-    VkFormatFeatureFlags     linearTilingFeatures;
-    VkFormatFeatureFlags     optimalTilingFeatures;
-    VkFormatFeatureFlags     bufferFeatures;
-} VkFormatProperties;
-
-typedef struct VkImageFormatProperties {
-    VkExtent3D               maxExtent;
-    uint32_t                 maxMipLevels;
-    uint32_t                 maxArrayLayers;
-    VkSampleCountFlags       sampleCounts;
-    VkDeviceSize             maxResourceSize;
-} VkImageFormatProperties;
-
-typedef struct VkDescriptorBufferInfo {
-    VkBuffer                 buffer;
-    VkDeviceSize             offset;
-    VkDeviceSize             range;
-} VkDescriptorBufferInfo;
-
-typedef struct VkWriteDescriptorSet {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDescriptorSet          dstSet;
-    uint32_t                 dstBinding;
-    uint32_t                 dstArrayElement;
-    uint32_t                 descriptorCount;
-    VkDescriptorType         descriptorType;
-    const  VkDescriptorImageInfo *  pImageInfo;
-    const  VkDescriptorBufferInfo *  pBufferInfo;
-    const  VkBufferView *     pTexelBufferView;
-} VkWriteDescriptorSet;
-
-typedef struct VkBufferCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkBufferCreateFlags      flags;
-    VkDeviceSize             size;
-    VkBufferUsageFlags       usage;
-    VkSharingMode            sharingMode;
-    uint32_t                 queueFamilyIndexCount;
-    const  uint32_t *         pQueueFamilyIndices;
-} VkBufferCreateInfo;
-
-typedef struct VkBufferViewCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkBufferViewCreateFlags flags;
-    VkBuffer                 buffer;
-    VkFormat                 format;
-    VkDeviceSize             offset;
-    VkDeviceSize             range;
-} VkBufferViewCreateInfo;
-
-typedef struct VkImageSubresource {
-    VkImageAspectFlags       aspectMask;
-    uint32_t                 mipLevel;
-    uint32_t                 arrayLayer;
-} VkImageSubresource;
-
-typedef struct VkImageSubresourceLayers {
-    VkImageAspectFlags       aspectMask;
-    uint32_t                 mipLevel;
-    uint32_t                 baseArrayLayer;
-    uint32_t                 layerCount;
-} VkImageSubresourceLayers;
-
-typedef struct VkImageSubresourceRange {
-    VkImageAspectFlags       aspectMask;
-    uint32_t                 baseMipLevel;
-    uint32_t                 levelCount;
-    uint32_t                 baseArrayLayer;
-    uint32_t                 layerCount;
-} VkImageSubresourceRange;
-
-typedef struct VkMemoryBarrier {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkAccessFlags            srcAccessMask;
-    VkAccessFlags            dstAccessMask;
-} VkMemoryBarrier;
-
-typedef struct VkBufferMemoryBarrier {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkAccessFlags            srcAccessMask;
-    VkAccessFlags            dstAccessMask;
-    uint32_t                 srcQueueFamilyIndex;
-    uint32_t                 dstQueueFamilyIndex;
-    VkBuffer                 buffer;
-    VkDeviceSize             offset;
-    VkDeviceSize             size;
-} VkBufferMemoryBarrier;
-
-typedef struct VkImageMemoryBarrier {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkAccessFlags            srcAccessMask;
-    VkAccessFlags            dstAccessMask;
-    VkImageLayout            oldLayout;
-    VkImageLayout            newLayout;
-    uint32_t                 srcQueueFamilyIndex;
-    uint32_t                 dstQueueFamilyIndex;
-    VkImage                  image;
-    VkImageSubresourceRange   subresourceRange;
-} VkImageMemoryBarrier;
-
-typedef struct VkImageCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkImageCreateFlags       flags;
-    VkImageType              imageType;
-    VkFormat                 format;
-    VkExtent3D               extent;
-    uint32_t                 mipLevels;
-    uint32_t                 arrayLayers;
-    VkSampleCountFlagBits    samples;
-    VkImageTiling            tiling;
-    VkImageUsageFlags        usage;
-    VkSharingMode            sharingMode;
-    uint32_t                 queueFamilyIndexCount;
-    const  uint32_t *         pQueueFamilyIndices;
-    VkImageLayout            initialLayout;
-} VkImageCreateInfo;
-
-typedef struct VkSubresourceLayout {
-    VkDeviceSize             offset;
-    VkDeviceSize             size;
-    VkDeviceSize             rowPitch;
-    VkDeviceSize             arrayPitch;
-    VkDeviceSize             depthPitch;
-} VkSubresourceLayout;
-
-typedef struct VkImageViewCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkImageViewCreateFlags   flags;
-    VkImage                  image;
-    VkImageViewType          viewType;
-    VkFormat                 format;
-    VkComponentMapping       components;
-    VkImageSubresourceRange   subresourceRange;
-} VkImageViewCreateInfo;
-
-typedef struct VkBufferCopy {
-    VkDeviceSize                         srcOffset;
-    VkDeviceSize                         dstOffset;
-    VkDeviceSize   size;
-} VkBufferCopy;
-
-typedef struct VkSparseMemoryBind {
-    VkDeviceSize             resourceOffset;
-    VkDeviceSize             size;
-    VkDeviceMemory           memory;
-    VkDeviceSize             memoryOffset;
-    VkSparseMemoryBindFlags flags;
-} VkSparseMemoryBind;
-
-typedef struct VkSparseImageMemoryBind {
-    VkImageSubresource       subresource;
-    VkOffset3D               offset;
-    VkExtent3D               extent;
-    VkDeviceMemory           memory;
-    VkDeviceSize             memoryOffset;
-    VkSparseMemoryBindFlags flags;
-} VkSparseImageMemoryBind;
-
-typedef struct VkSparseBufferMemoryBindInfo {
-    VkBuffer   buffer;
-    uint32_t                 bindCount;
-    const  VkSparseMemoryBind *  pBinds;
-} VkSparseBufferMemoryBindInfo;
-
-typedef struct VkSparseImageOpaqueMemoryBindInfo {
-    VkImage   image;
-    uint32_t                 bindCount;
-    const  VkSparseMemoryBind *  pBinds;
-} VkSparseImageOpaqueMemoryBindInfo;
-
-typedef struct VkSparseImageMemoryBindInfo {
-    VkImage   image;
-    uint32_t                 bindCount;
-    const  VkSparseImageMemoryBind *  pBinds;
-} VkSparseImageMemoryBindInfo;
-
-typedef struct VkBindSparseInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    uint32_t                 waitSemaphoreCount;
-    const  VkSemaphore *      pWaitSemaphores;
-    uint32_t                 bufferBindCount;
-    const  VkSparseBufferMemoryBindInfo *  pBufferBinds;
-    uint32_t                 imageOpaqueBindCount;
-    const  VkSparseImageOpaqueMemoryBindInfo *  pImageOpaqueBinds;
-    uint32_t                 imageBindCount;
-    const  VkSparseImageMemoryBindInfo *  pImageBinds;
-    uint32_t                 signalSemaphoreCount;
-    const  VkSemaphore *      pSignalSemaphores;
-} VkBindSparseInfo;
-
-typedef struct VkImageCopy {
-    VkImageSubresourceLayers   srcSubresource;
-    VkOffset3D               srcOffset;
-    VkImageSubresourceLayers   dstSubresource;
-    VkOffset3D               dstOffset;
-    VkExtent3D               extent;
-} VkImageCopy;
-
-typedef struct VkImageBlit {
-    VkImageSubresourceLayers   srcSubresource;
-    VkOffset3D               srcOffsets [2];
-    VkImageSubresourceLayers   dstSubresource;
-    VkOffset3D               dstOffsets [2];
-} VkImageBlit;
-
-typedef struct VkBufferImageCopy {
-    VkDeviceSize             bufferOffset;
-    uint32_t                 bufferRowLength;
-    uint32_t                 bufferImageHeight;
-    VkImageSubresourceLayers   imageSubresource;
-    VkOffset3D               imageOffset;
-    VkExtent3D               imageExtent;
-} VkBufferImageCopy;
-
-typedef struct VkImageResolve {
-    VkImageSubresourceLayers   srcSubresource;
-    VkOffset3D               srcOffset;
-    VkImageSubresourceLayers   dstSubresource;
-    VkOffset3D               dstOffset;
-    VkExtent3D               extent;
-} VkImageResolve;
-
-typedef struct VkShaderModuleCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkShaderModuleCreateFlags   flags;
-    size_t                   codeSize;
-    const  uint32_t *             pCode;
-} VkShaderModuleCreateInfo;
-
-typedef struct VkDescriptorSetLayoutBinding {
-    uint32_t                 binding;
-    VkDescriptorType         descriptorType;
-    uint32_t   descriptorCount;
-    VkShaderStageFlags       stageFlags;
-    const  VkSampler *        pImmutableSamplers;
-} VkDescriptorSetLayoutBinding;
-
-typedef struct VkDescriptorSetLayoutCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDescriptorSetLayoutCreateFlags      flags;
-    uint32_t                 bindingCount;
-    const  VkDescriptorSetLayoutBinding *  pBindings;
-} VkDescriptorSetLayoutCreateInfo;
-
-typedef struct VkDescriptorPoolCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkDescriptorPoolCreateFlags    flags;
-    uint32_t                 maxSets;
-    uint32_t                 poolSizeCount;
-    const  VkDescriptorPoolSize *  pPoolSizes;
-} VkDescriptorPoolCreateInfo;
-
-typedef struct VkPipelineShaderStageCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineShaderStageCreateFlags      flags;
-    VkShaderStageFlagBits    stage;
-    VkShaderModule           module;
-    const  char *             pName;
-    const  VkSpecializationInfo *  pSpecializationInfo;
-} VkPipelineShaderStageCreateInfo;
-
-typedef struct VkComputePipelineCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineCreateFlags    flags;
-    VkPipelineShaderStageCreateInfo   stage;
-    VkPipelineLayout         layout;
-    VkPipeline        basePipelineHandle;
-    int32_t                  basePipelineIndex;
-} VkComputePipelineCreateInfo;
-
-typedef struct VkPipelineVertexInputStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineVertexInputStateCreateFlags      flags;
-    uint32_t                 vertexBindingDescriptionCount;
-    const  VkVertexInputBindingDescription *  pVertexBindingDescriptions;
-    uint32_t                 vertexAttributeDescriptionCount;
-    const  VkVertexInputAttributeDescription *  pVertexAttributeDescriptions;
-} VkPipelineVertexInputStateCreateInfo;
-
-typedef struct VkPipelineInputAssemblyStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineInputAssemblyStateCreateFlags      flags;
-    VkPrimitiveTopology      topology;
-    VkBool32                 primitiveRestartEnable;
-} VkPipelineInputAssemblyStateCreateInfo;
-
-typedef struct VkPipelineTessellationStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineTessellationStateCreateFlags      flags;
-    uint32_t                 patchControlPoints;
-} VkPipelineTessellationStateCreateInfo;
-
-typedef struct VkPipelineViewportStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineViewportStateCreateFlags      flags;
-    uint32_t                 viewportCount;
-    const  VkViewport *       pViewports;
-    uint32_t                 scissorCount;
-    const  VkRect2D *         pScissors;
-} VkPipelineViewportStateCreateInfo;
-
-typedef struct VkPipelineRasterizationStateCreateInfo {
-    VkStructureType   sType;
-    const  void *  pNext;
-    VkPipelineRasterizationStateCreateFlags      flags;
-    VkBool32                 depthClampEnable;
-    VkBool32                 rasterizerDiscardEnable;
-    VkPolygonMode            polygonMode;
-    VkCullModeFlags          cullMode;
-    VkFrontFace              frontFace;
-    VkBool32                 depthBiasEnable;
-    float                    depthBiasConstantFactor;
-    float                    depthBiasClamp;
-    float                    depthBiasSlopeFactor;
-    float                    lineWidth;
-} VkPipelineRasterizationStateCreateInfo;
-
-typedef struct VkPipelineMultisampleStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineMultisampleStateCreateFlags      flags;
-    VkSampleCountFlagBits    rasterizationSamples;
-    VkBool32                 sampleShadingEnable;
-    float                    minSampleShading;
-    const  VkSampleMask *     pSampleMask;
-    VkBool32                 alphaToCoverageEnable;
-    VkBool32                 alphaToOneEnable;
-} VkPipelineMultisampleStateCreateInfo;
-
-typedef struct VkPipelineColorBlendAttachmentState {
-    VkBool32                 blendEnable;
-    VkBlendFactor            srcColorBlendFactor;
-    VkBlendFactor            dstColorBlendFactor;
-    VkBlendOp                colorBlendOp;
-    VkBlendFactor            srcAlphaBlendFactor;
-    VkBlendFactor            dstAlphaBlendFactor;
-    VkBlendOp                alphaBlendOp;
-    VkColorComponentFlags    colorWriteMask;
-} VkPipelineColorBlendAttachmentState;
-
-typedef struct VkPipelineColorBlendStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineColorBlendStateCreateFlags      flags;
-    VkBool32                 logicOpEnable;
-    VkLogicOp                logicOp;
-    uint32_t                 attachmentCount;
-    const  VkPipelineColorBlendAttachmentState *  pAttachments;
-    float                    blendConstants [4];
-} VkPipelineColorBlendStateCreateInfo;
-
-typedef struct VkPipelineDynamicStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineDynamicStateCreateFlags      flags;
-    uint32_t                 dynamicStateCount;
-    const  VkDynamicState *   pDynamicStates;
-} VkPipelineDynamicStateCreateInfo;
-
-typedef struct VkPipelineDepthStencilStateCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineDepthStencilStateCreateFlags      flags;
-    VkBool32                 depthTestEnable;
-    VkBool32                 depthWriteEnable;
-    VkCompareOp              depthCompareOp;
-    VkBool32                 depthBoundsTestEnable;
-    VkBool32                 stencilTestEnable;
-    VkStencilOpState         front;
-    VkStencilOpState         back;
-    float                    minDepthBounds;
-    float                    maxDepthBounds;
-} VkPipelineDepthStencilStateCreateInfo;
-
-typedef struct VkGraphicsPipelineCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineCreateFlags    flags;
-    uint32_t                 stageCount;
-    const  VkPipelineShaderStageCreateInfo *  pStages;
-    const  VkPipelineVertexInputStateCreateInfo *  pVertexInputState;
-    const  VkPipelineInputAssemblyStateCreateInfo *  pInputAssemblyState;
-    const  VkPipelineTessellationStateCreateInfo *  pTessellationState;
-    const  VkPipelineViewportStateCreateInfo *  pViewportState;
-    const  VkPipelineRasterizationStateCreateInfo *  pRasterizationState;
-    const  VkPipelineMultisampleStateCreateInfo *  pMultisampleState;
-    const  VkPipelineDepthStencilStateCreateInfo *  pDepthStencilState;
-    const  VkPipelineColorBlendStateCreateInfo *  pColorBlendState;
-    const  VkPipelineDynamicStateCreateInfo *  pDynamicState;
-    VkPipelineLayout         layout;
-    VkRenderPass             renderPass;
-    uint32_t                 subpass;
-    VkPipeline        basePipelineHandle;
-    int32_t                  basePipelineIndex;
-} VkGraphicsPipelineCreateInfo;
-
-typedef struct VkPipelineCacheCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineCacheCreateFlags      flags;
-    size_t                   initialDataSize;
-    const  void *             pInitialData;
-} VkPipelineCacheCreateInfo;
-
-typedef struct VkPushConstantRange {
-    VkShaderStageFlags       stageFlags;
-    uint32_t                 offset;
-    uint32_t                 size;
-} VkPushConstantRange;
-
-typedef struct VkPipelineLayoutCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkPipelineLayoutCreateFlags      flags;
-    uint32_t                 setLayoutCount;
-    const  VkDescriptorSetLayout *  pSetLayouts;
-    uint32_t                 pushConstantRangeCount;
-    const  VkPushConstantRange *  pPushConstantRanges;
-} VkPipelineLayoutCreateInfo;
-
-typedef struct VkSamplerCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSamplerCreateFlags     flags;
-    VkFilter                 magFilter;
-    VkFilter                 minFilter;
-    VkSamplerMipmapMode      mipmapMode;
-    VkSamplerAddressMode     addressModeU;
-    VkSamplerAddressMode     addressModeV;
-    VkSamplerAddressMode     addressModeW;
-    float                    mipLodBias;
-    VkBool32                 anisotropyEnable;
-    float                    maxAnisotropy;
-    VkBool32                 compareEnable;
-    VkCompareOp              compareOp;
-    float                    minLod;
-    float                    maxLod;
-    VkBorderColor            borderColor;
-    VkBool32                 unnormalizedCoordinates;
-} VkSamplerCreateInfo;
-
-typedef struct VkCommandPoolCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkCommandPoolCreateFlags     flags;
-    uint32_t                 queueFamilyIndex;
-} VkCommandPoolCreateInfo;
-
-typedef struct VkCommandBufferInheritanceInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkRenderPass      renderPass;
-    uint32_t                 subpass;
-    VkFramebuffer     framebuffer;
-    VkBool32                 occlusionQueryEnable;
-    VkQueryControlFlags      queryFlags;
-    VkQueryPipelineStatisticFlags   pipelineStatistics;
-} VkCommandBufferInheritanceInfo;
-
-typedef struct VkCommandBufferBeginInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkCommandBufferUsageFlags    flags;
-    const  VkCommandBufferInheritanceInfo *        pInheritanceInfo;
-} VkCommandBufferBeginInfo;
-
-typedef struct VkRenderPassBeginInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkRenderPass             renderPass;
-    VkFramebuffer            framebuffer;
-    VkRect2D                 renderArea;
-    uint32_t                 clearValueCount;
-    const  VkClearValue *     pClearValues;
-} VkRenderPassBeginInfo;
-
-typedef struct VkClearAttachment {
-    VkImageAspectFlags       aspectMask;
-    uint32_t                 colorAttachment;
-    VkClearValue             clearValue;
-} VkClearAttachment;
-
-typedef struct VkAttachmentDescription {
-    VkAttachmentDescriptionFlags   flags;
-    VkFormat                 format;
-    VkSampleCountFlagBits    samples;
-    VkAttachmentLoadOp       loadOp;
-    VkAttachmentStoreOp      storeOp;
-    VkAttachmentLoadOp       stencilLoadOp;
-    VkAttachmentStoreOp      stencilStoreOp;
-    VkImageLayout            initialLayout;
-    VkImageLayout            finalLayout;
-} VkAttachmentDescription;
-
-typedef struct VkSubpassDescription {
-    VkSubpassDescriptionFlags   flags;
-    VkPipelineBindPoint      pipelineBindPoint;
-    uint32_t                 inputAttachmentCount;
-    const  VkAttachmentReference *  pInputAttachments;
-    uint32_t                 colorAttachmentCount;
-    const  VkAttachmentReference *  pColorAttachments;
-    const  VkAttachmentReference *  pResolveAttachments;
-    const  VkAttachmentReference *  pDepthStencilAttachment;
-    uint32_t                 preserveAttachmentCount;
-    const  uint32_t *  pPreserveAttachments;
-} VkSubpassDescription;
-
-typedef struct VkSubpassDependency {
-    uint32_t                 srcSubpass;
-    uint32_t                 dstSubpass;
-    VkPipelineStageFlags     srcStageMask;
-    VkPipelineStageFlags     dstStageMask;
-    VkAccessFlags            srcAccessMask;
-    VkAccessFlags            dstAccessMask;
-    VkDependencyFlags        dependencyFlags;
-} VkSubpassDependency;
-
-typedef struct VkRenderPassCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkRenderPassCreateFlags   flags;
-    uint32_t     attachmentCount;
-    const  VkAttachmentDescription *  pAttachments;
-    uint32_t                 subpassCount;
-    const  VkSubpassDescription *  pSubpasses;
-    uint32_t         dependencyCount;
-    const  VkSubpassDependency *  pDependencies;
-} VkRenderPassCreateInfo;
-
-typedef struct VkEventCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkEventCreateFlags       flags;
-} VkEventCreateInfo;
-
-typedef struct VkFenceCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkFenceCreateFlags       flags;
-} VkFenceCreateInfo;
-
-typedef struct VkPhysicalDeviceFeatures {
-    VkBool32                 robustBufferAccess;
-    VkBool32                 fullDrawIndexUint32;
-    VkBool32                 imageCubeArray;
-    VkBool32                 independentBlend;
-    VkBool32                 geometryShader;
-    VkBool32                 tessellationShader;
-    VkBool32                 sampleRateShading;
-    VkBool32                 dualSrcBlend;
-    VkBool32                 logicOp;
-    VkBool32                 multiDrawIndirect;
-    VkBool32                 drawIndirectFirstInstance;
-    VkBool32                 depthClamp;
-    VkBool32                 depthBiasClamp;
-    VkBool32                 fillModeNonSolid;
-    VkBool32                 depthBounds;
-    VkBool32                 wideLines;
-    VkBool32                 largePoints;
-    VkBool32                 alphaToOne;
-    VkBool32                 multiViewport;
-    VkBool32                 samplerAnisotropy;
-    VkBool32                 textureCompressionETC2;
-    VkBool32                 textureCompressionASTC_LDR;
-    VkBool32                 textureCompressionBC;
-    VkBool32                 occlusionQueryPrecise;
-    VkBool32                 pipelineStatisticsQuery;
-    VkBool32                 vertexPipelineStoresAndAtomics;
-    VkBool32                 fragmentStoresAndAtomics;
-    VkBool32                 shaderTessellationAndGeometryPointSize;
-    VkBool32                 shaderImageGatherExtended;
-    VkBool32                 shaderStorageImageExtendedFormats;
-    VkBool32                 shaderStorageImageMultisample;
-    VkBool32                 shaderStorageImageReadWithoutFormat;
-    VkBool32                 shaderStorageImageWriteWithoutFormat;
-    VkBool32                 shaderUniformBufferArrayDynamicIndexing;
-    VkBool32                 shaderSampledImageArrayDynamicIndexing;
-    VkBool32                 shaderStorageBufferArrayDynamicIndexing;
-    VkBool32                 shaderStorageImageArrayDynamicIndexing;
-    VkBool32                 shaderClipDistance;
-    VkBool32                 shaderCullDistance;
-    VkBool32                 shaderFloat64;
-    VkBool32                 shaderInt64;
-    VkBool32                 shaderInt16;
-    VkBool32                 shaderResourceResidency;
-    VkBool32                 shaderResourceMinLod;
-    VkBool32                 sparseBinding;
-    VkBool32                 sparseResidencyBuffer;
-    VkBool32                 sparseResidencyImage2D;
-    VkBool32                 sparseResidencyImage3D;
-    VkBool32                 sparseResidency2Samples;
-    VkBool32                 sparseResidency4Samples;
-    VkBool32                 sparseResidency8Samples;
-    VkBool32                 sparseResidency16Samples;
-    VkBool32                 sparseResidencyAliased;
-    VkBool32                 variableMultisampleRate;
-    VkBool32                 inheritedQueries;
-} VkPhysicalDeviceFeatures;
-
-typedef struct VkPhysicalDeviceSparseProperties {
-    VkBool32             residencyStandard2DBlockShape;
-    VkBool32             residencyStandard2DMultisampleBlockShape;
-    VkBool32             residencyStandard3DBlockShape;
-    VkBool32             residencyAlignedMipSize;
-    VkBool32             residencyNonResidentStrict;
-} VkPhysicalDeviceSparseProperties;
-
-typedef struct VkPhysicalDeviceLimits {
-    uint32_t                 maxImageDimension1D;
-    uint32_t                 maxImageDimension2D;
-    uint32_t                 maxImageDimension3D;
-    uint32_t                 maxImageDimensionCube;
-    uint32_t                 maxImageArrayLayers;
-    uint32_t                 maxTexelBufferElements;
-    uint32_t                 maxUniformBufferRange;
-    uint32_t                 maxStorageBufferRange;
-    uint32_t                 maxPushConstantsSize;
-    uint32_t                 maxMemoryAllocationCount;
-    uint32_t                 maxSamplerAllocationCount;
-    VkDeviceSize             bufferImageGranularity;
-    VkDeviceSize             sparseAddressSpaceSize;
-    uint32_t                 maxBoundDescriptorSets;
-    uint32_t                 maxPerStageDescriptorSamplers;
-    uint32_t                 maxPerStageDescriptorUniformBuffers;
-    uint32_t                 maxPerStageDescriptorStorageBuffers;
-    uint32_t                 maxPerStageDescriptorSampledImages;
-    uint32_t                 maxPerStageDescriptorStorageImages;
-    uint32_t                 maxPerStageDescriptorInputAttachments;
-    uint32_t                 maxPerStageResources;
-    uint32_t                 maxDescriptorSetSamplers;
-    uint32_t                 maxDescriptorSetUniformBuffers;
-    uint32_t                 maxDescriptorSetUniformBuffersDynamic;
-    uint32_t                 maxDescriptorSetStorageBuffers;
-    uint32_t                 maxDescriptorSetStorageBuffersDynamic;
-    uint32_t                 maxDescriptorSetSampledImages;
-    uint32_t                 maxDescriptorSetStorageImages;
-    uint32_t                 maxDescriptorSetInputAttachments;
-    uint32_t                 maxVertexInputAttributes;
-    uint32_t                 maxVertexInputBindings;
-    uint32_t                 maxVertexInputAttributeOffset;
-    uint32_t                 maxVertexInputBindingStride;
-    uint32_t                 maxVertexOutputComponents;
-    uint32_t                 maxTessellationGenerationLevel;
-    uint32_t                 maxTessellationPatchSize;
-    uint32_t                 maxTessellationControlPerVertexInputComponents;
-    uint32_t                 maxTessellationControlPerVertexOutputComponents;
-    uint32_t                 maxTessellationControlPerPatchOutputComponents;
-    uint32_t                 maxTessellationControlTotalOutputComponents;
-    uint32_t                 maxTessellationEvaluationInputComponents;
-    uint32_t                 maxTessellationEvaluationOutputComponents;
-    uint32_t                 maxGeometryShaderInvocations;
-    uint32_t                 maxGeometryInputComponents;
-    uint32_t                 maxGeometryOutputComponents;
-    uint32_t                 maxGeometryOutputVertices;
-    uint32_t                 maxGeometryTotalOutputComponents;
-    uint32_t                 maxFragmentInputComponents;
-    uint32_t                 maxFragmentOutputAttachments;
-    uint32_t                 maxFragmentDualSrcAttachments;
-    uint32_t                 maxFragmentCombinedOutputResources;
-    uint32_t                 maxComputeSharedMemorySize;
-    uint32_t                 maxComputeWorkGroupCount [3];
-    uint32_t                 maxComputeWorkGroupInvocations;
-    uint32_t                 maxComputeWorkGroupSize [3];
-    uint32_t                subPixelPrecisionBits;
-    uint32_t                subTexelPrecisionBits;
-    uint32_t                mipmapPrecisionBits;
-    uint32_t                 maxDrawIndexedIndexValue;
-    uint32_t                 maxDrawIndirectCount;
-    float                    maxSamplerLodBias;
-    float                    maxSamplerAnisotropy;
-    uint32_t                 maxViewports;
-    uint32_t                 maxViewportDimensions [2];
-    float                  viewportBoundsRange [2];
-    uint32_t                viewportSubPixelBits;
-    size_t               minMemoryMapAlignment;
-    VkDeviceSize         minTexelBufferOffsetAlignment;
-    VkDeviceSize         minUniformBufferOffsetAlignment;
-    VkDeviceSize         minStorageBufferOffsetAlignment;
-    int32_t                  minTexelOffset;
-    uint32_t                 maxTexelOffset;
-    int32_t                  minTexelGatherOffset;
-    uint32_t                 maxTexelGatherOffset;
-    float                    minInterpolationOffset;
-    float                    maxInterpolationOffset;
-    uint32_t                subPixelInterpolationOffsetBits;
-    uint32_t                 maxFramebufferWidth;
-    uint32_t                 maxFramebufferHeight;
-    uint32_t                 maxFramebufferLayers;
-    VkSampleCountFlags       framebufferColorSampleCounts;
-    VkSampleCountFlags       framebufferDepthSampleCounts;
-    VkSampleCountFlags       framebufferStencilSampleCounts;
-    VkSampleCountFlags       framebufferNoAttachmentsSampleCounts;
-    uint32_t                 maxColorAttachments;
-    VkSampleCountFlags       sampledImageColorSampleCounts;
-    VkSampleCountFlags       sampledImageIntegerSampleCounts;
-    VkSampleCountFlags       sampledImageDepthSampleCounts;
-    VkSampleCountFlags       sampledImageStencilSampleCounts;
-    VkSampleCountFlags       storageImageSampleCounts;
-    uint32_t                 maxSampleMaskWords;
-    VkBool32             timestampComputeAndGraphics;
-    float                timestampPeriod;
-    uint32_t                 maxClipDistances;
-    uint32_t                 maxCullDistances;
-    uint32_t                 maxCombinedClipAndCullDistances;
-    uint32_t                 discreteQueuePriorities;
-    float                  pointSizeRange [2];
-    float                  lineWidthRange [2];
-    float                pointSizeGranularity;
-    float                lineWidthGranularity;
-    VkBool32             strictLines;
-    VkBool32             standardSampleLocations;
-    VkDeviceSize         optimalBufferCopyOffsetAlignment;
-    VkDeviceSize         optimalBufferCopyRowPitchAlignment;
-    VkDeviceSize         nonCoherentAtomSize;
-} VkPhysicalDeviceLimits;
-
-typedef struct VkSemaphoreCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSemaphoreCreateFlags   flags;
-} VkSemaphoreCreateInfo;
-
-typedef struct VkQueryPoolCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkQueryPoolCreateFlags   flags;
-    VkQueryType              queryType;
-    uint32_t                 queryCount;
-    VkQueryPipelineStatisticFlags   pipelineStatistics;
-} VkQueryPoolCreateInfo;
-
-typedef struct VkFramebufferCreateInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkFramebufferCreateFlags      flags;
-    VkRenderPass                             renderPass;
-    uint32_t                 attachmentCount;
-    const  VkImageView *      pAttachments;
-    uint32_t                 width;
-    uint32_t                 height;
-    uint32_t                 layers;
-} VkFramebufferCreateInfo;
-
-typedef struct VkSubmitInfo {
-    VkStructureType   sType;
-    const  void *  pNext;
-    uint32_t         waitSemaphoreCount;
-    const  VkSemaphore *      pWaitSemaphores;
-    const  VkPipelineStageFlags *            pWaitDstStageMask;
-    uint32_t         commandBufferCount;
-    const  VkCommandBuffer *      pCommandBuffers;
-    uint32_t         signalSemaphoreCount;
-    const  VkSemaphore *      pSignalSemaphores;
-} VkSubmitInfo;
-
-typedef struct VkSurfaceCapabilitiesKHR {
-    uint32_t                           minImageCount;
-    uint32_t                           maxImageCount;
-    VkExtent2D                         currentExtent;
-    VkExtent2D                         minImageExtent;
-    VkExtent2D                         maxImageExtent;
-    uint32_t                           maxImageArrayLayers;
-    VkSurfaceTransformFlagsKHR         supportedTransforms;
-    VkSurfaceTransformFlagBitsKHR      currentTransform;
-    VkCompositeAlphaFlagsKHR           supportedCompositeAlpha;
-    VkImageUsageFlags                  supportedUsageFlags;
-} VkSurfaceCapabilitiesKHR;
-
-typedef struct VkSwapchainCreateInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkSwapchainCreateFlagsKHR          flags;
-    VkSurfaceKHR                       surface;
-    uint32_t                           minImageCount;
-    VkFormat                           imageFormat;
-    VkColorSpaceKHR                    imageColorSpace;
-    VkExtent2D                         imageExtent;
-    uint32_t                           imageArrayLayers;
-    VkImageUsageFlags                  imageUsage;
-    VkSharingMode                      imageSharingMode;
-    uint32_t           queueFamilyIndexCount;
-    const  uint32_t *                   pQueueFamilyIndices;
-    VkSurfaceTransformFlagBitsKHR      preTransform;
-    VkCompositeAlphaFlagBitsKHR        compositeAlpha;
-    VkPresentModeKHR                   presentMode;
-    VkBool32                           clipped;
-    VkSwapchainKHR     oldSwapchain;
-} VkSwapchainCreateInfoKHR;
-
-typedef struct VkDebugReportCallbackCreateInfoEXT {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkDebugReportFlagsEXT              flags;
-    PFN_vkDebugReportCallbackEXT       pfnCallback;
-    void *             pUserData;
-} VkDebugReportCallbackCreateInfoEXT;
-
-typedef struct VkPrivateDataSlotCreateInfo {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    VkPrivateDataSlotCreateFlags          flags;
-} VkPrivateDataSlotCreateInfo;
-
-typedef struct VkPhysicalDevicePrivateDataFeatures {
-    VkStructureType   sType;
-    void *                                   pNext;
-    VkBool32                                 privateData;
-} VkPhysicalDevicePrivateDataFeatures;
-
-typedef struct VkPhysicalDeviceFeatures2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkPhysicalDeviceFeatures           features;
-} VkPhysicalDeviceFeatures2;
-
-typedef struct VkFormatProperties2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkFormatProperties                 formatProperties;
-} VkFormatProperties2;
-
-typedef struct VkImageFormatProperties2 {
-    VkStructureType   sType;
-    void *  pNext;
-    VkImageFormatProperties            imageFormatProperties;
-} VkImageFormatProperties2;
-
-typedef struct VkPhysicalDeviceImageFormatInfo2 {
-    VkStructureType   sType;
-    const  void *  pNext;
-    VkFormat                           format;
-    VkImageType                        type;
-    VkImageTiling                      tiling;
-    VkImageUsageFlags                  usage;
-    VkImageCreateFlags   flags;
-} VkPhysicalDeviceImageFormatInfo2;
-
-typedef struct VkQueueFamilyProperties2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkQueueFamilyProperties         queueFamilyProperties;
-} VkQueueFamilyProperties2;
-
-typedef struct VkSparseImageFormatProperties2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkSparseImageFormatProperties   properties;
-} VkSparseImageFormatProperties2;
-
-typedef struct VkPhysicalDeviceSparseImageFormatInfo2 {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkFormat                           format;
-    VkImageType                        type;
-    VkSampleCountFlagBits              samples;
-    VkImageUsageFlags                  usage;
-    VkImageTiling                      tiling;
-} VkPhysicalDeviceSparseImageFormatInfo2;
-
-typedef struct VkPhysicalDeviceVariablePointersFeatures {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                           variablePointersStorageBuffer;
-    VkBool32                           variablePointers;
-} VkPhysicalDeviceVariablePointersFeatures;
-
-typedef struct VkPhysicalDeviceVariablePointersFeatures  VkPhysicalDeviceVariablePointerFeatures;
-
-typedef struct VkExternalMemoryProperties {
-    VkExternalMemoryFeatureFlags    externalMemoryFeatures;
-    VkExternalMemoryHandleTypeFlags   exportFromImportedHandleTypes;
-    VkExternalMemoryHandleTypeFlags   compatibleHandleTypes;
-} VkExternalMemoryProperties;
-
-typedef struct VkExternalImageFormatProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkExternalMemoryProperties   externalMemoryProperties;
-} VkExternalImageFormatProperties;
-
-typedef struct VkPhysicalDeviceExternalBufferInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkBufferCreateFlags   flags;
-    VkBufferUsageFlags                 usage;
-    VkExternalMemoryHandleTypeFlagBits   handleType;
-} VkPhysicalDeviceExternalBufferInfo;
-
-typedef struct VkExternalBufferProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkExternalMemoryProperties      externalMemoryProperties;
-} VkExternalBufferProperties;
-
-typedef struct VkPhysicalDeviceIDProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    uint8_t                       deviceUUID [ VK_UUID_SIZE ];
-    uint8_t                       driverUUID [ VK_UUID_SIZE ];
-    uint8_t                       deviceLUID [ VK_LUID_SIZE ];
-    uint32_t                      deviceNodeMask;
-    VkBool32                      deviceLUIDValid;
-} VkPhysicalDeviceIDProperties;
-
-typedef struct VkExternalMemoryImageCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalMemoryHandleTypeFlags   handleTypes;
-} VkExternalMemoryImageCreateInfo;
-
-typedef struct VkExternalMemoryBufferCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalMemoryHandleTypeFlags   handleTypes;
-} VkExternalMemoryBufferCreateInfo;
-
-typedef struct VkExportMemoryAllocateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalMemoryHandleTypeFlags   handleTypes;
-} VkExportMemoryAllocateInfo;
-
-typedef struct VkExternalSemaphoreProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkExternalSemaphoreHandleTypeFlags   exportFromImportedHandleTypes;
-    VkExternalSemaphoreHandleTypeFlags   compatibleHandleTypes;
-    VkExternalSemaphoreFeatureFlags   externalSemaphoreFeatures;
-} VkExternalSemaphoreProperties;
-
-typedef struct VkExportSemaphoreCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalSemaphoreHandleTypeFlags   handleTypes;
-} VkExportSemaphoreCreateInfo;
-
-typedef struct VkExternalFenceProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkExternalFenceHandleTypeFlags   exportFromImportedHandleTypes;
-    VkExternalFenceHandleTypeFlags   compatibleHandleTypes;
-    VkExternalFenceFeatureFlags   externalFenceFeatures;
-} VkExternalFenceProperties;
-
-typedef struct VkExportFenceCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkExternalFenceHandleTypeFlags   handleTypes;
-} VkExportFenceCreateInfo;
-
-typedef struct VkPhysicalDeviceMultiviewFeatures {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                           multiview;
-    VkBool32                           multiviewGeometryShader;
-    VkBool32                           multiviewTessellationShader;
-} VkPhysicalDeviceMultiviewFeatures;
-
-typedef struct VkPhysicalDeviceGroupProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    uint32_t                           physicalDeviceCount;
-    VkPhysicalDevice                   physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ];
-    VkBool32                           subsetAllocation;
-} VkPhysicalDeviceGroupProperties;
-
-typedef struct VkMemoryAllocateFlagsInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkMemoryAllocateFlags   flags;
-    uint32_t                           deviceMask;
-} VkMemoryAllocateFlagsInfo;
-
-typedef struct VkBindBufferMemoryInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkBuffer                           buffer;
-    VkDeviceMemory                     memory;
-    VkDeviceSize                       memoryOffset;
-} VkBindBufferMemoryInfo;
-
-typedef struct VkBindImageMemoryInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkImage                            image;
-    VkDeviceMemory                     memory;
-    VkDeviceSize                       memoryOffset;
-} VkBindImageMemoryInfo;
-
-typedef struct VkDeviceGroupPresentCapabilitiesKHR {
-    VkStructureType   sType;
-    void *             pNext;
-    uint32_t                           presentMask [ VK_MAX_DEVICE_GROUP_SIZE ];
-    VkDeviceGroupPresentModeFlagsKHR   modes;
-} VkDeviceGroupPresentCapabilitiesKHR;
-
-typedef struct VkDeviceGroupSwapchainCreateInfoKHR {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkDeviceGroupPresentModeFlagsKHR                           modes;
-} VkDeviceGroupSwapchainCreateInfoKHR;
-
-typedef struct VkDescriptorUpdateTemplateCreateInfo {
-    VkStructureType   sType;
-    const  void *                                pNext;
-    VkDescriptorUpdateTemplateCreateFlags      flags;
-    uint32_t                   descriptorUpdateEntryCount;
-    const  VkDescriptorUpdateTemplateEntry *  pDescriptorUpdateEntries;
-    VkDescriptorUpdateTemplateType   templateType;
-    VkDescriptorSetLayout   descriptorSetLayout;
-    VkPipelineBindPoint   pipelineBindPoint;
-    VkPipelineLayout pipelineLayout;
-    uint32_t   set;
-} VkDescriptorUpdateTemplateCreateInfo;
-
-typedef struct VkInputAttachmentAspectReference {
-    uint32_t                          subpass;
-    uint32_t                          inputAttachmentIndex;
-    VkImageAspectFlags                aspectMask;
-} VkInputAttachmentAspectReference;
-
-typedef struct VkRenderPassInputAttachmentAspectCreateInfo {
-    VkStructureType   sType;
-    const  void *                      pNext;
-    uint32_t                          aspectReferenceCount;
-    const  VkInputAttachmentAspectReference *  pAspectReferences;
-} VkRenderPassInputAttachmentAspectCreateInfo;
-
-typedef struct VkPhysicalDevice16BitStorageFeatures {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                           storageBuffer16BitAccess;
-    VkBool32                           uniformAndStorageBuffer16BitAccess;
-    VkBool32                           storagePushConstant16;
-    VkBool32                           storageInputOutput16;
-} VkPhysicalDevice16BitStorageFeatures;
-
-typedef struct VkPhysicalDeviceSubgroupProperties {
-    VkStructureType   sType;
-    void *                    pNext;
-    uint32_t                       subgroupSize;
-    VkShaderStageFlags              supportedStages;
-    VkSubgroupFeatureFlags          supportedOperations;
-    VkBool32   quadOperationsInAllStages;
-} VkPhysicalDeviceSubgroupProperties;
-
-typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures {
-    VkStructureType   sType;
-    void *                           pNext;
-    VkBool32   shaderSubgroupExtendedTypes;
-} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures;
-
-typedef struct VkDeviceBufferMemoryRequirements {
-    VkStructureType   sType;
-    const  void *                                                            pNext;
-    const  VkBufferCreateInfo *                                                              pCreateInfo;
-} VkDeviceBufferMemoryRequirements;
-
-typedef struct VkDeviceImageMemoryRequirements {
-    VkStructureType   sType;
-    const  void *                                                           pNext;
-    const  VkImageCreateInfo *                                                              pCreateInfo;
-    VkImageAspectFlagBits                                                  planeAspect;
-} VkDeviceImageMemoryRequirements;
-
-typedef struct VkMemoryRequirements2 {
-    VkStructureType   sType;
-    void *  pNext;
-    VkMemoryRequirements                                                   memoryRequirements;
-} VkMemoryRequirements2;
-
-typedef struct VkSparseImageMemoryRequirements2 {
-    VkStructureType   sType;
-    void *                                        pNext;
-    VkSparseImageMemoryRequirements                                        memoryRequirements;
-} VkSparseImageMemoryRequirements2;
-
-typedef struct VkMemoryDedicatedRequirements {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                           prefersDedicatedAllocation;
-    VkBool32                           requiresDedicatedAllocation;
-} VkMemoryDedicatedRequirements;
-
-typedef struct VkImageViewUsageCreateInfo {
-    VkStructureType   sType;
-    const  void *  pNext;
-    VkImageUsageFlags   usage;
-} VkImageViewUsageCreateInfo;
-
-typedef struct VkSamplerYcbcrConversionCreateInfo {
-    VkStructureType   sType;
-    const  void *                       pNext;
-    VkFormat                           format;
-    VkSamplerYcbcrModelConversion   ycbcrModel;
-    VkSamplerYcbcrRange             ycbcrRange;
-    VkComponentMapping                 components;
-    VkChromaLocation                xChromaOffset;
-    VkChromaLocation                yChromaOffset;
-    VkFilter                           chromaFilter;
-    VkBool32                           forceExplicitReconstruction;
-} VkSamplerYcbcrConversionCreateInfo;
-
-typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                           samplerYcbcrConversion;
-} VkPhysicalDeviceSamplerYcbcrConversionFeatures;
-
-typedef struct VkProtectedSubmitInfo {
-    VkStructureType   sType;
-    const  void *                      pNext;
-    VkBool32                          protectedSubmit;
-} VkProtectedSubmitInfo;
-
-typedef struct VkPhysicalDeviceProtectedMemoryFeatures {
-    VkStructureType   sType;
-    void *                                pNext;
-    VkBool32                              protectedMemory;
-} VkPhysicalDeviceProtectedMemoryFeatures;
-
-typedef struct VkPhysicalDeviceProtectedMemoryProperties {
-    VkStructureType   sType;
-    void *                                pNext;
-    VkBool32                              protectedNoFault;
-} VkPhysicalDeviceProtectedMemoryProperties;
-
-typedef struct VkDeviceQueueInfo2 {
-    VkStructureType   sType;
-    const  void *                          pNext;
-    VkDeviceQueueCreateFlags              flags;
-    uint32_t                              queueFamilyIndex;
-    uint32_t                              queueIndex;
-} VkDeviceQueueInfo2;
-
-typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties {
-    VkStructureType   sType;
-    void *                   pNext;
-    VkBool32                 filterMinmaxSingleComponentFormats;
-    VkBool32                 filterMinmaxImageComponentMapping;
-} VkPhysicalDeviceSamplerFilterMinmaxProperties;
-
-typedef struct VkPhysicalDeviceInlineUniformBlockFeatures {
-    VkStructureType   sType;
-    void *   pNext;
-    VkBool32                 inlineUniformBlock;
-    VkBool32                 descriptorBindingInlineUniformBlockUpdateAfterBind;
-} VkPhysicalDeviceInlineUniformBlockFeatures;
-
-typedef struct VkPhysicalDeviceMaintenance3Properties {
-    VkStructureType   sType;
-    void *                             pNext;
-    uint32_t                           maxPerSetDescriptors;
-    VkDeviceSize                       maxMemoryAllocationSize;
-} VkPhysicalDeviceMaintenance3Properties;
-
-typedef struct VkPhysicalDeviceMaintenance4Features {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                                           maintenance4;
-} VkPhysicalDeviceMaintenance4Features;
-
-typedef struct VkPhysicalDeviceMaintenance4Properties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkDeviceSize                       maxBufferSize;
-} VkPhysicalDeviceMaintenance4Properties;
-
-typedef struct VkDescriptorSetLayoutSupport {
-    VkStructureType   sType;
-    void *             pNext;
-    VkBool32           supported;
-} VkDescriptorSetLayoutSupport;
-
-typedef struct VkPhysicalDeviceShaderDrawParametersFeatures {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                           shaderDrawParameters;
-} VkPhysicalDeviceShaderDrawParametersFeatures;
-
-typedef struct VkPhysicalDeviceShaderDrawParametersFeatures  VkPhysicalDeviceShaderDrawParameterFeatures;
-
-typedef struct VkPhysicalDeviceShaderFloat16Int8Features {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                           shaderFloat16;
-    VkBool32                           shaderInt8;
-} VkPhysicalDeviceShaderFloat16Int8Features;
-
-typedef struct VkPhysicalDeviceFloatControlsProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkShaderFloatControlsIndependence   denormBehaviorIndependence;
-    VkShaderFloatControlsIndependence   roundingModeIndependence;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat16;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat32;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat64;
-    VkBool32                           shaderDenormPreserveFloat16;
-    VkBool32                           shaderDenormPreserveFloat32;
-    VkBool32                           shaderDenormPreserveFloat64;
-    VkBool32                           shaderDenormFlushToZeroFloat16;
-    VkBool32                           shaderDenormFlushToZeroFloat32;
-    VkBool32                           shaderDenormFlushToZeroFloat64;
-    VkBool32                           shaderRoundingModeRTEFloat16;
-    VkBool32                           shaderRoundingModeRTEFloat32;
-    VkBool32                           shaderRoundingModeRTEFloat64;
-    VkBool32                           shaderRoundingModeRTZFloat16;
-    VkBool32                           shaderRoundingModeRTZFloat32;
-    VkBool32                           shaderRoundingModeRTZFloat64;
-} VkPhysicalDeviceFloatControlsProperties;
-
-typedef struct VkPhysicalDeviceHostQueryResetFeatures {
-    VkStructureType   sType;
-    void *         pNext;
-    VkBool32                             hostQueryReset;
-} VkPhysicalDeviceHostQueryResetFeatures;
-
-typedef struct VkPhysicalDeviceDescriptorIndexingFeatures {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkBool32                 shaderInputAttachmentArrayDynamicIndexing;
-    VkBool32                 shaderUniformTexelBufferArrayDynamicIndexing;
-    VkBool32                 shaderStorageTexelBufferArrayDynamicIndexing;
-    VkBool32                 shaderUniformBufferArrayNonUniformIndexing;
-    VkBool32                 shaderSampledImageArrayNonUniformIndexing;
-    VkBool32                 shaderStorageBufferArrayNonUniformIndexing;
-    VkBool32                 shaderStorageImageArrayNonUniformIndexing;
-    VkBool32                 shaderInputAttachmentArrayNonUniformIndexing;
-    VkBool32                 shaderUniformTexelBufferArrayNonUniformIndexing;
-    VkBool32                 shaderStorageTexelBufferArrayNonUniformIndexing;
-    VkBool32                 descriptorBindingUniformBufferUpdateAfterBind;
-    VkBool32                 descriptorBindingSampledImageUpdateAfterBind;
-    VkBool32                 descriptorBindingStorageImageUpdateAfterBind;
-    VkBool32                 descriptorBindingStorageBufferUpdateAfterBind;
-    VkBool32                 descriptorBindingUniformTexelBufferUpdateAfterBind;
-    VkBool32                 descriptorBindingStorageTexelBufferUpdateAfterBind;
-    VkBool32                 descriptorBindingUpdateUnusedWhilePending;
-    VkBool32                 descriptorBindingPartiallyBound;
-    VkBool32                 descriptorBindingVariableDescriptorCount;
-    VkBool32                 runtimeDescriptorArray;
-} VkPhysicalDeviceDescriptorIndexingFeatures;
-
-typedef struct VkPhysicalDeviceDescriptorIndexingProperties {
-    VkStructureType   sType;
-    void *                             pNext;
-    uint32_t                 maxUpdateAfterBindDescriptorsInAllPools;
-    VkBool32                 shaderUniformBufferArrayNonUniformIndexingNative;
-    VkBool32                 shaderSampledImageArrayNonUniformIndexingNative;
-    VkBool32                 shaderStorageBufferArrayNonUniformIndexingNative;
-    VkBool32                 shaderStorageImageArrayNonUniformIndexingNative;
-    VkBool32                 shaderInputAttachmentArrayNonUniformIndexingNative;
-    VkBool32                 robustBufferAccessUpdateAfterBind;
-    VkBool32                 quadDivergentImplicitLod;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindSamplers;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindUniformBuffers;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindStorageBuffers;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindSampledImages;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindStorageImages;
-    uint32_t                 maxPerStageDescriptorUpdateAfterBindInputAttachments;
-    uint32_t                 maxPerStageUpdateAfterBindResources;
-    uint32_t                 maxDescriptorSetUpdateAfterBindSamplers;
-    uint32_t                 maxDescriptorSetUpdateAfterBindUniformBuffers;
-    uint32_t                 maxDescriptorSetUpdateAfterBindUniformBuffersDynamic;
-    uint32_t                 maxDescriptorSetUpdateAfterBindStorageBuffers;
-    uint32_t                 maxDescriptorSetUpdateAfterBindStorageBuffersDynamic;
-    uint32_t                 maxDescriptorSetUpdateAfterBindSampledImages;
-    uint32_t                 maxDescriptorSetUpdateAfterBindStorageImages;
-    uint32_t                 maxDescriptorSetUpdateAfterBindInputAttachments;
-} VkPhysicalDeviceDescriptorIndexingProperties;
-
-typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo {
-    VkStructureType   sType;
-    const  void *                                                         pNext;
-    uint32_t                                             bindingCount;
-    const  VkDescriptorBindingFlags *  pBindingFlags;
-} VkDescriptorSetLayoutBindingFlagsCreateInfo;
-
-typedef struct VkAttachmentDescription2 {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkAttachmentDescriptionFlags   flags;
-    VkFormat                                       format;
-    VkSampleCountFlagBits                          samples;
-    VkAttachmentLoadOp                             loadOp;
-    VkAttachmentStoreOp                            storeOp;
-    VkAttachmentLoadOp                             stencilLoadOp;
-    VkAttachmentStoreOp                            stencilStoreOp;
-    VkImageLayout                                  initialLayout;
-    VkImageLayout                                  finalLayout;
-} VkAttachmentDescription2;
-
-typedef struct VkAttachmentReference2 {
-    VkStructureType   sType;
-    const  void *  pNext;
-    uint32_t                            attachment;
-    VkImageLayout                       layout;
-    VkImageAspectFlags   aspectMask;
-} VkAttachmentReference2;
-
-typedef struct VkSubpassDescription2 {
-    VkStructureType   sType;
-    const  void *                            pNext;
-    VkSubpassDescriptionFlags                     flags;
-    VkPipelineBindPoint                                           pipelineBindPoint;
-    uint32_t                                                      viewMask;
-    uint32_t                                      inputAttachmentCount;
-    const  VkAttachmentReference2 *     pInputAttachments;
-    uint32_t                                      colorAttachmentCount;
-    const  VkAttachmentReference2 *     pColorAttachments;
-    const  VkAttachmentReference2 *  pResolveAttachments;
-    const  VkAttachmentReference2 *                pDepthStencilAttachment;
-    uint32_t                                      preserveAttachmentCount;
-    const  uint32_t *                pPreserveAttachments;
-} VkSubpassDescription2;
-
-typedef struct VkSubpassDependency2 {
-    VkStructureType   sType;
-    const  void *  pNext;
-    uint32_t                            srcSubpass;
-    uint32_t                            dstSubpass;
-    VkPipelineStageFlags   srcStageMask;
-    VkPipelineStageFlags   dstStageMask;
-    VkAccessFlags       srcAccessMask;
-    VkAccessFlags       dstAccessMask;
-    VkDependencyFlags   dependencyFlags;
-    int32_t                             viewOffset;
-} VkSubpassDependency2;
-
-typedef struct VkRenderPassCreateInfo2 {
-    VkStructureType   sType;
-    const  void *                                               pNext;
-    VkRenderPassCreateFlags                    flags;
-    uint32_t                                   attachmentCount;
-    const  VkAttachmentDescription2 *     pAttachments;
-    uint32_t                                                   subpassCount;
-    const  VkSubpassDescription2 *           pSubpasses;
-    uint32_t                                   dependencyCount;
-    const  VkSubpassDependency2 *         pDependencies;
-    uint32_t                                   correlatedViewMaskCount;
-    const  uint32_t *             pCorrelatedViewMasks;
-} VkRenderPassCreateInfo2;
-
-typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures {
-    VkStructureType   sType;
-    void *                   pNext;
-    VkBool32                 timelineSemaphore;
-} VkPhysicalDeviceTimelineSemaphoreFeatures;
-
-typedef struct VkSemaphoreWaitInfo {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkSemaphoreWaitFlags   flags;
-    uint32_t                 semaphoreCount;
-    const  VkSemaphore *  pSemaphores;
-    const  uint64_t *     pValues;
-} VkSemaphoreWaitInfo;
-
-typedef struct VkPhysicalDevice8BitStorageFeatures {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                           storageBuffer8BitAccess;
-    VkBool32                           uniformAndStorageBuffer8BitAccess;
-    VkBool32                           storagePushConstant8;
-} VkPhysicalDevice8BitStorageFeatures;
-
-typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                           vulkanMemoryModel;
-    VkBool32                           vulkanMemoryModelDeviceScope;
-    VkBool32                           vulkanMemoryModelAvailabilityVisibilityChains;
-} VkPhysicalDeviceVulkanMemoryModelFeatures;
-
-typedef struct VkPhysicalDeviceShaderAtomicInt64Features {
-    VkStructureType   sType;
-    void *                                pNext;
-    VkBool32                              shaderBufferInt64Atomics;
-    VkBool32                              shaderSharedInt64Atomics;
-} VkPhysicalDeviceShaderAtomicInt64Features;
-
-typedef struct VkPhysicalDeviceDepthStencilResolveProperties {
-    VkStructureType   sType;
-    void *                                 pNext;
-    VkResolveModeFlags                     supportedDepthResolveModes;
-    VkResolveModeFlags                     supportedStencilResolveModes;
-    VkBool32                               independentResolveNone;
-    VkBool32                               independentResolve;
-} VkPhysicalDeviceDepthStencilResolveProperties;
-
-typedef struct VkSubpassDescriptionDepthStencilResolve {
-    VkStructureType   sType;
-    const  void *                               pNext;
-    VkResolveModeFlagBits                depthResolveMode;
-    VkResolveModeFlagBits                stencilResolveMode;
-    const  VkAttachmentReference2 *             pDepthStencilResolveAttachment;
-} VkSubpassDescriptionDepthStencilResolve;
-
-typedef struct VkImageStencilUsageCreateInfo {
-    VkStructureType   sType;
-    const  void *  pNext;
-    VkImageUsageFlags   stencilUsage;
-} VkImageStencilUsageCreateInfo;
-
-typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures {
-    VkStructureType   sType;
-    void *                                pNext;
-    VkBool32                              scalarBlockLayout;
-} VkPhysicalDeviceScalarBlockLayoutFeatures;
-
-typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures {
-    VkStructureType   sType;
-    void *                                pNext;
-    VkBool32                              uniformBufferStandardLayout;
-} VkPhysicalDeviceUniformBufferStandardLayoutFeatures;
-
-typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures {
-    VkStructureType   sType;
-    void *         pNext;
-    VkBool32                             bufferDeviceAddress;
-    VkBool32                             bufferDeviceAddressCaptureReplay;
-    VkBool32                             bufferDeviceAddressMultiDevice;
-} VkPhysicalDeviceBufferDeviceAddressFeatures;
-
-typedef struct VkPhysicalDeviceImagelessFramebufferFeatures {
-    VkStructureType   sType;
-    void *                                     pNext;
-    VkBool32                                   imagelessFramebuffer;
-} VkPhysicalDeviceImagelessFramebufferFeatures;
-
-typedef struct VkFramebufferAttachmentImageInfo {
-    VkStructureType   sType;
-    const  void *                               pNext;
-    VkImageCreateFlags         flags;
-    VkImageUsageFlags                          usage;
-    uint32_t                                   width;
-    uint32_t                                   height;
-    uint32_t                                   layerCount;
-    uint32_t                   viewFormatCount;
-    const  VkFormat *     pViewFormats;
-} VkFramebufferAttachmentImageInfo;
-
-typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures {
-    VkStructureType   sType;
-    void *   pNext;
-    VkBool32                 textureCompressionASTC_HDR;
-} VkPhysicalDeviceTextureCompressionASTCHDRFeatures;
-
-typedef struct VkPipelineCreationFeedback {
-    VkPipelineCreationFeedbackFlags       flags;
-    uint64_t                              duration;
-} VkPipelineCreationFeedback;
-
-typedef struct VkPipelineCreationFeedbackCreateInfo {
-    VkStructureType   sType;
-    const  void *          pNext;
-    VkPipelineCreationFeedback *          pPipelineCreationFeedback;
-    uint32_t              pipelineStageCreationFeedbackCount;
-    VkPipelineCreationFeedback *  pPipelineStageCreationFeedbacks;
-} VkPipelineCreationFeedbackCreateInfo;
-
-typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures {
-    VkStructureType sType;
-    void *     pNext;
-    VkBool32                         separateDepthStencilLayouts;
-} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures;
-
-typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures {
-    VkStructureType   sType;
-    void *       pNext;
-    VkBool32                     shaderDemoteToHelperInvocation;
-} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures;
-
-typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties {
-    VkStructureType   sType;
-    void *               pNext;
-    VkDeviceSize                         storageTexelBufferOffsetAlignmentBytes;
-    VkBool32                           storageTexelBufferOffsetSingleTexelAlignment;
-    VkDeviceSize                         uniformTexelBufferOffsetAlignmentBytes;
-    VkBool32                           uniformTexelBufferOffsetSingleTexelAlignment;
-} VkPhysicalDeviceTexelBufferAlignmentProperties;
-
-typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures {
-    VkStructureType   sType;
-    void *   pNext;
-    VkBool32                 subgroupSizeControl;
-    VkBool32                 computeFullSubgroups;
-} VkPhysicalDeviceSubgroupSizeControlFeatures;
-
-typedef struct VkPhysicalDeviceSubgroupSizeControlProperties {
-    VkStructureType   sType;
-    void *                           pNext;
-    uint32_t   minSubgroupSize;
-    uint32_t   maxSubgroupSize;
-    uint32_t   maxComputeWorkgroupSubgroups;
-    VkShaderStageFlags           requiredSubgroupSizeStages;
-} VkPhysicalDeviceSubgroupSizeControlProperties;
-
-typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures {
-    VkStructureType   sType;
-    void *  pNext;
-    VkBool32                pipelineCreationCacheControl;
-} VkPhysicalDevicePipelineCreationCacheControlFeatures;
-
-typedef struct VkPhysicalDeviceVulkan11Features {
-    VkStructureType sType;
-    void *     pNext;
-    VkBool32                           storageBuffer16BitAccess;
-    VkBool32                           uniformAndStorageBuffer16BitAccess;
-    VkBool32                           storagePushConstant16;
-    VkBool32                           storageInputOutput16;
-    VkBool32                           multiview;
-    VkBool32                           multiviewGeometryShader;
-    VkBool32                           multiviewTessellationShader;
-    VkBool32                           variablePointersStorageBuffer;
-    VkBool32                           variablePointers;
-    VkBool32                           protectedMemory;
-    VkBool32                           samplerYcbcrConversion;
-    VkBool32                           shaderDrawParameters;
-} VkPhysicalDeviceVulkan11Features;
-
-typedef struct VkPhysicalDeviceVulkan11Properties {
-    VkStructureType sType;
-    void *       pNext;
-    uint8_t                            deviceUUID [ VK_UUID_SIZE ];
-    uint8_t                            driverUUID [ VK_UUID_SIZE ];
-    uint8_t                            deviceLUID [ VK_LUID_SIZE ];
-    uint32_t                           deviceNodeMask;
-    VkBool32                           deviceLUIDValid;
-    uint32_t                        subgroupSize;
-    VkShaderStageFlags              subgroupSupportedStages;
-    VkSubgroupFeatureFlags          subgroupSupportedOperations;
-    VkBool32                        subgroupQuadOperationsInAllStages;
-    VkPointClippingBehavior       pointClippingBehavior;
-    uint32_t                           maxMultiviewViewCount;
-    uint32_t                           maxMultiviewInstanceIndex;
-    VkBool32                      protectedNoFault;
-    uint32_t                           maxPerSetDescriptors;
-    VkDeviceSize                       maxMemoryAllocationSize;
-} VkPhysicalDeviceVulkan11Properties;
-
-typedef struct VkPhysicalDeviceVulkan12Features {
-    VkStructureType sType;
-    void *     pNext;
-    VkBool32                           samplerMirrorClampToEdge;
-    VkBool32                           drawIndirectCount;
-    VkBool32                           storageBuffer8BitAccess;
-    VkBool32                           uniformAndStorageBuffer8BitAccess;
-    VkBool32                           storagePushConstant8;
-    VkBool32                           shaderBufferInt64Atomics;
-    VkBool32                           shaderSharedInt64Atomics;
-    VkBool32                           shaderFloat16;
-    VkBool32                           shaderInt8;
-    VkBool32                           descriptorIndexing;
-    VkBool32                           shaderInputAttachmentArrayDynamicIndexing;
-    VkBool32                           shaderUniformTexelBufferArrayDynamicIndexing;
-    VkBool32                           shaderStorageTexelBufferArrayDynamicIndexing;
-    VkBool32                           shaderUniformBufferArrayNonUniformIndexing;
-    VkBool32                           shaderSampledImageArrayNonUniformIndexing;
-    VkBool32                           shaderStorageBufferArrayNonUniformIndexing;
-    VkBool32                           shaderStorageImageArrayNonUniformIndexing;
-    VkBool32                           shaderInputAttachmentArrayNonUniformIndexing;
-    VkBool32                           shaderUniformTexelBufferArrayNonUniformIndexing;
-    VkBool32                           shaderStorageTexelBufferArrayNonUniformIndexing;
-    VkBool32                           descriptorBindingUniformBufferUpdateAfterBind;
-    VkBool32                           descriptorBindingSampledImageUpdateAfterBind;
-    VkBool32                           descriptorBindingStorageImageUpdateAfterBind;
-    VkBool32                           descriptorBindingStorageBufferUpdateAfterBind;
-    VkBool32                           descriptorBindingUniformTexelBufferUpdateAfterBind;
-    VkBool32                           descriptorBindingStorageTexelBufferUpdateAfterBind;
-    VkBool32                           descriptorBindingUpdateUnusedWhilePending;
-    VkBool32                           descriptorBindingPartiallyBound;
-    VkBool32                           descriptorBindingVariableDescriptorCount;
-    VkBool32                           runtimeDescriptorArray;
-    VkBool32                           samplerFilterMinmax;
-    VkBool32                           scalarBlockLayout;
-    VkBool32                           imagelessFramebuffer;
-    VkBool32                           uniformBufferStandardLayout;
-    VkBool32                           shaderSubgroupExtendedTypes;
-    VkBool32                           separateDepthStencilLayouts;
-    VkBool32                           hostQueryReset;
-    VkBool32                           timelineSemaphore;
-    VkBool32                           bufferDeviceAddress;
-    VkBool32                           bufferDeviceAddressCaptureReplay;
-    VkBool32                           bufferDeviceAddressMultiDevice;
-    VkBool32                           vulkanMemoryModel;
-    VkBool32                           vulkanMemoryModelDeviceScope;
-    VkBool32                           vulkanMemoryModelAvailabilityVisibilityChains;
-    VkBool32                           shaderOutputViewportIndex;
-    VkBool32                           shaderOutputLayer;
-    VkBool32                           subgroupBroadcastDynamicId;
-} VkPhysicalDeviceVulkan12Features;
-
-typedef struct VkPhysicalDeviceVulkan12Properties {
-    VkStructureType sType;
-    void *     pNext;
-    VkDriverId                         driverID;
-    char                               driverName [ VK_MAX_DRIVER_NAME_SIZE ];
-    char                               driverInfo [ VK_MAX_DRIVER_INFO_SIZE ];
-    VkConformanceVersion               conformanceVersion;
-    VkShaderFloatControlsIndependence denormBehaviorIndependence;
-    VkShaderFloatControlsIndependence roundingModeIndependence;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat16;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat32;
-    VkBool32                           shaderSignedZeroInfNanPreserveFloat64;
-    VkBool32                           shaderDenormPreserveFloat16;
-    VkBool32                           shaderDenormPreserveFloat32;
-    VkBool32                           shaderDenormPreserveFloat64;
-    VkBool32                           shaderDenormFlushToZeroFloat16;
-    VkBool32                           shaderDenormFlushToZeroFloat32;
-    VkBool32                           shaderDenormFlushToZeroFloat64;
-    VkBool32                           shaderRoundingModeRTEFloat16;
-    VkBool32                           shaderRoundingModeRTEFloat32;
-    VkBool32                           shaderRoundingModeRTEFloat64;
-    VkBool32                           shaderRoundingModeRTZFloat16;
-    VkBool32                           shaderRoundingModeRTZFloat32;
-    VkBool32                           shaderRoundingModeRTZFloat64;
-    uint32_t                           maxUpdateAfterBindDescriptorsInAllPools;
-    VkBool32                           shaderUniformBufferArrayNonUniformIndexingNative;
-    VkBool32                           shaderSampledImageArrayNonUniformIndexingNative;
-    VkBool32                           shaderStorageBufferArrayNonUniformIndexingNative;
-    VkBool32                           shaderStorageImageArrayNonUniformIndexingNative;
-    VkBool32                           shaderInputAttachmentArrayNonUniformIndexingNative;
-    VkBool32                           robustBufferAccessUpdateAfterBind;
-    VkBool32                           quadDivergentImplicitLod;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindSamplers;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindUniformBuffers;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindStorageBuffers;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindSampledImages;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindStorageImages;
-    uint32_t                           maxPerStageDescriptorUpdateAfterBindInputAttachments;
-    uint32_t                           maxPerStageUpdateAfterBindResources;
-    uint32_t                           maxDescriptorSetUpdateAfterBindSamplers;
-    uint32_t                           maxDescriptorSetUpdateAfterBindUniformBuffers;
-    uint32_t                           maxDescriptorSetUpdateAfterBindUniformBuffersDynamic;
-    uint32_t                           maxDescriptorSetUpdateAfterBindStorageBuffers;
-    uint32_t                           maxDescriptorSetUpdateAfterBindStorageBuffersDynamic;
-    uint32_t                           maxDescriptorSetUpdateAfterBindSampledImages;
-    uint32_t                           maxDescriptorSetUpdateAfterBindStorageImages;
-    uint32_t                           maxDescriptorSetUpdateAfterBindInputAttachments;
-    VkResolveModeFlags                 supportedDepthResolveModes;
-    VkResolveModeFlags                 supportedStencilResolveModes;
-    VkBool32                           independentResolveNone;
-    VkBool32                           independentResolve;
-    VkBool32                           filterMinmaxSingleComponentFormats;
-    VkBool32                           filterMinmaxImageComponentMapping;
-    uint64_t                           maxTimelineSemaphoreValueDifference;
-    VkSampleCountFlags   framebufferIntegerColorSampleCounts;
-} VkPhysicalDeviceVulkan12Properties;
-
-typedef struct VkPhysicalDeviceVulkan13Features {
-    VkStructureType sType;
-    void *             pNext;
-    VkBool32                           robustImageAccess;
-    VkBool32                           inlineUniformBlock;
-    VkBool32                           descriptorBindingInlineUniformBlockUpdateAfterBind;
-    VkBool32                           pipelineCreationCacheControl;
-    VkBool32                           privateData;
-    VkBool32                           shaderDemoteToHelperInvocation;
-    VkBool32                           shaderTerminateInvocation;
-    VkBool32                           subgroupSizeControl;
-    VkBool32                           computeFullSubgroups;
-    VkBool32                           synchronization2;
-    VkBool32                           textureCompressionASTC_HDR;
-    VkBool32                           shaderZeroInitializeWorkgroupMemory;
-    VkBool32                           dynamicRendering;
-    VkBool32                           shaderIntegerDotProduct;
-    VkBool32                           maintenance4;
-} VkPhysicalDeviceVulkan13Features;
-
-typedef struct VkPhysicalDeviceVulkan13Properties {
-    VkStructureType sType;
-    void *                           pNext;
-    uint32_t   minSubgroupSize;
-    uint32_t   maxSubgroupSize;
-    uint32_t   maxComputeWorkgroupSubgroups;
-    VkShaderStageFlags           requiredSubgroupSizeStages;
-    uint32_t                         maxInlineUniformBlockSize;
-    uint32_t                         maxPerStageDescriptorInlineUniformBlocks;
-    uint32_t                         maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
-    uint32_t                         maxDescriptorSetInlineUniformBlocks;
-    uint32_t                         maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
-    uint32_t                         maxInlineUniformTotalSize;
-    VkBool32                     integerDotProduct8BitUnsignedAccelerated;
-    VkBool32                     integerDotProduct8BitSignedAccelerated;
-    VkBool32                     integerDotProduct8BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProduct4x8BitPackedUnsignedAccelerated;
-    VkBool32                     integerDotProduct4x8BitPackedSignedAccelerated;
-    VkBool32                     integerDotProduct4x8BitPackedMixedSignednessAccelerated;
-    VkBool32                     integerDotProduct16BitUnsignedAccelerated;
-    VkBool32                     integerDotProduct16BitSignedAccelerated;
-    VkBool32                     integerDotProduct16BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProduct32BitUnsignedAccelerated;
-    VkBool32                     integerDotProduct32BitSignedAccelerated;
-    VkBool32                     integerDotProduct32BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProduct64BitUnsignedAccelerated;
-    VkBool32                     integerDotProduct64BitSignedAccelerated;
-    VkBool32                     integerDotProduct64BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating8BitUnsignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating8BitSignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating16BitUnsignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating16BitSignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating32BitUnsignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating32BitSignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating64BitUnsignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating64BitSignedAccelerated;
-    VkBool32                     integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated;
-    VkDeviceSize                  storageTexelBufferOffsetAlignmentBytes;
-    VkBool32                    storageTexelBufferOffsetSingleTexelAlignment;
-    VkDeviceSize                  uniformTexelBufferOffsetAlignmentBytes;
-    VkBool32                    uniformTexelBufferOffsetSingleTexelAlignment;
-    VkDeviceSize                     maxBufferSize;
-} VkPhysicalDeviceVulkan13Properties;
-
-typedef struct VkPhysicalDeviceToolProperties {
-    VkStructureType   sType;
-    void *  pNext;
-    char                    name [ VK_MAX_EXTENSION_NAME_SIZE ];
-    char                    version [ VK_MAX_EXTENSION_NAME_SIZE ];
-    VkToolPurposeFlags      purposes;
-    char                    description [ VK_MAX_DESCRIPTION_SIZE ];
-    char                    layer [ VK_MAX_EXTENSION_NAME_SIZE ];
-} VkPhysicalDeviceToolProperties;
-
-typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures {
-    VkStructureType   sType;
-    void *           pNext;
-    VkBool32         shaderZeroInitializeWorkgroupMemory;
-} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures;
-
-typedef struct VkPhysicalDeviceImageRobustnessFeatures {
-    VkStructureType   sType;
-    void *               pNext;
-    VkBool32                             robustImageAccess;
-} VkPhysicalDeviceImageRobustnessFeatures;
-
-typedef struct VkBufferCopy2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkDeviceSize                         srcOffset;
-    VkDeviceSize                         dstOffset;
-    VkDeviceSize   size;
-} VkBufferCopy2;
-
-typedef struct VkImageCopy2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkImageSubresourceLayers             srcSubresource;
-    VkOffset3D                           srcOffset;
-    VkImageSubresourceLayers             dstSubresource;
-    VkOffset3D                           dstOffset;
-    VkExtent3D                           extent;
-} VkImageCopy2;
-
-typedef struct VkImageBlit2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkImageSubresourceLayers             srcSubresource;
-    VkOffset3D                           srcOffsets [2];
-    VkImageSubresourceLayers             dstSubresource;
-    VkOffset3D                           dstOffsets [2];
-} VkImageBlit2;
-
-typedef struct VkBufferImageCopy2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkDeviceSize                         bufferOffset;
-    uint32_t                             bufferRowLength;
-    uint32_t                             bufferImageHeight;
-    VkImageSubresourceLayers             imageSubresource;
-    VkOffset3D                           imageOffset;
-    VkExtent3D                           imageExtent;
-} VkBufferImageCopy2;
-
-typedef struct VkImageResolve2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkImageSubresourceLayers             srcSubresource;
-    VkOffset3D                           srcOffset;
-    VkImageSubresourceLayers             dstSubresource;
-    VkOffset3D                           dstOffset;
-    VkExtent3D                           extent;
-} VkImageResolve2;
-
-typedef struct VkCopyBufferInfo2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkBuffer                             srcBuffer;
-    VkBuffer                             dstBuffer;
-    uint32_t                             regionCount;
-    const  VkBufferCopy2 *  pRegions;
-} VkCopyBufferInfo2;
-
-typedef struct VkCopyImageInfo2 {
-    VkStructureType   sType;
-    const  void *         pNext;
-    VkImage                              srcImage;
-    VkImageLayout                        srcImageLayout;
-    VkImage                              dstImage;
-    VkImageLayout                        dstImageLayout;
-    uint32_t                             regionCount;
-    const  VkImageCopy2 *  pRegions;
-} VkCopyImageInfo2;
-
-typedef struct VkBlitImageInfo2 {
-    VkStructureType   sType;
-    const  void *             pNext;
-    VkImage                                  srcImage;
-    VkImageLayout                            srcImageLayout;
-    VkImage                                  dstImage;
-    VkImageLayout                            dstImageLayout;
-    uint32_t                                 regionCount;
-    const  VkImageBlit2 *   pRegions;
-    VkFilter                                 filter;
-} VkBlitImageInfo2;
-
-typedef struct VkCopyBufferToImageInfo2 {
-    VkStructureType   sType;
-    const  void *                  pNext;
-    VkBuffer                                      srcBuffer;
-    VkImage                                       dstImage;
-    VkImageLayout                                 dstImageLayout;
-    uint32_t                                      regionCount;
-    const  VkBufferImageCopy2 *  pRegions;
-} VkCopyBufferToImageInfo2;
-
-typedef struct VkCopyImageToBufferInfo2 {
-    VkStructureType   sType;
-    const  void *                    pNext;
-    VkImage                                         srcImage;
-    VkImageLayout                                   srcImageLayout;
-    VkBuffer                                        dstBuffer;
-    uint32_t                                        regionCount;
-    const  VkBufferImageCopy2 *    pRegions;
-} VkCopyImageToBufferInfo2;
-
-typedef struct VkResolveImageInfo2 {
-    VkStructureType   sType;
-    const  void *                 pNext;
-    VkImage                                      srcImage;
-    VkImageLayout                                srcImageLayout;
-    VkImage                                      dstImage;
-    VkImageLayout                                dstImageLayout;
-    uint32_t                                     regionCount;
-    const  VkImageResolve2 *    pRegions;
-} VkResolveImageInfo2;
-
-typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures {
-    VkStructureType sType;
-    void *     pNext;
-    VkBool32                                         shaderTerminateInvocation;
-} VkPhysicalDeviceShaderTerminateInvocationFeatures;
-
-typedef struct VkMemoryBarrier2 {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    VkPipelineStageFlags2    srcStageMask;
-    VkAccessFlags2           srcAccessMask;
-    VkPipelineStageFlags2    dstStageMask;
-    VkAccessFlags2           dstAccessMask;
-} VkMemoryBarrier2;
-
-typedef struct VkImageMemoryBarrier2 {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    VkPipelineStageFlags2    srcStageMask;
-    VkAccessFlags2           srcAccessMask;
-    VkPipelineStageFlags2    dstStageMask;
-    VkAccessFlags2           dstAccessMask;
-    VkImageLayout                            oldLayout;
-    VkImageLayout                            newLayout;
-    uint32_t                                 srcQueueFamilyIndex;
-    uint32_t                                 dstQueueFamilyIndex;
-    VkImage                                  image;
-    VkImageSubresourceRange                  subresourceRange;
-} VkImageMemoryBarrier2;
-
-typedef struct VkBufferMemoryBarrier2 {
-    VkStructureType   sType;
-    const  void *                             pNext;
-    VkPipelineStageFlags2    srcStageMask;
-    VkAccessFlags2           srcAccessMask;
-    VkPipelineStageFlags2    dstStageMask;
-    VkAccessFlags2           dstAccessMask;
-    uint32_t                                 srcQueueFamilyIndex;
-    uint32_t                                 dstQueueFamilyIndex;
-    VkBuffer                                 buffer;
-    VkDeviceSize                             offset;
-    VkDeviceSize                             size;
-} VkBufferMemoryBarrier2;
-
-typedef struct VkDependencyInfo {
-    VkStructureType   sType;
-    const  void *                                                   pNext;
-    VkDependencyFlags                              dependencyFlags;
-    uint32_t                                       memoryBarrierCount;
-    const  VkMemoryBarrier2 *              pMemoryBarriers;
-    uint32_t                                       bufferMemoryBarrierCount;
-    const  VkBufferMemoryBarrier2 *  pBufferMemoryBarriers;
-    uint32_t                                       imageMemoryBarrierCount;
-    const  VkImageMemoryBarrier2 *    pImageMemoryBarriers;
-} VkDependencyInfo;
-
-typedef struct VkSemaphoreSubmitInfo {
-    VkStructureType             sType;
-    const  void *                                                                 pNext;
-    VkSemaphore                                                                  semaphore;
-    uint64_t                                                                     value;
-    VkPipelineStageFlags2                                        stageMask;
-    uint32_t                                                                     deviceIndex;
-} VkSemaphoreSubmitInfo;
-
-typedef struct VkSubmitInfo2 {
-    VkStructureType                     sType;
-    const  void *                                                                 pNext;
-    VkSubmitFlags                                                flags;
-    uint32_t                                                     waitSemaphoreInfoCount;
-    const  VkSemaphoreSubmitInfo *                   pWaitSemaphoreInfos;
-    uint32_t                                                     commandBufferInfoCount;
-    const  VkCommandBufferSubmitInfo *               pCommandBufferInfos;
-    uint32_t                                                     signalSemaphoreInfoCount;
-    const  VkSemaphoreSubmitInfo *                 pSignalSemaphoreInfos;
-} VkSubmitInfo2;
-
-typedef struct VkPhysicalDeviceSynchronization2Features {
-    VkStructureType   sType;
-    void *         pNext;
-    VkBool32                             synchronization2;
-} VkPhysicalDeviceSynchronization2Features;
-
-typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures {
-    VkStructureType   sType;
-    void *                pNext;
-    VkBool32                              shaderIntegerDotProduct;
-} VkPhysicalDeviceShaderIntegerDotProductFeatures;
-
-typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties {
-    VkStructureType   sType;
-    void *                pNext;
-    VkBool32          integerDotProduct8BitUnsignedAccelerated;
-    VkBool32          integerDotProduct8BitSignedAccelerated;
-    VkBool32          integerDotProduct8BitMixedSignednessAccelerated;
-    VkBool32          integerDotProduct4x8BitPackedUnsignedAccelerated;
-    VkBool32          integerDotProduct4x8BitPackedSignedAccelerated;
-    VkBool32          integerDotProduct4x8BitPackedMixedSignednessAccelerated;
-    VkBool32          integerDotProduct16BitUnsignedAccelerated;
-    VkBool32          integerDotProduct16BitSignedAccelerated;
-    VkBool32          integerDotProduct16BitMixedSignednessAccelerated;
-    VkBool32          integerDotProduct32BitUnsignedAccelerated;
-    VkBool32          integerDotProduct32BitSignedAccelerated;
-    VkBool32          integerDotProduct32BitMixedSignednessAccelerated;
-    VkBool32          integerDotProduct64BitUnsignedAccelerated;
-    VkBool32          integerDotProduct64BitSignedAccelerated;
-    VkBool32          integerDotProduct64BitMixedSignednessAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating8BitUnsignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating8BitSignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating16BitUnsignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating16BitSignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating32BitUnsignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating32BitSignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating64BitUnsignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating64BitSignedAccelerated;
-    VkBool32          integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated;
-} VkPhysicalDeviceShaderIntegerDotProductProperties;
-
-typedef struct VkFormatProperties3 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkFormatFeatureFlags2              linearTilingFeatures;
-    VkFormatFeatureFlags2              optimalTilingFeatures;
-    VkFormatFeatureFlags2              bufferFeatures;
-} VkFormatProperties3;
-
-typedef struct VkRenderingInfo {
-    VkStructureType                    sType;
-    const  void *                                                 pNext;
-    VkRenderingFlags                                             flags;
-    VkRect2D                                                                     renderArea;
-    uint32_t                                                                     layerCount;
-    uint32_t                                                                     viewMask;
-    uint32_t                                                     colorAttachmentCount;
-    const  VkRenderingAttachmentInfo *                 pColorAttachments;
-    const  VkRenderingAttachmentInfo *                            pDepthAttachment;
-    const  VkRenderingAttachmentInfo *                            pStencilAttachment;
-} VkRenderingInfo;
-
-typedef struct VkPhysicalDeviceDynamicRenderingFeatures {
-    VkStructureType   sType;
-    void *                                 pNext;
-    VkBool32                                                                     dynamicRendering;
-} VkPhysicalDeviceDynamicRenderingFeatures;
-
-typedef struct VkCommandBufferInheritanceRenderingInfo {
-    VkStructureType   sType;
-    const  void *                                                 pNext;
-    VkRenderingFlags                                             flags;
-    uint32_t                                                                     viewMask;
-    uint32_t                                                     colorAttachmentCount;
-    const  VkFormat *                                  pColorAttachmentFormats;
-    VkFormat                                                                     depthAttachmentFormat;
-    VkFormat                                                                     stencilAttachmentFormat;
-    VkSampleCountFlagBits                                        rasterizationSamples;
-} VkCommandBufferInheritanceRenderingInfo;
-
-typedef struct VkPhysicalDeviceProperties {
-    uint32_t         apiVersion;
-    uint32_t         driverVersion;
-    uint32_t         vendorID;
-    uint32_t         deviceID;
-    VkPhysicalDeviceType   deviceType;
-    char             deviceName [ VK_MAX_PHYSICAL_DEVICE_NAME_SIZE ];
-    uint8_t          pipelineCacheUUID [ VK_UUID_SIZE ];
-    VkPhysicalDeviceLimits   limits;
-    VkPhysicalDeviceSparseProperties   sparseProperties;
-} VkPhysicalDeviceProperties;
-
-typedef struct VkDeviceCreateInfo {
-    VkStructureType   sType;
-    const  void *      pNext;
-    VkDeviceCreateFlags      flags;
-    uint32_t          queueCreateInfoCount;
-    const  VkDeviceQueueCreateInfo *  pQueueCreateInfos;
-    uint32_t                 enabledLayerCount;
-    const  char * const*       ppEnabledLayerNames;
-    uint32_t                 enabledExtensionCount;
-    const  char * const*       ppEnabledExtensionNames;
-    const  VkPhysicalDeviceFeatures *  pEnabledFeatures;
-} VkDeviceCreateInfo;
-
-typedef struct VkPhysicalDeviceMemoryProperties {
-    uint32_t                 memoryTypeCount;
-    VkMemoryType             memoryTypes [ VK_MAX_MEMORY_TYPES ];
-    uint32_t                 memoryHeapCount;
-    VkMemoryHeap             memoryHeaps [ VK_MAX_MEMORY_HEAPS ];
-} VkPhysicalDeviceMemoryProperties;
-
-typedef struct VkPhysicalDeviceProperties2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkPhysicalDeviceProperties         properties;
-} VkPhysicalDeviceProperties2;
-
-typedef struct VkPhysicalDeviceMemoryProperties2 {
-    VkStructureType   sType;
-    void *                             pNext;
-    VkPhysicalDeviceMemoryProperties   memoryProperties;
-} VkPhysicalDeviceMemoryProperties2;
-
-typedef struct VkFramebufferAttachmentsCreateInfo {
-    VkStructureType   sType;
-    const  void *                               pNext;
-    uint32_t                   attachmentImageInfoCount;
-    const  VkFramebufferAttachmentImageInfo *  pAttachmentImageInfos;
-} VkFramebufferAttachmentsCreateInfo;
-
-
-
-#define VK_VERSION_1_0 1
-GLAD_API_CALL int GLAD_VK_VERSION_1_0;
-#define VK_VERSION_1_1 1
-GLAD_API_CALL int GLAD_VK_VERSION_1_1;
-#define VK_VERSION_1_2 1
-GLAD_API_CALL int GLAD_VK_VERSION_1_2;
-#define VK_VERSION_1_3 1
-GLAD_API_CALL int GLAD_VK_VERSION_1_3;
-#define VK_EXT_debug_report 1
-GLAD_API_CALL int GLAD_VK_EXT_debug_report;
-#define VK_KHR_portability_enumeration 1
-GLAD_API_CALL int GLAD_VK_KHR_portability_enumeration;
-#define VK_KHR_surface 1
-GLAD_API_CALL int GLAD_VK_KHR_surface;
-#define VK_KHR_swapchain 1
-GLAD_API_CALL int GLAD_VK_KHR_swapchain;
-
-
-typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR * pAcquireInfo, uint32_t * pImageIndex);
-typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t * pImageIndex);
-typedef VkResult (GLAD_API_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo * pAllocateInfo, VkCommandBuffer * pCommandBuffers);
-typedef VkResult (GLAD_API_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo * pAllocateInfo, VkDescriptorSet * pDescriptorSets);
-typedef VkResult (GLAD_API_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo * pAllocateInfo, const VkAllocationCallbacks * pAllocator, VkDeviceMemory * pMemory);
-typedef VkResult (GLAD_API_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo * pBeginInfo);
-typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset);
-typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos);
-typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset);
-typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos);
-typedef void (GLAD_API_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags);
-typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, VkSubpassContents contents);
-typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, const VkSubpassBeginInfo * pSubpassBeginInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo * pRenderingInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t * pDynamicOffsets);
-typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType);
-typedef void (GLAD_API_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
-typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets);
-typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes, const VkDeviceSize * pStrides);
-typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit * pRegions, VkFilter filter);
-typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 * pBlitImageInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment * pAttachments, uint32_t rectCount, const VkClearRect * pRects);
-typedef void (GLAD_API_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue * pColor, uint32_t rangeCount, const VkImageSubresourceRange * pRanges);
-typedef void (GLAD_API_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue * pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange * pRanges);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy * pRegions);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 * pCopyBufferInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy * pRegions);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 * pCopyBufferToImageInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy * pRegions);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 * pCopyImageInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy * pRegions);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 * pCopyImageToBufferInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags);
-typedef void (GLAD_API_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-typedef void (GLAD_API_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
-typedef void (GLAD_API_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
-typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
-typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
-typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
-typedef void (GLAD_API_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query);
-typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer);
-typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo * pSubpassEndInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer);
-typedef void (GLAD_API_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers);
-typedef void (GLAD_API_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
-typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents);
-typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo * pSubpassBeginInfo, const VkSubpassEndInfo * pSubpassEndInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers);
-typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo * pDependencyInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void * pValues);
-typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
-typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve * pRegions);
-typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 * pResolveImageInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants [4]);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo * pDependencyInfo);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D * pScissors);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D * pScissors);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport * pViewports);
-typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport * pViewports);
-typedef void (GLAD_API_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void * pData);
-typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers);
-typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, const VkDependencyInfo * pDependencyInfos);
-typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query);
-typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBuffer * pBuffer);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferView * pView);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCommandPool * pCommandPool);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugReportCallbackEXT * pCallback);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorPool * pDescriptorPool);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorSetLayout * pSetLayout);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice * pDevice);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkEvent * pEvent);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFramebuffer * pFramebuffer);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImage * pImage);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImageView * pView);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkInstance * pInstance);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineCache * pPipelineCache);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineLayout * pPipelineLayout);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlot * pPrivateDataSlot);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkQueryPool * pQueryPool);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2 * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSampler * pSampler);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSemaphore * pSemaphore);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkShaderModule * pShaderModule);
-typedef VkResult (GLAD_API_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchain);
-typedef void (GLAD_API_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char * pLayerPrefix, const char * pMessage);
-typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks * pAllocator);
-typedef void (GLAD_API_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks * pAllocator);
-typedef VkResult (GLAD_API_PTR *PFN_vkDeviceWaitIdle)(VkDevice device);
-typedef VkResult (GLAD_API_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char * pLayerName, uint32_t * pPropertyCount, VkExtensionProperties * pProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkLayerProperties * pProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char * pLayerName, uint32_t * pPropertyCount, VkExtensionProperties * pProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t * pPropertyCount, VkLayerProperties * pProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t * pApiVersion);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t * pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties * pPhysicalDeviceGroupProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t * pPhysicalDeviceCount, VkPhysicalDevice * pPhysicalDevices);
-typedef VkResult (GLAD_API_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges);
-typedef void (GLAD_API_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers);
-typedef VkResult (GLAD_API_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets);
-typedef void (GLAD_API_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks * pAllocator);
-typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo);
-typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements * pMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements);
-typedef uint64_t (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo);
-typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR * pDeviceGroupPresentCapabilities);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR * pModes);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize * pCommittedMemoryInBytes);
-typedef uint64_t (GLAD_API_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo);
-typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char * pName);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue * pQueue);
-typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2 * pQueueInfo, VkQueue * pQueue);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence);
-typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements * pMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements * pSparseMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements);
-typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource * pSubresource, VkSubresourceLayout * pLayout);
-typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char * pName);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo, VkExternalBufferProperties * pExternalBufferProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo * pExternalFenceInfo, VkExternalFenceProperties * pExternalFenceProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo * pExternalSemaphoreInfo, VkExternalSemaphoreProperties * pExternalSemaphoreProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures * pFeatures);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 * pFeatures);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties * pFormatProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties * pImageFormatProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties * pMemoryProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pRectCount, VkRect2D * pRects);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties * pProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 * pProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties * pQueueFamilyProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t * pPropertyCount, VkSparseImageFormatProperties * pProperties);
-typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR * pSurfaceCapabilities);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pSurfaceFormatCount, VkSurfaceFormatKHR * pSurfaceFormats);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 * pSupported);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolProperties * pToolProperties);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t * pDataSize, void * pData);
-typedef void (GLAD_API_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t * pData);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void * pData, VkDeviceSize stride, VkQueryResultFlags flags);
-typedef void (GLAD_API_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D * pGranularity);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t * pValue);
-typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pSwapchainImageCount, VkImage * pSwapchainImages);
-typedef VkResult (GLAD_API_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges);
-typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void ** ppData);
-typedef VkResult (GLAD_API_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache * pSrcCaches);
-typedef VkResult (GLAD_API_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo * pBindInfo, VkFence fence);
-typedef VkResult (GLAD_API_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR * pPresentInfo);
-typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo * pSubmits, VkFence fence);
-typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 * pSubmits, VkFence fence);
-typedef VkResult (GLAD_API_PTR *PFN_vkQueueWaitIdle)(VkQueue queue);
-typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);
-typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);
-typedef VkResult (GLAD_API_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);
-typedef VkResult (GLAD_API_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event);
-typedef VkResult (GLAD_API_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences);
-typedef void (GLAD_API_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
-typedef VkResult (GLAD_API_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event);
-typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data);
-typedef VkResult (GLAD_API_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo * pSignalInfo);
-typedef void (GLAD_API_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
-typedef void (GLAD_API_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory);
-typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData);
-typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet * pDescriptorCopies);
-typedef VkResult (GLAD_API_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences, VkBool32 waitAll, uint64_t timeout);
-typedef VkResult (GLAD_API_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo * pWaitInfo, uint64_t timeout);
-
-GLAD_API_CALL PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR;
-#define vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR
-GLAD_API_CALL PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR;
-#define vkAcquireNextImageKHR glad_vkAcquireNextImageKHR
-GLAD_API_CALL PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers;
-#define vkAllocateCommandBuffers glad_vkAllocateCommandBuffers
-GLAD_API_CALL PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets;
-#define vkAllocateDescriptorSets glad_vkAllocateDescriptorSets
-GLAD_API_CALL PFN_vkAllocateMemory glad_vkAllocateMemory;
-#define vkAllocateMemory glad_vkAllocateMemory
-GLAD_API_CALL PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer;
-#define vkBeginCommandBuffer glad_vkBeginCommandBuffer
-GLAD_API_CALL PFN_vkBindBufferMemory glad_vkBindBufferMemory;
-#define vkBindBufferMemory glad_vkBindBufferMemory
-GLAD_API_CALL PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2;
-#define vkBindBufferMemory2 glad_vkBindBufferMemory2
-GLAD_API_CALL PFN_vkBindImageMemory glad_vkBindImageMemory;
-#define vkBindImageMemory glad_vkBindImageMemory
-GLAD_API_CALL PFN_vkBindImageMemory2 glad_vkBindImageMemory2;
-#define vkBindImageMemory2 glad_vkBindImageMemory2
-GLAD_API_CALL PFN_vkCmdBeginQuery glad_vkCmdBeginQuery;
-#define vkCmdBeginQuery glad_vkCmdBeginQuery
-GLAD_API_CALL PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass;
-#define vkCmdBeginRenderPass glad_vkCmdBeginRenderPass
-GLAD_API_CALL PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2;
-#define vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2
-GLAD_API_CALL PFN_vkCmdBeginRendering glad_vkCmdBeginRendering;
-#define vkCmdBeginRendering glad_vkCmdBeginRendering
-GLAD_API_CALL PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets;
-#define vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets
-GLAD_API_CALL PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer;
-#define vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer
-GLAD_API_CALL PFN_vkCmdBindPipeline glad_vkCmdBindPipeline;
-#define vkCmdBindPipeline glad_vkCmdBindPipeline
-GLAD_API_CALL PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers;
-#define vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers
-GLAD_API_CALL PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2;
-#define vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2
-GLAD_API_CALL PFN_vkCmdBlitImage glad_vkCmdBlitImage;
-#define vkCmdBlitImage glad_vkCmdBlitImage
-GLAD_API_CALL PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2;
-#define vkCmdBlitImage2 glad_vkCmdBlitImage2
-GLAD_API_CALL PFN_vkCmdClearAttachments glad_vkCmdClearAttachments;
-#define vkCmdClearAttachments glad_vkCmdClearAttachments
-GLAD_API_CALL PFN_vkCmdClearColorImage glad_vkCmdClearColorImage;
-#define vkCmdClearColorImage glad_vkCmdClearColorImage
-GLAD_API_CALL PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage;
-#define vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage
-GLAD_API_CALL PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer;
-#define vkCmdCopyBuffer glad_vkCmdCopyBuffer
-GLAD_API_CALL PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2;
-#define vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2
-GLAD_API_CALL PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage;
-#define vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage
-GLAD_API_CALL PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2;
-#define vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2
-GLAD_API_CALL PFN_vkCmdCopyImage glad_vkCmdCopyImage;
-#define vkCmdCopyImage glad_vkCmdCopyImage
-GLAD_API_CALL PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2;
-#define vkCmdCopyImage2 glad_vkCmdCopyImage2
-GLAD_API_CALL PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer;
-#define vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer
-GLAD_API_CALL PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2;
-#define vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2
-GLAD_API_CALL PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults;
-#define vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults
-GLAD_API_CALL PFN_vkCmdDispatch glad_vkCmdDispatch;
-#define vkCmdDispatch glad_vkCmdDispatch
-GLAD_API_CALL PFN_vkCmdDispatchBase glad_vkCmdDispatchBase;
-#define vkCmdDispatchBase glad_vkCmdDispatchBase
-GLAD_API_CALL PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect;
-#define vkCmdDispatchIndirect glad_vkCmdDispatchIndirect
-GLAD_API_CALL PFN_vkCmdDraw glad_vkCmdDraw;
-#define vkCmdDraw glad_vkCmdDraw
-GLAD_API_CALL PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed;
-#define vkCmdDrawIndexed glad_vkCmdDrawIndexed
-GLAD_API_CALL PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect;
-#define vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect
-GLAD_API_CALL PFN_vkCmdDrawIndexedIndirectCount glad_vkCmdDrawIndexedIndirectCount;
-#define vkCmdDrawIndexedIndirectCount glad_vkCmdDrawIndexedIndirectCount
-GLAD_API_CALL PFN_vkCmdDrawIndirect glad_vkCmdDrawIndirect;
-#define vkCmdDrawIndirect glad_vkCmdDrawIndirect
-GLAD_API_CALL PFN_vkCmdDrawIndirectCount glad_vkCmdDrawIndirectCount;
-#define vkCmdDrawIndirectCount glad_vkCmdDrawIndirectCount
-GLAD_API_CALL PFN_vkCmdEndQuery glad_vkCmdEndQuery;
-#define vkCmdEndQuery glad_vkCmdEndQuery
-GLAD_API_CALL PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass;
-#define vkCmdEndRenderPass glad_vkCmdEndRenderPass
-GLAD_API_CALL PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2;
-#define vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2
-GLAD_API_CALL PFN_vkCmdEndRendering glad_vkCmdEndRendering;
-#define vkCmdEndRendering glad_vkCmdEndRendering
-GLAD_API_CALL PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands;
-#define vkCmdExecuteCommands glad_vkCmdExecuteCommands
-GLAD_API_CALL PFN_vkCmdFillBuffer glad_vkCmdFillBuffer;
-#define vkCmdFillBuffer glad_vkCmdFillBuffer
-GLAD_API_CALL PFN_vkCmdNextSubpass glad_vkCmdNextSubpass;
-#define vkCmdNextSubpass glad_vkCmdNextSubpass
-GLAD_API_CALL PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2;
-#define vkCmdNextSubpass2 glad_vkCmdNextSubpass2
-GLAD_API_CALL PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier;
-#define vkCmdPipelineBarrier glad_vkCmdPipelineBarrier
-GLAD_API_CALL PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2;
-#define vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2
-GLAD_API_CALL PFN_vkCmdPushConstants glad_vkCmdPushConstants;
-#define vkCmdPushConstants glad_vkCmdPushConstants
-GLAD_API_CALL PFN_vkCmdResetEvent glad_vkCmdResetEvent;
-#define vkCmdResetEvent glad_vkCmdResetEvent
-GLAD_API_CALL PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2;
-#define vkCmdResetEvent2 glad_vkCmdResetEvent2
-GLAD_API_CALL PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool;
-#define vkCmdResetQueryPool glad_vkCmdResetQueryPool
-GLAD_API_CALL PFN_vkCmdResolveImage glad_vkCmdResolveImage;
-#define vkCmdResolveImage glad_vkCmdResolveImage
-GLAD_API_CALL PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2;
-#define vkCmdResolveImage2 glad_vkCmdResolveImage2
-GLAD_API_CALL PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants;
-#define vkCmdSetBlendConstants glad_vkCmdSetBlendConstants
-GLAD_API_CALL PFN_vkCmdSetCullMode glad_vkCmdSetCullMode;
-#define vkCmdSetCullMode glad_vkCmdSetCullMode
-GLAD_API_CALL PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias;
-#define vkCmdSetDepthBias glad_vkCmdSetDepthBias
-GLAD_API_CALL PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable;
-#define vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable
-GLAD_API_CALL PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds;
-#define vkCmdSetDepthBounds glad_vkCmdSetDepthBounds
-GLAD_API_CALL PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable;
-#define vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable
-GLAD_API_CALL PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp;
-#define vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp
-GLAD_API_CALL PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable;
-#define vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable
-GLAD_API_CALL PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable;
-#define vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable
-GLAD_API_CALL PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask;
-#define vkCmdSetDeviceMask glad_vkCmdSetDeviceMask
-GLAD_API_CALL PFN_vkCmdSetEvent glad_vkCmdSetEvent;
-#define vkCmdSetEvent glad_vkCmdSetEvent
-GLAD_API_CALL PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2;
-#define vkCmdSetEvent2 glad_vkCmdSetEvent2
-GLAD_API_CALL PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace;
-#define vkCmdSetFrontFace glad_vkCmdSetFrontFace
-GLAD_API_CALL PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth;
-#define vkCmdSetLineWidth glad_vkCmdSetLineWidth
-GLAD_API_CALL PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable;
-#define vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable
-GLAD_API_CALL PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology;
-#define vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology
-GLAD_API_CALL PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable;
-#define vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable
-GLAD_API_CALL PFN_vkCmdSetScissor glad_vkCmdSetScissor;
-#define vkCmdSetScissor glad_vkCmdSetScissor
-GLAD_API_CALL PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount;
-#define vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount
-GLAD_API_CALL PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask;
-#define vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask
-GLAD_API_CALL PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp;
-#define vkCmdSetStencilOp glad_vkCmdSetStencilOp
-GLAD_API_CALL PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference;
-#define vkCmdSetStencilReference glad_vkCmdSetStencilReference
-GLAD_API_CALL PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable;
-#define vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable
-GLAD_API_CALL PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask;
-#define vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask
-GLAD_API_CALL PFN_vkCmdSetViewport glad_vkCmdSetViewport;
-#define vkCmdSetViewport glad_vkCmdSetViewport
-GLAD_API_CALL PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount;
-#define vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount
-GLAD_API_CALL PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer;
-#define vkCmdUpdateBuffer glad_vkCmdUpdateBuffer
-GLAD_API_CALL PFN_vkCmdWaitEvents glad_vkCmdWaitEvents;
-#define vkCmdWaitEvents glad_vkCmdWaitEvents
-GLAD_API_CALL PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2;
-#define vkCmdWaitEvents2 glad_vkCmdWaitEvents2
-GLAD_API_CALL PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp;
-#define vkCmdWriteTimestamp glad_vkCmdWriteTimestamp
-GLAD_API_CALL PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2;
-#define vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2
-GLAD_API_CALL PFN_vkCreateBuffer glad_vkCreateBuffer;
-#define vkCreateBuffer glad_vkCreateBuffer
-GLAD_API_CALL PFN_vkCreateBufferView glad_vkCreateBufferView;
-#define vkCreateBufferView glad_vkCreateBufferView
-GLAD_API_CALL PFN_vkCreateCommandPool glad_vkCreateCommandPool;
-#define vkCreateCommandPool glad_vkCreateCommandPool
-GLAD_API_CALL PFN_vkCreateComputePipelines glad_vkCreateComputePipelines;
-#define vkCreateComputePipelines glad_vkCreateComputePipelines
-GLAD_API_CALL PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT;
-#define vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT
-GLAD_API_CALL PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool;
-#define vkCreateDescriptorPool glad_vkCreateDescriptorPool
-GLAD_API_CALL PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout;
-#define vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout
-GLAD_API_CALL PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate;
-#define vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate
-GLAD_API_CALL PFN_vkCreateDevice glad_vkCreateDevice;
-#define vkCreateDevice glad_vkCreateDevice
-GLAD_API_CALL PFN_vkCreateEvent glad_vkCreateEvent;
-#define vkCreateEvent glad_vkCreateEvent
-GLAD_API_CALL PFN_vkCreateFence glad_vkCreateFence;
-#define vkCreateFence glad_vkCreateFence
-GLAD_API_CALL PFN_vkCreateFramebuffer glad_vkCreateFramebuffer;
-#define vkCreateFramebuffer glad_vkCreateFramebuffer
-GLAD_API_CALL PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines;
-#define vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines
-GLAD_API_CALL PFN_vkCreateImage glad_vkCreateImage;
-#define vkCreateImage glad_vkCreateImage
-GLAD_API_CALL PFN_vkCreateImageView glad_vkCreateImageView;
-#define vkCreateImageView glad_vkCreateImageView
-GLAD_API_CALL PFN_vkCreateInstance glad_vkCreateInstance;
-#define vkCreateInstance glad_vkCreateInstance
-GLAD_API_CALL PFN_vkCreatePipelineCache glad_vkCreatePipelineCache;
-#define vkCreatePipelineCache glad_vkCreatePipelineCache
-GLAD_API_CALL PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout;
-#define vkCreatePipelineLayout glad_vkCreatePipelineLayout
-GLAD_API_CALL PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot;
-#define vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot
-GLAD_API_CALL PFN_vkCreateQueryPool glad_vkCreateQueryPool;
-#define vkCreateQueryPool glad_vkCreateQueryPool
-GLAD_API_CALL PFN_vkCreateRenderPass glad_vkCreateRenderPass;
-#define vkCreateRenderPass glad_vkCreateRenderPass
-GLAD_API_CALL PFN_vkCreateRenderPass2 glad_vkCreateRenderPass2;
-#define vkCreateRenderPass2 glad_vkCreateRenderPass2
-GLAD_API_CALL PFN_vkCreateSampler glad_vkCreateSampler;
-#define vkCreateSampler glad_vkCreateSampler
-GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion;
-#define vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion
-GLAD_API_CALL PFN_vkCreateSemaphore glad_vkCreateSemaphore;
-#define vkCreateSemaphore glad_vkCreateSemaphore
-GLAD_API_CALL PFN_vkCreateShaderModule glad_vkCreateShaderModule;
-#define vkCreateShaderModule glad_vkCreateShaderModule
-GLAD_API_CALL PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR;
-#define vkCreateSwapchainKHR glad_vkCreateSwapchainKHR
-GLAD_API_CALL PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT;
-#define vkDebugReportMessageEXT glad_vkDebugReportMessageEXT
-GLAD_API_CALL PFN_vkDestroyBuffer glad_vkDestroyBuffer;
-#define vkDestroyBuffer glad_vkDestroyBuffer
-GLAD_API_CALL PFN_vkDestroyBufferView glad_vkDestroyBufferView;
-#define vkDestroyBufferView glad_vkDestroyBufferView
-GLAD_API_CALL PFN_vkDestroyCommandPool glad_vkDestroyCommandPool;
-#define vkDestroyCommandPool glad_vkDestroyCommandPool
-GLAD_API_CALL PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT;
-#define vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT
-GLAD_API_CALL PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool;
-#define vkDestroyDescriptorPool glad_vkDestroyDescriptorPool
-GLAD_API_CALL PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout;
-#define vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout
-GLAD_API_CALL PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate;
-#define vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate
-GLAD_API_CALL PFN_vkDestroyDevice glad_vkDestroyDevice;
-#define vkDestroyDevice glad_vkDestroyDevice
-GLAD_API_CALL PFN_vkDestroyEvent glad_vkDestroyEvent;
-#define vkDestroyEvent glad_vkDestroyEvent
-GLAD_API_CALL PFN_vkDestroyFence glad_vkDestroyFence;
-#define vkDestroyFence glad_vkDestroyFence
-GLAD_API_CALL PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer;
-#define vkDestroyFramebuffer glad_vkDestroyFramebuffer
-GLAD_API_CALL PFN_vkDestroyImage glad_vkDestroyImage;
-#define vkDestroyImage glad_vkDestroyImage
-GLAD_API_CALL PFN_vkDestroyImageView glad_vkDestroyImageView;
-#define vkDestroyImageView glad_vkDestroyImageView
-GLAD_API_CALL PFN_vkDestroyInstance glad_vkDestroyInstance;
-#define vkDestroyInstance glad_vkDestroyInstance
-GLAD_API_CALL PFN_vkDestroyPipeline glad_vkDestroyPipeline;
-#define vkDestroyPipeline glad_vkDestroyPipeline
-GLAD_API_CALL PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache;
-#define vkDestroyPipelineCache glad_vkDestroyPipelineCache
-GLAD_API_CALL PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout;
-#define vkDestroyPipelineLayout glad_vkDestroyPipelineLayout
-GLAD_API_CALL PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot;
-#define vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot
-GLAD_API_CALL PFN_vkDestroyQueryPool glad_vkDestroyQueryPool;
-#define vkDestroyQueryPool glad_vkDestroyQueryPool
-GLAD_API_CALL PFN_vkDestroyRenderPass glad_vkDestroyRenderPass;
-#define vkDestroyRenderPass glad_vkDestroyRenderPass
-GLAD_API_CALL PFN_vkDestroySampler glad_vkDestroySampler;
-#define vkDestroySampler glad_vkDestroySampler
-GLAD_API_CALL PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion;
-#define vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion
-GLAD_API_CALL PFN_vkDestroySemaphore glad_vkDestroySemaphore;
-#define vkDestroySemaphore glad_vkDestroySemaphore
-GLAD_API_CALL PFN_vkDestroyShaderModule glad_vkDestroyShaderModule;
-#define vkDestroyShaderModule glad_vkDestroyShaderModule
-GLAD_API_CALL PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR;
-#define vkDestroySurfaceKHR glad_vkDestroySurfaceKHR
-GLAD_API_CALL PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR;
-#define vkDestroySwapchainKHR glad_vkDestroySwapchainKHR
-GLAD_API_CALL PFN_vkDeviceWaitIdle glad_vkDeviceWaitIdle;
-#define vkDeviceWaitIdle glad_vkDeviceWaitIdle
-GLAD_API_CALL PFN_vkEndCommandBuffer glad_vkEndCommandBuffer;
-#define vkEndCommandBuffer glad_vkEndCommandBuffer
-GLAD_API_CALL PFN_vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties;
-#define vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties
-GLAD_API_CALL PFN_vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties;
-#define vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties
-GLAD_API_CALL PFN_vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties;
-#define vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties
-GLAD_API_CALL PFN_vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties;
-#define vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties
-GLAD_API_CALL PFN_vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion;
-#define vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion
-GLAD_API_CALL PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups;
-#define vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups
-GLAD_API_CALL PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices;
-#define vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices
-GLAD_API_CALL PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges;
-#define vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges
-GLAD_API_CALL PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers;
-#define vkFreeCommandBuffers glad_vkFreeCommandBuffers
-GLAD_API_CALL PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets;
-#define vkFreeDescriptorSets glad_vkFreeDescriptorSets
-GLAD_API_CALL PFN_vkFreeMemory glad_vkFreeMemory;
-#define vkFreeMemory glad_vkFreeMemory
-GLAD_API_CALL PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress;
-#define vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress
-GLAD_API_CALL PFN_vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements;
-#define vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements
-GLAD_API_CALL PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2;
-#define vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2
-GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress;
-#define vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress
-GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport;
-#define vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport
-GLAD_API_CALL PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements;
-#define vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements
-GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures;
-#define vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures
-GLAD_API_CALL PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR;
-#define vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR
-GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR;
-#define vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR
-GLAD_API_CALL PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements;
-#define vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements
-GLAD_API_CALL PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements;
-#define vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements
-GLAD_API_CALL PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment;
-#define vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment
-GLAD_API_CALL PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress;
-#define vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress
-GLAD_API_CALL PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr;
-#define vkGetDeviceProcAddr glad_vkGetDeviceProcAddr
-GLAD_API_CALL PFN_vkGetDeviceQueue glad_vkGetDeviceQueue;
-#define vkGetDeviceQueue glad_vkGetDeviceQueue
-GLAD_API_CALL PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2;
-#define vkGetDeviceQueue2 glad_vkGetDeviceQueue2
-GLAD_API_CALL PFN_vkGetEventStatus glad_vkGetEventStatus;
-#define vkGetEventStatus glad_vkGetEventStatus
-GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus;
-#define vkGetFenceStatus glad_vkGetFenceStatus
-GLAD_API_CALL PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements;
-#define vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements
-GLAD_API_CALL PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2;
-#define vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2
-GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements;
-#define vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements
-GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2;
-#define vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2
-GLAD_API_CALL PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout;
-#define vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout
-GLAD_API_CALL PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr;
-#define vkGetInstanceProcAddr glad_vkGetInstanceProcAddr
-GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties;
-#define vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties;
-#define vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties;
-#define vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures;
-#define vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures
-GLAD_API_CALL PFN_vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2;
-#define vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties;
-#define vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2;
-#define vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties;
-#define vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2;
-#define vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties;
-#define vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2;
-#define vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR;
-#define vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR
-GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties;
-#define vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2;
-#define vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties;
-#define vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2;
-#define vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties;
-#define vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2;
-#define vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
-#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR;
-#define vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR;
-#define vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR
-GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR;
-#define vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR
-GLAD_API_CALL PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties;
-#define vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties
-GLAD_API_CALL PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData;
-#define vkGetPipelineCacheData glad_vkGetPipelineCacheData
-GLAD_API_CALL PFN_vkGetPrivateData glad_vkGetPrivateData;
-#define vkGetPrivateData glad_vkGetPrivateData
-GLAD_API_CALL PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults;
-#define vkGetQueryPoolResults glad_vkGetQueryPoolResults
-GLAD_API_CALL PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity;
-#define vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity
-GLAD_API_CALL PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue;
-#define vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue
-GLAD_API_CALL PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR;
-#define vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR
-GLAD_API_CALL PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges;
-#define vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges
-GLAD_API_CALL PFN_vkMapMemory glad_vkMapMemory;
-#define vkMapMemory glad_vkMapMemory
-GLAD_API_CALL PFN_vkMergePipelineCaches glad_vkMergePipelineCaches;
-#define vkMergePipelineCaches glad_vkMergePipelineCaches
-GLAD_API_CALL PFN_vkQueueBindSparse glad_vkQueueBindSparse;
-#define vkQueueBindSparse glad_vkQueueBindSparse
-GLAD_API_CALL PFN_vkQueuePresentKHR glad_vkQueuePresentKHR;
-#define vkQueuePresentKHR glad_vkQueuePresentKHR
-GLAD_API_CALL PFN_vkQueueSubmit glad_vkQueueSubmit;
-#define vkQueueSubmit glad_vkQueueSubmit
-GLAD_API_CALL PFN_vkQueueSubmit2 glad_vkQueueSubmit2;
-#define vkQueueSubmit2 glad_vkQueueSubmit2
-GLAD_API_CALL PFN_vkQueueWaitIdle glad_vkQueueWaitIdle;
-#define vkQueueWaitIdle glad_vkQueueWaitIdle
-GLAD_API_CALL PFN_vkResetCommandBuffer glad_vkResetCommandBuffer;
-#define vkResetCommandBuffer glad_vkResetCommandBuffer
-GLAD_API_CALL PFN_vkResetCommandPool glad_vkResetCommandPool;
-#define vkResetCommandPool glad_vkResetCommandPool
-GLAD_API_CALL PFN_vkResetDescriptorPool glad_vkResetDescriptorPool;
-#define vkResetDescriptorPool glad_vkResetDescriptorPool
-GLAD_API_CALL PFN_vkResetEvent glad_vkResetEvent;
-#define vkResetEvent glad_vkResetEvent
-GLAD_API_CALL PFN_vkResetFences glad_vkResetFences;
-#define vkResetFences glad_vkResetFences
-GLAD_API_CALL PFN_vkResetQueryPool glad_vkResetQueryPool;
-#define vkResetQueryPool glad_vkResetQueryPool
-GLAD_API_CALL PFN_vkSetEvent glad_vkSetEvent;
-#define vkSetEvent glad_vkSetEvent
-GLAD_API_CALL PFN_vkSetPrivateData glad_vkSetPrivateData;
-#define vkSetPrivateData glad_vkSetPrivateData
-GLAD_API_CALL PFN_vkSignalSemaphore glad_vkSignalSemaphore;
-#define vkSignalSemaphore glad_vkSignalSemaphore
-GLAD_API_CALL PFN_vkTrimCommandPool glad_vkTrimCommandPool;
-#define vkTrimCommandPool glad_vkTrimCommandPool
-GLAD_API_CALL PFN_vkUnmapMemory glad_vkUnmapMemory;
-#define vkUnmapMemory glad_vkUnmapMemory
-GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate;
-#define vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate
-GLAD_API_CALL PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets;
-#define vkUpdateDescriptorSets glad_vkUpdateDescriptorSets
-GLAD_API_CALL PFN_vkWaitForFences glad_vkWaitForFences;
-#define vkWaitForFences glad_vkWaitForFences
-GLAD_API_CALL PFN_vkWaitSemaphores glad_vkWaitSemaphores;
-#define vkWaitSemaphores glad_vkWaitSemaphores
-
-
-
-
-
-GLAD_API_CALL int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc load, void *userptr);
-GLAD_API_CALL int gladLoadVulkan( VkPhysicalDevice physical_device, GLADloadfunc load);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-/* Source */
-#ifdef GLAD_VULKAN_IMPLEMENTATION
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef GLAD_IMPL_UTIL_C_
-#define GLAD_IMPL_UTIL_C_
-
-#ifdef _MSC_VER
-#define GLAD_IMPL_UTIL_SSCANF sscanf_s
-#else
-#define GLAD_IMPL_UTIL_SSCANF sscanf
-#endif
-
-#endif /* GLAD_IMPL_UTIL_C_ */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-
-int GLAD_VK_VERSION_1_0 = 0;
-int GLAD_VK_VERSION_1_1 = 0;
-int GLAD_VK_VERSION_1_2 = 0;
-int GLAD_VK_VERSION_1_3 = 0;
-int GLAD_VK_EXT_debug_report = 0;
-int GLAD_VK_KHR_portability_enumeration = 0;
-int GLAD_VK_KHR_surface = 0;
-int GLAD_VK_KHR_swapchain = 0;
-
-
-
-PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR = NULL;
-PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR = NULL;
-PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers = NULL;
-PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets = NULL;
-PFN_vkAllocateMemory glad_vkAllocateMemory = NULL;
-PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer = NULL;
-PFN_vkBindBufferMemory glad_vkBindBufferMemory = NULL;
-PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2 = NULL;
-PFN_vkBindImageMemory glad_vkBindImageMemory = NULL;
-PFN_vkBindImageMemory2 glad_vkBindImageMemory2 = NULL;
-PFN_vkCmdBeginQuery glad_vkCmdBeginQuery = NULL;
-PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass = NULL;
-PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2 = NULL;
-PFN_vkCmdBeginRendering glad_vkCmdBeginRendering = NULL;
-PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets = NULL;
-PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer = NULL;
-PFN_vkCmdBindPipeline glad_vkCmdBindPipeline = NULL;
-PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers = NULL;
-PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2 = NULL;
-PFN_vkCmdBlitImage glad_vkCmdBlitImage = NULL;
-PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2 = NULL;
-PFN_vkCmdClearAttachments glad_vkCmdClearAttachments = NULL;
-PFN_vkCmdClearColorImage glad_vkCmdClearColorImage = NULL;
-PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage = NULL;
-PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer = NULL;
-PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2 = NULL;
-PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage = NULL;
-PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2 = NULL;
-PFN_vkCmdCopyImage glad_vkCmdCopyImage = NULL;
-PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2 = NULL;
-PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer = NULL;
-PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2 = NULL;
-PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults = NULL;
-PFN_vkCmdDispatch glad_vkCmdDispatch = NULL;
-PFN_vkCmdDispatchBase glad_vkCmdDispatchBase = NULL;
-PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect = NULL;
-PFN_vkCmdDraw glad_vkCmdDraw = NULL;
-PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed = NULL;
-PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect = NULL;
-PFN_vkCmdDrawIndexedIndirectCount glad_vkCmdDrawIndexedIndirectCount = NULL;
-PFN_vkCmdDrawIndirect glad_vkCmdDrawIndirect = NULL;
-PFN_vkCmdDrawIndirectCount glad_vkCmdDrawIndirectCount = NULL;
-PFN_vkCmdEndQuery glad_vkCmdEndQuery = NULL;
-PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass = NULL;
-PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2 = NULL;
-PFN_vkCmdEndRendering glad_vkCmdEndRendering = NULL;
-PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands = NULL;
-PFN_vkCmdFillBuffer glad_vkCmdFillBuffer = NULL;
-PFN_vkCmdNextSubpass glad_vkCmdNextSubpass = NULL;
-PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2 = NULL;
-PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier = NULL;
-PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2 = NULL;
-PFN_vkCmdPushConstants glad_vkCmdPushConstants = NULL;
-PFN_vkCmdResetEvent glad_vkCmdResetEvent = NULL;
-PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2 = NULL;
-PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool = NULL;
-PFN_vkCmdResolveImage glad_vkCmdResolveImage = NULL;
-PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2 = NULL;
-PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants = NULL;
-PFN_vkCmdSetCullMode glad_vkCmdSetCullMode = NULL;
-PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias = NULL;
-PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable = NULL;
-PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds = NULL;
-PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable = NULL;
-PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp = NULL;
-PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable = NULL;
-PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable = NULL;
-PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask = NULL;
-PFN_vkCmdSetEvent glad_vkCmdSetEvent = NULL;
-PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2 = NULL;
-PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace = NULL;
-PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth = NULL;
-PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable = NULL;
-PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology = NULL;
-PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable = NULL;
-PFN_vkCmdSetScissor glad_vkCmdSetScissor = NULL;
-PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount = NULL;
-PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask = NULL;
-PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp = NULL;
-PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference = NULL;
-PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable = NULL;
-PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask = NULL;
-PFN_vkCmdSetViewport glad_vkCmdSetViewport = NULL;
-PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount = NULL;
-PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer = NULL;
-PFN_vkCmdWaitEvents glad_vkCmdWaitEvents = NULL;
-PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2 = NULL;
-PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp = NULL;
-PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2 = NULL;
-PFN_vkCreateBuffer glad_vkCreateBuffer = NULL;
-PFN_vkCreateBufferView glad_vkCreateBufferView = NULL;
-PFN_vkCreateCommandPool glad_vkCreateCommandPool = NULL;
-PFN_vkCreateComputePipelines glad_vkCreateComputePipelines = NULL;
-PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT = NULL;
-PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool = NULL;
-PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout = NULL;
-PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate = NULL;
-PFN_vkCreateDevice glad_vkCreateDevice = NULL;
-PFN_vkCreateEvent glad_vkCreateEvent = NULL;
-PFN_vkCreateFence glad_vkCreateFence = NULL;
-PFN_vkCreateFramebuffer glad_vkCreateFramebuffer = NULL;
-PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines = NULL;
-PFN_vkCreateImage glad_vkCreateImage = NULL;
-PFN_vkCreateImageView glad_vkCreateImageView = NULL;
-PFN_vkCreateInstance glad_vkCreateInstance = NULL;
-PFN_vkCreatePipelineCache glad_vkCreatePipelineCache = NULL;
-PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout = NULL;
-PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot = NULL;
-PFN_vkCreateQueryPool glad_vkCreateQueryPool = NULL;
-PFN_vkCreateRenderPass glad_vkCreateRenderPass = NULL;
-PFN_vkCreateRenderPass2 glad_vkCreateRenderPass2 = NULL;
-PFN_vkCreateSampler glad_vkCreateSampler = NULL;
-PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion = NULL;
-PFN_vkCreateSemaphore glad_vkCreateSemaphore = NULL;
-PFN_vkCreateShaderModule glad_vkCreateShaderModule = NULL;
-PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR = NULL;
-PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT = NULL;
-PFN_vkDestroyBuffer glad_vkDestroyBuffer = NULL;
-PFN_vkDestroyBufferView glad_vkDestroyBufferView = NULL;
-PFN_vkDestroyCommandPool glad_vkDestroyCommandPool = NULL;
-PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT = NULL;
-PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool = NULL;
-PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout = NULL;
-PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate = NULL;
-PFN_vkDestroyDevice glad_vkDestroyDevice = NULL;
-PFN_vkDestroyEvent glad_vkDestroyEvent = NULL;
-PFN_vkDestroyFence glad_vkDestroyFence = NULL;
-PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer = NULL;
-PFN_vkDestroyImage glad_vkDestroyImage = NULL;
-PFN_vkDestroyImageView glad_vkDestroyImageView = NULL;
-PFN_vkDestroyInstance glad_vkDestroyInstance = NULL;
-PFN_vkDestroyPipeline glad_vkDestroyPipeline = NULL;
-PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache = NULL;
-PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout = NULL;
-PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot = NULL;
-PFN_vkDestroyQueryPool glad_vkDestroyQueryPool = NULL;
-PFN_vkDestroyRenderPass glad_vkDestroyRenderPass = NULL;
-PFN_vkDestroySampler glad_vkDestroySampler = NULL;
-PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion = NULL;
-PFN_vkDestroySemaphore glad_vkDestroySemaphore = NULL;
-PFN_vkDestroyShaderModule glad_vkDestroyShaderModule = NULL;
-PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR = NULL;
-PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR = NULL;
-PFN_vkDeviceWaitIdle glad_vkDeviceWaitIdle = NULL;
-PFN_vkEndCommandBuffer glad_vkEndCommandBuffer = NULL;
-PFN_vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties = NULL;
-PFN_vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties = NULL;
-PFN_vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties = NULL;
-PFN_vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties = NULL;
-PFN_vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion = NULL;
-PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups = NULL;
-PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices = NULL;
-PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges = NULL;
-PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers = NULL;
-PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets = NULL;
-PFN_vkFreeMemory glad_vkFreeMemory = NULL;
-PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress = NULL;
-PFN_vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements = NULL;
-PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 = NULL;
-PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress = NULL;
-PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport = NULL;
-PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements = NULL;
-PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures = NULL;
-PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR = NULL;
-PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR = NULL;
-PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements = NULL;
-PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements = NULL;
-PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment = NULL;
-PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress = NULL;
-PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr = NULL;
-PFN_vkGetDeviceQueue glad_vkGetDeviceQueue = NULL;
-PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2 = NULL;
-PFN_vkGetEventStatus glad_vkGetEventStatus = NULL;
-PFN_vkGetFenceStatus glad_vkGetFenceStatus = NULL;
-PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements = NULL;
-PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 = NULL;
-PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements = NULL;
-PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 = NULL;
-PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout = NULL;
-PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr = NULL;
-PFN_vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties = NULL;
-PFN_vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties = NULL;
-PFN_vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties = NULL;
-PFN_vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures = NULL;
-PFN_vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2 = NULL;
-PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties = NULL;
-PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 = NULL;
-PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties = NULL;
-PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 = NULL;
-PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties = NULL;
-PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 = NULL;
-PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR = NULL;
-PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties = NULL;
-PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 = NULL;
-PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties = NULL;
-PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 = NULL;
-PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties = NULL;
-PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
-PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = NULL;
-PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR = NULL;
-PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR = NULL;
-PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR = NULL;
-PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties = NULL;
-PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData = NULL;
-PFN_vkGetPrivateData glad_vkGetPrivateData = NULL;
-PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults = NULL;
-PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity = NULL;
-PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue = NULL;
-PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR = NULL;
-PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges = NULL;
-PFN_vkMapMemory glad_vkMapMemory = NULL;
-PFN_vkMergePipelineCaches glad_vkMergePipelineCaches = NULL;
-PFN_vkQueueBindSparse glad_vkQueueBindSparse = NULL;
-PFN_vkQueuePresentKHR glad_vkQueuePresentKHR = NULL;
-PFN_vkQueueSubmit glad_vkQueueSubmit = NULL;
-PFN_vkQueueSubmit2 glad_vkQueueSubmit2 = NULL;
-PFN_vkQueueWaitIdle glad_vkQueueWaitIdle = NULL;
-PFN_vkResetCommandBuffer glad_vkResetCommandBuffer = NULL;
-PFN_vkResetCommandPool glad_vkResetCommandPool = NULL;
-PFN_vkResetDescriptorPool glad_vkResetDescriptorPool = NULL;
-PFN_vkResetEvent glad_vkResetEvent = NULL;
-PFN_vkResetFences glad_vkResetFences = NULL;
-PFN_vkResetQueryPool glad_vkResetQueryPool = NULL;
-PFN_vkSetEvent glad_vkSetEvent = NULL;
-PFN_vkSetPrivateData glad_vkSetPrivateData = NULL;
-PFN_vkSignalSemaphore glad_vkSignalSemaphore = NULL;
-PFN_vkTrimCommandPool glad_vkTrimCommandPool = NULL;
-PFN_vkUnmapMemory glad_vkUnmapMemory = NULL;
-PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate = NULL;
-PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets = NULL;
-PFN_vkWaitForFences glad_vkWaitForFences = NULL;
-PFN_vkWaitSemaphores glad_vkWaitSemaphores = NULL;
-
-
-static void glad_vk_load_VK_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_VERSION_1_0) return;
-    glad_vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers) load(userptr, "vkAllocateCommandBuffers");
-    glad_vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets) load(userptr, "vkAllocateDescriptorSets");
-    glad_vkAllocateMemory = (PFN_vkAllocateMemory) load(userptr, "vkAllocateMemory");
-    glad_vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer) load(userptr, "vkBeginCommandBuffer");
-    glad_vkBindBufferMemory = (PFN_vkBindBufferMemory) load(userptr, "vkBindBufferMemory");
-    glad_vkBindImageMemory = (PFN_vkBindImageMemory) load(userptr, "vkBindImageMemory");
-    glad_vkCmdBeginQuery = (PFN_vkCmdBeginQuery) load(userptr, "vkCmdBeginQuery");
-    glad_vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass) load(userptr, "vkCmdBeginRenderPass");
-    glad_vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets) load(userptr, "vkCmdBindDescriptorSets");
-    glad_vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer) load(userptr, "vkCmdBindIndexBuffer");
-    glad_vkCmdBindPipeline = (PFN_vkCmdBindPipeline) load(userptr, "vkCmdBindPipeline");
-    glad_vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers) load(userptr, "vkCmdBindVertexBuffers");
-    glad_vkCmdBlitImage = (PFN_vkCmdBlitImage) load(userptr, "vkCmdBlitImage");
-    glad_vkCmdClearAttachments = (PFN_vkCmdClearAttachments) load(userptr, "vkCmdClearAttachments");
-    glad_vkCmdClearColorImage = (PFN_vkCmdClearColorImage) load(userptr, "vkCmdClearColorImage");
-    glad_vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage) load(userptr, "vkCmdClearDepthStencilImage");
-    glad_vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer) load(userptr, "vkCmdCopyBuffer");
-    glad_vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage) load(userptr, "vkCmdCopyBufferToImage");
-    glad_vkCmdCopyImage = (PFN_vkCmdCopyImage) load(userptr, "vkCmdCopyImage");
-    glad_vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer) load(userptr, "vkCmdCopyImageToBuffer");
-    glad_vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults) load(userptr, "vkCmdCopyQueryPoolResults");
-    glad_vkCmdDispatch = (PFN_vkCmdDispatch) load(userptr, "vkCmdDispatch");
-    glad_vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect) load(userptr, "vkCmdDispatchIndirect");
-    glad_vkCmdDraw = (PFN_vkCmdDraw) load(userptr, "vkCmdDraw");
-    glad_vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed) load(userptr, "vkCmdDrawIndexed");
-    glad_vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect) load(userptr, "vkCmdDrawIndexedIndirect");
-    glad_vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect) load(userptr, "vkCmdDrawIndirect");
-    glad_vkCmdEndQuery = (PFN_vkCmdEndQuery) load(userptr, "vkCmdEndQuery");
-    glad_vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass) load(userptr, "vkCmdEndRenderPass");
-    glad_vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands) load(userptr, "vkCmdExecuteCommands");
-    glad_vkCmdFillBuffer = (PFN_vkCmdFillBuffer) load(userptr, "vkCmdFillBuffer");
-    glad_vkCmdNextSubpass = (PFN_vkCmdNextSubpass) load(userptr, "vkCmdNextSubpass");
-    glad_vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier) load(userptr, "vkCmdPipelineBarrier");
-    glad_vkCmdPushConstants = (PFN_vkCmdPushConstants) load(userptr, "vkCmdPushConstants");
-    glad_vkCmdResetEvent = (PFN_vkCmdResetEvent) load(userptr, "vkCmdResetEvent");
-    glad_vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool) load(userptr, "vkCmdResetQueryPool");
-    glad_vkCmdResolveImage = (PFN_vkCmdResolveImage) load(userptr, "vkCmdResolveImage");
-    glad_vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants) load(userptr, "vkCmdSetBlendConstants");
-    glad_vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias) load(userptr, "vkCmdSetDepthBias");
-    glad_vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds) load(userptr, "vkCmdSetDepthBounds");
-    glad_vkCmdSetEvent = (PFN_vkCmdSetEvent) load(userptr, "vkCmdSetEvent");
-    glad_vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth) load(userptr, "vkCmdSetLineWidth");
-    glad_vkCmdSetScissor = (PFN_vkCmdSetScissor) load(userptr, "vkCmdSetScissor");
-    glad_vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask) load(userptr, "vkCmdSetStencilCompareMask");
-    glad_vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference) load(userptr, "vkCmdSetStencilReference");
-    glad_vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask) load(userptr, "vkCmdSetStencilWriteMask");
-    glad_vkCmdSetViewport = (PFN_vkCmdSetViewport) load(userptr, "vkCmdSetViewport");
-    glad_vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer) load(userptr, "vkCmdUpdateBuffer");
-    glad_vkCmdWaitEvents = (PFN_vkCmdWaitEvents) load(userptr, "vkCmdWaitEvents");
-    glad_vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp) load(userptr, "vkCmdWriteTimestamp");
-    glad_vkCreateBuffer = (PFN_vkCreateBuffer) load(userptr, "vkCreateBuffer");
-    glad_vkCreateBufferView = (PFN_vkCreateBufferView) load(userptr, "vkCreateBufferView");
-    glad_vkCreateCommandPool = (PFN_vkCreateCommandPool) load(userptr, "vkCreateCommandPool");
-    glad_vkCreateComputePipelines = (PFN_vkCreateComputePipelines) load(userptr, "vkCreateComputePipelines");
-    glad_vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool) load(userptr, "vkCreateDescriptorPool");
-    glad_vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout) load(userptr, "vkCreateDescriptorSetLayout");
-    glad_vkCreateDevice = (PFN_vkCreateDevice) load(userptr, "vkCreateDevice");
-    glad_vkCreateEvent = (PFN_vkCreateEvent) load(userptr, "vkCreateEvent");
-    glad_vkCreateFence = (PFN_vkCreateFence) load(userptr, "vkCreateFence");
-    glad_vkCreateFramebuffer = (PFN_vkCreateFramebuffer) load(userptr, "vkCreateFramebuffer");
-    glad_vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines) load(userptr, "vkCreateGraphicsPipelines");
-    glad_vkCreateImage = (PFN_vkCreateImage) load(userptr, "vkCreateImage");
-    glad_vkCreateImageView = (PFN_vkCreateImageView) load(userptr, "vkCreateImageView");
-    glad_vkCreateInstance = (PFN_vkCreateInstance) load(userptr, "vkCreateInstance");
-    glad_vkCreatePipelineCache = (PFN_vkCreatePipelineCache) load(userptr, "vkCreatePipelineCache");
-    glad_vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout) load(userptr, "vkCreatePipelineLayout");
-    glad_vkCreateQueryPool = (PFN_vkCreateQueryPool) load(userptr, "vkCreateQueryPool");
-    glad_vkCreateRenderPass = (PFN_vkCreateRenderPass) load(userptr, "vkCreateRenderPass");
-    glad_vkCreateSampler = (PFN_vkCreateSampler) load(userptr, "vkCreateSampler");
-    glad_vkCreateSemaphore = (PFN_vkCreateSemaphore) load(userptr, "vkCreateSemaphore");
-    glad_vkCreateShaderModule = (PFN_vkCreateShaderModule) load(userptr, "vkCreateShaderModule");
-    glad_vkDestroyBuffer = (PFN_vkDestroyBuffer) load(userptr, "vkDestroyBuffer");
-    glad_vkDestroyBufferView = (PFN_vkDestroyBufferView) load(userptr, "vkDestroyBufferView");
-    glad_vkDestroyCommandPool = (PFN_vkDestroyCommandPool) load(userptr, "vkDestroyCommandPool");
-    glad_vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool) load(userptr, "vkDestroyDescriptorPool");
-    glad_vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout) load(userptr, "vkDestroyDescriptorSetLayout");
-    glad_vkDestroyDevice = (PFN_vkDestroyDevice) load(userptr, "vkDestroyDevice");
-    glad_vkDestroyEvent = (PFN_vkDestroyEvent) load(userptr, "vkDestroyEvent");
-    glad_vkDestroyFence = (PFN_vkDestroyFence) load(userptr, "vkDestroyFence");
-    glad_vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer) load(userptr, "vkDestroyFramebuffer");
-    glad_vkDestroyImage = (PFN_vkDestroyImage) load(userptr, "vkDestroyImage");
-    glad_vkDestroyImageView = (PFN_vkDestroyImageView) load(userptr, "vkDestroyImageView");
-    glad_vkDestroyInstance = (PFN_vkDestroyInstance) load(userptr, "vkDestroyInstance");
-    glad_vkDestroyPipeline = (PFN_vkDestroyPipeline) load(userptr, "vkDestroyPipeline");
-    glad_vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache) load(userptr, "vkDestroyPipelineCache");
-    glad_vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout) load(userptr, "vkDestroyPipelineLayout");
-    glad_vkDestroyQueryPool = (PFN_vkDestroyQueryPool) load(userptr, "vkDestroyQueryPool");
-    glad_vkDestroyRenderPass = (PFN_vkDestroyRenderPass) load(userptr, "vkDestroyRenderPass");
-    glad_vkDestroySampler = (PFN_vkDestroySampler) load(userptr, "vkDestroySampler");
-    glad_vkDestroySemaphore = (PFN_vkDestroySemaphore) load(userptr, "vkDestroySemaphore");
-    glad_vkDestroyShaderModule = (PFN_vkDestroyShaderModule) load(userptr, "vkDestroyShaderModule");
-    glad_vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle) load(userptr, "vkDeviceWaitIdle");
-    glad_vkEndCommandBuffer = (PFN_vkEndCommandBuffer) load(userptr, "vkEndCommandBuffer");
-    glad_vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties) load(userptr, "vkEnumerateDeviceExtensionProperties");
-    glad_vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties) load(userptr, "vkEnumerateDeviceLayerProperties");
-    glad_vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) load(userptr, "vkEnumerateInstanceExtensionProperties");
-    glad_vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties) load(userptr, "vkEnumerateInstanceLayerProperties");
-    glad_vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) load(userptr, "vkEnumeratePhysicalDevices");
-    glad_vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges) load(userptr, "vkFlushMappedMemoryRanges");
-    glad_vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers) load(userptr, "vkFreeCommandBuffers");
-    glad_vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets) load(userptr, "vkFreeDescriptorSets");
-    glad_vkFreeMemory = (PFN_vkFreeMemory) load(userptr, "vkFreeMemory");
-    glad_vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements) load(userptr, "vkGetBufferMemoryRequirements");
-    glad_vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment) load(userptr, "vkGetDeviceMemoryCommitment");
-    glad_vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) load(userptr, "vkGetDeviceProcAddr");
-    glad_vkGetDeviceQueue = (PFN_vkGetDeviceQueue) load(userptr, "vkGetDeviceQueue");
-    glad_vkGetEventStatus = (PFN_vkGetEventStatus) load(userptr, "vkGetEventStatus");
-    glad_vkGetFenceStatus = (PFN_vkGetFenceStatus) load(userptr, "vkGetFenceStatus");
-    glad_vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements) load(userptr, "vkGetImageMemoryRequirements");
-    glad_vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements) load(userptr, "vkGetImageSparseMemoryRequirements");
-    glad_vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout) load(userptr, "vkGetImageSubresourceLayout");
-    glad_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) load(userptr, "vkGetInstanceProcAddr");
-    glad_vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures) load(userptr, "vkGetPhysicalDeviceFeatures");
-    glad_vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties) load(userptr, "vkGetPhysicalDeviceFormatProperties");
-    glad_vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties) load(userptr, "vkGetPhysicalDeviceImageFormatProperties");
-    glad_vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) load(userptr, "vkGetPhysicalDeviceMemoryProperties");
-    glad_vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) load(userptr, "vkGetPhysicalDeviceProperties");
-    glad_vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties) load(userptr, "vkGetPhysicalDeviceQueueFamilyProperties");
-    glad_vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties) load(userptr, "vkGetPhysicalDeviceSparseImageFormatProperties");
-    glad_vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData) load(userptr, "vkGetPipelineCacheData");
-    glad_vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults) load(userptr, "vkGetQueryPoolResults");
-    glad_vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity) load(userptr, "vkGetRenderAreaGranularity");
-    glad_vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges) load(userptr, "vkInvalidateMappedMemoryRanges");
-    glad_vkMapMemory = (PFN_vkMapMemory) load(userptr, "vkMapMemory");
-    glad_vkMergePipelineCaches = (PFN_vkMergePipelineCaches) load(userptr, "vkMergePipelineCaches");
-    glad_vkQueueBindSparse = (PFN_vkQueueBindSparse) load(userptr, "vkQueueBindSparse");
-    glad_vkQueueSubmit = (PFN_vkQueueSubmit) load(userptr, "vkQueueSubmit");
-    glad_vkQueueWaitIdle = (PFN_vkQueueWaitIdle) load(userptr, "vkQueueWaitIdle");
-    glad_vkResetCommandBuffer = (PFN_vkResetCommandBuffer) load(userptr, "vkResetCommandBuffer");
-    glad_vkResetCommandPool = (PFN_vkResetCommandPool) load(userptr, "vkResetCommandPool");
-    glad_vkResetDescriptorPool = (PFN_vkResetDescriptorPool) load(userptr, "vkResetDescriptorPool");
-    glad_vkResetEvent = (PFN_vkResetEvent) load(userptr, "vkResetEvent");
-    glad_vkResetFences = (PFN_vkResetFences) load(userptr, "vkResetFences");
-    glad_vkSetEvent = (PFN_vkSetEvent) load(userptr, "vkSetEvent");
-    glad_vkUnmapMemory = (PFN_vkUnmapMemory) load(userptr, "vkUnmapMemory");
-    glad_vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets) load(userptr, "vkUpdateDescriptorSets");
-    glad_vkWaitForFences = (PFN_vkWaitForFences) load(userptr, "vkWaitForFences");
-}
-static void glad_vk_load_VK_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_VERSION_1_1) return;
-    glad_vkBindBufferMemory2 = (PFN_vkBindBufferMemory2) load(userptr, "vkBindBufferMemory2");
-    glad_vkBindImageMemory2 = (PFN_vkBindImageMemory2) load(userptr, "vkBindImageMemory2");
-    glad_vkCmdDispatchBase = (PFN_vkCmdDispatchBase) load(userptr, "vkCmdDispatchBase");
-    glad_vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask) load(userptr, "vkCmdSetDeviceMask");
-    glad_vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate) load(userptr, "vkCreateDescriptorUpdateTemplate");
-    glad_vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion) load(userptr, "vkCreateSamplerYcbcrConversion");
-    glad_vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate) load(userptr, "vkDestroyDescriptorUpdateTemplate");
-    glad_vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion) load(userptr, "vkDestroySamplerYcbcrConversion");
-    glad_vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) load(userptr, "vkEnumerateInstanceVersion");
-    glad_vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups) load(userptr, "vkEnumeratePhysicalDeviceGroups");
-    glad_vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2) load(userptr, "vkGetBufferMemoryRequirements2");
-    glad_vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport) load(userptr, "vkGetDescriptorSetLayoutSupport");
-    glad_vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures) load(userptr, "vkGetDeviceGroupPeerMemoryFeatures");
-    glad_vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2) load(userptr, "vkGetDeviceQueue2");
-    glad_vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2) load(userptr, "vkGetImageMemoryRequirements2");
-    glad_vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2) load(userptr, "vkGetImageSparseMemoryRequirements2");
-    glad_vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties) load(userptr, "vkGetPhysicalDeviceExternalBufferProperties");
-    glad_vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties) load(userptr, "vkGetPhysicalDeviceExternalFenceProperties");
-    glad_vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties) load(userptr, "vkGetPhysicalDeviceExternalSemaphoreProperties");
-    glad_vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2) load(userptr, "vkGetPhysicalDeviceFeatures2");
-    glad_vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2) load(userptr, "vkGetPhysicalDeviceFormatProperties2");
-    glad_vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2) load(userptr, "vkGetPhysicalDeviceImageFormatProperties2");
-    glad_vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2) load(userptr, "vkGetPhysicalDeviceMemoryProperties2");
-    glad_vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) load(userptr, "vkGetPhysicalDeviceProperties2");
-    glad_vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2) load(userptr, "vkGetPhysicalDeviceQueueFamilyProperties2");
-    glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2) load(userptr, "vkGetPhysicalDeviceSparseImageFormatProperties2");
-    glad_vkTrimCommandPool = (PFN_vkTrimCommandPool) load(userptr, "vkTrimCommandPool");
-    glad_vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate) load(userptr, "vkUpdateDescriptorSetWithTemplate");
-}
-static void glad_vk_load_VK_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_VERSION_1_2) return;
-    glad_vkCmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2) load(userptr, "vkCmdBeginRenderPass2");
-    glad_vkCmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount) load(userptr, "vkCmdDrawIndexedIndirectCount");
-    glad_vkCmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount) load(userptr, "vkCmdDrawIndirectCount");
-    glad_vkCmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2) load(userptr, "vkCmdEndRenderPass2");
-    glad_vkCmdNextSubpass2 = (PFN_vkCmdNextSubpass2) load(userptr, "vkCmdNextSubpass2");
-    glad_vkCreateRenderPass2 = (PFN_vkCreateRenderPass2) load(userptr, "vkCreateRenderPass2");
-    glad_vkGetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress) load(userptr, "vkGetBufferDeviceAddress");
-    glad_vkGetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress) load(userptr, "vkGetBufferOpaqueCaptureAddress");
-    glad_vkGetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress) load(userptr, "vkGetDeviceMemoryOpaqueCaptureAddress");
-    glad_vkGetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue) load(userptr, "vkGetSemaphoreCounterValue");
-    glad_vkResetQueryPool = (PFN_vkResetQueryPool) load(userptr, "vkResetQueryPool");
-    glad_vkSignalSemaphore = (PFN_vkSignalSemaphore) load(userptr, "vkSignalSemaphore");
-    glad_vkWaitSemaphores = (PFN_vkWaitSemaphores) load(userptr, "vkWaitSemaphores");
-}
-static void glad_vk_load_VK_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_VERSION_1_3) return;
-    glad_vkCmdBeginRendering = (PFN_vkCmdBeginRendering) load(userptr, "vkCmdBeginRendering");
-    glad_vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2) load(userptr, "vkCmdBindVertexBuffers2");
-    glad_vkCmdBlitImage2 = (PFN_vkCmdBlitImage2) load(userptr, "vkCmdBlitImage2");
-    glad_vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2) load(userptr, "vkCmdCopyBuffer2");
-    glad_vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2) load(userptr, "vkCmdCopyBufferToImage2");
-    glad_vkCmdCopyImage2 = (PFN_vkCmdCopyImage2) load(userptr, "vkCmdCopyImage2");
-    glad_vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2) load(userptr, "vkCmdCopyImageToBuffer2");
-    glad_vkCmdEndRendering = (PFN_vkCmdEndRendering) load(userptr, "vkCmdEndRendering");
-    glad_vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2) load(userptr, "vkCmdPipelineBarrier2");
-    glad_vkCmdResetEvent2 = (PFN_vkCmdResetEvent2) load(userptr, "vkCmdResetEvent2");
-    glad_vkCmdResolveImage2 = (PFN_vkCmdResolveImage2) load(userptr, "vkCmdResolveImage2");
-    glad_vkCmdSetCullMode = (PFN_vkCmdSetCullMode) load(userptr, "vkCmdSetCullMode");
-    glad_vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable) load(userptr, "vkCmdSetDepthBiasEnable");
-    glad_vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable) load(userptr, "vkCmdSetDepthBoundsTestEnable");
-    glad_vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp) load(userptr, "vkCmdSetDepthCompareOp");
-    glad_vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable) load(userptr, "vkCmdSetDepthTestEnable");
-    glad_vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable) load(userptr, "vkCmdSetDepthWriteEnable");
-    glad_vkCmdSetEvent2 = (PFN_vkCmdSetEvent2) load(userptr, "vkCmdSetEvent2");
-    glad_vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace) load(userptr, "vkCmdSetFrontFace");
-    glad_vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable) load(userptr, "vkCmdSetPrimitiveRestartEnable");
-    glad_vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology) load(userptr, "vkCmdSetPrimitiveTopology");
-    glad_vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable) load(userptr, "vkCmdSetRasterizerDiscardEnable");
-    glad_vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount) load(userptr, "vkCmdSetScissorWithCount");
-    glad_vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp) load(userptr, "vkCmdSetStencilOp");
-    glad_vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable) load(userptr, "vkCmdSetStencilTestEnable");
-    glad_vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount) load(userptr, "vkCmdSetViewportWithCount");
-    glad_vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2) load(userptr, "vkCmdWaitEvents2");
-    glad_vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2) load(userptr, "vkCmdWriteTimestamp2");
-    glad_vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot) load(userptr, "vkCreatePrivateDataSlot");
-    glad_vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot) load(userptr, "vkDestroyPrivateDataSlot");
-    glad_vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements) load(userptr, "vkGetDeviceBufferMemoryRequirements");
-    glad_vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements) load(userptr, "vkGetDeviceImageMemoryRequirements");
-    glad_vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements) load(userptr, "vkGetDeviceImageSparseMemoryRequirements");
-    glad_vkGetPhysicalDeviceToolProperties = (PFN_vkGetPhysicalDeviceToolProperties) load(userptr, "vkGetPhysicalDeviceToolProperties");
-    glad_vkGetPrivateData = (PFN_vkGetPrivateData) load(userptr, "vkGetPrivateData");
-    glad_vkQueueSubmit2 = (PFN_vkQueueSubmit2) load(userptr, "vkQueueSubmit2");
-    glad_vkSetPrivateData = (PFN_vkSetPrivateData) load(userptr, "vkSetPrivateData");
-}
-static void glad_vk_load_VK_EXT_debug_report( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_EXT_debug_report) return;
-    glad_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) load(userptr, "vkCreateDebugReportCallbackEXT");
-    glad_vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT) load(userptr, "vkDebugReportMessageEXT");
-    glad_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT) load(userptr, "vkDestroyDebugReportCallbackEXT");
-}
-static void glad_vk_load_VK_KHR_surface( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_KHR_surface) return;
-    glad_vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR) load(userptr, "vkDestroySurfaceKHR");
-    glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR) load(userptr, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
-    glad_vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR) load(userptr, "vkGetPhysicalDeviceSurfaceFormatsKHR");
-    glad_vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) load(userptr, "vkGetPhysicalDeviceSurfacePresentModesKHR");
-    glad_vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) load(userptr, "vkGetPhysicalDeviceSurfaceSupportKHR");
-}
-static void glad_vk_load_VK_KHR_swapchain( GLADuserptrloadfunc load, void* userptr) {
-    if(!GLAD_VK_KHR_swapchain) return;
-    glad_vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR) load(userptr, "vkAcquireNextImage2KHR");
-    glad_vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) load(userptr, "vkAcquireNextImageKHR");
-    glad_vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) load(userptr, "vkCreateSwapchainKHR");
-    glad_vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) load(userptr, "vkDestroySwapchainKHR");
-    glad_vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR) load(userptr, "vkGetDeviceGroupPresentCapabilitiesKHR");
-    glad_vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR) load(userptr, "vkGetDeviceGroupSurfacePresentModesKHR");
-    glad_vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR) load(userptr, "vkGetPhysicalDevicePresentRectanglesKHR");
-    glad_vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) load(userptr, "vkGetSwapchainImagesKHR");
-    glad_vkQueuePresentKHR = (PFN_vkQueuePresentKHR) load(userptr, "vkQueuePresentKHR");
-}
-
-
-
-static int glad_vk_get_extensions( VkPhysicalDevice physical_device, uint32_t *out_extension_count, char ***out_extensions) {
-    uint32_t i;
-    uint32_t instance_extension_count = 0;
-    uint32_t device_extension_count = 0;
-    uint32_t max_extension_count = 0;
-    uint32_t total_extension_count = 0;
-    char **extensions = NULL;
-    VkExtensionProperties *ext_properties = NULL;
-    VkResult result;
-
-    if (glad_vkEnumerateInstanceExtensionProperties == NULL || (physical_device != NULL && glad_vkEnumerateDeviceExtensionProperties == NULL)) {
-        return 0;
-    }
-
-    result = glad_vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL);
-    if (result != VK_SUCCESS) {
-        return 0;
-    }
-
-    if (physical_device != NULL) {
-        result = glad_vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, NULL);
-        if (result != VK_SUCCESS) {
-            return 0;
-        }
-    }
-
-    total_extension_count = instance_extension_count + device_extension_count;
-    if (total_extension_count <= 0) {
-        return 0;
-    }
-
-    max_extension_count = instance_extension_count > device_extension_count
-        ? instance_extension_count : device_extension_count;
-
-    ext_properties = (VkExtensionProperties*) malloc(max_extension_count * sizeof(VkExtensionProperties));
-    if (ext_properties == NULL) {
-        goto glad_vk_get_extensions_error;
-    }
-
-    result = glad_vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, ext_properties);
-    if (result != VK_SUCCESS) {
-        goto glad_vk_get_extensions_error;
-    }
-
-    extensions = (char**) calloc(total_extension_count, sizeof(char*));
-    if (extensions == NULL) {
-        goto glad_vk_get_extensions_error;
-    }
-
-    for (i = 0; i < instance_extension_count; ++i) {
-        VkExtensionProperties ext = ext_properties[i];
-
-        size_t extension_name_length = strlen(ext.extensionName) + 1;
-        extensions[i] = (char*) malloc(extension_name_length * sizeof(char));
-        if (extensions[i] == NULL) {
-            goto glad_vk_get_extensions_error;
-        }
-        memcpy(extensions[i], ext.extensionName, extension_name_length * sizeof(char));
-    }
-
-    if (physical_device != NULL) {
-        result = glad_vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, ext_properties);
-        if (result != VK_SUCCESS) {
-            goto glad_vk_get_extensions_error;
-        }
-
-        for (i = 0; i < device_extension_count; ++i) {
-            VkExtensionProperties ext = ext_properties[i];
-
-            size_t extension_name_length = strlen(ext.extensionName) + 1;
-            extensions[instance_extension_count + i] = (char*) malloc(extension_name_length * sizeof(char));
-            if (extensions[instance_extension_count + i] == NULL) {
-                goto glad_vk_get_extensions_error;
-            }
-            memcpy(extensions[instance_extension_count + i], ext.extensionName, extension_name_length * sizeof(char));
-        }
-    }
-
-    free((void*) ext_properties);
-
-    *out_extension_count = total_extension_count;
-    *out_extensions = extensions;
-
-    return 1;
-
-glad_vk_get_extensions_error:
-    free((void*) ext_properties);
-    if (extensions != NULL) {
-        for (i = 0; i < total_extension_count; ++i) {
-            free((void*) extensions[i]);
-        }
-        free(extensions);
-    }
-    return 0;
-}
-
-static void glad_vk_free_extensions(uint32_t extension_count, char **extensions) {
-    uint32_t i;
-
-    for(i = 0; i < extension_count ; ++i) {
-        free((void*) (extensions[i]));
-    }
-
-    free((void*) extensions);
-}
-
-static int glad_vk_has_extension(const char *name, uint32_t extension_count, char **extensions) {
-    uint32_t i;
-
-    for (i = 0; i < extension_count; ++i) {
-        if(extensions[i] != NULL && strcmp(name, extensions[i]) == 0) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-static GLADapiproc glad_vk_get_proc_from_userptr(void *userptr, const char* name) {
-    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
-}
-
-static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) {
-    uint32_t extension_count = 0;
-    char **extensions = NULL;
-    if (!glad_vk_get_extensions(physical_device, &extension_count, &extensions)) return 0;
-
-    GLAD_VK_EXT_debug_report = glad_vk_has_extension("VK_EXT_debug_report", extension_count, extensions);
-    GLAD_VK_KHR_portability_enumeration = glad_vk_has_extension("VK_KHR_portability_enumeration", extension_count, extensions);
-    GLAD_VK_KHR_surface = glad_vk_has_extension("VK_KHR_surface", extension_count, extensions);
-    GLAD_VK_KHR_swapchain = glad_vk_has_extension("VK_KHR_swapchain", extension_count, extensions);
-
-    (void) glad_vk_has_extension;
-
-    glad_vk_free_extensions(extension_count, extensions);
-
-    return 1;
-}
-
-static int glad_vk_find_core_vulkan( VkPhysicalDevice physical_device) {
-    int major = 1;
-    int minor = 0;
-
-#ifdef VK_VERSION_1_1
-    if (glad_vkEnumerateInstanceVersion != NULL) {
-        uint32_t version;
-        VkResult result;
-
-        result = glad_vkEnumerateInstanceVersion(&version);
-        if (result == VK_SUCCESS) {
-            major = (int) VK_VERSION_MAJOR(version);
-            minor = (int) VK_VERSION_MINOR(version);
-        }
-    }
-#endif
-
-    if (physical_device != NULL && glad_vkGetPhysicalDeviceProperties != NULL) {
-        VkPhysicalDeviceProperties properties;
-        glad_vkGetPhysicalDeviceProperties(physical_device, &properties);
-
-        major = (int) VK_VERSION_MAJOR(properties.apiVersion);
-        minor = (int) VK_VERSION_MINOR(properties.apiVersion);
-    }
-
-    GLAD_VK_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
-    GLAD_VK_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
-    GLAD_VK_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
-    GLAD_VK_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
-
-    return GLAD_MAKE_VERSION(major, minor);
-}
-
-int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc load, void *userptr) {
-    int version;
-
-#ifdef VK_VERSION_1_1
-    glad_vkEnumerateInstanceVersion  = (PFN_vkEnumerateInstanceVersion) load(userptr, "vkEnumerateInstanceVersion");
-#endif
-    version = glad_vk_find_core_vulkan( physical_device);
-    if (!version) {
-        return 0;
-    }
-
-    glad_vk_load_VK_VERSION_1_0(load, userptr);
-    glad_vk_load_VK_VERSION_1_1(load, userptr);
-    glad_vk_load_VK_VERSION_1_2(load, userptr);
-    glad_vk_load_VK_VERSION_1_3(load, userptr);
-
-    if (!glad_vk_find_extensions_vulkan( physical_device)) return 0;
-    glad_vk_load_VK_EXT_debug_report(load, userptr);
-    glad_vk_load_VK_KHR_surface(load, userptr);
-    glad_vk_load_VK_KHR_swapchain(load, userptr);
-
-
-    return version;
-}
-
-
-int gladLoadVulkan( VkPhysicalDevice physical_device, GLADloadfunc load) {
-    return gladLoadVulkanUserPtr( physical_device, glad_vk_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
-}
-
-
-
- 
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GLAD_VULKAN_IMPLEMENTATION */
-
diff --git a/raylib/src/external/glfw/deps/mingw/_mingw_dxhelper.h b/raylib/src/external/glfw/deps/mingw/_mingw_dxhelper.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/mingw/_mingw_dxhelper.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is part of the mingw-w64 runtime package.
- * No warranty is given; refer to the file DISCLAIMER within this package.
- */
-
-#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS)
-#define NONAMELESSUNION		1
-#endif
-#if defined(NONAMELESSSTRUCT) && \
-   !defined(NONAMELESSUNION)
-#define NONAMELESSUNION		1
-#endif
-#if defined(NONAMELESSUNION)  && \
-   !defined(NONAMELESSSTRUCT)
-#define NONAMELESSSTRUCT	1
-#endif
-#if !defined(__GNU_EXTENSION)
-#if defined(__GNUC__) || defined(__GNUG__)
-#define __GNU_EXTENSION		__extension__
-#else
-#define __GNU_EXTENSION
-#endif
-#endif /* __extension__ */
-
-#ifndef __ANONYMOUS_DEFINED
-#define __ANONYMOUS_DEFINED
-#if defined(__GNUC__) || defined(__GNUG__)
-#define _ANONYMOUS_UNION	__extension__
-#define _ANONYMOUS_STRUCT	__extension__
-#else
-#define _ANONYMOUS_UNION
-#define _ANONYMOUS_STRUCT
-#endif
-#ifndef NONAMELESSUNION
-#define _UNION_NAME(x)
-#define _STRUCT_NAME(x)
-#else /* NONAMELESSUNION */
-#define _UNION_NAME(x)  x
-#define _STRUCT_NAME(x) x
-#endif
-#endif	/* __ANONYMOUS_DEFINED */
-
-#ifndef DUMMYUNIONNAME
-# ifdef NONAMELESSUNION
-#  define DUMMYUNIONNAME  u
-#  define DUMMYUNIONNAME1 u1	/* Wine uses this variant */
-#  define DUMMYUNIONNAME2 u2
-#  define DUMMYUNIONNAME3 u3
-#  define DUMMYUNIONNAME4 u4
-#  define DUMMYUNIONNAME5 u5
-#  define DUMMYUNIONNAME6 u6
-#  define DUMMYUNIONNAME7 u7
-#  define DUMMYUNIONNAME8 u8
-#  define DUMMYUNIONNAME9 u9
-# else /* NONAMELESSUNION */
-#  define DUMMYUNIONNAME
-#  define DUMMYUNIONNAME1	/* Wine uses this variant */
-#  define DUMMYUNIONNAME2
-#  define DUMMYUNIONNAME3
-#  define DUMMYUNIONNAME4
-#  define DUMMYUNIONNAME5
-#  define DUMMYUNIONNAME6
-#  define DUMMYUNIONNAME7
-#  define DUMMYUNIONNAME8
-#  define DUMMYUNIONNAME9
-# endif
-#endif	/* DUMMYUNIONNAME */
-
-#if !defined(DUMMYUNIONNAME1)	/* MinGW does not define this one */
-# ifdef NONAMELESSUNION
-#  define DUMMYUNIONNAME1 u1	/* Wine uses this variant */
-# else
-#  define DUMMYUNIONNAME1	/* Wine uses this variant */
-# endif
-#endif	/* DUMMYUNIONNAME1 */
-
-#ifndef DUMMYSTRUCTNAME
-# ifdef NONAMELESSUNION
-#  define DUMMYSTRUCTNAME  s
-#  define DUMMYSTRUCTNAME1 s1	/* Wine uses this variant */
-#  define DUMMYSTRUCTNAME2 s2
-#  define DUMMYSTRUCTNAME3 s3
-#  define DUMMYSTRUCTNAME4 s4
-#  define DUMMYSTRUCTNAME5 s5
-# else
-#  define DUMMYSTRUCTNAME
-#  define DUMMYSTRUCTNAME1	/* Wine uses this variant */
-#  define DUMMYSTRUCTNAME2
-#  define DUMMYSTRUCTNAME3
-#  define DUMMYSTRUCTNAME4
-#  define DUMMYSTRUCTNAME5
-# endif
-#endif /* DUMMYSTRUCTNAME */
-
-/* These are for compatibility with the Wine source tree */
-
-#ifndef WINELIB_NAME_AW
-# ifdef __MINGW_NAME_AW
-#   define WINELIB_NAME_AW  __MINGW_NAME_AW
-# else
-#  ifdef UNICODE
-#   define WINELIB_NAME_AW(func) func##W
-#  else
-#   define WINELIB_NAME_AW(func) func##A
-#  endif
-# endif
-#endif	/* WINELIB_NAME_AW */
-
-#ifndef DECL_WINELIB_TYPE_AW
-# ifdef __MINGW_TYPEDEF_AW
-#  define DECL_WINELIB_TYPE_AW  __MINGW_TYPEDEF_AW
-# else
-#  define DECL_WINELIB_TYPE_AW(type)  typedef WINELIB_NAME_AW(type) type;
-# endif
-#endif	/* DECL_WINELIB_TYPE_AW */
-
diff --git a/raylib/src/external/glfw/deps/mingw/dinput.h b/raylib/src/external/glfw/deps/mingw/dinput.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/mingw/dinput.h
+++ /dev/null
@@ -1,2467 +0,0 @@
-/*
- * Copyright (C) the Wine project
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __DINPUT_INCLUDED__
-#define __DINPUT_INCLUDED__
-
-#define COM_NO_WINDOWS_H
-#include <objbase.h>
-#include <_mingw_dxhelper.h>
-
-#ifndef DIRECTINPUT_VERSION
-#define DIRECTINPUT_VERSION	0x0800
-#endif
-
-/* Classes */
-DEFINE_GUID(CLSID_DirectInput,		0x25E609E0,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(CLSID_DirectInputDevice,	0x25E609E1,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-
-DEFINE_GUID(CLSID_DirectInput8,		0x25E609E4,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(CLSID_DirectInputDevice8,	0x25E609E5,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-
-/* Interfaces */
-DEFINE_GUID(IID_IDirectInputA,		0x89521360,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInputW,		0x89521361,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInput2A,		0x5944E662,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInput2W,		0x5944E663,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInput7A,		0x9A4CB684,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE);
-DEFINE_GUID(IID_IDirectInput7W,		0x9A4CB685,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE);
-DEFINE_GUID(IID_IDirectInput8A,		0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00);
-DEFINE_GUID(IID_IDirectInput8W,		0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00);
-DEFINE_GUID(IID_IDirectInputDeviceA,	0x5944E680,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInputDeviceW,	0x5944E681,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInputDevice2A,	0x5944E682,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInputDevice2W,	0x5944E683,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(IID_IDirectInputDevice7A,	0x57D7C6BC,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE);
-DEFINE_GUID(IID_IDirectInputDevice7W,	0x57D7C6BD,0x2356,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE);
-DEFINE_GUID(IID_IDirectInputDevice8A,	0x54D41080,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79);
-DEFINE_GUID(IID_IDirectInputDevice8W,	0x54D41081,0xDC15,0x4833,0xA4,0x1B,0x74,0x8F,0x73,0xA3,0x81,0x79);
-DEFINE_GUID(IID_IDirectInputEffect,	0xE7E1F7C0,0x88D2,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-
-/* Predefined object types */
-DEFINE_GUID(GUID_XAxis,	0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_YAxis,	0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_ZAxis,	0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_RxAxis,0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_RyAxis,0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_RzAxis,0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_Slider,0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_Button,0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_Key,	0x55728220,0xD33C,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_POV,	0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_Unknown,0xA36D02F3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-
-/* Predefined product GUIDs */
-DEFINE_GUID(GUID_SysMouse,	0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_SysKeyboard,	0x6F1D2B61,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_Joystick,	0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_SysMouseEm,	0x6F1D2B80,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_SysMouseEm2,	0x6F1D2B81,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_SysKeyboardEm,	0x6F1D2B82,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_SysKeyboardEm2,0x6F1D2B83,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-
-/* predefined forcefeedback effects */
-DEFINE_GUID(GUID_ConstantForce,	0x13541C20,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_RampForce,	0x13541C21,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Square,	0x13541C22,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Sine,		0x13541C23,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Triangle,	0x13541C24,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_SawtoothUp,	0x13541C25,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_SawtoothDown,	0x13541C26,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Spring,	0x13541C27,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Damper,	0x13541C28,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Inertia,	0x13541C29,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_Friction,	0x13541C2A,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-DEFINE_GUID(GUID_CustomForce,	0x13541C2B,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35);
-
-typedef struct IDirectInputA *LPDIRECTINPUTA;
-typedef struct IDirectInputW *LPDIRECTINPUTW;
-typedef struct IDirectInput2A *LPDIRECTINPUT2A;
-typedef struct IDirectInput2W *LPDIRECTINPUT2W;
-typedef struct IDirectInput7A *LPDIRECTINPUT7A;
-typedef struct IDirectInput7W *LPDIRECTINPUT7W;
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef struct IDirectInput8A *LPDIRECTINPUT8A;
-typedef struct IDirectInput8W *LPDIRECTINPUT8W;
-#endif /* DI8 */
-typedef struct IDirectInputDeviceA *LPDIRECTINPUTDEVICEA;
-typedef struct IDirectInputDeviceW *LPDIRECTINPUTDEVICEW;
-#if DIRECTINPUT_VERSION >= 0x0500
-typedef struct IDirectInputDevice2A *LPDIRECTINPUTDEVICE2A;
-typedef struct IDirectInputDevice2W *LPDIRECTINPUTDEVICE2W;
-#endif /* DI5 */
-#if DIRECTINPUT_VERSION >= 0x0700
-typedef struct IDirectInputDevice7A *LPDIRECTINPUTDEVICE7A;
-typedef struct IDirectInputDevice7W *LPDIRECTINPUTDEVICE7W;
-#endif /* DI7 */
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef struct IDirectInputDevice8A *LPDIRECTINPUTDEVICE8A;
-typedef struct IDirectInputDevice8W *LPDIRECTINPUTDEVICE8W;
-#endif /* DI8 */
-#if DIRECTINPUT_VERSION >= 0x0500
-typedef struct IDirectInputEffect *LPDIRECTINPUTEFFECT;
-#endif /* DI5 */
-typedef struct SysKeyboardA *LPSYSKEYBOARDA;
-typedef struct SysMouseA *LPSYSMOUSEA;
-
-#define IID_IDirectInput WINELIB_NAME_AW(IID_IDirectInput)
-#define IDirectInput WINELIB_NAME_AW(IDirectInput)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUT)
-#define IID_IDirectInput2 WINELIB_NAME_AW(IID_IDirectInput2)
-#define IDirectInput2 WINELIB_NAME_AW(IDirectInput2)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUT2)
-#define IID_IDirectInput7 WINELIB_NAME_AW(IID_IDirectInput7)
-#define IDirectInput7 WINELIB_NAME_AW(IDirectInput7)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUT7)
-#if DIRECTINPUT_VERSION >= 0x0800
-#define IID_IDirectInput8 WINELIB_NAME_AW(IID_IDirectInput8)
-#define IDirectInput8 WINELIB_NAME_AW(IDirectInput8)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUT8)
-#endif /* DI8 */
-#define IID_IDirectInputDevice WINELIB_NAME_AW(IID_IDirectInputDevice)
-#define IDirectInputDevice WINELIB_NAME_AW(IDirectInputDevice)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE)
-#if DIRECTINPUT_VERSION >= 0x0500
-#define IID_IDirectInputDevice2 WINELIB_NAME_AW(IID_IDirectInputDevice2)
-#define IDirectInputDevice2 WINELIB_NAME_AW(IDirectInputDevice2)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE2)
-#endif /* DI5 */
-#if DIRECTINPUT_VERSION >= 0x0700
-#define IID_IDirectInputDevice7 WINELIB_NAME_AW(IID_IDirectInputDevice7)
-#define IDirectInputDevice7 WINELIB_NAME_AW(IDirectInputDevice7)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE7)
-#endif /* DI7 */
-#if DIRECTINPUT_VERSION >= 0x0800
-#define IID_IDirectInputDevice8 WINELIB_NAME_AW(IID_IDirectInputDevice8)
-#define IDirectInputDevice8 WINELIB_NAME_AW(IDirectInputDevice8)
-DECL_WINELIB_TYPE_AW(LPDIRECTINPUTDEVICE8)
-#endif /* DI8 */
-
-#define DI_OK                           S_OK
-#define DI_NOTATTACHED                  S_FALSE
-#define DI_BUFFEROVERFLOW               S_FALSE
-#define DI_PROPNOEFFECT                 S_FALSE
-#define DI_NOEFFECT                     S_FALSE
-#define DI_POLLEDDEVICE                 ((HRESULT)0x00000002L)
-#define DI_DOWNLOADSKIPPED              ((HRESULT)0x00000003L)
-#define DI_EFFECTRESTARTED              ((HRESULT)0x00000004L)
-#define DI_TRUNCATED                    ((HRESULT)0x00000008L)
-#define DI_SETTINGSNOTSAVED             ((HRESULT)0x0000000BL)
-#define DI_TRUNCATEDANDRESTARTED        ((HRESULT)0x0000000CL)
-#define DI_WRITEPROTECT                 ((HRESULT)0x00000013L)
-
-#define DIERR_OLDDIRECTINPUTVERSION     \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION)
-#define DIERR_BETADIRECTINPUTVERSION    \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP)
-#define DIERR_BADDRIVERVER              \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL)
-#define DIERR_DEVICENOTREG              REGDB_E_CLASSNOTREG
-#define DIERR_NOTFOUND                  \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND)
-#define DIERR_OBJECTNOTFOUND            \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND)
-#define DIERR_INVALIDPARAM              E_INVALIDARG
-#define DIERR_NOINTERFACE               E_NOINTERFACE
-#define DIERR_GENERIC                   E_FAIL
-#define DIERR_OUTOFMEMORY               E_OUTOFMEMORY
-#define DIERR_UNSUPPORTED               E_NOTIMPL
-#define DIERR_NOTINITIALIZED            \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY)
-#define DIERR_ALREADYINITIALIZED        \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED)
-#define DIERR_NOAGGREGATION             CLASS_E_NOAGGREGATION
-#define DIERR_OTHERAPPHASPRIO           E_ACCESSDENIED
-#define DIERR_INPUTLOST                 \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT)
-#define DIERR_ACQUIRED                  \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY)
-#define DIERR_NOTACQUIRED               \
-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS)
-#define DIERR_READONLY                  E_ACCESSDENIED
-#define DIERR_HANDLEEXISTS              E_ACCESSDENIED
-#ifndef E_PENDING
-#define E_PENDING                       0x8000000AL
-#endif
-#define DIERR_INSUFFICIENTPRIVS         0x80040200L
-#define DIERR_DEVICEFULL                0x80040201L
-#define DIERR_MOREDATA                  0x80040202L
-#define DIERR_NOTDOWNLOADED             0x80040203L
-#define DIERR_HASEFFECTS                0x80040204L
-#define DIERR_NOTEXCLUSIVEACQUIRED      0x80040205L
-#define DIERR_INCOMPLETEEFFECT          0x80040206L
-#define DIERR_NOTBUFFERED               0x80040207L
-#define DIERR_EFFECTPLAYING             0x80040208L
-#define DIERR_UNPLUGGED                 0x80040209L
-#define DIERR_REPORTFULL                0x8004020AL
-#define DIERR_MAPFILEFAIL               0x8004020BL
-
-#define DIENUM_STOP                     0
-#define DIENUM_CONTINUE                 1
-
-#define DIEDFL_ALLDEVICES               0x00000000
-#define DIEDFL_ATTACHEDONLY             0x00000001
-#define DIEDFL_FORCEFEEDBACK            0x00000100
-#define DIEDFL_INCLUDEALIASES           0x00010000
-#define DIEDFL_INCLUDEPHANTOMS          0x00020000
-#define DIEDFL_INCLUDEHIDDEN		0x00040000
-
-#define DIDEVTYPE_DEVICE                1
-#define DIDEVTYPE_MOUSE                 2
-#define DIDEVTYPE_KEYBOARD              3
-#define DIDEVTYPE_JOYSTICK              4
-#define DIDEVTYPE_HID                   0x00010000
-
-#define DI8DEVCLASS_ALL             0
-#define DI8DEVCLASS_DEVICE          1
-#define DI8DEVCLASS_POINTER         2
-#define DI8DEVCLASS_KEYBOARD        3
-#define DI8DEVCLASS_GAMECTRL        4
-
-#define DI8DEVTYPE_DEVICE           0x11
-#define DI8DEVTYPE_MOUSE            0x12
-#define DI8DEVTYPE_KEYBOARD         0x13
-#define DI8DEVTYPE_JOYSTICK         0x14
-#define DI8DEVTYPE_GAMEPAD          0x15
-#define DI8DEVTYPE_DRIVING          0x16
-#define DI8DEVTYPE_FLIGHT           0x17
-#define DI8DEVTYPE_1STPERSON        0x18
-#define DI8DEVTYPE_DEVICECTRL       0x19
-#define DI8DEVTYPE_SCREENPOINTER    0x1A
-#define DI8DEVTYPE_REMOTE           0x1B
-#define DI8DEVTYPE_SUPPLEMENTAL     0x1C
-	
-#define DIDEVTYPEMOUSE_UNKNOWN          1
-#define DIDEVTYPEMOUSE_TRADITIONAL      2
-#define DIDEVTYPEMOUSE_FINGERSTICK      3
-#define DIDEVTYPEMOUSE_TOUCHPAD         4
-#define DIDEVTYPEMOUSE_TRACKBALL        5
-
-#define DIDEVTYPEKEYBOARD_UNKNOWN       0
-#define DIDEVTYPEKEYBOARD_PCXT          1
-#define DIDEVTYPEKEYBOARD_OLIVETTI      2
-#define DIDEVTYPEKEYBOARD_PCAT          3
-#define DIDEVTYPEKEYBOARD_PCENH         4
-#define DIDEVTYPEKEYBOARD_NOKIA1050     5
-#define DIDEVTYPEKEYBOARD_NOKIA9140     6
-#define DIDEVTYPEKEYBOARD_NEC98         7
-#define DIDEVTYPEKEYBOARD_NEC98LAPTOP   8
-#define DIDEVTYPEKEYBOARD_NEC98106      9
-#define DIDEVTYPEKEYBOARD_JAPAN106     10
-#define DIDEVTYPEKEYBOARD_JAPANAX      11
-#define DIDEVTYPEKEYBOARD_J3100        12
-
-#define DIDEVTYPEJOYSTICK_UNKNOWN       1
-#define DIDEVTYPEJOYSTICK_TRADITIONAL   2
-#define DIDEVTYPEJOYSTICK_FLIGHTSTICK   3
-#define DIDEVTYPEJOYSTICK_GAMEPAD       4
-#define DIDEVTYPEJOYSTICK_RUDDER        5
-#define DIDEVTYPEJOYSTICK_WHEEL         6
-#define DIDEVTYPEJOYSTICK_HEADTRACKER   7
-
-#define DI8DEVTYPEMOUSE_UNKNOWN                     1
-#define DI8DEVTYPEMOUSE_TRADITIONAL                 2
-#define DI8DEVTYPEMOUSE_FINGERSTICK                 3
-#define DI8DEVTYPEMOUSE_TOUCHPAD                    4
-#define DI8DEVTYPEMOUSE_TRACKBALL                   5
-#define DI8DEVTYPEMOUSE_ABSOLUTE                    6
-
-#define DI8DEVTYPEKEYBOARD_UNKNOWN                  0
-#define DI8DEVTYPEKEYBOARD_PCXT                     1
-#define DI8DEVTYPEKEYBOARD_OLIVETTI                 2
-#define DI8DEVTYPEKEYBOARD_PCAT                     3
-#define DI8DEVTYPEKEYBOARD_PCENH                    4
-#define DI8DEVTYPEKEYBOARD_NOKIA1050                5
-#define DI8DEVTYPEKEYBOARD_NOKIA9140                6
-#define DI8DEVTYPEKEYBOARD_NEC98                    7
-#define DI8DEVTYPEKEYBOARD_NEC98LAPTOP              8
-#define DI8DEVTYPEKEYBOARD_NEC98106                 9
-#define DI8DEVTYPEKEYBOARD_JAPAN106                10
-#define DI8DEVTYPEKEYBOARD_JAPANAX                 11
-#define DI8DEVTYPEKEYBOARD_J3100                   12
-
-#define DI8DEVTYPE_LIMITEDGAMESUBTYPE               1
-
-#define DI8DEVTYPEJOYSTICK_LIMITED                  DI8DEVTYPE_LIMITEDGAMESUBTYPE
-#define DI8DEVTYPEJOYSTICK_STANDARD                 2
-
-#define DI8DEVTYPEGAMEPAD_LIMITED                   DI8DEVTYPE_LIMITEDGAMESUBTYPE
-#define DI8DEVTYPEGAMEPAD_STANDARD                  2
-#define DI8DEVTYPEGAMEPAD_TILT                      3
-
-#define DI8DEVTYPEDRIVING_LIMITED                   DI8DEVTYPE_LIMITEDGAMESUBTYPE
-#define DI8DEVTYPEDRIVING_COMBINEDPEDALS            2
-#define DI8DEVTYPEDRIVING_DUALPEDALS                3
-#define DI8DEVTYPEDRIVING_THREEPEDALS               4
-#define DI8DEVTYPEDRIVING_HANDHELD                  5
-
-#define DI8DEVTYPEFLIGHT_LIMITED                    DI8DEVTYPE_LIMITEDGAMESUBTYPE
-#define DI8DEVTYPEFLIGHT_STICK                      2
-#define DI8DEVTYPEFLIGHT_YOKE                       3
-#define DI8DEVTYPEFLIGHT_RC                         4
-
-#define DI8DEVTYPE1STPERSON_LIMITED                 DI8DEVTYPE_LIMITEDGAMESUBTYPE
-#define DI8DEVTYPE1STPERSON_UNKNOWN                 2
-#define DI8DEVTYPE1STPERSON_SIXDOF                  3
-#define DI8DEVTYPE1STPERSON_SHOOTER                 4
-
-#define DI8DEVTYPESCREENPTR_UNKNOWN                 2
-#define DI8DEVTYPESCREENPTR_LIGHTGUN                3
-#define DI8DEVTYPESCREENPTR_LIGHTPEN                4
-#define DI8DEVTYPESCREENPTR_TOUCH                   5
-
-#define DI8DEVTYPEREMOTE_UNKNOWN                    2
-
-#define DI8DEVTYPEDEVICECTRL_UNKNOWN                2
-#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION         3
-#define DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED 4
-
-#define DI8DEVTYPESUPPLEMENTAL_UNKNOWN              2
-#define DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER    3
-#define DI8DEVTYPESUPPLEMENTAL_HEADTRACKER          4
-#define DI8DEVTYPESUPPLEMENTAL_HANDTRACKER          5
-#define DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE       6
-#define DI8DEVTYPESUPPLEMENTAL_SHIFTER              7
-#define DI8DEVTYPESUPPLEMENTAL_THROTTLE             8
-#define DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE        9
-#define DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS      10
-#define DI8DEVTYPESUPPLEMENTAL_DUALPEDALS          11
-#define DI8DEVTYPESUPPLEMENTAL_THREEPEDALS         12
-#define DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS        13
-	
-#define GET_DIDEVICE_TYPE(dwDevType)     LOBYTE(dwDevType)
-#define GET_DIDEVICE_SUBTYPE(dwDevType)  HIBYTE(dwDevType)
-
-typedef struct DIDEVICEOBJECTINSTANCE_DX3A {
-    DWORD   dwSize;
-    GUID    guidType;
-    DWORD   dwOfs;
-    DWORD   dwType;
-    DWORD   dwFlags;
-    CHAR    tszName[MAX_PATH];
-} DIDEVICEOBJECTINSTANCE_DX3A, *LPDIDEVICEOBJECTINSTANCE_DX3A;
-typedef const DIDEVICEOBJECTINSTANCE_DX3A *LPCDIDEVICEOBJECTINSTANCE_DX3A;
-typedef struct DIDEVICEOBJECTINSTANCE_DX3W {
-    DWORD   dwSize;
-    GUID    guidType;
-    DWORD   dwOfs;
-    DWORD   dwType;
-    DWORD   dwFlags;
-    WCHAR   tszName[MAX_PATH];
-} DIDEVICEOBJECTINSTANCE_DX3W, *LPDIDEVICEOBJECTINSTANCE_DX3W;
-typedef const DIDEVICEOBJECTINSTANCE_DX3W *LPCDIDEVICEOBJECTINSTANCE_DX3W;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE_DX3)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE_DX3)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE_DX3)
-
-typedef struct DIDEVICEOBJECTINSTANCEA {
-    DWORD	dwSize;
-    GUID	guidType;
-    DWORD	dwOfs;
-    DWORD	dwType;
-    DWORD	dwFlags;
-    CHAR	tszName[MAX_PATH];
-#if(DIRECTINPUT_VERSION >= 0x0500)
-    DWORD	dwFFMaxForce;
-    DWORD	dwFFForceResolution;
-    WORD	wCollectionNumber;
-    WORD	wDesignatorIndex;
-    WORD	wUsagePage;
-    WORD	wUsage;
-    DWORD	dwDimension;
-    WORD	wExponent;
-    WORD	wReserved;
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-} DIDEVICEOBJECTINSTANCEA, *LPDIDEVICEOBJECTINSTANCEA;
-typedef const DIDEVICEOBJECTINSTANCEA *LPCDIDEVICEOBJECTINSTANCEA;
-
-typedef struct DIDEVICEOBJECTINSTANCEW {
-    DWORD	dwSize;
-    GUID	guidType;
-    DWORD	dwOfs;
-    DWORD	dwType;
-    DWORD	dwFlags;
-    WCHAR	tszName[MAX_PATH];
-#if(DIRECTINPUT_VERSION >= 0x0500)
-    DWORD	dwFFMaxForce;
-    DWORD	dwFFForceResolution;
-    WORD	wCollectionNumber;
-    WORD	wDesignatorIndex;
-    WORD	wUsagePage;
-    WORD	wUsage;
-    DWORD	dwDimension;
-    WORD	wExponent;
-    WORD	wReserved;
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-} DIDEVICEOBJECTINSTANCEW, *LPDIDEVICEOBJECTINSTANCEW;
-typedef const DIDEVICEOBJECTINSTANCEW *LPCDIDEVICEOBJECTINSTANCEW;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEOBJECTINSTANCE)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEOBJECTINSTANCE)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEOBJECTINSTANCE)
-
-typedef struct DIDEVICEINSTANCE_DX3A {
-    DWORD   dwSize;
-    GUID    guidInstance;
-    GUID    guidProduct;
-    DWORD   dwDevType;
-    CHAR    tszInstanceName[MAX_PATH];
-    CHAR    tszProductName[MAX_PATH];
-} DIDEVICEINSTANCE_DX3A, *LPDIDEVICEINSTANCE_DX3A;
-typedef const DIDEVICEINSTANCE_DX3A *LPCDIDEVICEINSTANCE_DX3A;
-typedef struct DIDEVICEINSTANCE_DX3W {
-    DWORD   dwSize;
-    GUID    guidInstance;
-    GUID    guidProduct;
-    DWORD   dwDevType;
-    WCHAR   tszInstanceName[MAX_PATH];
-    WCHAR   tszProductName[MAX_PATH];
-} DIDEVICEINSTANCE_DX3W, *LPDIDEVICEINSTANCE_DX3W;
-typedef const DIDEVICEINSTANCE_DX3W *LPCDIDEVICEINSTANCE_DX3W;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE_DX3)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE_DX3)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE_DX3)
-
-typedef struct DIDEVICEINSTANCEA {
-    DWORD	dwSize;
-    GUID	guidInstance;
-    GUID	guidProduct;
-    DWORD	dwDevType;
-    CHAR	tszInstanceName[MAX_PATH];
-    CHAR	tszProductName[MAX_PATH];
-#if(DIRECTINPUT_VERSION >= 0x0500)
-    GUID	guidFFDriver;
-    WORD	wUsagePage;
-    WORD	wUsage;
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-} DIDEVICEINSTANCEA, *LPDIDEVICEINSTANCEA;
-typedef const DIDEVICEINSTANCEA *LPCDIDEVICEINSTANCEA;
-
-typedef struct DIDEVICEINSTANCEW {
-    DWORD	dwSize;
-    GUID	guidInstance;
-    GUID	guidProduct;
-    DWORD	dwDevType;
-    WCHAR	tszInstanceName[MAX_PATH];
-    WCHAR	tszProductName[MAX_PATH];
-#if(DIRECTINPUT_VERSION >= 0x0500)
-    GUID	guidFFDriver;
-    WORD	wUsagePage;
-    WORD	wUsage;
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-} DIDEVICEINSTANCEW, *LPDIDEVICEINSTANCEW;
-typedef const DIDEVICEINSTANCEW *LPCDIDEVICEINSTANCEW;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE)
-
-typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA,LPVOID);
-typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW,LPVOID);
-DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESCALLBACK)
-
-#define DIEDBS_MAPPEDPRI1		0x00000001
-#define DIEDBS_MAPPEDPRI2		0x00000002
-#define DIEDBS_RECENTDEVICE		0x00000010
-#define DIEDBS_NEWDEVICE		0x00000020
-
-#define DIEDBSFL_ATTACHEDONLY		0x00000000
-#define DIEDBSFL_THISUSER		0x00000010
-#define DIEDBSFL_FORCEFEEDBACK		DIEDFL_FORCEFEEDBACK
-#define DIEDBSFL_AVAILABLEDEVICES	0x00001000
-#define DIEDBSFL_MULTIMICEKEYBOARDS	0x00002000
-#define DIEDBSFL_NONGAMINGDEVICES	0x00004000
-#define DIEDBSFL_VALID			0x00007110
-
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBA)(LPCDIDEVICEINSTANCEA,LPDIRECTINPUTDEVICE8A,DWORD,DWORD,LPVOID);
-typedef BOOL (CALLBACK *LPDIENUMDEVICESBYSEMANTICSCBW)(LPCDIDEVICEINSTANCEW,LPDIRECTINPUTDEVICE8W,DWORD,DWORD,LPVOID);
-DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESBYSEMANTICSCB)
-#endif
-
-typedef BOOL (CALLBACK *LPDICONFIGUREDEVICESCALLBACK)(LPUNKNOWN,LPVOID);
-
-typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKA)(LPCDIDEVICEOBJECTINSTANCEA,LPVOID);
-typedef BOOL (CALLBACK *LPDIENUMDEVICEOBJECTSCALLBACKW)(LPCDIDEVICEOBJECTINSTANCEW,LPVOID);
-DECL_WINELIB_TYPE_AW(LPDIENUMDEVICEOBJECTSCALLBACK)
-
-#if DIRECTINPUT_VERSION >= 0x0500
-typedef BOOL (CALLBACK *LPDIENUMCREATEDEFFECTOBJECTSCALLBACK)(LPDIRECTINPUTEFFECT, LPVOID);
-#endif
-
-#define DIK_ESCAPE          0x01
-#define DIK_1               0x02
-#define DIK_2               0x03
-#define DIK_3               0x04
-#define DIK_4               0x05
-#define DIK_5               0x06
-#define DIK_6               0x07
-#define DIK_7               0x08
-#define DIK_8               0x09
-#define DIK_9               0x0A
-#define DIK_0               0x0B
-#define DIK_MINUS           0x0C    /* - on main keyboard */
-#define DIK_EQUALS          0x0D
-#define DIK_BACK            0x0E    /* backspace */
-#define DIK_TAB             0x0F
-#define DIK_Q               0x10
-#define DIK_W               0x11
-#define DIK_E               0x12
-#define DIK_R               0x13
-#define DIK_T               0x14
-#define DIK_Y               0x15
-#define DIK_U               0x16
-#define DIK_I               0x17
-#define DIK_O               0x18
-#define DIK_P               0x19
-#define DIK_LBRACKET        0x1A
-#define DIK_RBRACKET        0x1B
-#define DIK_RETURN          0x1C    /* Enter on main keyboard */
-#define DIK_LCONTROL        0x1D
-#define DIK_A               0x1E
-#define DIK_S               0x1F
-#define DIK_D               0x20
-#define DIK_F               0x21
-#define DIK_G               0x22
-#define DIK_H               0x23
-#define DIK_J               0x24
-#define DIK_K               0x25
-#define DIK_L               0x26
-#define DIK_SEMICOLON       0x27
-#define DIK_APOSTROPHE      0x28
-#define DIK_GRAVE           0x29    /* accent grave */
-#define DIK_LSHIFT          0x2A
-#define DIK_BACKSLASH       0x2B
-#define DIK_Z               0x2C
-#define DIK_X               0x2D
-#define DIK_C               0x2E
-#define DIK_V               0x2F
-#define DIK_B               0x30
-#define DIK_N               0x31
-#define DIK_M               0x32
-#define DIK_COMMA           0x33
-#define DIK_PERIOD          0x34    /* . on main keyboard */
-#define DIK_SLASH           0x35    /* / on main keyboard */
-#define DIK_RSHIFT          0x36
-#define DIK_MULTIPLY        0x37    /* * on numeric keypad */
-#define DIK_LMENU           0x38    /* left Alt */
-#define DIK_SPACE           0x39
-#define DIK_CAPITAL         0x3A
-#define DIK_F1              0x3B
-#define DIK_F2              0x3C
-#define DIK_F3              0x3D
-#define DIK_F4              0x3E
-#define DIK_F5              0x3F
-#define DIK_F6              0x40
-#define DIK_F7              0x41
-#define DIK_F8              0x42
-#define DIK_F9              0x43
-#define DIK_F10             0x44
-#define DIK_NUMLOCK         0x45
-#define DIK_SCROLL          0x46    /* Scroll Lock */
-#define DIK_NUMPAD7         0x47
-#define DIK_NUMPAD8         0x48
-#define DIK_NUMPAD9         0x49
-#define DIK_SUBTRACT        0x4A    /* - on numeric keypad */
-#define DIK_NUMPAD4         0x4B
-#define DIK_NUMPAD5         0x4C
-#define DIK_NUMPAD6         0x4D
-#define DIK_ADD             0x4E    /* + on numeric keypad */
-#define DIK_NUMPAD1         0x4F
-#define DIK_NUMPAD2         0x50
-#define DIK_NUMPAD3         0x51
-#define DIK_NUMPAD0         0x52
-#define DIK_DECIMAL         0x53    /* . on numeric keypad */
-#define DIK_OEM_102         0x56    /* < > | on UK/Germany keyboards */
-#define DIK_F11             0x57
-#define DIK_F12             0x58
-#define DIK_F13             0x64    /*                     (NEC PC98) */
-#define DIK_F14             0x65    /*                     (NEC PC98) */
-#define DIK_F15             0x66    /*                     (NEC PC98) */
-#define DIK_KANA            0x70    /* (Japanese keyboard)            */
-#define DIK_ABNT_C1         0x73    /* / ? on Portugese (Brazilian) keyboards */
-#define DIK_CONVERT         0x79    /* (Japanese keyboard)            */
-#define DIK_NOCONVERT       0x7B    /* (Japanese keyboard)            */
-#define DIK_YEN             0x7D    /* (Japanese keyboard)            */
-#define DIK_ABNT_C2         0x7E    /* Numpad . on Portugese (Brazilian) keyboards */
-#define DIK_NUMPADEQUALS    0x8D    /* = on numeric keypad (NEC PC98) */
-#define DIK_CIRCUMFLEX      0x90    /* (Japanese keyboard)            */
-#define DIK_AT              0x91    /*                     (NEC PC98) */
-#define DIK_COLON           0x92    /*                     (NEC PC98) */
-#define DIK_UNDERLINE       0x93    /*                     (NEC PC98) */
-#define DIK_KANJI           0x94    /* (Japanese keyboard)            */
-#define DIK_STOP            0x95    /*                     (NEC PC98) */
-#define DIK_AX              0x96    /*                     (Japan AX) */
-#define DIK_UNLABELED       0x97    /*                        (J3100) */
-#define DIK_NEXTTRACK       0x99    /* Next Track */
-#define DIK_NUMPADENTER     0x9C    /* Enter on numeric keypad */
-#define DIK_RCONTROL        0x9D
-#define DIK_MUTE	    0xA0    /* Mute */
-#define DIK_CALCULATOR      0xA1    /* Calculator */
-#define DIK_PLAYPAUSE       0xA2    /* Play / Pause */
-#define DIK_MEDIASTOP       0xA4    /* Media Stop */
-#define DIK_VOLUMEDOWN      0xAE    /* Volume - */
-#define DIK_VOLUMEUP        0xB0    /* Volume + */
-#define DIK_WEBHOME         0xB2    /* Web home */
-#define DIK_NUMPADCOMMA     0xB3    /* , on numeric keypad (NEC PC98) */
-#define DIK_DIVIDE          0xB5    /* / on numeric keypad */
-#define DIK_SYSRQ           0xB7
-#define DIK_RMENU           0xB8    /* right Alt */
-#define DIK_PAUSE           0xC5    /* Pause */
-#define DIK_HOME            0xC7    /* Home on arrow keypad */
-#define DIK_UP              0xC8    /* UpArrow on arrow keypad */
-#define DIK_PRIOR           0xC9    /* PgUp on arrow keypad */
-#define DIK_LEFT            0xCB    /* LeftArrow on arrow keypad */
-#define DIK_RIGHT           0xCD    /* RightArrow on arrow keypad */
-#define DIK_END             0xCF    /* End on arrow keypad */
-#define DIK_DOWN            0xD0    /* DownArrow on arrow keypad */
-#define DIK_NEXT            0xD1    /* PgDn on arrow keypad */
-#define DIK_INSERT          0xD2    /* Insert on arrow keypad */
-#define DIK_DELETE          0xD3    /* Delete on arrow keypad */
-#define DIK_LWIN            0xDB    /* Left Windows key */
-#define DIK_RWIN            0xDC    /* Right Windows key */
-#define DIK_APPS            0xDD    /* AppMenu key */
-#define DIK_POWER           0xDE
-#define DIK_SLEEP           0xDF
-#define DIK_WAKE            0xE3    /* System Wake */
-#define DIK_WEBSEARCH       0xE5    /* Web Search */
-#define DIK_WEBFAVORITES    0xE6    /* Web Favorites */
-#define DIK_WEBREFRESH      0xE7    /* Web Refresh */
-#define DIK_WEBSTOP         0xE8    /* Web Stop */
-#define DIK_WEBFORWARD      0xE9    /* Web Forward */
-#define DIK_WEBBACK         0xEA    /* Web Back */
-#define DIK_MYCOMPUTER      0xEB    /* My Computer */
-#define DIK_MAIL            0xEC    /* Mail */
-#define DIK_MEDIASELECT     0xED    /* Media Select */
-
-#define DIK_BACKSPACE       DIK_BACK            /* backspace */
-#define DIK_NUMPADSTAR      DIK_MULTIPLY        /* * on numeric keypad */
-#define DIK_LALT            DIK_LMENU           /* left Alt */
-#define DIK_CAPSLOCK        DIK_CAPITAL         /* CapsLock */
-#define DIK_NUMPADMINUS     DIK_SUBTRACT        /* - on numeric keypad */
-#define DIK_NUMPADPLUS      DIK_ADD             /* + on numeric keypad */
-#define DIK_NUMPADPERIOD    DIK_DECIMAL         /* . on numeric keypad */
-#define DIK_NUMPADSLASH     DIK_DIVIDE          /* / on numeric keypad */
-#define DIK_RALT            DIK_RMENU           /* right Alt */
-#define DIK_UPARROW         DIK_UP              /* UpArrow on arrow keypad */
-#define DIK_PGUP            DIK_PRIOR           /* PgUp on arrow keypad */
-#define DIK_LEFTARROW       DIK_LEFT            /* LeftArrow on arrow keypad */
-#define DIK_RIGHTARROW      DIK_RIGHT           /* RightArrow on arrow keypad */
-#define DIK_DOWNARROW       DIK_DOWN            /* DownArrow on arrow keypad */
-#define DIK_PGDN            DIK_NEXT            /* PgDn on arrow keypad */
-
-#define DIDFT_ALL		0x00000000
-#define DIDFT_RELAXIS		0x00000001
-#define DIDFT_ABSAXIS		0x00000002
-#define DIDFT_AXIS		0x00000003
-#define DIDFT_PSHBUTTON		0x00000004
-#define DIDFT_TGLBUTTON		0x00000008
-#define DIDFT_BUTTON		0x0000000C
-#define DIDFT_POV		0x00000010
-#define DIDFT_COLLECTION	0x00000040
-#define DIDFT_NODATA		0x00000080
-#define DIDFT_ANYINSTANCE	0x00FFFF00
-#define DIDFT_INSTANCEMASK	DIDFT_ANYINSTANCE
-#define DIDFT_MAKEINSTANCE(n)	((WORD)(n) << 8)
-#define DIDFT_GETTYPE(n)	LOBYTE(n)
-#define DIDFT_GETINSTANCE(n)	LOWORD((n) >> 8)
-#define DIDFT_FFACTUATOR	0x01000000
-#define DIDFT_FFEFFECTTRIGGER	0x02000000
-#if DIRECTINPUT_VERSION >= 0x050a
-#define DIDFT_OUTPUT		0x10000000
-#define DIDFT_VENDORDEFINED	0x04000000
-#define DIDFT_ALIAS		0x08000000
-#endif /* DI5a */
-#ifndef DIDFT_OPTIONAL
-#define DIDFT_OPTIONAL		0x80000000
-#endif
-#define DIDFT_ENUMCOLLECTION(n)	((WORD)(n) << 8)
-#define DIDFT_NOCOLLECTION	0x00FFFF00
-
-#define DIDF_ABSAXIS		0x00000001
-#define DIDF_RELAXIS		0x00000002
-
-#define DIGDD_PEEK		0x00000001
-
-#define DISEQUENCE_COMPARE(dwSq1,cmp,dwSq2) ((int)((dwSq1) - (dwSq2)) cmp 0)
-
-typedef struct DIDEVICEOBJECTDATA_DX3 {
-    DWORD	dwOfs;
-    DWORD	dwData;
-    DWORD	dwTimeStamp;
-    DWORD	dwSequence;
-} DIDEVICEOBJECTDATA_DX3,*LPDIDEVICEOBJECTDATA_DX3;
-typedef const DIDEVICEOBJECTDATA_DX3 *LPCDIDEVICEOBJECTDATA_DX3;
-
-typedef struct DIDEVICEOBJECTDATA {
-    DWORD	dwOfs;
-    DWORD	dwData;
-    DWORD	dwTimeStamp;
-    DWORD	dwSequence;
-#if(DIRECTINPUT_VERSION >= 0x0800)
-    UINT_PTR	uAppData;
-#endif /* DIRECTINPUT_VERSION >= 0x0800 */
-} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA;
-typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA;
-
-typedef struct _DIOBJECTDATAFORMAT {
-    const GUID *pguid;
-    DWORD	dwOfs;
-    DWORD	dwType;
-    DWORD	dwFlags;
-} DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT;
-typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT;
-
-typedef struct _DIDATAFORMAT {
-    DWORD			dwSize;
-    DWORD			dwObjSize;
-    DWORD			dwFlags;
-    DWORD			dwDataSize;
-    DWORD			dwNumObjs;
-    LPDIOBJECTDATAFORMAT	rgodf;
-} DIDATAFORMAT, *LPDIDATAFORMAT;
-typedef const DIDATAFORMAT *LPCDIDATAFORMAT;
-
-#if DIRECTINPUT_VERSION >= 0x0500
-#define DIDOI_FFACTUATOR	0x00000001
-#define DIDOI_FFEFFECTTRIGGER	0x00000002
-#define DIDOI_POLLED		0x00008000
-#define DIDOI_ASPECTPOSITION	0x00000100
-#define DIDOI_ASPECTVELOCITY	0x00000200
-#define DIDOI_ASPECTACCEL	0x00000300
-#define DIDOI_ASPECTFORCE	0x00000400
-#define DIDOI_ASPECTMASK	0x00000F00
-#endif /* DI5 */
-#if DIRECTINPUT_VERSION >= 0x050a
-#define DIDOI_GUIDISUSAGE	0x00010000
-#endif /* DI5a */
-
-typedef struct DIPROPHEADER {
-    DWORD	dwSize;
-    DWORD	dwHeaderSize;
-    DWORD	dwObj;
-    DWORD	dwHow;
-} DIPROPHEADER,*LPDIPROPHEADER;
-typedef const DIPROPHEADER *LPCDIPROPHEADER;
-
-#define DIPH_DEVICE	0
-#define DIPH_BYOFFSET	1
-#define DIPH_BYID	2
-#if DIRECTINPUT_VERSION >= 0x050a
-#define DIPH_BYUSAGE	3
-
-#define DIMAKEUSAGEDWORD(UsagePage, Usage) (DWORD)MAKELONG(Usage, UsagePage)
-#endif /* DI5a */
-
-typedef struct DIPROPDWORD {
-	DIPROPHEADER	diph;
-	DWORD		dwData;
-} DIPROPDWORD, *LPDIPROPDWORD;
-typedef const DIPROPDWORD *LPCDIPROPDWORD;
-
-typedef struct DIPROPRANGE {
-	DIPROPHEADER	diph;
-	LONG		lMin;
-	LONG		lMax;
-} DIPROPRANGE, *LPDIPROPRANGE;
-typedef const DIPROPRANGE *LPCDIPROPRANGE;
-
-#define DIPROPRANGE_NOMIN	((LONG)0x80000000)
-#define DIPROPRANGE_NOMAX	((LONG)0x7FFFFFFF)
-
-#if DIRECTINPUT_VERSION >= 0x050a
-typedef struct DIPROPCAL {
-	DIPROPHEADER diph;
-	LONG	lMin;
-	LONG	lCenter;
-	LONG	lMax;
-} DIPROPCAL, *LPDIPROPCAL;
-typedef const DIPROPCAL *LPCDIPROPCAL;
-
-typedef struct DIPROPCALPOV {
-	DIPROPHEADER	diph;
-	LONG		lMin[5];
-	LONG		lMax[5];
-} DIPROPCALPOV, *LPDIPROPCALPOV;
-typedef const DIPROPCALPOV *LPCDIPROPCALPOV;
-
-typedef struct DIPROPGUIDANDPATH {
-	DIPROPHEADER diph;
-	GUID    guidClass;
-	WCHAR   wszPath[MAX_PATH];
-} DIPROPGUIDANDPATH, *LPDIPROPGUIDANDPATH;
-typedef const DIPROPGUIDANDPATH *LPCDIPROPGUIDANDPATH;
-
-typedef struct DIPROPSTRING {
-        DIPROPHEADER diph;
-        WCHAR        wsz[MAX_PATH];
-} DIPROPSTRING, *LPDIPROPSTRING;
-typedef const DIPROPSTRING *LPCDIPROPSTRING;
-#endif /* DI5a */
-
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef struct DIPROPPOINTER {
-	DIPROPHEADER diph;
-	UINT_PTR     uData;
-} DIPROPPOINTER, *LPDIPROPPOINTER;
-typedef const DIPROPPOINTER *LPCDIPROPPOINTER;
-#endif /* DI8 */
-
-/* special property GUIDs */
-#ifdef __cplusplus
-#define MAKEDIPROP(prop)	(*(const GUID *)(prop))
-#else
-#define MAKEDIPROP(prop)	((REFGUID)(prop))
-#endif
-#define DIPROP_BUFFERSIZE	MAKEDIPROP(1)
-#define DIPROP_AXISMODE		MAKEDIPROP(2)
-
-#define DIPROPAXISMODE_ABS	0
-#define DIPROPAXISMODE_REL	1
-
-#define DIPROP_GRANULARITY	MAKEDIPROP(3)
-#define DIPROP_RANGE		MAKEDIPROP(4)
-#define DIPROP_DEADZONE		MAKEDIPROP(5)
-#define DIPROP_SATURATION	MAKEDIPROP(6)
-#define DIPROP_FFGAIN		MAKEDIPROP(7)
-#define DIPROP_FFLOAD		MAKEDIPROP(8)
-#define DIPROP_AUTOCENTER	MAKEDIPROP(9)
-
-#define DIPROPAUTOCENTER_OFF	0
-#define DIPROPAUTOCENTER_ON	1
-
-#define DIPROP_CALIBRATIONMODE	MAKEDIPROP(10)
-
-#define DIPROPCALIBRATIONMODE_COOKED	0
-#define DIPROPCALIBRATIONMODE_RAW	1
-
-#if DIRECTINPUT_VERSION >= 0x050a
-#define DIPROP_CALIBRATION	MAKEDIPROP(11)
-#define DIPROP_GUIDANDPATH	MAKEDIPROP(12)
-#define DIPROP_INSTANCENAME	MAKEDIPROP(13)
-#define DIPROP_PRODUCTNAME	MAKEDIPROP(14)
-#endif
-
-#if DIRECTINPUT_VERSION >= 0x5B2
-#define DIPROP_JOYSTICKID	MAKEDIPROP(15)
-#define DIPROP_GETPORTDISPLAYNAME	MAKEDIPROP(16)
-#endif
-
-#if DIRECTINPUT_VERSION >= 0x0700
-#define DIPROP_PHYSICALRANGE	MAKEDIPROP(18)
-#define DIPROP_LOGICALRANGE	MAKEDIPROP(19)
-#endif
-
-#if(DIRECTINPUT_VERSION >= 0x0800)
-#define DIPROP_KEYNAME		MAKEDIPROP(20)
-#define DIPROP_CPOINTS		MAKEDIPROP(21)
-#define DIPROP_APPDATA		MAKEDIPROP(22)
-#define DIPROP_SCANCODE		MAKEDIPROP(23)
-#define DIPROP_VIDPID		MAKEDIPROP(24)
-#define DIPROP_USERNAME		MAKEDIPROP(25)
-#define DIPROP_TYPENAME		MAKEDIPROP(26)
-
-#define MAXCPOINTSNUM		8
-
-typedef struct _CPOINT {
-    LONG	lP;
-    DWORD	dwLog;
-} CPOINT, *PCPOINT;
-
-typedef struct DIPROPCPOINTS {
-    DIPROPHEADER diph;
-    DWORD	dwCPointsNum;
-    CPOINT	cp[MAXCPOINTSNUM];
-} DIPROPCPOINTS, *LPDIPROPCPOINTS;
-typedef const DIPROPCPOINTS *LPCDIPROPCPOINTS;
-#endif /* DI8 */
-
-
-typedef struct DIDEVCAPS_DX3 {
-    DWORD	dwSize;
-    DWORD	dwFlags;
-    DWORD	dwDevType;
-    DWORD	dwAxes;
-    DWORD	dwButtons;
-    DWORD	dwPOVs;
-} DIDEVCAPS_DX3, *LPDIDEVCAPS_DX3;
-
-typedef struct DIDEVCAPS {
-    DWORD	dwSize;
-    DWORD	dwFlags;
-    DWORD	dwDevType;
-    DWORD	dwAxes;
-    DWORD	dwButtons;
-    DWORD	dwPOVs;
-#if(DIRECTINPUT_VERSION >= 0x0500)
-    DWORD	dwFFSamplePeriod;
-    DWORD	dwFFMinTimeResolution;
-    DWORD	dwFirmwareRevision;
-    DWORD	dwHardwareRevision;
-    DWORD	dwFFDriverVersion;
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-} DIDEVCAPS,*LPDIDEVCAPS;
-
-#define DIDC_ATTACHED		0x00000001
-#define DIDC_POLLEDDEVICE	0x00000002
-#define DIDC_EMULATED		0x00000004
-#define DIDC_POLLEDDATAFORMAT	0x00000008
-#define DIDC_FORCEFEEDBACK	0x00000100
-#define DIDC_FFATTACK		0x00000200
-#define DIDC_FFFADE		0x00000400
-#define DIDC_SATURATION		0x00000800
-#define DIDC_POSNEGCOEFFICIENTS	0x00001000
-#define DIDC_POSNEGSATURATION	0x00002000
-#define DIDC_DEADBAND		0x00004000
-#define DIDC_STARTDELAY		0x00008000
-#define DIDC_ALIAS		0x00010000
-#define DIDC_PHANTOM		0x00020000
-#define DIDC_HIDDEN		0x00040000
-
-
-/* SetCooperativeLevel dwFlags */
-#define DISCL_EXCLUSIVE		0x00000001
-#define DISCL_NONEXCLUSIVE	0x00000002
-#define DISCL_FOREGROUND	0x00000004
-#define DISCL_BACKGROUND	0x00000008
-#define DISCL_NOWINKEY          0x00000010
-
-#if (DIRECTINPUT_VERSION >= 0x0500)
-/* Device FF flags */
-#define DISFFC_RESET            0x00000001
-#define DISFFC_STOPALL          0x00000002
-#define DISFFC_PAUSE            0x00000004
-#define DISFFC_CONTINUE         0x00000008
-#define DISFFC_SETACTUATORSON   0x00000010
-#define DISFFC_SETACTUATORSOFF  0x00000020
-
-#define DIGFFS_EMPTY            0x00000001
-#define DIGFFS_STOPPED          0x00000002
-#define DIGFFS_PAUSED           0x00000004
-#define DIGFFS_ACTUATORSON      0x00000010
-#define DIGFFS_ACTUATORSOFF     0x00000020
-#define DIGFFS_POWERON          0x00000040
-#define DIGFFS_POWEROFF         0x00000080
-#define DIGFFS_SAFETYSWITCHON   0x00000100
-#define DIGFFS_SAFETYSWITCHOFF  0x00000200
-#define DIGFFS_USERFFSWITCHON   0x00000400
-#define DIGFFS_USERFFSWITCHOFF  0x00000800
-#define DIGFFS_DEVICELOST       0x80000000
-
-/* Effect flags */
-#define DIEFT_ALL		0x00000000
-
-#define DIEFT_CONSTANTFORCE	0x00000001
-#define DIEFT_RAMPFORCE		0x00000002
-#define DIEFT_PERIODIC		0x00000003
-#define DIEFT_CONDITION		0x00000004
-#define DIEFT_CUSTOMFORCE	0x00000005
-#define DIEFT_HARDWARE		0x000000FF
-#define DIEFT_FFATTACK		0x00000200
-#define DIEFT_FFFADE		0x00000400
-#define DIEFT_SATURATION	0x00000800
-#define DIEFT_POSNEGCOEFFICIENTS 0x00001000
-#define DIEFT_POSNEGSATURATION	0x00002000
-#define DIEFT_DEADBAND		0x00004000
-#define DIEFT_STARTDELAY	0x00008000
-#define DIEFT_GETTYPE(n)	LOBYTE(n)
-
-#define DIEFF_OBJECTIDS         0x00000001
-#define DIEFF_OBJECTOFFSETS     0x00000002
-#define DIEFF_CARTESIAN         0x00000010
-#define DIEFF_POLAR             0x00000020
-#define DIEFF_SPHERICAL         0x00000040
-
-#define DIEP_DURATION           0x00000001
-#define DIEP_SAMPLEPERIOD       0x00000002
-#define DIEP_GAIN               0x00000004
-#define DIEP_TRIGGERBUTTON      0x00000008
-#define DIEP_TRIGGERREPEATINTERVAL 0x00000010
-#define DIEP_AXES               0x00000020
-#define DIEP_DIRECTION          0x00000040
-#define DIEP_ENVELOPE           0x00000080
-#define DIEP_TYPESPECIFICPARAMS 0x00000100
-#if(DIRECTINPUT_VERSION >= 0x0600)
-#define DIEP_STARTDELAY         0x00000200
-#define DIEP_ALLPARAMS_DX5      0x000001FF
-#define DIEP_ALLPARAMS          0x000003FF
-#else
-#define DIEP_ALLPARAMS          0x000001FF
-#endif /* DIRECTINPUT_VERSION >= 0x0600 */
-#define DIEP_START              0x20000000
-#define DIEP_NORESTART          0x40000000
-#define DIEP_NODOWNLOAD         0x80000000
-#define DIEB_NOTRIGGER          0xFFFFFFFF
-
-#define DIES_SOLO               0x00000001
-#define DIES_NODOWNLOAD         0x80000000
-
-#define DIEGES_PLAYING          0x00000001
-#define DIEGES_EMULATED         0x00000002
-
-#define DI_DEGREES		100
-#define DI_FFNOMINALMAX		10000
-#define DI_SECONDS		1000000
-
-typedef struct DICONSTANTFORCE {
-	LONG			lMagnitude;
-} DICONSTANTFORCE, *LPDICONSTANTFORCE;
-typedef const DICONSTANTFORCE *LPCDICONSTANTFORCE;
-
-typedef struct DIRAMPFORCE {
-	LONG			lStart;
-	LONG			lEnd;
-} DIRAMPFORCE, *LPDIRAMPFORCE;
-typedef const DIRAMPFORCE *LPCDIRAMPFORCE;
-
-typedef struct DIPERIODIC {
-	DWORD			dwMagnitude;
-	LONG			lOffset;
-	DWORD			dwPhase;
-	DWORD			dwPeriod;
-} DIPERIODIC, *LPDIPERIODIC;
-typedef const DIPERIODIC *LPCDIPERIODIC;
-
-typedef struct DICONDITION {
-	LONG			lOffset;
-	LONG			lPositiveCoefficient;
-	LONG			lNegativeCoefficient;
-	DWORD			dwPositiveSaturation;
-	DWORD			dwNegativeSaturation;
-	LONG			lDeadBand;
-} DICONDITION, *LPDICONDITION;
-typedef const DICONDITION *LPCDICONDITION;
-
-typedef struct DICUSTOMFORCE {
-	DWORD			cChannels;
-	DWORD			dwSamplePeriod;
-	DWORD			cSamples;
-	LPLONG			rglForceData;
-} DICUSTOMFORCE, *LPDICUSTOMFORCE;
-typedef const DICUSTOMFORCE *LPCDICUSTOMFORCE;
-
-typedef struct DIENVELOPE {
-	DWORD			dwSize;
-	DWORD			dwAttackLevel;
-	DWORD			dwAttackTime;
-	DWORD			dwFadeLevel;
-	DWORD			dwFadeTime;
-} DIENVELOPE, *LPDIENVELOPE;
-typedef const DIENVELOPE *LPCDIENVELOPE;
-
-typedef struct DIEFFECT_DX5 {
-	DWORD			dwSize;
-	DWORD			dwFlags;
-	DWORD			dwDuration;
-	DWORD			dwSamplePeriod;
-	DWORD			dwGain;
-	DWORD			dwTriggerButton;
-	DWORD			dwTriggerRepeatInterval;
-	DWORD			cAxes;
-	LPDWORD			rgdwAxes;
-	LPLONG			rglDirection;
-	LPDIENVELOPE		lpEnvelope;
-	DWORD			cbTypeSpecificParams;
-	LPVOID			lpvTypeSpecificParams;
-} DIEFFECT_DX5, *LPDIEFFECT_DX5;
-typedef const DIEFFECT_DX5 *LPCDIEFFECT_DX5;
-
-typedef struct DIEFFECT {
-	DWORD			dwSize;
-	DWORD			dwFlags;
-	DWORD			dwDuration;
-	DWORD			dwSamplePeriod;
-	DWORD			dwGain;
-	DWORD			dwTriggerButton;
-	DWORD			dwTriggerRepeatInterval;
-	DWORD			cAxes;
-	LPDWORD			rgdwAxes;
-	LPLONG			rglDirection;
-	LPDIENVELOPE		lpEnvelope;
-	DWORD			cbTypeSpecificParams;
-	LPVOID			lpvTypeSpecificParams;
-#if(DIRECTINPUT_VERSION >= 0x0600)
-	DWORD			dwStartDelay;
-#endif /* DIRECTINPUT_VERSION >= 0x0600 */
-} DIEFFECT, *LPDIEFFECT;
-typedef const DIEFFECT *LPCDIEFFECT;
-typedef DIEFFECT DIEFFECT_DX6;
-typedef LPDIEFFECT LPDIEFFECT_DX6;
-
-typedef struct DIEFFECTINFOA {
-	DWORD			dwSize;
-	GUID			guid;
-	DWORD			dwEffType;
-	DWORD			dwStaticParams;
-	DWORD			dwDynamicParams;
-	CHAR			tszName[MAX_PATH];
-} DIEFFECTINFOA, *LPDIEFFECTINFOA;
-typedef const DIEFFECTINFOA *LPCDIEFFECTINFOA;
-
-typedef struct DIEFFECTINFOW {
-	DWORD			dwSize;
-	GUID			guid;
-	DWORD			dwEffType;
-	DWORD			dwStaticParams;
-	DWORD			dwDynamicParams;
-	WCHAR			tszName[MAX_PATH];
-} DIEFFECTINFOW, *LPDIEFFECTINFOW;
-typedef const DIEFFECTINFOW *LPCDIEFFECTINFOW;
-
-DECL_WINELIB_TYPE_AW(DIEFFECTINFO)
-DECL_WINELIB_TYPE_AW(LPDIEFFECTINFO)
-DECL_WINELIB_TYPE_AW(LPCDIEFFECTINFO)
-
-typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKA)(LPCDIEFFECTINFOA, LPVOID);
-typedef BOOL (CALLBACK *LPDIENUMEFFECTSCALLBACKW)(LPCDIEFFECTINFOW, LPVOID);
-
-typedef struct DIEFFESCAPE {
-	DWORD	dwSize;
-	DWORD	dwCommand;
-	LPVOID	lpvInBuffer;
-	DWORD	cbInBuffer;
-	LPVOID	lpvOutBuffer;
-	DWORD	cbOutBuffer;
-} DIEFFESCAPE, *LPDIEFFESCAPE;
-
-typedef struct DIJOYSTATE {
-	LONG	lX;
-	LONG	lY;
-	LONG	lZ;
-	LONG	lRx;
-	LONG	lRy;
-	LONG	lRz;
-	LONG	rglSlider[2];
-	DWORD	rgdwPOV[4];
-	BYTE	rgbButtons[32];
-} DIJOYSTATE, *LPDIJOYSTATE;
-
-typedef struct DIJOYSTATE2 {
-	LONG	lX;
-	LONG	lY;
-	LONG	lZ;
-	LONG	lRx;
-	LONG	lRy;
-	LONG	lRz;
-	LONG	rglSlider[2];
-	DWORD	rgdwPOV[4];
-	BYTE	rgbButtons[128];
-	LONG	lVX;		/* 'v' as in velocity */
-	LONG	lVY;
-	LONG	lVZ;
-	LONG	lVRx;
-	LONG	lVRy;
-	LONG	lVRz;
-	LONG	rglVSlider[2];
-	LONG	lAX;		/* 'a' as in acceleration */
-	LONG	lAY;
-	LONG	lAZ;
-	LONG	lARx;
-	LONG	lARy;
-	LONG	lARz;
-	LONG	rglASlider[2];
-	LONG	lFX;		/* 'f' as in force */
-	LONG	lFY;
-	LONG	lFZ;
-	LONG	lFRx;		/* 'fr' as in rotational force aka torque */
-	LONG	lFRy;
-	LONG	lFRz;
-	LONG	rglFSlider[2];
-} DIJOYSTATE2, *LPDIJOYSTATE2;
-
-#define DIJOFS_X		FIELD_OFFSET(DIJOYSTATE, lX)
-#define DIJOFS_Y		FIELD_OFFSET(DIJOYSTATE, lY)
-#define DIJOFS_Z		FIELD_OFFSET(DIJOYSTATE, lZ)
-#define DIJOFS_RX		FIELD_OFFSET(DIJOYSTATE, lRx)
-#define DIJOFS_RY		FIELD_OFFSET(DIJOYSTATE, lRy)
-#define DIJOFS_RZ		FIELD_OFFSET(DIJOYSTATE, lRz)
-#define DIJOFS_SLIDER(n)	(FIELD_OFFSET(DIJOYSTATE, rglSlider) + \
-                                                        (n) * sizeof(LONG))
-#define DIJOFS_POV(n)		(FIELD_OFFSET(DIJOYSTATE, rgdwPOV) + \
-                                                        (n) * sizeof(DWORD))
-#define DIJOFS_BUTTON(n)	(FIELD_OFFSET(DIJOYSTATE, rgbButtons) + (n))
-#define DIJOFS_BUTTON0		DIJOFS_BUTTON(0)
-#define DIJOFS_BUTTON1		DIJOFS_BUTTON(1)
-#define DIJOFS_BUTTON2		DIJOFS_BUTTON(2)
-#define DIJOFS_BUTTON3		DIJOFS_BUTTON(3)
-#define DIJOFS_BUTTON4		DIJOFS_BUTTON(4)
-#define DIJOFS_BUTTON5		DIJOFS_BUTTON(5)
-#define DIJOFS_BUTTON6		DIJOFS_BUTTON(6)
-#define DIJOFS_BUTTON7		DIJOFS_BUTTON(7)
-#define DIJOFS_BUTTON8		DIJOFS_BUTTON(8)
-#define DIJOFS_BUTTON9		DIJOFS_BUTTON(9)
-#define DIJOFS_BUTTON10		DIJOFS_BUTTON(10)
-#define DIJOFS_BUTTON11		DIJOFS_BUTTON(11)
-#define DIJOFS_BUTTON12		DIJOFS_BUTTON(12)
-#define DIJOFS_BUTTON13		DIJOFS_BUTTON(13)
-#define DIJOFS_BUTTON14		DIJOFS_BUTTON(14)
-#define DIJOFS_BUTTON15		DIJOFS_BUTTON(15)
-#define DIJOFS_BUTTON16		DIJOFS_BUTTON(16)
-#define DIJOFS_BUTTON17		DIJOFS_BUTTON(17)
-#define DIJOFS_BUTTON18		DIJOFS_BUTTON(18)
-#define DIJOFS_BUTTON19		DIJOFS_BUTTON(19)
-#define DIJOFS_BUTTON20		DIJOFS_BUTTON(20)
-#define DIJOFS_BUTTON21		DIJOFS_BUTTON(21)
-#define DIJOFS_BUTTON22		DIJOFS_BUTTON(22)
-#define DIJOFS_BUTTON23		DIJOFS_BUTTON(23)
-#define DIJOFS_BUTTON24		DIJOFS_BUTTON(24)
-#define DIJOFS_BUTTON25		DIJOFS_BUTTON(25)
-#define DIJOFS_BUTTON26		DIJOFS_BUTTON(26)
-#define DIJOFS_BUTTON27		DIJOFS_BUTTON(27)
-#define DIJOFS_BUTTON28		DIJOFS_BUTTON(28)
-#define DIJOFS_BUTTON29		DIJOFS_BUTTON(29)
-#define DIJOFS_BUTTON30		DIJOFS_BUTTON(30)
-#define DIJOFS_BUTTON31		DIJOFS_BUTTON(31)
-#endif /* DIRECTINPUT_VERSION >= 0x0500 */
-
-/* DInput 7 structures, types */
-#if(DIRECTINPUT_VERSION >= 0x0700)
-typedef struct DIFILEEFFECT {
-  DWORD       dwSize;
-  GUID        GuidEffect;
-  LPCDIEFFECT lpDiEffect;
-  CHAR        szFriendlyName[MAX_PATH];
-} DIFILEEFFECT, *LPDIFILEEFFECT;
-
-typedef const DIFILEEFFECT *LPCDIFILEEFFECT;
-typedef BOOL (CALLBACK *LPDIENUMEFFECTSINFILECALLBACK)(LPCDIFILEEFFECT , LPVOID);
-#endif /* DIRECTINPUT_VERSION >= 0x0700 */
-
-/* DInput 8 structures and types */
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef struct _DIACTIONA {
-	UINT_PTR	uAppData;
-	DWORD		dwSemantic;
-	DWORD		dwFlags;
-	__GNU_EXTENSION union {
-		LPCSTR	lptszActionName;
-		UINT	uResIdString;
-	} DUMMYUNIONNAME;
-	GUID		guidInstance;
-	DWORD		dwObjID;
-	DWORD		dwHow;
-} DIACTIONA, *LPDIACTIONA;
-typedef const DIACTIONA *LPCDIACTIONA;
-
-typedef struct _DIACTIONW {
-	UINT_PTR	uAppData;
-	DWORD		dwSemantic;
-	DWORD		dwFlags;
-	__GNU_EXTENSION union {
-		LPCWSTR	lptszActionName;
-		UINT	uResIdString;
-	} DUMMYUNIONNAME;
-	GUID		guidInstance;
-	DWORD		dwObjID;
-	DWORD		dwHow;
-} DIACTIONW, *LPDIACTIONW;
-typedef const DIACTIONW *LPCDIACTIONW;
-
-DECL_WINELIB_TYPE_AW(DIACTION)
-DECL_WINELIB_TYPE_AW(LPDIACTION)
-DECL_WINELIB_TYPE_AW(LPCDIACTION)
-
-#define DIA_FORCEFEEDBACK	0x00000001
-#define DIA_APPMAPPED		0x00000002
-#define DIA_APPNOMAP		0x00000004
-#define DIA_NORANGE		0x00000008
-#define DIA_APPFIXED		0x00000010
-
-#define DIAH_UNMAPPED		0x00000000
-#define DIAH_USERCONFIG		0x00000001
-#define DIAH_APPREQUESTED	0x00000002
-#define DIAH_HWAPP		0x00000004
-#define DIAH_HWDEFAULT		0x00000008
-#define DIAH_DEFAULT		0x00000020
-#define DIAH_ERROR		0x80000000
-
-typedef struct _DIACTIONFORMATA {
-	DWORD		dwSize;
-	DWORD		dwActionSize;
-	DWORD		dwDataSize;
-	DWORD		dwNumActions;
-	LPDIACTIONA	rgoAction;
-	GUID		guidActionMap;
-	DWORD		dwGenre;
-	DWORD		dwBufferSize;
-	LONG		lAxisMin;
-	LONG		lAxisMax;
-	HINSTANCE	hInstString;
-	FILETIME	ftTimeStamp;
-	DWORD		dwCRC;
-	CHAR		tszActionMap[MAX_PATH];
-} DIACTIONFORMATA, *LPDIACTIONFORMATA;
-typedef const DIACTIONFORMATA *LPCDIACTIONFORMATA;
-
-typedef struct _DIACTIONFORMATW {
-	DWORD		dwSize;
-	DWORD		dwActionSize;
-	DWORD		dwDataSize;
-	DWORD		dwNumActions;
-	LPDIACTIONW	rgoAction;
-	GUID		guidActionMap;
-	DWORD		dwGenre;
-	DWORD		dwBufferSize;
-	LONG		lAxisMin;
-	LONG		lAxisMax;
-	HINSTANCE	hInstString;
-	FILETIME	ftTimeStamp;
-	DWORD		dwCRC;
-	WCHAR		tszActionMap[MAX_PATH];
-} DIACTIONFORMATW, *LPDIACTIONFORMATW;
-typedef const DIACTIONFORMATW *LPCDIACTIONFORMATW;
-
-DECL_WINELIB_TYPE_AW(DIACTIONFORMAT)
-DECL_WINELIB_TYPE_AW(LPDIACTIONFORMAT)
-DECL_WINELIB_TYPE_AW(LPCDIACTIONFORMAT)
-
-#define DIAFTS_NEWDEVICELOW	0xFFFFFFFF
-#define DIAFTS_NEWDEVICEHIGH	0xFFFFFFFF
-#define DIAFTS_UNUSEDDEVICELOW	0x00000000
-#define DIAFTS_UNUSEDDEVICEHIGH	0x00000000
-
-#define DIDBAM_DEFAULT		0x00000000
-#define DIDBAM_PRESERVE		0x00000001
-#define DIDBAM_INITIALIZE	0x00000002
-#define DIDBAM_HWDEFAULTS	0x00000004
-
-#define DIDSAM_DEFAULT		0x00000000
-#define DIDSAM_NOUSER		0x00000001
-#define DIDSAM_FORCESAVE	0x00000002
-
-#define DICD_DEFAULT		0x00000000
-#define DICD_EDIT		0x00000001
-
-#ifndef D3DCOLOR_DEFINED
-typedef DWORD D3DCOLOR;
-#define D3DCOLOR_DEFINED
-#endif
-
-typedef struct _DICOLORSET {
-	DWORD		dwSize;
-	D3DCOLOR	cTextFore;
-	D3DCOLOR	cTextHighlight;
-	D3DCOLOR	cCalloutLine;
-	D3DCOLOR	cCalloutHighlight;
-	D3DCOLOR	cBorder;
-	D3DCOLOR	cControlFill;
-	D3DCOLOR	cHighlightFill;
-	D3DCOLOR	cAreaFill;
-} DICOLORSET, *LPDICOLORSET;
-typedef const DICOLORSET *LPCDICOLORSET;
-
-typedef struct _DICONFIGUREDEVICESPARAMSA {
-	DWORD			dwSize;
-	DWORD			dwcUsers;
-	LPSTR			lptszUserNames;
-	DWORD			dwcFormats;
-	LPDIACTIONFORMATA	lprgFormats;
-	HWND			hwnd;
-	DICOLORSET		dics;
-	LPUNKNOWN		lpUnkDDSTarget;
-} DICONFIGUREDEVICESPARAMSA, *LPDICONFIGUREDEVICESPARAMSA;
-typedef const DICONFIGUREDEVICESPARAMSA *LPCDICONFIGUREDEVICESPARAMSA;
-
-typedef struct _DICONFIGUREDEVICESPARAMSW {
-	DWORD			dwSize;
-	DWORD			dwcUsers;
-	LPWSTR			lptszUserNames;
-	DWORD			dwcFormats;
-	LPDIACTIONFORMATW	lprgFormats;
-	HWND			hwnd;
-	DICOLORSET		dics;
-	LPUNKNOWN		lpUnkDDSTarget;
-} DICONFIGUREDEVICESPARAMSW, *LPDICONFIGUREDEVICESPARAMSW;
-typedef const DICONFIGUREDEVICESPARAMSW *LPCDICONFIGUREDEVICESPARAMSW;
-
-DECL_WINELIB_TYPE_AW(DICONFIGUREDEVICESPARAMS)
-DECL_WINELIB_TYPE_AW(LPDICONFIGUREDEVICESPARAMS)
-DECL_WINELIB_TYPE_AW(LPCDICONFIGUREDEVICESPARAMS)
-
-#define DIDIFT_CONFIGURATION	0x00000001
-#define DIDIFT_OVERLAY		0x00000002
-
-#define DIDAL_CENTERED		0x00000000
-#define DIDAL_LEFTALIGNED	0x00000001
-#define DIDAL_RIGHTALIGNED	0x00000002
-#define DIDAL_MIDDLE		0x00000000
-#define DIDAL_TOPALIGNED	0x00000004
-#define DIDAL_BOTTOMALIGNED	0x00000008
-
-typedef struct _DIDEVICEIMAGEINFOA {
-	CHAR	tszImagePath[MAX_PATH];
-	DWORD	dwFlags;
-	DWORD	dwViewID;
-	RECT	rcOverlay;
-	DWORD	dwObjID;
-	DWORD	dwcValidPts;
-	POINT	rgptCalloutLine[5];
-	RECT	rcCalloutRect;
-	DWORD	dwTextAlign;
-} DIDEVICEIMAGEINFOA, *LPDIDEVICEIMAGEINFOA;
-typedef const DIDEVICEIMAGEINFOA *LPCDIDEVICEIMAGEINFOA;
-
-typedef struct _DIDEVICEIMAGEINFOW {
-	WCHAR	tszImagePath[MAX_PATH];
-	DWORD	dwFlags;
-	DWORD	dwViewID;
-	RECT	rcOverlay;
-	DWORD	dwObjID;
-	DWORD	dwcValidPts;
-	POINT	rgptCalloutLine[5];
-	RECT	rcCalloutRect;
-	DWORD	dwTextAlign;
-} DIDEVICEIMAGEINFOW, *LPDIDEVICEIMAGEINFOW;
-typedef const DIDEVICEIMAGEINFOW *LPCDIDEVICEIMAGEINFOW;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFO)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFO)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFO)
-
-typedef struct _DIDEVICEIMAGEINFOHEADERA {
-	DWORD	dwSize;
-	DWORD	dwSizeImageInfo;
-	DWORD	dwcViews;
-	DWORD	dwcButtons;
-	DWORD	dwcAxes;
-	DWORD	dwcPOVs;
-	DWORD	dwBufferSize;
-	DWORD	dwBufferUsed;
-	LPDIDEVICEIMAGEINFOA	lprgImageInfoArray;
-} DIDEVICEIMAGEINFOHEADERA, *LPDIDEVICEIMAGEINFOHEADERA;
-typedef const DIDEVICEIMAGEINFOHEADERA *LPCDIDEVICEIMAGEINFOHEADERA;
-
-typedef struct _DIDEVICEIMAGEINFOHEADERW {
-	DWORD	dwSize;
-	DWORD	dwSizeImageInfo;
-	DWORD	dwcViews;
-	DWORD	dwcButtons;
-	DWORD	dwcAxes;
-	DWORD	dwcPOVs;
-	DWORD	dwBufferSize;
-	DWORD	dwBufferUsed;
-	LPDIDEVICEIMAGEINFOW	lprgImageInfoArray;
-} DIDEVICEIMAGEINFOHEADERW, *LPDIDEVICEIMAGEINFOHEADERW;
-typedef const DIDEVICEIMAGEINFOHEADERW *LPCDIDEVICEIMAGEINFOHEADERW;
-
-DECL_WINELIB_TYPE_AW(DIDEVICEIMAGEINFOHEADER)
-DECL_WINELIB_TYPE_AW(LPDIDEVICEIMAGEINFOHEADER)
-DECL_WINELIB_TYPE_AW(LPCDIDEVICEIMAGEINFOHEADER)
-
-#endif /* DI8 */
-
-
-/*****************************************************************************
- * IDirectInputEffect interface
- */
-#if (DIRECTINPUT_VERSION >= 0x0500)
-#undef INTERFACE
-#define INTERFACE IDirectInputEffect
-DECLARE_INTERFACE_(IDirectInputEffect,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputEffect methods ***/
-    STDMETHOD(Initialize)(THIS_ HINSTANCE, DWORD, REFGUID) PURE;
-    STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE;
-    STDMETHOD(GetParameters)(THIS_ LPDIEFFECT, DWORD) PURE;
-    STDMETHOD(SetParameters)(THIS_ LPCDIEFFECT, DWORD) PURE;
-    STDMETHOD(Start)(THIS_ DWORD, DWORD) PURE;
-    STDMETHOD(Stop)(THIS) PURE;
-    STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE;
-    STDMETHOD(Download)(THIS) PURE;
-    STDMETHOD(Unload)(THIS) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInputEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInputEffect_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInputEffect_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInputEffect methods ***/
-#define IDirectInputEffect_Initialize(p,a,b,c)    (p)->lpVtbl->Initialize(p,a,b,c)
-#define IDirectInputEffect_GetEffectGuid(p,a)     (p)->lpVtbl->GetEffectGuid(p,a)
-#define IDirectInputEffect_GetParameters(p,a,b)   (p)->lpVtbl->GetParameters(p,a,b)
-#define IDirectInputEffect_SetParameters(p,a,b)   (p)->lpVtbl->SetParameters(p,a,b)
-#define IDirectInputEffect_Start(p,a,b)           (p)->lpVtbl->Start(p,a,b)
-#define IDirectInputEffect_Stop(p)                (p)->lpVtbl->Stop(p)
-#define IDirectInputEffect_GetEffectStatus(p,a)   (p)->lpVtbl->GetEffectStatus(p,a)
-#define IDirectInputEffect_Download(p)            (p)->lpVtbl->Download(p)
-#define IDirectInputEffect_Unload(p)              (p)->lpVtbl->Unload(p)
-#define IDirectInputEffect_Escape(p,a)            (p)->lpVtbl->Escape(p,a)
-#else
-/*** IUnknown methods ***/
-#define IDirectInputEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInputEffect_AddRef(p)             (p)->AddRef()
-#define IDirectInputEffect_Release(p)            (p)->Release()
-/*** IDirectInputEffect methods ***/
-#define IDirectInputEffect_Initialize(p,a,b,c)    (p)->Initialize(a,b,c)
-#define IDirectInputEffect_GetEffectGuid(p,a)     (p)->GetEffectGuid(a)
-#define IDirectInputEffect_GetParameters(p,a,b)   (p)->GetParameters(a,b)
-#define IDirectInputEffect_SetParameters(p,a,b)   (p)->SetParameters(a,b)
-#define IDirectInputEffect_Start(p,a,b)           (p)->Start(a,b)
-#define IDirectInputEffect_Stop(p)                (p)->Stop()
-#define IDirectInputEffect_GetEffectStatus(p,a)   (p)->GetEffectStatus(a)
-#define IDirectInputEffect_Download(p)            (p)->Download()
-#define IDirectInputEffect_Unload(p)              (p)->Unload()
-#define IDirectInputEffect_Escape(p,a)            (p)->Escape(a)
-#endif
-
-#endif /* DI5 */
-
-
-/*****************************************************************************
- * IDirectInputDeviceA interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDeviceA
-DECLARE_INTERFACE_(IDirectInputDeviceA,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceA methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-};
-
-/*****************************************************************************
- * IDirectInputDeviceW interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDeviceW
-DECLARE_INTERFACE_(IDirectInputDeviceW,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceW methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInputDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInputDevice_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInputDevice_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice_GetCapabilities(p,a)       (p)->lpVtbl->GetCapabilities(p,a)
-#define IDirectInputDevice_EnumObjects(p,a,b,c)       (p)->lpVtbl->EnumObjects(p,a,b,c)
-#define IDirectInputDevice_GetProperty(p,a,b)         (p)->lpVtbl->GetProperty(p,a,b)
-#define IDirectInputDevice_SetProperty(p,a,b)         (p)->lpVtbl->SetProperty(p,a,b)
-#define IDirectInputDevice_Acquire(p)                 (p)->lpVtbl->Acquire(p)
-#define IDirectInputDevice_Unacquire(p)               (p)->lpVtbl->Unacquire(p)
-#define IDirectInputDevice_GetDeviceState(p,a,b)      (p)->lpVtbl->GetDeviceState(p,a,b)
-#define IDirectInputDevice_GetDeviceData(p,a,b,c,d)   (p)->lpVtbl->GetDeviceData(p,a,b,c,d)
-#define IDirectInputDevice_SetDataFormat(p,a)         (p)->lpVtbl->SetDataFormat(p,a)
-#define IDirectInputDevice_SetEventNotification(p,a)  (p)->lpVtbl->SetEventNotification(p,a)
-#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b)
-#define IDirectInputDevice_GetObjectInfo(p,a,b,c)     (p)->lpVtbl->GetObjectInfo(p,a,b,c)
-#define IDirectInputDevice_GetDeviceInfo(p,a)         (p)->lpVtbl->GetDeviceInfo(p,a)
-#define IDirectInputDevice_RunControlPanel(p,a,b)     (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInputDevice_Initialize(p,a,b,c)        (p)->lpVtbl->Initialize(p,a,b,c)
-#else
-/*** IUnknown methods ***/
-#define IDirectInputDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInputDevice_AddRef(p)             (p)->AddRef()
-#define IDirectInputDevice_Release(p)            (p)->Release()
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice_GetCapabilities(p,a)       (p)->GetCapabilities(a)
-#define IDirectInputDevice_EnumObjects(p,a,b,c)       (p)->EnumObjects(a,b,c)
-#define IDirectInputDevice_GetProperty(p,a,b)         (p)->GetProperty(a,b)
-#define IDirectInputDevice_SetProperty(p,a,b)         (p)->SetProperty(a,b)
-#define IDirectInputDevice_Acquire(p)                 (p)->Acquire()
-#define IDirectInputDevice_Unacquire(p)               (p)->Unacquire()
-#define IDirectInputDevice_GetDeviceState(p,a,b)      (p)->GetDeviceState(a,b)
-#define IDirectInputDevice_GetDeviceData(p,a,b,c,d)   (p)->GetDeviceData(a,b,c,d)
-#define IDirectInputDevice_SetDataFormat(p,a)         (p)->SetDataFormat(a)
-#define IDirectInputDevice_SetEventNotification(p,a)  (p)->SetEventNotification(a)
-#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b)
-#define IDirectInputDevice_GetObjectInfo(p,a,b,c)     (p)->GetObjectInfo(a,b,c)
-#define IDirectInputDevice_GetDeviceInfo(p,a)         (p)->GetDeviceInfo(a)
-#define IDirectInputDevice_RunControlPanel(p,a,b)     (p)->RunControlPanel(a,b)
-#define IDirectInputDevice_Initialize(p,a,b,c)        (p)->Initialize(a,b,c)
-#endif
-
-
-#if (DIRECTINPUT_VERSION >= 0x0500)
-/*****************************************************************************
- * IDirectInputDevice2A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice2A
-DECLARE_INTERFACE_(IDirectInputDevice2A,IDirectInputDeviceA)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceA methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2A methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-};
-
-/*****************************************************************************
- * IDirectInputDevice2W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice2W
-DECLARE_INTERFACE_(IDirectInputDevice2W,IDirectInputDeviceW)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceW methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2W methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInputDevice2_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInputDevice2_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice2_GetCapabilities(p,a)       (p)->lpVtbl->GetCapabilities(p,a)
-#define IDirectInputDevice2_EnumObjects(p,a,b,c)       (p)->lpVtbl->EnumObjects(p,a,b,c)
-#define IDirectInputDevice2_GetProperty(p,a,b)         (p)->lpVtbl->GetProperty(p,a,b)
-#define IDirectInputDevice2_SetProperty(p,a,b)         (p)->lpVtbl->SetProperty(p,a,b)
-#define IDirectInputDevice2_Acquire(p)                 (p)->lpVtbl->Acquire(p)
-#define IDirectInputDevice2_Unacquire(p)               (p)->lpVtbl->Unacquire(p)
-#define IDirectInputDevice2_GetDeviceState(p,a,b)      (p)->lpVtbl->GetDeviceState(p,a,b)
-#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d)   (p)->lpVtbl->GetDeviceData(p,a,b,c,d)
-#define IDirectInputDevice2_SetDataFormat(p,a)         (p)->lpVtbl->SetDataFormat(p,a)
-#define IDirectInputDevice2_SetEventNotification(p,a)  (p)->lpVtbl->SetEventNotification(p,a)
-#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b)
-#define IDirectInputDevice2_GetObjectInfo(p,a,b,c)     (p)->lpVtbl->GetObjectInfo(p,a,b,c)
-#define IDirectInputDevice2_GetDeviceInfo(p,a)         (p)->lpVtbl->GetDeviceInfo(p,a)
-#define IDirectInputDevice2_RunControlPanel(p,a,b)     (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInputDevice2_Initialize(p,a,b,c)        (p)->lpVtbl->Initialize(p,a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice2_CreateEffect(p,a,b,c,d)           (p)->lpVtbl->CreateEffect(p,a,b,c,d)
-#define IDirectInputDevice2_EnumEffects(p,a,b,c)              (p)->lpVtbl->EnumEffects(p,a,b,c)
-#define IDirectInputDevice2_GetEffectInfo(p,a,b)              (p)->lpVtbl->GetEffectInfo(p,a,b)
-#define IDirectInputDevice2_GetForceFeedbackState(p,a)        (p)->lpVtbl->GetForceFeedbackState(p,a)
-#define IDirectInputDevice2_SendForceFeedbackCommand(p,a)     (p)->lpVtbl->SendForceFeedbackCommand(p,a)
-#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c)
-#define IDirectInputDevice2_Escape(p,a)                       (p)->lpVtbl->Escape(p,a)
-#define IDirectInputDevice2_Poll(p)                           (p)->lpVtbl->Poll(p)
-#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d)         (p)->lpVtbl->SendDeviceData(p,a,b,c,d)
-#else
-/*** IUnknown methods ***/
-#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInputDevice2_AddRef(p)             (p)->AddRef()
-#define IDirectInputDevice2_Release(p)            (p)->Release()
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice2_GetCapabilities(p,a)       (p)->GetCapabilities(a)
-#define IDirectInputDevice2_EnumObjects(p,a,b,c)       (p)->EnumObjects(a,b,c)
-#define IDirectInputDevice2_GetProperty(p,a,b)         (p)->GetProperty(a,b)
-#define IDirectInputDevice2_SetProperty(p,a,b)         (p)->SetProperty(a,b)
-#define IDirectInputDevice2_Acquire(p)                 (p)->Acquire()
-#define IDirectInputDevice2_Unacquire(p)               (p)->Unacquire()
-#define IDirectInputDevice2_GetDeviceState(p,a,b)      (p)->GetDeviceState(a,b)
-#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d)   (p)->GetDeviceData(a,b,c,d)
-#define IDirectInputDevice2_SetDataFormat(p,a)         (p)->SetDataFormat(a)
-#define IDirectInputDevice2_SetEventNotification(p,a)  (p)->SetEventNotification(a)
-#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b)
-#define IDirectInputDevice2_GetObjectInfo(p,a,b,c)     (p)->GetObjectInfo(a,b,c)
-#define IDirectInputDevice2_GetDeviceInfo(p,a)         (p)->GetDeviceInfo(a)
-#define IDirectInputDevice2_RunControlPanel(p,a,b)     (p)->RunControlPanel(a,b)
-#define IDirectInputDevice2_Initialize(p,a,b,c)        (p)->Initialize(a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice2_CreateEffect(p,a,b,c,d)           (p)->CreateEffect(a,b,c,d)
-#define IDirectInputDevice2_EnumEffects(p,a,b,c)              (p)->EnumEffects(a,b,c)
-#define IDirectInputDevice2_GetEffectInfo(p,a,b)              (p)->GetEffectInfo(a,b)
-#define IDirectInputDevice2_GetForceFeedbackState(p,a)        (p)->GetForceFeedbackState(a)
-#define IDirectInputDevice2_SendForceFeedbackCommand(p,a)     (p)->SendForceFeedbackCommand(a)
-#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c)
-#define IDirectInputDevice2_Escape(p,a)                       (p)->Escape(a)
-#define IDirectInputDevice2_Poll(p)                           (p)->Poll()
-#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d)         (p)->SendDeviceData(a,b,c,d)
-#endif
-#endif /* DI5 */
-
-#if DIRECTINPUT_VERSION >= 0x0700
-/*****************************************************************************
- * IDirectInputDevice7A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice7A
-DECLARE_INTERFACE_(IDirectInputDevice7A,IDirectInputDevice2A)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceA methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2A methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-    /*** IDirectInputDevice7A methods ***/
-    STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE;
-    STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE;
-};
-
-/*****************************************************************************
- * IDirectInputDevice7W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice7W
-DECLARE_INTERFACE_(IDirectInputDevice7W,IDirectInputDevice2W)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceW methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2W methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-    /*** IDirectInputDevice7W methods ***/
-    STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE;
-    STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInputDevice7_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInputDevice7_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice7_GetCapabilities(p,a)       (p)->lpVtbl->GetCapabilities(p,a)
-#define IDirectInputDevice7_EnumObjects(p,a,b,c)       (p)->lpVtbl->EnumObjects(p,a,b,c)
-#define IDirectInputDevice7_GetProperty(p,a,b)         (p)->lpVtbl->GetProperty(p,a,b)
-#define IDirectInputDevice7_SetProperty(p,a,b)         (p)->lpVtbl->SetProperty(p,a,b)
-#define IDirectInputDevice7_Acquire(p)                 (p)->lpVtbl->Acquire(p)
-#define IDirectInputDevice7_Unacquire(p)               (p)->lpVtbl->Unacquire(p)
-#define IDirectInputDevice7_GetDeviceState(p,a,b)      (p)->lpVtbl->GetDeviceState(p,a,b)
-#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d)   (p)->lpVtbl->GetDeviceData(p,a,b,c,d)
-#define IDirectInputDevice7_SetDataFormat(p,a)         (p)->lpVtbl->SetDataFormat(p,a)
-#define IDirectInputDevice7_SetEventNotification(p,a)  (p)->lpVtbl->SetEventNotification(p,a)
-#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b)
-#define IDirectInputDevice7_GetObjectInfo(p,a,b,c)     (p)->lpVtbl->GetObjectInfo(p,a,b,c)
-#define IDirectInputDevice7_GetDeviceInfo(p,a)         (p)->lpVtbl->GetDeviceInfo(p,a)
-#define IDirectInputDevice7_RunControlPanel(p,a,b)     (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInputDevice7_Initialize(p,a,b,c)        (p)->lpVtbl->Initialize(p,a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice7_CreateEffect(p,a,b,c,d)           (p)->lpVtbl->CreateEffect(p,a,b,c,d)
-#define IDirectInputDevice7_EnumEffects(p,a,b,c)              (p)->lpVtbl->EnumEffects(p,a,b,c)
-#define IDirectInputDevice7_GetEffectInfo(p,a,b)              (p)->lpVtbl->GetEffectInfo(p,a,b)
-#define IDirectInputDevice7_GetForceFeedbackState(p,a)        (p)->lpVtbl->GetForceFeedbackState(p,a)
-#define IDirectInputDevice7_SendForceFeedbackCommand(p,a)     (p)->lpVtbl->SendForceFeedbackCommand(p,a)
-#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c)
-#define IDirectInputDevice7_Escape(p,a)                       (p)->lpVtbl->Escape(p,a)
-#define IDirectInputDevice7_Poll(p)                           (p)->lpVtbl->Poll(p)
-#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d)         (p)->lpVtbl->SendDeviceData(p,a,b,c,d)
-/*** IDirectInputDevice7 methods ***/
-#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d)
-#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d)
-#else
-/*** IUnknown methods ***/
-#define IDirectInputDevice7_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInputDevice7_AddRef(p)             (p)->AddRef()
-#define IDirectInputDevice7_Release(p)            (p)->Release()
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice7_GetCapabilities(p,a)       (p)->GetCapabilities(a)
-#define IDirectInputDevice7_EnumObjects(p,a,b,c)       (p)->EnumObjects(a,b,c)
-#define IDirectInputDevice7_GetProperty(p,a,b)         (p)->GetProperty(a,b)
-#define IDirectInputDevice7_SetProperty(p,a,b)         (p)->SetProperty(a,b)
-#define IDirectInputDevice7_Acquire(p)                 (p)->Acquire()
-#define IDirectInputDevice7_Unacquire(p)               (p)->Unacquire()
-#define IDirectInputDevice7_GetDeviceState(p,a,b)      (p)->GetDeviceState(a,b)
-#define IDirectInputDevice7_GetDeviceData(p,a,b,c,d)   (p)->GetDeviceData(a,b,c,d)
-#define IDirectInputDevice7_SetDataFormat(p,a)         (p)->SetDataFormat(a)
-#define IDirectInputDevice7_SetEventNotification(p,a)  (p)->SetEventNotification(a)
-#define IDirectInputDevice7_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b)
-#define IDirectInputDevice7_GetObjectInfo(p,a,b,c)     (p)->GetObjectInfo(a,b,c)
-#define IDirectInputDevice7_GetDeviceInfo(p,a)         (p)->GetDeviceInfo(a)
-#define IDirectInputDevice7_RunControlPanel(p,a,b)     (p)->RunControlPanel(a,b)
-#define IDirectInputDevice7_Initialize(p,a,b,c)        (p)->Initialize(a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice7_CreateEffect(p,a,b,c,d)           (p)->CreateEffect(a,b,c,d)
-#define IDirectInputDevice7_EnumEffects(p,a,b,c)              (p)->EnumEffects(a,b,c)
-#define IDirectInputDevice7_GetEffectInfo(p,a,b)              (p)->GetEffectInfo(a,b)
-#define IDirectInputDevice7_GetForceFeedbackState(p,a)        (p)->GetForceFeedbackState(a)
-#define IDirectInputDevice7_SendForceFeedbackCommand(p,a)     (p)->SendForceFeedbackCommand(a)
-#define IDirectInputDevice7_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c)
-#define IDirectInputDevice7_Escape(p,a)                       (p)->Escape(a)
-#define IDirectInputDevice7_Poll(p)                           (p)->Poll()
-#define IDirectInputDevice7_SendDeviceData(p,a,b,c,d)         (p)->SendDeviceData(a,b,c,d)
-/*** IDirectInputDevice7 methods ***/
-#define IDirectInputDevice7_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d)
-#define IDirectInputDevice7_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d)
-#endif
-
-#endif /* DI7 */
-
-#if DIRECTINPUT_VERSION >= 0x0800
-/*****************************************************************************
- * IDirectInputDevice8A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice8A
-DECLARE_INTERFACE_(IDirectInputDevice8A,IDirectInputDevice7A)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceA methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2A methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-    /*** IDirectInputDevice7A methods ***/
-    STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE;
-    STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE;
-    /*** IDirectInputDevice8A methods ***/
-    STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE;
-    STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATA lpdiaf, LPCSTR lpszUserName, DWORD dwFlags) PURE;
-    STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) PURE;
-};
-
-/*****************************************************************************
- * IDirectInputDevice8W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputDevice8W
-DECLARE_INTERFACE_(IDirectInputDevice8W,IDirectInputDevice7W)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputDeviceW methods ***/
-    STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS lpDIDevCaps) PURE;
-    STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetProperty)(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph) PURE;
-    STDMETHOD(SetProperty)(THIS_ REFGUID rguidProp, LPCDIPROPHEADER pdiph) PURE;
-    STDMETHOD(Acquire)(THIS) PURE;
-    STDMETHOD(Unacquire)(THIS) PURE;
-    STDMETHOD(GetDeviceState)(THIS_ DWORD cbData, LPVOID lpvData) PURE;
-    STDMETHOD(GetDeviceData)(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) PURE;
-    STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT lpdf) PURE;
-    STDMETHOD(SetEventNotification)(THIS_ HANDLE hEvent) PURE;
-    STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwFlags) PURE;
-    STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) PURE;
-    STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW pdidi) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) PURE;
-    /*** IDirectInputDevice2W methods ***/
-    STDMETHOD(CreateEffect)(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) PURE;
-    STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) PURE;
-    STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW pdei, REFGUID rguid) PURE;
-    STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD pdwOut) PURE;
-    STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD dwFlags) PURE;
-    STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) PURE;
-    STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE pesc) PURE;
-    STDMETHOD(Poll)(THIS) PURE;
-    STDMETHOD(SendDeviceData)(THIS_ DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) PURE;
-    /*** IDirectInputDevice7W methods ***/
-    STDMETHOD(EnumEffectsInFile)(THIS_ LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) PURE;
-    STDMETHOD(WriteEffectToFile)(THIS_ LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) PURE;
-    /*** IDirectInputDevice8W methods ***/
-    STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE;
-    STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) PURE;
-    STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInputDevice8_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInputDevice8_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice8_GetCapabilities(p,a)       (p)->lpVtbl->GetCapabilities(p,a)
-#define IDirectInputDevice8_EnumObjects(p,a,b,c)       (p)->lpVtbl->EnumObjects(p,a,b,c)
-#define IDirectInputDevice8_GetProperty(p,a,b)         (p)->lpVtbl->GetProperty(p,a,b)
-#define IDirectInputDevice8_SetProperty(p,a,b)         (p)->lpVtbl->SetProperty(p,a,b)
-#define IDirectInputDevice8_Acquire(p)                 (p)->lpVtbl->Acquire(p)
-#define IDirectInputDevice8_Unacquire(p)               (p)->lpVtbl->Unacquire(p)
-#define IDirectInputDevice8_GetDeviceState(p,a,b)      (p)->lpVtbl->GetDeviceState(p,a,b)
-#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d)   (p)->lpVtbl->GetDeviceData(p,a,b,c,d)
-#define IDirectInputDevice8_SetDataFormat(p,a)         (p)->lpVtbl->SetDataFormat(p,a)
-#define IDirectInputDevice8_SetEventNotification(p,a)  (p)->lpVtbl->SetEventNotification(p,a)
-#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b)
-#define IDirectInputDevice8_GetObjectInfo(p,a,b,c)     (p)->lpVtbl->GetObjectInfo(p,a,b,c)
-#define IDirectInputDevice8_GetDeviceInfo(p,a)         (p)->lpVtbl->GetDeviceInfo(p,a)
-#define IDirectInputDevice8_RunControlPanel(p,a,b)     (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInputDevice8_Initialize(p,a,b,c)        (p)->lpVtbl->Initialize(p,a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice8_CreateEffect(p,a,b,c,d)           (p)->lpVtbl->CreateEffect(p,a,b,c,d)
-#define IDirectInputDevice8_EnumEffects(p,a,b,c)              (p)->lpVtbl->EnumEffects(p,a,b,c)
-#define IDirectInputDevice8_GetEffectInfo(p,a,b)              (p)->lpVtbl->GetEffectInfo(p,a,b)
-#define IDirectInputDevice8_GetForceFeedbackState(p,a)        (p)->lpVtbl->GetForceFeedbackState(p,a)
-#define IDirectInputDevice8_SendForceFeedbackCommand(p,a)     (p)->lpVtbl->SendForceFeedbackCommand(p,a)
-#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c)
-#define IDirectInputDevice8_Escape(p,a)                       (p)->lpVtbl->Escape(p,a)
-#define IDirectInputDevice8_Poll(p)                           (p)->lpVtbl->Poll(p)
-#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d)         (p)->lpVtbl->SendDeviceData(p,a,b,c,d)
-/*** IDirectInputDevice7 methods ***/
-#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->lpVtbl->EnumEffectsInFile(p,a,b,c,d)
-#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->lpVtbl->WriteEffectToFile(p,a,b,c,d)
-/*** IDirectInputDevice8 methods ***/
-#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->lpVtbl->BuildActionMap(p,a,b,c)
-#define IDirectInputDevice8_SetActionMap(p,a,b,c)   (p)->lpVtbl->SetActionMap(p,a,b,c)
-#define IDirectInputDevice8_GetImageInfo(p,a)       (p)->lpVtbl->GetImageInfo(p,a)
-#else
-/*** IUnknown methods ***/
-#define IDirectInputDevice8_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInputDevice8_AddRef(p)             (p)->AddRef()
-#define IDirectInputDevice8_Release(p)            (p)->Release()
-/*** IDirectInputDevice methods ***/
-#define IDirectInputDevice8_GetCapabilities(p,a)       (p)->GetCapabilities(a)
-#define IDirectInputDevice8_EnumObjects(p,a,b,c)       (p)->EnumObjects(a,b,c)
-#define IDirectInputDevice8_GetProperty(p,a,b)         (p)->GetProperty(a,b)
-#define IDirectInputDevice8_SetProperty(p,a,b)         (p)->SetProperty(a,b)
-#define IDirectInputDevice8_Acquire(p)                 (p)->Acquire()
-#define IDirectInputDevice8_Unacquire(p)               (p)->Unacquire()
-#define IDirectInputDevice8_GetDeviceState(p,a,b)      (p)->GetDeviceState(a,b)
-#define IDirectInputDevice8_GetDeviceData(p,a,b,c,d)   (p)->GetDeviceData(a,b,c,d)
-#define IDirectInputDevice8_SetDataFormat(p,a)         (p)->SetDataFormat(a)
-#define IDirectInputDevice8_SetEventNotification(p,a)  (p)->SetEventNotification(a)
-#define IDirectInputDevice8_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b)
-#define IDirectInputDevice8_GetObjectInfo(p,a,b,c)     (p)->GetObjectInfo(a,b,c)
-#define IDirectInputDevice8_GetDeviceInfo(p,a)         (p)->GetDeviceInfo(a)
-#define IDirectInputDevice8_RunControlPanel(p,a,b)     (p)->RunControlPanel(a,b)
-#define IDirectInputDevice8_Initialize(p,a,b,c)        (p)->Initialize(a,b,c)
-/*** IDirectInputDevice2 methods ***/
-#define IDirectInputDevice8_CreateEffect(p,a,b,c,d)           (p)->CreateEffect(a,b,c,d)
-#define IDirectInputDevice8_EnumEffects(p,a,b,c)              (p)->EnumEffects(a,b,c)
-#define IDirectInputDevice8_GetEffectInfo(p,a,b)              (p)->GetEffectInfo(a,b)
-#define IDirectInputDevice8_GetForceFeedbackState(p,a)        (p)->GetForceFeedbackState(a)
-#define IDirectInputDevice8_SendForceFeedbackCommand(p,a)     (p)->SendForceFeedbackCommand(a)
-#define IDirectInputDevice8_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c)
-#define IDirectInputDevice8_Escape(p,a)                       (p)->Escape(a)
-#define IDirectInputDevice8_Poll(p)                           (p)->Poll()
-#define IDirectInputDevice8_SendDeviceData(p,a,b,c,d)         (p)->SendDeviceData(a,b,c,d)
-/*** IDirectInputDevice7 methods ***/
-#define IDirectInputDevice8_EnumEffectsInFile(p,a,b,c,d) (p)->EnumEffectsInFile(a,b,c,d)
-#define IDirectInputDevice8_WriteEffectToFile(p,a,b,c,d) (p)->WriteEffectToFile(a,b,c,d)
-/*** IDirectInputDevice8 methods ***/
-#define IDirectInputDevice8_BuildActionMap(p,a,b,c) (p)->BuildActionMap(a,b,c)
-#define IDirectInputDevice8_SetActionMap(p,a,b,c)   (p)->SetActionMap(a,b,c)
-#define IDirectInputDevice8_GetImageInfo(p,a)       (p)->GetImageInfo(a)
-#endif
-
-#endif /* DI8 */
-
-/* "Standard" Mouse report... */
-typedef struct DIMOUSESTATE {
-  LONG lX;
-  LONG lY;
-  LONG lZ;
-  BYTE rgbButtons[4];
-} DIMOUSESTATE;
-
-#if DIRECTINPUT_VERSION >= 0x0700
-/* "Standard" Mouse report for DInput 7... */
-typedef struct DIMOUSESTATE2 {
-  LONG lX;
-  LONG lY;
-  LONG lZ;
-  BYTE rgbButtons[8];
-} DIMOUSESTATE2;
-#endif /* DI7 */
-
-#define DIMOFS_X        FIELD_OFFSET(DIMOUSESTATE, lX)
-#define DIMOFS_Y        FIELD_OFFSET(DIMOUSESTATE, lY)
-#define DIMOFS_Z        FIELD_OFFSET(DIMOUSESTATE, lZ)
-#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0)
-#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1)
-#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2)
-#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3)
-#if DIRECTINPUT_VERSION >= 0x0700
-#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4)
-#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5)
-#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6)
-#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7)
-#endif /* DI7 */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern const DIDATAFORMAT c_dfDIMouse;
-#if DIRECTINPUT_VERSION >= 0x0700
-extern const DIDATAFORMAT c_dfDIMouse2; /* DX 7 */
-#endif /* DI7 */
-extern const DIDATAFORMAT c_dfDIKeyboard;
-#if DIRECTINPUT_VERSION >= 0x0500
-extern const DIDATAFORMAT c_dfDIJoystick;
-extern const DIDATAFORMAT c_dfDIJoystick2;
-#endif /* DI5 */
-#ifdef __cplusplus
-};
-#endif
-
-/*****************************************************************************
- * IDirectInputA interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputA
-DECLARE_INTERFACE_(IDirectInputA,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputA methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-};
-
-/*****************************************************************************
- * IDirectInputW interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInputW
-DECLARE_INTERFACE_(IDirectInputW,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputW methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInput_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInput_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInput methods ***/
-#define IDirectInput_CreateDevice(p,a,b,c)  (p)->lpVtbl->CreateDevice(p,a,b,c)
-#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d)
-#define IDirectInput_GetDeviceStatus(p,a)   (p)->lpVtbl->GetDeviceStatus(p,a)
-#define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInput_Initialize(p,a,b)      (p)->lpVtbl->Initialize(p,a,b)
-#else
-/*** IUnknown methods ***/
-#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInput_AddRef(p)             (p)->AddRef()
-#define IDirectInput_Release(p)            (p)->Release()
-/*** IDirectInput methods ***/
-#define IDirectInput_CreateDevice(p,a,b,c)  (p)->CreateDevice(a,b,c)
-#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d)
-#define IDirectInput_GetDeviceStatus(p,a)   (p)->GetDeviceStatus(a)
-#define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b)
-#define IDirectInput_Initialize(p,a,b)      (p)->Initialize(a,b)
-#endif
-
-/*****************************************************************************
- * IDirectInput2A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput2A
-DECLARE_INTERFACE_(IDirectInput2A,IDirectInputA)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputA methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    /*** IDirectInput2A methods ***/
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE;
-};
-
-/*****************************************************************************
- * IDirectInput2W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput2W
-DECLARE_INTERFACE_(IDirectInput2W,IDirectInputW)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputW methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    /*** IDirectInput2W methods ***/
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInput2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInput2_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInput2_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInput methods ***/
-#define IDirectInput2_CreateDevice(p,a,b,c)  (p)->lpVtbl->CreateDevice(p,a,b,c)
-#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d)
-#define IDirectInput2_GetDeviceStatus(p,a)   (p)->lpVtbl->GetDeviceStatus(p,a)
-#define IDirectInput2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInput2_Initialize(p,a,b)      (p)->lpVtbl->Initialize(p,a,b)
-/*** IDirectInput2 methods ***/
-#define IDirectInput2_FindDevice(p,a,b,c)    (p)->lpVtbl->FindDevice(p,a,b,c)
-#else
-/*** IUnknown methods ***/
-#define IDirectInput2_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInput2_AddRef(p)             (p)->AddRef()
-#define IDirectInput2_Release(p)            (p)->Release()
-/*** IDirectInput methods ***/
-#define IDirectInput2_CreateDevice(p,a,b,c)  (p)->CreateDevice(a,b,c)
-#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d)
-#define IDirectInput2_GetDeviceStatus(p,a)   (p)->GetDeviceStatus(a)
-#define IDirectInput2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b)
-#define IDirectInput2_Initialize(p,a,b)      (p)->Initialize(a,b)
-/*** IDirectInput2 methods ***/
-#define IDirectInput2_FindDevice(p,a,b,c)    (p)->FindDevice(a,b,c)
-#endif
-
-/*****************************************************************************
- * IDirectInput7A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput7A
-DECLARE_INTERFACE_(IDirectInput7A,IDirectInput2A)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputA methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEA *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    /*** IDirectInput2A methods ***/
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE;
-    /*** IDirectInput7A methods ***/
-    STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE;
-};
-
-/*****************************************************************************
- * IDirectInput7W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput7W
-DECLARE_INTERFACE_(IDirectInput7W,IDirectInput2W)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInputW methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICEW *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    /*** IDirectInput2W methods ***/
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE;
-    /*** IDirectInput7W methods ***/
-    STDMETHOD(CreateDeviceEx)(THIS_ REFGUID rguid, REFIID riid, LPVOID *pvOut, LPUNKNOWN lpUnknownOuter) PURE;
-};
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInput7_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInput7_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInput7_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInput methods ***/
-#define IDirectInput7_CreateDevice(p,a,b,c)  (p)->lpVtbl->CreateDevice(p,a,b,c)
-#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d)
-#define IDirectInput7_GetDeviceStatus(p,a)   (p)->lpVtbl->GetDeviceStatus(p,a)
-#define IDirectInput7_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInput7_Initialize(p,a,b)      (p)->lpVtbl->Initialize(p,a,b)
-/*** IDirectInput2 methods ***/
-#define IDirectInput7_FindDevice(p,a,b,c)    (p)->lpVtbl->FindDevice(p,a,b,c)
-/*** IDirectInput7 methods ***/
-#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d)
-#else
-/*** IUnknown methods ***/
-#define IDirectInput7_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInput7_AddRef(p)             (p)->AddRef()
-#define IDirectInput7_Release(p)            (p)->Release()
-/*** IDirectInput methods ***/
-#define IDirectInput7_CreateDevice(p,a,b,c)  (p)->CreateDevice(a,b,c)
-#define IDirectInput7_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d)
-#define IDirectInput7_GetDeviceStatus(p,a)   (p)->GetDeviceStatus(a)
-#define IDirectInput7_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b)
-#define IDirectInput7_Initialize(p,a,b)      (p)->Initialize(a,b)
-/*** IDirectInput2 methods ***/
-#define IDirectInput7_FindDevice(p,a,b,c)    (p)->FindDevice(a,b,c)
-/*** IDirectInput7 methods ***/
-#define IDirectInput7_CreateDeviceEx(p,a,b,c,d) (p)->CreateDeviceEx(a,b,c,d)
-#endif
-
-
-#if DIRECTINPUT_VERSION >= 0x0800
-/*****************************************************************************
- * IDirectInput8A interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput8A
-DECLARE_INTERFACE_(IDirectInput8A,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInput8A methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8A *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) PURE;
-    STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE;
-};
-
-/*****************************************************************************
- * IDirectInput8W interface
- */
-#undef INTERFACE
-#define INTERFACE IDirectInput8W
-DECLARE_INTERFACE_(IDirectInput8W,IUnknown)
-{
-    /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef)(THIS) PURE;
-    STDMETHOD_(ULONG,Release)(THIS) PURE;
-    /*** IDirectInput8W methods ***/
-    STDMETHOD(CreateDevice)(THIS_ REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) PURE;
-    STDMETHOD(EnumDevices)(THIS_ DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(GetDeviceStatus)(THIS_ REFGUID rguidInstance) PURE;
-    STDMETHOD(RunControlPanel)(THIS_ HWND hwndOwner, DWORD dwFlags) PURE;
-    STDMETHOD(Initialize)(THIS_ HINSTANCE hinst, DWORD dwVersion) PURE;
-    STDMETHOD(FindDevice)(THIS_ REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) PURE;
-    STDMETHOD(EnumDevicesBySemantics)(THIS_ LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) PURE;
-    STDMETHOD(ConfigureDevices)(THIS_ LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) PURE;
-};
-#undef INTERFACE
-
-#if !defined(__cplusplus) || defined(CINTERFACE)
-/*** IUnknown methods ***/
-#define IDirectInput8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
-#define IDirectInput8_AddRef(p)             (p)->lpVtbl->AddRef(p)
-#define IDirectInput8_Release(p)            (p)->lpVtbl->Release(p)
-/*** IDirectInput8 methods ***/
-#define IDirectInput8_CreateDevice(p,a,b,c)       (p)->lpVtbl->CreateDevice(p,a,b,c)
-#define IDirectInput8_EnumDevices(p,a,b,c,d)      (p)->lpVtbl->EnumDevices(p,a,b,c,d)
-#define IDirectInput8_GetDeviceStatus(p,a)        (p)->lpVtbl->GetDeviceStatus(p,a)
-#define IDirectInput8_RunControlPanel(p,a,b)      (p)->lpVtbl->RunControlPanel(p,a,b)
-#define IDirectInput8_Initialize(p,a,b)           (p)->lpVtbl->Initialize(p,a,b)
-#define IDirectInput8_FindDevice(p,a,b,c)         (p)->lpVtbl->FindDevice(p,a,b,c)
-#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->lpVtbl->EnumDevicesBySemantics(p,a,b,c,d,e)
-#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->lpVtbl->ConfigureDevices(p,a,b,c,d)
-#else
-/*** IUnknown methods ***/
-#define IDirectInput8_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
-#define IDirectInput8_AddRef(p)             (p)->AddRef()
-#define IDirectInput8_Release(p)            (p)->Release()
-/*** IDirectInput8 methods ***/
-#define IDirectInput8_CreateDevice(p,a,b,c)       (p)->CreateDevice(a,b,c)
-#define IDirectInput8_EnumDevices(p,a,b,c,d)      (p)->EnumDevices(a,b,c,d)
-#define IDirectInput8_GetDeviceStatus(p,a)        (p)->GetDeviceStatus(a)
-#define IDirectInput8_RunControlPanel(p,a,b)      (p)->RunControlPanel(a,b)
-#define IDirectInput8_Initialize(p,a,b)           (p)->Initialize(a,b)
-#define IDirectInput8_FindDevice(p,a,b,c)         (p)->FindDevice(a,b,c)
-#define IDirectInput8_EnumDevicesBySemantics(p,a,b,c,d,e) (p)->EnumDevicesBySemantics(a,b,c,d,e)
-#define IDirectInput8_ConfigureDevices(p,a,b,c,d) (p)->ConfigureDevices(a,b,c,d)
-#endif
-
-#endif /* DI8 */
-
-/* Export functions */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if DIRECTINPUT_VERSION >= 0x0800
-HRESULT WINAPI DirectInput8Create(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN);
-#else /* DI < 8 */
-HRESULT WINAPI DirectInputCreateA(HINSTANCE,DWORD,LPDIRECTINPUTA *,LPUNKNOWN);
-HRESULT WINAPI DirectInputCreateW(HINSTANCE,DWORD,LPDIRECTINPUTW *,LPUNKNOWN);
-#define DirectInputCreate WINELIB_NAME_AW(DirectInputCreate)
-
-HRESULT WINAPI DirectInputCreateEx(HINSTANCE,DWORD,REFIID,LPVOID *,LPUNKNOWN);
-#endif /* DI8 */
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* __DINPUT_INCLUDED__ */
diff --git a/raylib/src/external/glfw/deps/mingw/xinput.h b/raylib/src/external/glfw/deps/mingw/xinput.h
deleted file mode 100644
--- a/raylib/src/external/glfw/deps/mingw/xinput.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * The Wine project - Xinput Joystick Library
- * Copyright 2008 Andrew Fenn
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __WINE_XINPUT_H
-#define __WINE_XINPUT_H
-
-#include <windef.h>
-
-/*
- * Bitmasks for the joysticks buttons, determines what has
- * been pressed on the joystick, these need to be mapped
- * to whatever device you're using instead of an xbox 360
- * joystick
- */
-
-#define XINPUT_GAMEPAD_DPAD_UP          0x0001
-#define XINPUT_GAMEPAD_DPAD_DOWN        0x0002
-#define XINPUT_GAMEPAD_DPAD_LEFT        0x0004
-#define XINPUT_GAMEPAD_DPAD_RIGHT       0x0008
-#define XINPUT_GAMEPAD_START            0x0010
-#define XINPUT_GAMEPAD_BACK             0x0020
-#define XINPUT_GAMEPAD_LEFT_THUMB       0x0040
-#define XINPUT_GAMEPAD_RIGHT_THUMB      0x0080
-#define XINPUT_GAMEPAD_LEFT_SHOULDER    0x0100
-#define XINPUT_GAMEPAD_RIGHT_SHOULDER   0x0200
-#define XINPUT_GAMEPAD_A                0x1000
-#define XINPUT_GAMEPAD_B                0x2000
-#define XINPUT_GAMEPAD_X                0x4000
-#define XINPUT_GAMEPAD_Y                0x8000
-
-/*
- * Defines the flags used to determine if the user is pushing
- * down on a button, not holding a button, etc
- */
-
-#define XINPUT_KEYSTROKE_KEYDOWN        0x0001
-#define XINPUT_KEYSTROKE_KEYUP          0x0002
-#define XINPUT_KEYSTROKE_REPEAT         0x0004
-
-/*
- * Defines the codes which are returned by XInputGetKeystroke
- */
-
-#define VK_PAD_A                        0x5800
-#define VK_PAD_B                        0x5801
-#define VK_PAD_X                        0x5802
-#define VK_PAD_Y                        0x5803
-#define VK_PAD_RSHOULDER                0x5804
-#define VK_PAD_LSHOULDER                0x5805
-#define VK_PAD_LTRIGGER                 0x5806
-#define VK_PAD_RTRIGGER                 0x5807
-#define VK_PAD_DPAD_UP                  0x5810
-#define VK_PAD_DPAD_DOWN                0x5811
-#define VK_PAD_DPAD_LEFT                0x5812
-#define VK_PAD_DPAD_RIGHT               0x5813
-#define VK_PAD_START                    0x5814
-#define VK_PAD_BACK                     0x5815
-#define VK_PAD_LTHUMB_PRESS             0x5816
-#define VK_PAD_RTHUMB_PRESS             0x5817
-#define VK_PAD_LTHUMB_UP                0x5820
-#define VK_PAD_LTHUMB_DOWN              0x5821
-#define VK_PAD_LTHUMB_RIGHT             0x5822
-#define VK_PAD_LTHUMB_LEFT              0x5823
-#define VK_PAD_LTHUMB_UPLEFT            0x5824
-#define VK_PAD_LTHUMB_UPRIGHT           0x5825
-#define VK_PAD_LTHUMB_DOWNRIGHT         0x5826
-#define VK_PAD_LTHUMB_DOWNLEFT          0x5827
-#define VK_PAD_RTHUMB_UP                0x5830
-#define VK_PAD_RTHUMB_DOWN              0x5831
-#define VK_PAD_RTHUMB_RIGHT             0x5832
-#define VK_PAD_RTHUMB_LEFT              0x5833
-#define VK_PAD_RTHUMB_UPLEFT            0x5834
-#define VK_PAD_RTHUMB_UPRIGHT           0x5835
-#define VK_PAD_RTHUMB_DOWNRIGHT         0x5836
-#define VK_PAD_RTHUMB_DOWNLEFT          0x5837
-
-/*
- * Deadzones are for analogue joystick controls on the joypad
- * which determine when input should be assumed to be in the
- * middle of the pad. This is a threshold to stop a joypad
- * controlling the game when the player isn't touching the
- * controls.
- */
-
-#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  7849
-#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
-#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    30
-
-
-/*
- * Defines what type of abilities the type of joystick has
- * DEVTYPE_GAMEPAD is available for all joysticks, however
- * there may be more specific identifiers for other joysticks
- * which are being used.
- */
-
-#define XINPUT_DEVTYPE_GAMEPAD          0x01
-#define XINPUT_DEVSUBTYPE_GAMEPAD       0x01
-#define XINPUT_DEVSUBTYPE_WHEEL         0x02
-#define XINPUT_DEVSUBTYPE_ARCADE_STICK  0x03
-#define XINPUT_DEVSUBTYPE_FLIGHT_SICK   0x04
-#define XINPUT_DEVSUBTYPE_DANCE_PAD     0x05
-#define XINPUT_DEVSUBTYPE_GUITAR        0x06
-#define XINPUT_DEVSUBTYPE_DRUM_KIT      0x08
-
-/*
- * These are used with the XInputGetCapabilities function to
- * determine the abilities to the joystick which has been
- * plugged in.
- */
-
-#define XINPUT_CAPS_VOICE_SUPPORTED     0x0004
-#define XINPUT_FLAG_GAMEPAD             0x00000001
-
-/*
- * Defines the status of the battery if one is used in the
- * attached joystick. The first two define if the joystick
- * supports a battery. Disconnected means that the joystick
- * isn't connected. Wired shows that the joystick is a wired
- * joystick.
- */
-
-#define BATTERY_DEVTYPE_GAMEPAD         0x00
-#define BATTERY_DEVTYPE_HEADSET         0x01
-#define BATTERY_TYPE_DISCONNECTED       0x00
-#define BATTERY_TYPE_WIRED              0x01
-#define BATTERY_TYPE_ALKALINE           0x02
-#define BATTERY_TYPE_NIMH               0x03
-#define BATTERY_TYPE_UNKNOWN            0xFF
-#define BATTERY_LEVEL_EMPTY             0x00
-#define BATTERY_LEVEL_LOW               0x01
-#define BATTERY_LEVEL_MEDIUM            0x02
-#define BATTERY_LEVEL_FULL              0x03
-
-/*
- * How many joysticks can be used with this library. Games that
- * use the xinput library will not go over this number.
- */
-
-#define XUSER_MAX_COUNT                 4
-#define XUSER_INDEX_ANY                 0x000000FF
-
-/*
- * Defines the structure of an xbox 360 joystick.
- */
-
-typedef struct _XINPUT_GAMEPAD {
-    WORD wButtons;
-    BYTE bLeftTrigger;
-    BYTE bRightTrigger;
-    SHORT sThumbLX;
-    SHORT sThumbLY;
-    SHORT sThumbRX;
-    SHORT sThumbRY;
-} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
-
-typedef struct _XINPUT_STATE {
-    DWORD dwPacketNumber;
-    XINPUT_GAMEPAD Gamepad;
-} XINPUT_STATE, *PXINPUT_STATE;
-
-/*
- * Defines the structure of how much vibration is set on both the
- * right and left motors in a joystick. If you're not using a 360
- * joystick you will have to map these to your device.
- */
-
-typedef struct _XINPUT_VIBRATION {
-    WORD wLeftMotorSpeed;
-    WORD wRightMotorSpeed;
-} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
-
-/*
- * Defines the structure for what kind of abilities the joystick has
- * such abilities are things such as if the joystick has the ability
- * to send and receive audio, if the joystick is in fact a driving
- * wheel or perhaps if the joystick is some kind of dance pad or
- * guitar.
- */
-
-typedef struct _XINPUT_CAPABILITIES {
-    BYTE Type;
-    BYTE SubType;
-    WORD Flags;
-    XINPUT_GAMEPAD Gamepad;
-    XINPUT_VIBRATION Vibration;
-} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
-
-/*
- * Defines the structure for a joystick input event which is
- * retrieved using the function XInputGetKeystroke
- */
-typedef struct _XINPUT_KEYSTROKE {
-    WORD VirtualKey;
-    WCHAR Unicode;
-    WORD Flags;
-    BYTE UserIndex;
-    BYTE HidCode;
-} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
-
-typedef struct _XINPUT_BATTERY_INFORMATION
-{
-    BYTE BatteryType;
-    BYTE BatteryLevel;
-} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void WINAPI XInputEnable(WINBOOL);
-DWORD WINAPI XInputSetState(DWORD, XINPUT_VIBRATION*);
-DWORD WINAPI XInputGetState(DWORD, XINPUT_STATE*);
-DWORD WINAPI XInputGetKeystroke(DWORD, DWORD, PXINPUT_KEYSTROKE);
-DWORD WINAPI XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*);
-DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*);
-DWORD WINAPI XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WINE_XINPUT_H */
diff --git a/raylib/src/external/glfw/include/GLFW/glfw3.h b/raylib/src/external/glfw/include/GLFW/glfw3.h
--- a/raylib/src/external/glfw/include/GLFW/glfw3.h
+++ b/raylib/src/external/glfw/include/GLFW/glfw3.h
@@ -1,5 +1,5 @@
 /*************************************************************************
- * GLFW 3.4 - www.glfw.org
+ * GLFW 3.5 - www.glfw.org
  * A library for OpenGL, window and input
  *------------------------------------------------------------------------
  * Copyright (c) 2002-2006 Marcus Geelnard
@@ -291,14 +291,14 @@
  *  features are added to the API but it remains backward-compatible.
  *  @ingroup init
  */
-#define GLFW_VERSION_MINOR          4
+#define GLFW_VERSION_MINOR          5
 /*! @brief The revision number of the GLFW header.
  *
  *  The revision number of the GLFW header.  This is incremented when a bug fix
  *  release is made that does not contain any API changes.
  *  @ingroup init
  */
-#define GLFW_VERSION_REVISION       0
+#define GLFW_VERSION_REVISION       1
 /*! @} */
 
 /*! @brief One.
@@ -1149,11 +1149,12 @@
 #define GLFW_OPENGL_CORE_PROFILE    0x00032001
 #define GLFW_OPENGL_COMPAT_PROFILE  0x00032002
 
-#define GLFW_CURSOR                 0x00033001
-#define GLFW_STICKY_KEYS            0x00033002
-#define GLFW_STICKY_MOUSE_BUTTONS   0x00033003
-#define GLFW_LOCK_KEY_MODS          0x00033004
-#define GLFW_RAW_MOUSE_MOTION       0x00033005
+#define GLFW_CURSOR                  0x00033001
+#define GLFW_STICKY_KEYS             0x00033002
+#define GLFW_STICKY_MOUSE_BUTTONS    0x00033003
+#define GLFW_LOCK_KEY_MODS           0x00033004
+#define GLFW_RAW_MOUSE_MOTION        0x00033005
+#define GLFW_UNLIMITED_MOUSE_BUTTONS 0x00033006
 
 #define GLFW_CURSOR_NORMAL          0x00034001
 #define GLFW_CURSOR_HIDDEN          0x00034002
@@ -1227,13 +1228,13 @@
  *  The top-left to bottom-right diagonal resize/move shape.  This is usually
  *  a diagonal double-headed arrow.
  *
- *  @note @macos This shape is provided by a private system API and may fail
+ *  @note __macOS:__ This shape is provided by a private system API and may fail
  *  with @ref GLFW_CURSOR_UNAVAILABLE in the future.
  *
- *  @note @wayland This shape is provided by a newer standard not supported by
+ *  @note __Wayland:__ This shape is provided by a newer standard not supported by
  *  all cursor themes.
  *
- *  @note @x11 This shape is provided by a newer standard not supported by all
+ *  @note __X11:__ This shape is provided by a newer standard not supported by all
  *  cursor themes.
  */
 #define GLFW_RESIZE_NWSE_CURSOR     0x00036007
@@ -1242,13 +1243,13 @@
  *  The top-right to bottom-left diagonal resize/move shape.  This is usually
  *  a diagonal double-headed arrow.
  *
- *  @note @macos This shape is provided by a private system API and may fail
+ *  @note __macOS:__ This shape is provided by a private system API and may fail
  *  with @ref GLFW_CURSOR_UNAVAILABLE in the future.
  *
- *  @note @wayland This shape is provided by a newer standard not supported by
+ *  @note __Wayland:__ This shape is provided by a newer standard not supported by
  *  all cursor themes.
  *
- *  @note @x11 This shape is provided by a newer standard not supported by all
+ *  @note __X11:__ This shape is provided by a newer standard not supported by all
  *  cursor themes.
  */
 #define GLFW_RESIZE_NESW_CURSOR     0x00036008
@@ -1263,10 +1264,10 @@
  *  The operation-not-allowed shape.  This is usually a circle with a diagonal
  *  line through it.
  *
- *  @note @wayland This shape is provided by a newer standard not supported by
+ *  @note __Wayland:__ This shape is provided by a newer standard not supported by
  *  all cursor themes.
  *
- *  @note @x11 This shape is provided by a newer standard not supported by all
+ *  @note __X11:__ This shape is provided by a newer standard not supported by all
  *  cursor themes.
  */
 #define GLFW_NOT_ALLOWED_CURSOR     0x0003600A
@@ -1343,6 +1344,10 @@
 #define GLFW_PLATFORM_NULL          0x00060005
 /*! @} */
 
+/* Reserved platform define for external Emscripten ports: 0x00060006
+ * See https://github.com/pongasoft/emscripten-glfw
+ */
+
 #define GLFW_DONT_CARE              -1
 
 
@@ -1628,7 +1633,7 @@
  *  @sa @ref glfwSetWindowSizeCallback
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -1648,7 +1653,7 @@
  *  @sa @ref glfwSetWindowCloseCallback
  *
  *  @since Added in version 2.5.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -1668,7 +1673,7 @@
  *  @sa @ref glfwSetWindowRefreshCallback
  *
  *  @since Added in version 2.5.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -1799,7 +1804,7 @@
  *  @sa @ref glfwSetMouseButtonCallback
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle and modifier mask parameters.
+ *  __GLFW 3:__ Added window handle and modifier mask parameters.
  *
  *  @ingroup input
  */
@@ -1890,7 +1895,7 @@
  *  @sa @ref glfwSetKeyCallback
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle, scancode and modifier mask parameters.
+ *  __GLFW 3:__ Added window handle, scancode and modifier mask parameters.
  *
  *  @ingroup input
  */
@@ -1911,7 +1916,7 @@
  *  @sa @ref glfwSetCharCallback
  *
  *  @since Added in version 2.4.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup input
  */
@@ -2019,7 +2024,7 @@
  *  @sa @ref glfwGetVideoModes
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added refresh rate member.
+ *  __GLFW 3:__ Added refresh rate member.
  *
  *  @ingroup monitor
  */
@@ -2082,7 +2087,7 @@
  *  @sa @ref window_icon
  *
  *  @since Added in version 2.1.
- *  @glfw3 Removed format and bytes-per-pixel members.
+ *  __GLFW 3:__ Removed format and bytes-per-pixel members.
  *
  *  @ingroup window
  */
@@ -2182,12 +2187,12 @@
  *  @errors Possible errors include @ref GLFW_PLATFORM_UNAVAILABLE and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @macos This function will change the current directory of the
+ *  @remark __macOS:__ This function will change the current directory of the
  *  application to the `Contents/Resources` subdirectory of the application's
  *  bundle, if present.  This can be disabled with the @ref
  *  GLFW_COCOA_CHDIR_RESOURCES init hint.
  *
- *  @remark @macos This function will create the main menu and dock icon for the
+ *  @remark __macOS:__ This function will create the main menu and dock icon for the
  *  application.  If GLFW finds a `MainMenu.nib` it is loaded and assumed to
  *  contain a menu bar.  Otherwise a minimal menu bar is created manually with
  *  common commands like Hide, Quit and About.  The About entry opens a minimal
@@ -2202,7 +2207,7 @@
  *  to something other than `wayland` or `x11`, the regular detection mechanism
  *  will be used instead.
  *
- *  @remark @x11 This function will set the `LC_CTYPE` category of the
+ *  @remark __X11:__ This function will set the `LC_CTYPE` category of the
  *  application locale according to the current environment if that category is
  *  still "C".  This is because the "C" locale breaks Unicode text input.
  *
@@ -2678,7 +2683,7 @@
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
  *
- *  @remark @win32 On Windows 8 and earlier the physical size is calculated from
+ *  @remark __Win32:__ On Windows 8 and earlier the physical size is calculated from
  *  the current resolution and system DPI instead of querying the monitor EDID data.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -2712,7 +2717,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @wayland Fractional scaling information is not yet available for
+ *  @remark __Wayland:__ Fractional scaling information is not yet available for
  *  monitors, so this function only returns integer content scales.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -2860,7 +2865,7 @@
  *  @sa @ref glfwGetVideoMode
  *
  *  @since Added in version 1.0.
- *  @glfw3 Changed to return an array of modes for a specific monitor.
+ *  __GLFW 3:__ Changed to return an array of modes for a specific monitor.
  *
  *  @ingroup monitor
  */
@@ -2914,8 +2919,8 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE,
  *  @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland Gamma handling is a privileged protocol, this function
- *  will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
+ *  @remark __Wayland:__ Monitor gamma is a privileged protocol, so this function
+ *  cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
  *
@@ -2938,8 +2943,8 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR
  *  and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland Gamma handling is a privileged protocol, this function
- *  will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
+ *  @remark __Wayland:__ Monitor gamma is a privileged protocol, so this function
+ *  cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
  *  returning `NULL`.
  *
  *  @pointer_lifetime The returned structure and its arrays are allocated and
@@ -2980,10 +2985,10 @@
  *  @remark The size of the specified gamma ramp should match the size of the
  *  current ramp for that monitor.
  *
- *  @remark @win32 The gamma ramp size must be 256.
+ *  @remark __Win32:__ The gamma ramp size must be 256.
  *
- *  @remark @wayland Gamma handling is a privileged protocol, this function
- *  will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
+ *  @remark __Wayland:__ Monitor gamma is a privileged protocol, so this function
+ *  cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
  *
  *  @pointer_lifetime The specified gamma ramp is copied before this function
  *  returns.
@@ -3158,32 +3163,32 @@
  *  GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE, @ref
  *  GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
  *
- *  @remark @win32 Window creation will fail if the Microsoft GDI software
+ *  @remark __Win32:__ Window creation will fail if the Microsoft GDI software
  *  OpenGL implementation is the only one available.
  *
- *  @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it
+ *  @remark __Win32:__ If the executable has an icon resource named `GLFW_ICON,` it
  *  will be set as the initial icon for the window.  If no such icon is present,
  *  the `IDI_APPLICATION` icon will be used instead.  To set a different icon,
  *  see @ref glfwSetWindowIcon.
  *
- *  @remark @win32 The context to share resources with must not be current on
+ *  @remark __Win32:__ The context to share resources with must not be current on
  *  any other thread.
  *
- *  @remark @macos The OS only supports core profile contexts for OpenGL
+ *  @remark __macOS:__ The OS only supports core profile contexts for OpenGL
  *  versions 3.2 and later.  Before creating an OpenGL context of version 3.2 or
  *  later you must set the [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint)
  *  hint accordingly.  OpenGL 3.0 and 3.1 contexts are not supported at all
  *  on macOS.
  *
- *  @remark @macos The GLFW window has no icon, as it is not a document
+ *  @remark __macOS:__ The GLFW window has no icon, as it is not a document
  *  window, but the dock icon will be the same as the application bundle's icon.
  *  For more information on bundles, see the
  *  [Bundle Programming Guide][bundle-guide] in the Mac Developer Library.
  *
  *  [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/
  *
- *  @remark @macos On OS X 10.10 and later the window frame will not be rendered
- *  at full resolution on Retina displays unless the
+ *  @remark __macOS:__  The window frame will not be rendered at full resolution
+ *  on Retina displays unless the
  *  [GLFW_SCALE_FRAMEBUFFER](@ref GLFW_SCALE_FRAMEBUFFER_hint)
  *  hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the
  *  application bundle's `Info.plist`.  For more information, see
@@ -3194,11 +3199,11 @@
  *
  *  [hidpi-guide]: https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
  *
- *  @remark @macos When activating frame autosaving with
+ *  @remark __macOS:__ When activating frame autosaving with
  *  [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified
  *  window size and position may be overridden by previously saved values.
  *
- *  @remark @wayland GLFW uses [libdecor][] where available to create its window
+ *  @remark __Wayland:__ GLFW uses [libdecor][] where available to create its window
  *  decorations.  This in turn uses server-side XDG decorations where available
  *  and provides high quality client-side decorations on compositors like GNOME.
  *  If both XDG decorations and libdecor are unavailable, GLFW falls back to
@@ -3207,15 +3212,15 @@
  *
  *  [libdecor]: https://gitlab.freedesktop.org/libdecor/libdecor
  *
- *  @remark @x11 Some window managers will not respect the placement of
+ *  @remark __X11:__ Some window managers will not respect the placement of
  *  initially hidden windows.
  *
- *  @remark @x11 Due to the asynchronous nature of X11, it may take a moment for
+ *  @remark __X11:__ Due to the asynchronous nature of X11, it may take a moment for
  *  a window to reach its requested state.  This means you may not be able to
  *  query the final size, position or other attributes directly after window
  *  creation.
  *
- *  @remark @x11 The class part of the `WM_CLASS` window property will by
+ *  @remark __X11:__ The class part of the `WM_CLASS` window property will by
  *  default be set to the window title passed to this function.  The instance
  *  part will use the contents of the `RESOURCE_NAME` environment variable, if
  *  present and not empty, or fall back to the window title.  Set the
@@ -3348,7 +3353,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @macos The window title will not be updated until the next time you
+ *  @remark __macOS:__ The window title will not be updated until the next time you
  *  process events.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3357,7 +3362,7 @@
  *  @sa @ref glfwGetWindowTitle
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3391,14 +3396,14 @@
  *  @pointer_lifetime The specified image data is copied before this function
  *  returns.
  *
- *  @remark @macos Regular windows do not have icons on macOS.  This function
+ *  @remark __macOS:__ Regular windows do not have icons on macOS.  This function
  *  will emit @ref GLFW_FEATURE_UNAVAILABLE.  The dock icon will be the same as
  *  the application bundle's icon.  For more information on bundles, see the
  *  [Bundle Programming Guide][bundle-guide] in the Mac Developer Library.
  *
  *  [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/
  *
- *  @remark @wayland There is no existing protocol to change an icon, the
+ *  @remark __Wayland:__ There is no existing protocol to change an icon, the
  *  window will thus inherit the one defined in the application's desktop file.
  *  This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
  *
@@ -3429,8 +3434,8 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland There is no way for an application to retrieve the global
- *  position of its windows.  This function will emit @ref
+ *  @remark __Wayland:__ Window positions are not currently part of any common
+ *  Wayland protocol, so this function cannot be implemented and will emit @ref
  *  GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3463,8 +3468,8 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland There is no way for an application to set the global
- *  position of its windows.  This function will emit @ref
+ *  @remark __Wayland:__ Window positions are not currently part of any common
+ *  Wayland protocol, so this function cannot be implemented and will emit @ref
  *  GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3473,7 +3478,7 @@
  *  @sa @ref glfwGetWindowPos
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3503,7 +3508,7 @@
  *  @sa @ref glfwSetWindowSize
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3538,7 +3543,7 @@
  *  @remark If you set size limits and an aspect ratio that conflict, the
  *  results are undefined.
  *
- *  @remark @wayland The size limits will not be applied until the window is
+ *  @remark __Wayland:__ The size limits will not be applied until the window is
  *  actually resized, either by the user or by the compositor.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3581,7 +3586,7 @@
  *  @remark If you set size limits and an aspect ratio that conflict, the
  *  results are undefined.
  *
- *  @remark @wayland The aspect ratio will not be applied until the window is
+ *  @remark __Wayland:__ The aspect ratio will not be applied until the window is
  *  actually resized, either by the user or by the compositor.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3627,7 +3632,7 @@
  *  @sa @ref glfwSetWindowMonitor
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3777,7 +3782,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland There is no way to set an opacity factor for a window.
+ *  @remark __Wayland:__ There is no way to set an opacity factor for a window.
  *  This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3806,10 +3811,6 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @wayland Once a window is iconified, @ref glfwRestoreWindow won’t
- *  be able to restore it.  This is a design decision of the xdg-shell
- *  protocol.
- *
  *  @thread_safety This function must only be called from the main thread.
  *
  *  @sa @ref window_iconify
@@ -3817,7 +3818,7 @@
  *  @sa @ref glfwMaximizeWindow
  *
  *  @since Added in version 2.1.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3837,6 +3838,10 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
+ *  @remark __Wayland:__ Restoring a window from maximization is not currently
+ *  part of any common Wayland protocol, so this function can only restore
+ *  windows from maximization.
+ *
  *  @thread_safety This function must only be called from the main thread.
  *
  *  @sa @ref window_iconify
@@ -3844,7 +3849,7 @@
  *  @sa @ref glfwMaximizeWindow
  *
  *  @since Added in version 2.1.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -3891,7 +3896,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @wayland Because Wayland wants every frame of the desktop to be
+ *  @remark __Wayland:__ Because Wayland wants every frame of the desktop to be
  *  complete, this function does not immediately make the window visible.
  *  Instead it will become visible the next time the window framebuffer is
  *  updated after this call.
@@ -3954,7 +3959,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @wayland The compositor will likely ignore focus requests unless
+ *  @remark __Wayland:__ The compositor will likely ignore focus requests unless
  *  another window created by the same application already has input focus.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -3982,7 +3987,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @macos Attention is requested to the application as a whole, not the
+ *  @remark __macOS:__ Attention is requested to the application as a whole, not the
  *  specific window.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -4057,8 +4062,8 @@
  *  affected by any resizing or mode switching, although you may need to update
  *  your viewport if the framebuffer size has changed.
  *
- *  @remark @wayland The desired window position is ignored, as there is no way
- *  for an application to set this property.
+ *  @remark __Wayland:__ Window positions are not currently part of any common
+ *  Wayland protocol.  The window position arguments are ignored.
  *
  *  @thread_safety This function must only be called from the main thread.
  *
@@ -4095,8 +4100,9 @@
  *  errors.  However, this function should not fail as long as it is passed
  *  valid arguments and the library has been [initialized](@ref intro_init).
  *
- *  @remark @wayland The Wayland protocol provides no way to check whether a
- *  window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`.
+ *  @remark __Wayland:__ Checking whether a window is iconified is not currently
+ *  part of any common Wayland protocol, so the @ref GLFW_ICONIFIED attribute
+ *  cannot be implemented and is always `GLFW_FALSE`.
  *
  *  @thread_safety This function must only be called from the main thread.
  *
@@ -4138,7 +4144,7 @@
  *  @remark Calling @ref glfwGetWindowAttrib will always return the latest
  *  value, even if that value is ignored by the current mode of the window.
  *
- *  @remark @wayland The [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) window attribute is
+ *  @remark __Wayland:__ The [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) window attribute is
  *  not supported.  Setting this will emit @ref GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -4218,8 +4224,8 @@
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
  *
- *  @remark @wayland This callback will never be called, as there is no way for
- *  an application to know its global position.
+ *  @remark __Wayland:__ This callback will not be called.  The Wayland protocol
+ *  provides no way to be notified of when a window is moved.
  *
  *  @thread_safety This function must only be called from the main thread.
  *
@@ -4257,7 +4263,7 @@
  *  @sa @ref window_size
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup window
  */
@@ -4289,7 +4295,7 @@
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
  *
- *  @remark @macos Selecting Quit from the application menu will trigger the
+ *  @remark __macOS:__ Selecting Quit from the application menu will trigger the
  *  close callback for all windows.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -4297,7 +4303,7 @@
  *  @sa @ref window_close
  *
  *  @since Added in version 2.5.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup window
  */
@@ -4333,7 +4339,7 @@
  *  @sa @ref window_refresh
  *
  *  @since Added in version 2.5.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup window
  */
@@ -4394,6 +4400,10 @@
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
  *
+ *  @remark __Wayland:__ This callback will not be called.  The Wayland protocol
+ *  provides no way to be notified of when a window is iconified, and no way to
+ *  check whether a window is currently iconified.
+ *
  *  @thread_safety This function must only be called from the main thread.
  *
  *  @sa @ref window_iconify
@@ -4514,7 +4524,8 @@
  *  GLFW will pass those events on to the application callbacks before
  *  returning.
  *
- *  Event processing is not required for joystick input to work.
+ *  Event processing is not required to receive joystick input.  Joystick state
+ *  is polled when a joystick input or gamepad input function is called.
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
@@ -4559,7 +4570,8 @@
  *  GLFW will pass those events on to the application callbacks before
  *  returning.
  *
- *  Event processing is not required for joystick input to work.
+ *  Event processing is not required to receive joystick input.  Joystick state
+ *  is polled when a joystick input or gamepad input function is called.
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
@@ -4606,7 +4618,8 @@
  *  GLFW will pass those events on to the application callbacks before
  *  returning.
  *
- *  Event processing is not required for joystick input to work.
+ *  Event processing is not required to receive joystick input.  Joystick state
+ *  is polled when a joystick input or gamepad input function is called.
  *
  *  @param[in] timeout The maximum amount of time, in seconds, to wait.
  *
@@ -4676,8 +4689,8 @@
  *
  *  This function sets an input mode option for the specified window.  The mode
  *  must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
- *  @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or
- *  @ref GLFW_RAW_MOUSE_MOTION.
+ *  @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS
+ *  @ref GLFW_RAW_MOUSE_MOTION, or @ref GLFW_UNLIMITED_MOUSE_BUTTONS.
  *
  *  If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
  *  modes:
@@ -4717,6 +4730,11 @@
  *  attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE.  Call @ref
  *  glfwRawMouseMotionSupported to check for support.
  *
+ *  If the mode is `GLFW_UNLIMITED_MOUSE_BUTTONS`, the value must be either
+ *  `GLFW_TRUE` to disable the mouse button limit when calling the mouse button
+ *  callback, or `GLFW_FALSE` to limit the mouse buttons sent to the callback
+ *  to the mouse button token values up to `GLFW_MOUSE_BUTTON_LAST`.
+ *
  *  @param[in] window The window whose input mode to set.
  *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
  *  `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
@@ -4894,7 +4912,7 @@
  *  @sa @ref input_key
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup input
  */
@@ -4911,8 +4929,11 @@
  *  returns `GLFW_PRESS` the first time you call it for a mouse button that was
  *  pressed, even if that mouse button has already been released.
  *
+ *  The @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode does not effect the
+ *  limit on buttons which can be polled with this function.
+ *
  *  @param[in] window The desired window.
- *  @param[in] button The desired [mouse button](@ref buttons).
+ *  @param[in] button The desired [mouse button token](@ref buttons).
  *  @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
@@ -4923,7 +4944,7 @@
  *  @sa @ref input_mouse_button
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup input
  */
@@ -4993,7 +5014,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
  *
- *  @remark @wayland This function will only work when the cursor mode is
+ *  @remark __Wayland:__ This function will only work when the cursor mode is
  *  `GLFW_CURSOR_DISABLED`, otherwise it will emit @ref GLFW_FEATURE_UNAVAILABLE.
  *
  *  @thread_safety This function must only be called from the main thread.
@@ -5191,7 +5212,7 @@
  *  @sa @ref input_key
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup input
  */
@@ -5234,7 +5255,7 @@
  *  @sa @ref input_char
  *
  *  @since Added in version 2.4.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup input
  */
@@ -5288,11 +5309,16 @@
  *  is called when a mouse button is pressed or released.
  *
  *  When a window loses input focus, it will generate synthetic mouse button
- *  release events for all pressed mouse buttons.  You can tell these events
- *  from user-generated events by the fact that the synthetic ones are generated
- *  after the focus loss event has been processed, i.e. after the
- *  [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
+ *  release events for all pressed mouse buttons with associated button tokens.
+ *  You can tell these events from user-generated events by the fact that the
+ *  synthetic ones are generated after the focus loss event has been processed,
+ *  i.e. after the [window focus callback](@ref glfwSetWindowFocusCallback) has
+ *  been called.
  *
+ *  The reported `button` value can be higher than `GLFW_MOUSE_BUTTON_LAST` if
+ *  the button does not have an associated [button token](@ref buttons) and the
+ *  @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode is set.
+ *
  *  @param[in] window The window whose callback to set.
  *  @param[in] callback The new callback, or `NULL` to remove the currently set
  *  callback.
@@ -5313,7 +5339,7 @@
  *  @sa @ref input_mouse_button
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter and return value.
+ *  __GLFW 3:__ Added window handle parameter and return value.
  *
  *  @ingroup input
  */
@@ -5543,7 +5569,7 @@
  *  @sa @ref joystick_button
  *
  *  @since Added in version 2.2.
- *  @glfw3 Changed to return a dynamic array.
+ *  __GLFW 3:__ Changed to return a dynamic array.
  *
  *  @ingroup input
  */
@@ -5907,7 +5933,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_PLATFORM_ERROR.
  *
- *  @remark @win32 The clipboard on Windows has a single global lock for reading and
+ *  @remark __Win32:__ The clipboard on Windows has a single global lock for reading and
  *  writing.  GLFW tries to acquire it a few times, which is almost always enough.  If it
  *  cannot acquire the lock then this function emits @ref GLFW_PLATFORM_ERROR and returns.
  *  It is safe to try this multiple times.
@@ -5940,7 +5966,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_FORMAT_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
  *
- *  @remark @win32 The clipboard on Windows has a single global lock for reading and
+ *  @remark __Win32:__ The clipboard on Windows has a single global lock for reading and
  *  writing.  GLFW tries to acquire it a few times, which is almost always enough.  If it
  *  cannot acquire the lock then this function emits @ref GLFW_PLATFORM_ERROR and returns.
  *  It is safe to try this multiple times.
@@ -6148,6 +6174,10 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
  *
+ *  @remark __Wayland:__ When the swap interval is greater than zero and the
+ *  window is not in view, this function may take a few extra milliseconds to
+ *  return.
+ *
  *  @remark __EGL:__ The context of the specified window must be current on the
  *  calling thread.
  *
@@ -6157,7 +6187,7 @@
  *  @sa @ref glfwSwapInterval
  *
  *  @since Added in version 1.0.
- *  @glfw3 Added window handle parameter.
+ *  __GLFW 3:__ Added window handle parameter.
  *
  *  @ingroup window
  */
@@ -6424,7 +6454,7 @@
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
  *
- *  @remark @macos This function currently always returns `GLFW_TRUE`, as the
+ *  @remark __macOS:__ This function currently always returns `GLFW_TRUE`, as the
  *  `VK_MVK_macos_surface` and `VK_EXT_metal_surface` extensions do not provide
  *  a `vkGetPhysicalDevice*PresentationSupport` type function.
  *
@@ -6482,15 +6512,15 @@
  *  @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should
  *  eliminate almost all occurrences of these errors.
  *
- *  @remark @macos GLFW prefers the `VK_EXT_metal_surface` extension, with the
+ *  @remark __macOS:__ GLFW prefers the `VK_EXT_metal_surface` extension, with the
  *  `VK_MVK_macos_surface` extension as a fallback.  The name of the selected
  *  extension, if any, is included in the array returned by @ref
  *  glfwGetRequiredInstanceExtensions.
  *
- *  @remark @macos This function creates and sets a `CAMetalLayer` instance for
+ *  @remark __macOS:__ This function creates and sets a `CAMetalLayer` instance for
  *  the window content view, which is required for MoltenVK to function.
  *
- *  @remark @x11 By default GLFW prefers the `VK_KHR_xcb_surface` extension,
+ *  @remark __X11:__ By default GLFW prefers the `VK_KHR_xcb_surface` extension,
  *  with the `VK_KHR_xlib_surface` extension as a fallback.  You can make
  *  `VK_KHR_xlib_surface` the preferred extension by setting the
  *  [GLFW_X11_XCB_VULKAN_SURFACE](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint) init
diff --git a/raylib/src/external/glfw/include/GLFW/glfw3native.h b/raylib/src/external/glfw/include/GLFW/glfw3native.h
--- a/raylib/src/external/glfw/include/GLFW/glfw3native.h
+++ b/raylib/src/external/glfw/include/GLFW/glfw3native.h
@@ -1,5 +1,5 @@
 /*************************************************************************
- * GLFW 3.4 - www.glfw.org
+ * GLFW 3.5 - www.glfw.org
  * A library for OpenGL, window and input
  *------------------------------------------------------------------------
  * Copyright (c) 2002-2006 Marcus Geelnard
@@ -478,6 +478,29 @@
  *  @ingroup native
  */
 GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
+
+/*! @brief Retrieves the `GLXFBConfig` of the specified window's `GLXWindow`.
+ *
+ *  @param[in] window The window whose `GLXWindow` to query.
+ *  @param[out] config The `GLXFBConfig` of the window `GLXWindow`, if available.
+ *  @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
+ *  GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_UNAVAILABLE.
+ *
+ *  @remark `GLXFBConfig` is an opaque type.  Unlike other GLFW functions, the
+ *  @p config out parameter is not cleared on error, as core GLX does not define
+ *  any invalid value.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.5
+ *
+ *  @ingroup native
+ */
+GLFWAPI int glfwGetGLXFBConfig(GLFWwindow* window, GLXFBConfig* config);
 #endif
 
 #if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
@@ -586,6 +609,29 @@
  *  @ingroup native
  */
 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
+
+/*! @brief Retrieves the `EGLConfig` of the specified window's `EGLSurface`.
+ *
+ *  @param[in] window The window whose `EGLSurface` to query.
+ *  @param[out] config The `EGLConfig` of the window `EGLSurface`, if available.
+ *  @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
+ *  [error](@ref error_handling) occurred.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_NO_WINDOW_CONTEXT.
+ *
+ *  @remark `EGLConfig` is an opaque type.  Unlike other GLFW functions, the @p
+ *  config out parameter is not cleared on error, as core EGL does not define
+ *  any invalid value.
+ *
+ *  @thread_safety This function may be called from any thread.  Access is not
+ *  synchronized.
+ *
+ *  @since Added in version 3.5.
+ *
+ *  @ingroup native
+ */
+GLFWAPI int glfwGetEGLConfig(GLFWwindow* window, EGLConfig* config);
 #endif
 
 #if defined(GLFW_EXPOSE_NATIVE_OSMESA)
diff --git a/raylib/src/external/glfw/src/cocoa_init.m b/raylib/src/external/glfw/src/cocoa_init.m
--- a/raylib/src/external/glfw/src/cocoa_init.m
+++ b/raylib/src/external/glfw/src/cocoa_init.m
@@ -1,8 +1,7 @@
 //========================================================================
-// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -176,7 +175,7 @@
 
 // Create key code translation tables
 //
-static void createKeyTablesCocoa(void)
+static void createKeyTables(void)
 {
     memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
     memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
@@ -451,42 +450,7 @@
 
 @end // GLFWApplicationDelegate
 
-
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW internal API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void* _glfwLoadLocalVulkanLoaderCocoa(void)
-{
-    CFBundleRef bundle = CFBundleGetMainBundle();
-    if (!bundle)
-        return NULL;
-
-    CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);
-    if (!frameworksUrl)
-        return NULL;
-
-    CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(
-        kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);
-    if (!loaderUrl)
-    {
-        CFRelease(frameworksUrl);
-        return NULL;
-    }
-
-    char path[PATH_MAX];
-    void* handle = NULL;
-
-    if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1))
-        handle = _glfwPlatformLoadModule(path);
-
-    CFRelease(loaderUrl);
-    CFRelease(frameworksUrl);
-    return handle;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
@@ -619,7 +583,7 @@
                name:NSTextInputContextKeyboardSelectionDidChangeNotification
              object:nil];
 
-    createKeyTablesCocoa();
+    createKeyTables();
 
     _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
     if (!_glfw.ns.eventSource)
@@ -688,6 +652,8 @@
     _glfwTerminateNSGL();
     _glfwTerminateEGL();
     _glfwTerminateOSMesa();
+
+    memset(&_glfw.ns, 0, sizeof(_glfw.ns));
 
     } // autoreleasepool
 }
diff --git a/raylib/src/external/glfw/src/cocoa_joystick.h b/raylib/src/external/glfw/src/cocoa_joystick.h
--- a/raylib/src/external/glfw/src/cocoa_joystick.h
+++ b/raylib/src/external/glfw/src/cocoa_joystick.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Cocoa - www.glfw.org
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/cocoa_joystick.m b/raylib/src/external/glfw/src/cocoa_joystick.m
--- a/raylib/src/external/glfw/src/cocoa_joystick.m
+++ b/raylib/src/external/glfw/src/cocoa_joystick.m
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Cocoa - www.glfw.org
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
 // Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
diff --git a/raylib/src/external/glfw/src/cocoa_monitor.m b/raylib/src/external/glfw/src/cocoa_monitor.m
--- a/raylib/src/external/glfw/src/cocoa_monitor.m
+++ b/raylib/src/external/glfw/src/cocoa_monitor.m
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -33,6 +32,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <math.h>
+#include <assert.h>
 
 #include <IOKit/graphics/IOGraphicsLib.h>
 #include <ApplicationServices/ApplicationServices.h>
@@ -137,7 +137,7 @@
     if (flags & kDisplayModeStretchedFlag)
         return GLFW_FALSE;
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
+#if MAC_OS_X_VERSION_MAX_ALLOWED == 101100
     CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
     if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
         CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
@@ -164,7 +164,7 @@
     if (result.refreshRate == 0)
         result.refreshRate = (int) round(fallbackRefreshRate);
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
+#if MAC_OS_X_VERSION_MAX_ALLOWED == 101100
     CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
     if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0)
     {
@@ -180,7 +180,7 @@
         result.blueBits = 8;
     }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
+#if MAC_OS_X_VERSION_MAX_ALLOWED == 101100
     CFRelease(format);
 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
     return result;
@@ -628,7 +628,6 @@
 
 GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
@@ -636,6 +635,9 @@
         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Cocoa: Platform not initialized");
         return kCGNullDirectDisplay;
     }
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     return monitor->ns.displayID;
 }
diff --git a/raylib/src/external/glfw/src/cocoa_platform.h b/raylib/src/external/glfw/src/cocoa_platform.h
--- a/raylib/src/external/glfw/src/cocoa_platform.h
+++ b/raylib/src/external/glfw/src/cocoa_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 macOS - www.glfw.org
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
 //
@@ -290,8 +290,6 @@
 void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor);
 
 float _glfwTransformYCocoa(float y);
-
-void* _glfwLoadLocalVulkanLoaderCocoa(void);
 
 GLFWbool _glfwInitNSGL(void);
 void _glfwTerminateNSGL(void);
diff --git a/raylib/src/external/glfw/src/cocoa_time.c b/raylib/src/external/glfw/src/cocoa_time.c
deleted file mode 100644
--- a/raylib/src/external/glfw/src/cocoa_time.c
+++ /dev/null
@@ -1,57 +0,0 @@
-//========================================================================
-// GLFW 3.4 macOS - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
-//
-// 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.
-//
-//========================================================================
-
-#include "internal.h"
-
-#if defined(GLFW_BUILD_COCOA_TIMER)
-
-#include <mach/mach_time.h>
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-void _glfwPlatformInitTimer(void)
-{
-    mach_timebase_info_data_t info;
-    mach_timebase_info(&info);
-
-    _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer;
-}
-
-uint64_t _glfwPlatformGetTimerValue(void)
-{
-    return mach_absolute_time();
-}
-
-uint64_t _glfwPlatformGetTimerFrequency(void)
-{
-    return _glfw.timer.ns.frequency;
-}
-
-#endif // GLFW_BUILD_COCOA_TIMER
-
diff --git a/raylib/src/external/glfw/src/cocoa_time.h b/raylib/src/external/glfw/src/cocoa_time.h
deleted file mode 100644
--- a/raylib/src/external/glfw/src/cocoa_time.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//========================================================================
-// GLFW 3.4 macOS - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2009-2021 Camilla Löwy <elmindreda@glfw.org>
-//
-// 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 GLFW_COCOA_LIBRARY_TIMER_STATE  _GLFWtimerNS   ns;
-
-// Cocoa-specific global timer data
-//
-typedef struct _GLFWtimerNS
-{
-    uint64_t        frequency;
-} _GLFWtimerNS;
-
diff --git a/raylib/src/external/glfw/src/cocoa_window.m b/raylib/src/external/glfw/src/cocoa_window.m
--- a/raylib/src/external/glfw/src/cocoa_window.m
+++ b/raylib/src/external/glfw/src/cocoa_window.m
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 macOS - www.glfw.org
+// GLFW 3.5 Cocoa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
 //
@@ -28,8 +28,11 @@
 
 #if defined(_GLFW_COCOA)
 
+#import <QuartzCore/CAMetalLayer.h>
+
 #include <float.h>
 #include <string.h>
+#include <assert.h>
 
 // HACK: This enum value is missing from framework headers on OS X 10.11 despite
 //       having been (according to documentation) added in Mac OS X 10.7
@@ -111,7 +114,7 @@
 
 // Make the specified window and its video mode active on its monitor
 //
-static void acquireMonitorCocoa(_GLFWwindow* window)
+static void acquireMonitor(_GLFWwindow* window)
 {
     _glfwSetVideoModeCocoa(window->monitor, &window->videoMode);
     const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
@@ -127,7 +130,7 @@
 
 // Remove the window and restore the original video mode
 //
-static void releaseMonitorCocoa(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
     if (window->monitor->window != window)
         return;
@@ -158,7 +161,7 @@
 
 // Translates a macOS keycode to a GLFW keycode
 //
-static int translateKeyCocoa(unsigned int key)
+static int translateKey(unsigned int key)
 {
     if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0]))
         return GLFW_KEY_UNKNOWN;
@@ -277,7 +280,7 @@
 - (void)windowDidMiniaturize:(NSNotification *)notification
 {
     if (window->monitor)
-        releaseMonitorCocoa(window);
+        releaseMonitor(window);
 
     _glfwInputWindowIconify(window, GLFW_TRUE);
 }
@@ -285,7 +288,7 @@
 - (void)windowDidDeminiaturize:(NSNotification *)notification
 {
     if (window->monitor)
-        acquireMonitorCocoa(window);
+        acquireMonitor(window);
 
     _glfwInputWindowIconify(window, GLFW_FALSE);
 }
@@ -309,7 +312,6 @@
 
 - (void)windowDidChangeOcclusionState:(NSNotification* )notification
 {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
     if ([window->ns.object respondsToSelector:@selector(occlusionState)])
     {
         if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
@@ -317,7 +319,6 @@
         else
             window->ns.occluded = GLFW_TRUE;
     }
-#endif
 }
 
 @end
@@ -561,7 +562,7 @@
 
 - (void)keyDown:(NSEvent *)event
 {
-    const int key = translateKeyCocoa([event keyCode]);
+    const int key = translateKey([event keyCode]);
     const int mods = translateFlags([event modifierFlags]);
 
     _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
@@ -574,7 +575,7 @@
     int action;
     const unsigned int modifierFlags =
         [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
-    const int key = translateKeyCocoa([event keyCode]);
+    const int key = translateKey([event keyCode]);
     const int mods = translateFlags(modifierFlags);
     const NSUInteger keyFlag = translateKeyToModifierFlag(key);
 
@@ -593,11 +594,39 @@
 
 - (void)keyUp:(NSEvent *)event
 {
-    const int key = translateKeyCocoa([event keyCode]);
+    const int key = translateKey([event keyCode]);
     const int mods = translateFlags([event modifierFlags]);
     _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods);
 }
 
+- (BOOL)performKeyEquivalent:(NSEvent *)event
+{
+    // HACK: Some key combinations are consumed before reaching keyDown:
+    //       so we claim those events and emit them here
+    const int key = translateKey([event keyCode]);
+    const int mods = translateFlags([event modifierFlags]);
+
+    if (mods & GLFW_MOD_CONTROL)
+    {
+        if (key == GLFW_KEY_TAB || key == GLFW_KEY_ESCAPE)
+        {
+            _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
+            return YES;
+        }
+    }
+
+    if (mods & GLFW_MOD_SUPER)
+    {
+        if (key == GLFW_KEY_PERIOD)
+        {
+            _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
+            return YES;
+        }
+    }
+
+    return [super performKeyEquivalent:event];
+}
+
 - (void)scrollWheel:(NSEvent *)event
 {
     double deltaX = [event scrollingDeltaX];
@@ -883,7 +912,7 @@
 
     [window->ns.object setContentView:window->ns.view];
     [window->ns.object makeFirstResponder:window->ns.view];
-    [window->ns.object setTitle:@(wndconfig->title)];
+    [window->ns.object setTitle:@(window->title)];
     [window->ns.object setDelegate:window->ns.delegate];
     [window->ns.object setAcceptsMouseMovedEvents:YES];
     [window->ns.object setRestorable:NO];
@@ -966,7 +995,7 @@
     {
         _glfwShowWindowCocoa(window);
         _glfwFocusWindowCocoa(window);
-        acquireMonitorCocoa(window);
+        acquireMonitor(window);
 
         if (wndconfig->centerCursor)
             _glfwCenterCursorInContentArea(window);
@@ -996,7 +1025,7 @@
     [window->ns.object orderOut:nil];
 
     if (window->monitor)
-        releaseMonitorCocoa(window);
+        releaseMonitor(window);
 
     if (window->context.destroy)
         window->context.destroy(window);
@@ -1083,7 +1112,7 @@
     if (window->monitor)
     {
         if (window->monitor->window == window)
-            acquireMonitorCocoa(window);
+            acquireMonitor(window);
     }
     else
     {
@@ -1252,7 +1281,7 @@
         if (monitor)
         {
             if (monitor->window == window)
-                acquireMonitorCocoa(window);
+                acquireMonitor(window);
         }
         else
         {
@@ -1270,7 +1299,7 @@
     }
 
     if (window->monitor)
-        releaseMonitorCocoa(window);
+        releaseMonitor(window);
 
     _glfwInputWindowMonitor(window, monitor);
 
@@ -1308,7 +1337,7 @@
         [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
         [window->ns.object setHasShadow:NO];
 
-        acquireMonitorCocoa(window);
+        acquireMonitor(window);
     }
     else
     {
@@ -1949,19 +1978,8 @@
 {
     @autoreleasepool {
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
-    // HACK: Dynamically load Core Animation to avoid adding an extra
-    //       dependency for the majority who don't use MoltenVK
-    NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"];
-    if (!bundle)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Cocoa: Failed to find QuartzCore.framework");
-        return VK_ERROR_EXTENSION_NOT_PRESENT;
-    }
-
     // NOTE: Create the layer here as makeBackingLayer should not return nil
-    window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer];
+    window->ns.layer = [CAMetalLayer layer];
     if (!window->ns.layer)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
@@ -2026,9 +2044,6 @@
     }
 
     return err;
-#else
-    return VK_ERROR_EXTENSION_NOT_PRESENT;
-#endif
 
     } // autoreleasepool
 }
@@ -2040,7 +2055,6 @@
 
 GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
@@ -2050,12 +2064,14 @@
         return nil;
     }
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     return window->ns.object;
 }
 
 GLFWAPI id glfwGetCocoaView(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
@@ -2064,6 +2080,9 @@
                         "Cocoa: Platform not initialized");
         return nil;
     }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     return window->ns.view;
 }
diff --git a/raylib/src/external/glfw/src/context.c b/raylib/src/external/glfw/src/context.c
--- a/raylib/src/external/glfw/src/context.c
+++ b/raylib/src/external/glfw/src/context.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
@@ -195,7 +195,7 @@
     {
         current = alternatives + i;
 
-        if (desired->stereo > 0 && current->stereo == 0)
+        if (desired->stereo && !current->stereo)
         {
             // Stereo is a hard constraint
             continue;
@@ -359,7 +359,7 @@
     window->context.source = ctxconfig->source;
     window->context.client = GLFW_OPENGL_API;
 
-    previous = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    previous = _glfwPlatformGetTls(&_glfw.contextSlot);
     glfwMakeContextCurrent((GLFWwindow*) window);
     if (_glfwPlatformGetTls(&_glfw.contextSlot) != window)
         return GLFW_FALSE;
@@ -368,7 +368,12 @@
         window->context.getProcAddress("glGetIntegerv");
     window->context.GetString = (PFNGLGETSTRINGPROC)
         window->context.getProcAddress("glGetString");
-    if (!window->context.GetIntegerv || !window->context.GetString)
+    window->context.Flush = (PFNGLFLUSHPROC)
+        window->context.getProcAddress("glFlush");
+
+    if (!window->context.GetIntegerv ||
+        !window->context.GetString ||
+        !window->context.Flush)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
         glfwMakeContextCurrent((GLFWwindow*) previous);
@@ -615,13 +620,13 @@
 
 GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow *) handle;
-    _GLFWwindow* previous;
-
     _GLFW_REQUIRE_INIT();
 
-    previous = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFWwindow* previous;
 
+    previous = _glfwPlatformGetTls(&_glfw.contextSlot);
+
     if (window && window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
@@ -642,16 +647,16 @@
 GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
 {
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-    return (GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    return _glfwPlatformGetTls(&_glfw.contextSlot);
 }
 
 GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow *) handle;
-    assert(window != NULL);
-
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
@@ -668,7 +673,7 @@
 
     _GLFW_REQUIRE_INIT();
 
-    window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    window = _glfwPlatformGetTls(&_glfw.contextSlot);
     if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
@@ -686,7 +691,7 @@
 
     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
 
-    window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    window = _glfwPlatformGetTls(&_glfw.contextSlot);
     if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
@@ -752,7 +757,7 @@
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
-    window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
+    window = _glfwPlatformGetTls(&_glfw.contextSlot);
     if (!window)
     {
         _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
@@ -762,3 +767,4 @@
 
     return window->context.getProcAddress(procname);
 }
+
diff --git a/raylib/src/external/glfw/src/egl_context.c b/raylib/src/external/glfw/src/egl_context.c
--- a/raylib/src/external/glfw/src/egl_context.c
+++ b/raylib/src/external/glfw/src/egl_context.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 EGL - www.glfw.org
+// GLFW 3.5 EGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -92,7 +92,7 @@
     EGLConfig* nativeConfigs;
     _GLFWfbconfig* usableConfigs;
     const _GLFWfbconfig* closest;
-    int i, nativeCount, usableCount, apiBit;
+    int i, nativeCount, usableCount, apiBit, surfaceTypeBit;
     GLFWbool wrongApiAvailable = GLFW_FALSE;
 
     if (ctxconfig->client == GLFW_OPENGL_ES_API)
@@ -105,6 +105,11 @@
     else
         apiBit = EGL_OPENGL_BIT;
 
+    if (_glfw.egl.platform == EGL_PLATFORM_SURFACELESS_MESA)
+        surfaceTypeBit = EGL_PBUFFER_BIT;
+    else
+        surfaceTypeBit = EGL_WINDOW_BIT;
+
     if (fbconfig->stereo)
     {
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");
@@ -118,10 +123,10 @@
         return GLFW_FALSE;
     }
 
-    nativeConfigs = (EGLConfig *)_glfw_calloc(nativeCount, sizeof(EGLConfig));
+    nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig));
     eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
 
-    usableConfigs = (_GLFWfbconfig *)_glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
+    usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableCount = 0;
 
     for (i = 0;  i < nativeCount;  i++)
@@ -133,8 +138,7 @@
         if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
             continue;
 
-        // Only consider window EGLConfigs
-        if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
+        if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & surfaceTypeBit))
             continue;
 
 #if defined(_GLFW_X11)
@@ -250,6 +254,12 @@
                             getEGLErrorString(eglGetError()));
             return;
         }
+
+#if defined(_GLFW_WAYLAND)
+        // NOTE: Disable EGL vsync so we can substitute our own that includes a timeout
+        if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
+            eglSwapInterval(_glfw.egl.display, 0);
+#endif // _GLFW_WAYLAND
     }
     else
     {
@@ -283,6 +293,15 @@
         // NOTE: Swapping buffers on a hidden window on Wayland makes it visible
         if (!window->wl.visible)
             return;
+
+        // NOTE: We wait for a frame manually so we can add a timeout,
+        //       as the EGL implementation will wait indefinitely
+        if (window->wl.egl.interval > 0)
+        {
+            window->context.Flush();
+            if (!_glfwWaitForEGLFrameWayland(window))
+                return;
+        }
     }
 #endif
 
@@ -291,6 +310,16 @@
 
 static void swapIntervalEGL(int interval)
 {
+#if defined(_GLFW_WAYLAND)
+    if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
+    {
+        _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
+        assert(window != NULL);
+        window->wl.egl.interval = interval;
+        return;
+    }
+#endif
+
     eglSwapInterval(_glfw.egl.display, interval);
 }
 
@@ -308,18 +337,19 @@
 
 static GLFWglproc getProcAddressEGL(const char* procname)
 {
-    _GLFWwindow* window = (_GLFWwindow *)_glfwPlatformGetTls(&_glfw.contextSlot);
-    assert(window != NULL);
+    const GLFWglproc proc = (GLFWglproc) eglGetProcAddress(procname);
+    if (proc)
+        return proc;
 
-    if (window->context.egl.client)
+    if (!_glfw.egl.KHR_get_all_proc_addresses)
     {
-        GLFWglproc proc = (GLFWglproc)
-            _glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
-        if (proc)
-            return proc;
+        _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
+        assert(window != NULL);
+
+        return _glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
     }
 
-    return eglGetProcAddress(procname);
+    return NULL;
 }
 
 static void destroyContextEGL(_GLFWwindow* window)
@@ -329,11 +359,8 @@
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11 ||
         window->context.client != GLFW_OPENGL_API)
     {
-        if (window->context.egl.client)
-        {
-            _glfwPlatformFreeModule(window->context.egl.client);
-            window->context.egl.client = NULL;
-        }
+        _glfwPlatformFreeModule(window->context.egl.client);
+        window->context.egl.client = NULL;
     }
 
     if (window->context.egl.surface)
@@ -354,8 +381,6 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-// Initialize EGL
-//
 GLFWbool _glfwInitEGL(void)
 {
     int i;
@@ -365,10 +390,10 @@
     {
 #if defined(_GLFW_EGL_LIBRARY)
         _GLFW_EGL_LIBRARY,
-#elif defined(_GLFW_WIN32)
+#elif defined(_WIN32)
         "libEGL.dll",
         "EGL.dll",
-#elif defined(_GLFW_COCOA)
+#elif defined(__APPLE__)
         "libEGL.dylib",
 #elif defined(__CYGWIN__)
         "libEGL-1.so",
@@ -420,6 +445,8 @@
         _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext");
     _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
         _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface");
+    _glfw.egl.CreatePbufferSurface = (PFN_eglCreatePbufferSurface)
+        _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreatePbufferSurface");
     _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
         _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent");
     _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
@@ -442,6 +469,7 @@
         !_glfw.egl.DestroySurface ||
         !_glfw.egl.DestroyContext ||
         !_glfw.egl.CreateWindowSurface ||
+        !_glfw.egl.CreatePbufferSurface ||
         !_glfw.egl.MakeCurrent ||
         !_glfw.egl.SwapBuffers ||
         !_glfw.egl.SwapInterval ||
@@ -477,6 +505,8 @@
             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions);
         _glfw.egl.ANGLE_platform_angle_metal =
             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions);
+        _glfw.egl.MESA_platform_surfaceless =
+            _glfwStringInExtensionString("EGL_MESA_platform_surfaceless", extensions);
     }
 
     if (_glfw.egl.EXT_platform_base)
@@ -536,8 +566,6 @@
     return GLFW_TRUE;
 }
 
-// Terminate EGL
-//
 void _glfwTerminateEGL(void)
 {
     if (_glfw.egl.display)
@@ -546,7 +574,8 @@
         _glfw.egl.display = EGL_NO_DISPLAY;
     }
 
-    if (_glfw.egl.handle)
+    // Free modules only after all wayland termination functions are called
+    if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
     {
         _glfwPlatformFreeModule(_glfw.egl.handle);
         _glfw.egl.handle = NULL;
@@ -560,8 +589,6 @@
     attribs[index++] = v; \
 }
 
-// Create the OpenGL or OpenGL ES context
-//
 GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
                                const _GLFWctxconfig* ctxconfig,
                                const _GLFWfbconfig* fbconfig)
@@ -648,7 +675,7 @@
         if (ctxconfig->noerror)
         {
             if (_glfw.egl.KHR_create_context_no_error)
-                SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
+                SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true);
         }
 
         if (mask)
@@ -708,20 +735,36 @@
             SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
     }
 
+    if (_glfw.egl.platform == EGL_PLATFORM_SURFACELESS_MESA)
+    {
+        int width, height;
+        _glfw.platform.getFramebufferSize(window, &width, &height);
+
+        SET_ATTRIB(EGL_WIDTH, width);
+        SET_ATTRIB(EGL_HEIGHT, height);
+    }
+
     SET_ATTRIB(EGL_NONE, EGL_NONE);
 
     native = _glfw.platform.getEGLNativeWindow(window);
-    // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
-    //       despite reporting EGL_EXT_platform_base
-    if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
+    if (!_glfw.egl.platform || _glfw.egl.platform == EGL_PLATFORM_ANGLE_ANGLE)
     {
+        // HACK: Also use non-platform function for ANGLE, as it does not
+        //       implement eglCreatePlatformWindowSurfaceEXT despite reporting
+        //       support for EGL_EXT_platform_base
         window->context.egl.surface =
-            eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
+            eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
     }
+    else if (_glfw.egl.platform == EGL_PLATFORM_SURFACELESS_MESA)
+    {
+        // HACK: Use a pbuffer surface as the default framebuffer
+        window->context.egl.surface =
+            eglCreatePbufferSurface(_glfw.egl.display, config, attribs);
+    }
     else
     {
         window->context.egl.surface =
-            eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
+            eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
     }
 
     if (window->context.egl.surface == EGL_NO_SURFACE)
@@ -743,10 +786,10 @@
         {
 #if defined(_GLFW_GLESV1_LIBRARY)
             _GLFW_GLESV1_LIBRARY,
-#elif defined(_GLFW_WIN32)
+#elif defined(_WIN32)
             "GLESv1_CM.dll",
             "libGLES_CM.dll",
-#elif defined(_GLFW_COCOA)
+#elif defined(__APPLE__)
             "libGLESv1_CM.dylib",
 #elif defined(__OpenBSD__) || defined(__NetBSD__)
             "libGLESv1_CM.so",
@@ -760,10 +803,10 @@
         {
 #if defined(_GLFW_GLESV2_LIBRARY)
             _GLFW_GLESV2_LIBRARY,
-#elif defined(_GLFW_WIN32)
+#elif defined(_WIN32)
             "GLESv2.dll",
             "libGLESv2.dll",
-#elif defined(_GLFW_COCOA)
+#elif defined(__APPLE__)
             "libGLESv2.dylib",
 #elif defined(__CYGWIN__)
             "libGLESv2-2.so",
@@ -778,8 +821,8 @@
         {
 #if defined(_GLFW_OPENGL_LIBRARY)
             _GLFW_OPENGL_LIBRARY,
-#elif defined(_GLFW_WIN32)
-#elif defined(_GLFW_COCOA)
+#elif defined(_WIN32)
+#elif defined(__APPLE__)
 #elif defined(__OpenBSD__) || defined(__NetBSD__)
             "libGL.so",
 #else
@@ -883,13 +926,19 @@
 
 GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow *) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_EGL_CONTEXT_API)
     {
-        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
-        return EGL_NO_CONTEXT;
+        if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND ||
+            window->context.source != GLFW_NATIVE_CONTEXT_API)
+        {
+            _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+            return EGL_NO_CONTEXT;
+        }
     }
 
     return window->context.egl.handle;
@@ -897,14 +946,43 @@
 
 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow *) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_EGL_CONTEXT_API)
     {
-        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
-        return EGL_NO_SURFACE;
+        if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND ||
+            window->context.source != GLFW_NATIVE_CONTEXT_API)
+        {
+            _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+            return EGL_NO_SURFACE;
+        }
     }
 
     return window->context.egl.surface;
 }
+
+GLFWAPI int glfwGetEGLConfig(GLFWwindow* handle, EGLConfig* config)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(config != NULL);
+
+    if (window->context.source != GLFW_EGL_CONTEXT_API)
+    {
+        if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND ||
+            window->context.source != GLFW_NATIVE_CONTEXT_API)
+        {
+            _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+            return GLFW_FALSE;
+        }
+    }
+
+    *config = window->context.egl.config;
+    return GLFW_TRUE;
+}
+
diff --git a/raylib/src/external/glfw/src/glx_context.c b/raylib/src/external/glfw/src/glx_context.c
--- a/raylib/src/external/glfw/src/glx_context.c
+++ b/raylib/src/external/glfw/src/glx_context.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 GLX - www.glfw.org
+// GLFW 3.5 GLX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -119,9 +119,7 @@
         u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
 
         u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
-
-        if (getGLXFBConfigAttrib(n, GLX_STEREO))
-            u->stereo = GLFW_TRUE;
+        u->stereo = getGLXFBConfigAttrib(n, GLX_STEREO);
 
         if (_glfw.glx.ARB_multisample)
             u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
@@ -253,8 +251,6 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-// Initialize GLX
-//
 GLFWbool _glfwInitGLX(void)
 {
     const char* sonames[] =
@@ -369,7 +365,7 @@
             getProcAddressGLX("glXSwapIntervalEXT");
 
         if (_glfw.glx.SwapIntervalEXT)
-            _glfw.glx.EXT_swap_control = GLFW_TRUE;
+            _glfw.glx.EXT_swap_control = true;
     }
 
     if (extensionSupportedGLX("GLX_SGI_swap_control"))
@@ -378,7 +374,7 @@
             getProcAddressGLX("glXSwapIntervalSGI");
 
         if (_glfw.glx.SwapIntervalSGI)
-            _glfw.glx.SGI_swap_control = GLFW_TRUE;
+            _glfw.glx.SGI_swap_control = true;
     }
 
     if (extensionSupportedGLX("GLX_MESA_swap_control"))
@@ -387,17 +383,17 @@
             getProcAddressGLX("glXSwapIntervalMESA");
 
         if (_glfw.glx.SwapIntervalMESA)
-            _glfw.glx.MESA_swap_control = GLFW_TRUE;
+            _glfw.glx.MESA_swap_control = true;
     }
 
     if (extensionSupportedGLX("GLX_ARB_multisample"))
-        _glfw.glx.ARB_multisample = GLFW_TRUE;
+        _glfw.glx.ARB_multisample = true;
 
     if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
-        _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
+        _glfw.glx.ARB_framebuffer_sRGB = true;
 
     if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
-        _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
+        _glfw.glx.EXT_framebuffer_sRGB = true;
 
     if (extensionSupportedGLX("GLX_ARB_create_context"))
     {
@@ -405,39 +401,34 @@
             getProcAddressGLX("glXCreateContextAttribsARB");
 
         if (_glfw.glx.CreateContextAttribsARB)
-            _glfw.glx.ARB_create_context = GLFW_TRUE;
+            _glfw.glx.ARB_create_context = true;
     }
 
     if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
-        _glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
+        _glfw.glx.ARB_create_context_robustness = true;
 
     if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
-        _glfw.glx.ARB_create_context_profile = GLFW_TRUE;
+        _glfw.glx.ARB_create_context_profile = true;
 
     if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
-        _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
+        _glfw.glx.EXT_create_context_es2_profile = true;
 
     if (extensionSupportedGLX("GLX_ARB_create_context_no_error"))
-        _glfw.glx.ARB_create_context_no_error = GLFW_TRUE;
+        _glfw.glx.ARB_create_context_no_error = true;
 
     if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
-        _glfw.glx.ARB_context_flush_control = GLFW_TRUE;
+        _glfw.glx.ARB_context_flush_control = true;
 
     return GLFW_TRUE;
 }
 
-// Terminate GLX
-//
 void _glfwTerminateGLX(void)
 {
     // NOTE: This function must not call any X11 functions, as it is called
     //       after XCloseDisplay (see _glfwTerminateX11 for details)
 
-    if (_glfw.glx.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.glx.handle);
-        _glfw.glx.handle = NULL;
-    }
+    _glfwPlatformFreeModule(_glfw.glx.handle);
+    _glfw.glx.handle = NULL;
 }
 
 #define SET_ATTRIB(a, v) \
@@ -447,8 +438,6 @@
     attribs[index++] = v; \
 }
 
-// Create the OpenGL or OpenGL ES context
-//
 GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
                                const _GLFWctxconfig* ctxconfig,
                                const _GLFWfbconfig* fbconfig)
@@ -626,6 +615,8 @@
         return GLFW_FALSE;
     }
 
+    window->context.glx.fbconfig = native;
+
     window->context.makeCurrent = makeContextCurrentGLX;
     window->context.swapBuffers = swapBuffersGLX;
     window->context.swapInterval = swapIntervalGLX;
@@ -677,7 +668,6 @@
 
 GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
@@ -686,6 +676,9 @@
         return NULL;
     }
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_NATIVE_CONTEXT_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
@@ -697,7 +690,6 @@
 
 GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(None);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
@@ -706,6 +698,9 @@
         return None;
     }
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_NATIVE_CONTEXT_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
@@ -713,6 +708,30 @@
     }
 
     return window->context.glx.window;
+}
+
+GLFWAPI int glfwGetGLXFBConfig(GLFWwindow* handle, GLXFBConfig* config)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+
+    if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
+    {
+        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "GLX: Platform not initialized");
+        return GLFW_FALSE;
+    }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(config != NULL);
+
+    if (window->context.source != GLFW_NATIVE_CONTEXT_API)
+    {
+        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
+        return GLFW_FALSE;
+    }
+
+    *config = window->context.glx.fbconfig;
+    return GLFW_TRUE;
 }
 
 #endif // _GLFW_X11
diff --git a/raylib/src/external/glfw/src/init.c b/raylib/src/external/glfw/src/init.c
--- a/raylib/src/external/glfw/src/init.c
+++ b/raylib/src/external/glfw/src/init.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@@ -49,18 +49,18 @@
 static GLFWallocator _glfwInitAllocator;
 static _GLFWinitconfig _glfwInitHints =
 {
-    .hatButtons = GLFW_TRUE,
+    .hatButtons = true,
     .angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
     .platformID = GLFW_ANY_PLATFORM,
     .vulkanLoader = NULL,
     .ns =
     {
-        .menubar = GLFW_TRUE,
-        .chdir = GLFW_TRUE
+        .menubar = true,
+        .chdir = true
     },
     .x11 =
     {
-        .xcbVulkanSurface = GLFW_TRUE,
+        .xcbVulkanSurface = true,
     },
     .wl =
     {
diff --git a/raylib/src/external/glfw/src/input.c b/raylib/src/external/glfw/src/input.c
--- a/raylib/src/external/glfw/src/input.c
+++ b/raylib/src/external/glfw/src/input.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -333,10 +333,8 @@
 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
 {
     assert(window != NULL);
-    assert(xoffset > -FLT_MAX);
-    assert(xoffset < FLT_MAX);
-    assert(yoffset > -FLT_MAX);
-    assert(yoffset < FLT_MAX);
+    assert(isfinite(xoffset));
+    assert(isfinite(yoffset));
 
     if (window->callbacks.scroll)
         window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
@@ -348,20 +346,22 @@
 {
     assert(window != NULL);
     assert(button >= 0);
-    assert(button <= GLFW_MOUSE_BUTTON_LAST);
     assert(action == GLFW_PRESS || action == GLFW_RELEASE);
     assert(mods == (mods & GLFW_MOD_MASK));
 
-    if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
+    if (button < 0 || (!window->disableMouseButtonLimit && button > GLFW_MOUSE_BUTTON_LAST))
         return;
 
     if (!window->lockKeyMods)
         mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
 
-    if (action == GLFW_RELEASE && window->stickyMouseButtons)
-        window->mouseButtons[button] = _GLFW_STICK;
-    else
-        window->mouseButtons[button] = (char) action;
+    if (button <= GLFW_MOUSE_BUTTON_LAST)
+    {
+        if (action == GLFW_RELEASE && window->stickyMouseButtons)
+            window->mouseButtons[button] = _GLFW_STICK;
+        else
+            window->mouseButtons[button] = (char) action;
+    }
 
     if (window->callbacks.mouseButton)
         window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
@@ -373,10 +373,8 @@
 void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
 {
     assert(window != NULL);
-    assert(xpos > -FLT_MAX);
-    assert(xpos < FLT_MAX);
-    assert(ypos > -FLT_MAX);
-    assert(ypos < FLT_MAX);
+    assert(isfinite(xpos));
+    assert(isfinite(ypos));
 
     if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
         return;
@@ -434,6 +432,7 @@
     assert(js != NULL);
     assert(axis >= 0);
     assert(axis < js->axisCount);
+    assert(isfinite(value));
 
     js->axes[axis] = value;
 }
@@ -559,11 +558,11 @@
 
 GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(0);
-
     switch (mode)
     {
         case GLFW_CURSOR:
@@ -576,6 +575,8 @@
             return window->lockKeyMods;
         case GLFW_RAW_MOUSE_MOTION:
             return window->rawMouseMotion;
+        case GLFW_UNLIMITED_MOUSE_BUTTONS:
+            return window->disableMouseButtonLimit;
     }
 
     _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@@ -584,11 +585,11 @@
 
 GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     switch (mode)
     {
         case GLFW_CURSOR:
@@ -683,6 +684,12 @@
             _glfw.platform.setRawMouseMotion(window, value);
             return;
         }
+
+        case GLFW_UNLIMITED_MOUSE_BUTTONS:
+        {
+            window->disableMouseButtonLimit = value ? GLFW_TRUE : GLFW_FALSE;
+            return;
+        }
     }
 
     _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@@ -734,11 +741,11 @@
 
 GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
-
     if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
     {
         _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
@@ -757,11 +764,11 @@
 
 GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
-
     if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
     {
         _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
@@ -780,9 +787,6 @@
 
 GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (xpos)
         *xpos = 0;
     if (ypos)
@@ -790,6 +794,9 @@
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
         if (xpos)
@@ -803,13 +810,12 @@
 
 GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
-    if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
-        ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
+    if (!isfinite(xpos) || !isfinite(ypos))
     {
         _glfwInputError(GLFW_INVALID_VALUE,
                         "Invalid cursor position %f %f",
@@ -897,10 +903,10 @@
 
 GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
 {
-    _GLFWcursor* cursor = (_GLFWcursor*) handle;
-
     _GLFW_REQUIRE_INIT();
 
+    _GLFWcursor* cursor = (_GLFWcursor*) handle;
+
     if (cursor == NULL)
         return;
 
@@ -932,12 +938,12 @@
 
 GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) windowHandle;
     _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     window->cursor = cursor;
 
     _glfw.platform.setCursor(window, cursor);
@@ -945,30 +951,33 @@
 
 GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWkeyfun, window->callbacks.key, cbfun);
     return cbfun;
 }
 
 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWcharfun, window->callbacks.character, cbfun);
     return cbfun;
 }
 
 GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWcharmodsfun, window->callbacks.charmods, cbfun);
     return cbfun;
 }
@@ -976,10 +985,11 @@
 GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
                                                       GLFWmousebuttonfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWmousebuttonfun, window->callbacks.mouseButton, cbfun);
     return cbfun;
 }
@@ -987,10 +997,11 @@
 GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
                                                   GLFWcursorposfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWcursorposfun, window->callbacks.cursorPos, cbfun);
     return cbfun;
 }
@@ -998,10 +1009,11 @@
 GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
                                                       GLFWcursorenterfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWcursorenterfun, window->callbacks.cursorEnter, cbfun);
     return cbfun;
 }
@@ -1009,20 +1021,22 @@
 GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
                                             GLFWscrollfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWscrollfun, window->callbacks.scroll, cbfun);
     return cbfun;
 }
 
 GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWdropfun, window->callbacks.drop, cbfun);
     return cbfun;
 }
@@ -1481,7 +1495,7 @@
 {
     _GLFW_REQUIRE_INIT();
 
-    if (time != time || time < 0.0 || time > 18446744073.0)
+    if (!isfinite(time) || time < 0.0 || time > 18446744073.0)
     {
         _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
         return;
diff --git a/raylib/src/external/glfw/src/internal.h b/raylib/src/external/glfw/src/internal.h
--- a/raylib/src/external/glfw/src/internal.h
+++ b/raylib/src/external/glfw/src/internal.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -48,6 +48,8 @@
 #define GLFW_INCLUDE_NONE
 #include "../include/GLFW/glfw3.h"
 
+#include <stdbool.h>
+
 #define _GLFW_INSERT_FIRST      0
 #define _GLFW_INSERT_LAST       1
 
@@ -107,6 +109,7 @@
 typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
 typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
 typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
+typedef void (APIENTRY * PFNGLFLUSHPROC)(void);
 
 #define EGL_SUCCESS 0x3000
 #define EGL_NOT_INITIALIZED 0x3001
@@ -150,6 +153,9 @@
 #define EGL_NO_DISPLAY ((EGLDisplay) 0)
 #define EGL_NO_CONTEXT ((EGLContext) 0)
 #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_WIDTH 0x3057
+#define EGL_HEIGHT 0x3056
 
 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
@@ -181,6 +187,7 @@
 #define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
 #define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
 #define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348f
+#define EGL_PLATFORM_SURFACELESS_MESA 0x31dd
 
 typedef int EGLint;
 typedef unsigned int EGLBoolean;
@@ -205,6 +212,7 @@
 typedef EGLBoolean (APIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface);
 typedef EGLBoolean (APIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext);
 typedef EGLSurface (APIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*);
+typedef EGLSurface (APIENTRY * PFN_eglCreatePbufferSurface)(EGLDisplay,EGLContext,const EGLint*);
 typedef EGLBoolean (APIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext);
 typedef EGLBoolean (APIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface);
 typedef EGLBoolean (APIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint);
@@ -221,6 +229,7 @@
 #define eglDestroySurface _glfw.egl.DestroySurface
 #define eglDestroyContext _glfw.egl.DestroyContext
 #define eglCreateWindowSurface _glfw.egl.CreateWindowSurface
+#define eglCreatePbufferSurface _glfw.egl.CreatePbufferSurface
 #define eglMakeCurrent _glfw.egl.MakeCurrent
 #define eglSwapBuffers _glfw.egl.SwapBuffers
 #define eglSwapInterval _glfw.egl.SwapInterval
@@ -277,6 +286,7 @@
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
     VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
     VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
+    VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000,
     VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkStructureType;
 
@@ -365,16 +375,16 @@
 //
 struct _GLFWinitconfig
 {
-    GLFWbool      hatButtons;
+    bool          hatButtons;
     int           angleType;
     int           platformID;
     PFN_vkGetInstanceProcAddr vulkanLoader;
     struct {
-        GLFWbool  menubar;
-        GLFWbool  chdir;
+        bool      menubar;
+        bool      chdir;
     } ns;
     struct {
-        GLFWbool  xcbVulkanSurface;
+        bool      xcbVulkanSurface;
     } x11;
     struct {
         int       libdecorMode;
@@ -393,19 +403,18 @@
     int           ypos;
     int           width;
     int           height;
-    const char*   title;
-    GLFWbool      resizable;
-    GLFWbool      visible;
-    GLFWbool      decorated;
-    GLFWbool      focused;
-    GLFWbool      autoIconify;
-    GLFWbool      floating;
-    GLFWbool      maximized;
-    GLFWbool      centerCursor;
-    GLFWbool      focusOnShow;
-    GLFWbool      mousePassthrough;
-    GLFWbool      scaleToMonitor;
-    GLFWbool      scaleFramebuffer;
+    bool          resizable;
+    bool          visible;
+    bool          decorated;
+    bool          focused;
+    bool          autoIconify;
+    bool          floating;
+    bool          maximized;
+    bool          centerCursor;
+    bool          focusOnShow;
+    bool          mousePassthrough;
+    bool          scaleToMonitor;
+    bool          scaleFramebuffer;
     struct {
         char      frameName[256];
     } ns;
@@ -414,8 +423,8 @@
         char      instanceName[256];
     } x11;
     struct {
-        GLFWbool  keymenu;
-        GLFWbool  showDefault;
+        bool      keymenu;
+        bool      showDefault;
     } win32;
     struct {
         char      appId[256];
@@ -434,15 +443,15 @@
     int           source;
     int           major;
     int           minor;
-    GLFWbool      forward;
-    GLFWbool      debug;
-    GLFWbool      noerror;
+    bool          forward;
+    bool          debug;
+    bool          noerror;
     int           profile;
     int           robustness;
     int           release;
     _GLFWwindow*  share;
     struct {
-        GLFWbool  offline;
+        bool      offline;
     } nsgl;
 };
 
@@ -467,11 +476,11 @@
     int         accumBlueBits;
     int         accumAlphaBits;
     int         auxBuffers;
-    GLFWbool    stereo;
+    bool        stereo;
     int         samples;
-    GLFWbool    sRGB;
-    GLFWbool    doublebuffer;
-    GLFWbool    transparent;
+    bool        sRGB;
+    bool        doublebuffer;
+    bool        transparent;
     uintptr_t   handle;
 };
 
@@ -490,6 +499,7 @@
     PFNGLGETSTRINGIPROC  GetStringi;
     PFNGLGETINTEGERVPROC GetIntegerv;
     PFNGLGETSTRINGPROC   GetString;
+    PFNGLFLUSHPROC       Flush;
 
     void (*makeCurrent)(_GLFWwindow*);
     void (*swapBuffers)(_GLFWwindow*);
@@ -544,6 +554,7 @@
     GLFWbool            stickyKeys;
     GLFWbool            stickyMouseButtons;
     GLFWbool            lockKeyMods;
+    GLFWbool            disableMouseButtonLimit;
     int                 cursorMode;
     char                mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
     char                keys[GLFW_KEY_LAST + 1];
@@ -796,21 +807,22 @@
         EGLint          major, minor;
         GLFWbool        prefix;
 
-        GLFWbool        KHR_create_context;
-        GLFWbool        KHR_create_context_no_error;
-        GLFWbool        KHR_gl_colorspace;
-        GLFWbool        KHR_get_all_proc_addresses;
-        GLFWbool        KHR_context_flush_control;
-        GLFWbool        EXT_client_extensions;
-        GLFWbool        EXT_platform_base;
-        GLFWbool        EXT_platform_x11;
-        GLFWbool        EXT_platform_wayland;
-        GLFWbool        EXT_present_opaque;
-        GLFWbool        ANGLE_platform_angle;
-        GLFWbool        ANGLE_platform_angle_opengl;
-        GLFWbool        ANGLE_platform_angle_d3d;
-        GLFWbool        ANGLE_platform_angle_vulkan;
-        GLFWbool        ANGLE_platform_angle_metal;
+        bool            KHR_create_context;
+        bool            KHR_create_context_no_error;
+        bool            KHR_gl_colorspace;
+        bool            KHR_get_all_proc_addresses;
+        bool            KHR_context_flush_control;
+        bool            EXT_client_extensions;
+        bool            EXT_platform_base;
+        bool            EXT_platform_x11;
+        bool            EXT_platform_wayland;
+        bool            EXT_present_opaque;
+        bool            ANGLE_platform_angle;
+        bool            ANGLE_platform_angle_opengl;
+        bool            ANGLE_platform_angle_d3d;
+        bool            ANGLE_platform_angle_vulkan;
+        bool            ANGLE_platform_angle_metal;
+        bool            MESA_platform_surfaceless;
 
         void*           handle;
 
@@ -825,6 +837,7 @@
         PFN_eglDestroySurface       DestroySurface;
         PFN_eglDestroyContext       DestroyContext;
         PFN_eglCreateWindowSurface  CreateWindowSurface;
+        PFN_eglCreatePbufferSurface CreatePbufferSurface;
         PFN_eglMakeCurrent          MakeCurrent;
         PFN_eglSwapBuffers          SwapBuffers;
         PFN_eglSwapInterval         SwapInterval;
@@ -853,13 +866,14 @@
         void*           handle;
         char*           extensions[2];
         PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
-        GLFWbool        KHR_surface;
-        GLFWbool        KHR_win32_surface;
-        GLFWbool        MVK_macos_surface;
-        GLFWbool        EXT_metal_surface;
-        GLFWbool        KHR_xlib_surface;
-        GLFWbool        KHR_xcb_surface;
-        GLFWbool        KHR_wayland_surface;
+        bool            KHR_surface;
+        bool            KHR_win32_surface;
+        bool            MVK_macos_surface;
+        bool            EXT_metal_surface;
+        bool            KHR_xlib_surface;
+        bool            KHR_xcb_surface;
+        bool            KHR_wayland_surface;
+        bool            EXT_headless_surface;
     } vk;
 
     struct {
diff --git a/raylib/src/external/glfw/src/linux_joystick.c b/raylib/src/external/glfw/src/linux_joystick.c
--- a/raylib/src/external/glfw/src/linux_joystick.c
+++ b/raylib/src/external/glfw/src/linux_joystick.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Linux - www.glfw.org
+// GLFW 3.5 Linux - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/inotify.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <dirent.h>
diff --git a/raylib/src/external/glfw/src/linux_joystick.h b/raylib/src/external/glfw/src/linux_joystick.h
--- a/raylib/src/external/glfw/src/linux_joystick.h
+++ b/raylib/src/external/glfw/src/linux_joystick.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Linux - www.glfw.org
+// GLFW 3.5 Linux - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
diff --git a/raylib/src/external/glfw/src/macos_time.c b/raylib/src/external/glfw/src/macos_time.c
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/glfw/src/macos_time.c
@@ -0,0 +1,57 @@
+//========================================================================
+// GLFW 3.5 macOS - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
+//
+// 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.
+//
+//========================================================================
+
+#include "internal.h"
+
+#if defined(GLFW_BUILD_MACOS_TIMER)
+
+#include <mach/mach_time.h>
+
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
+void _glfwPlatformInitTimer(void)
+{
+    mach_timebase_info_data_t info;
+    mach_timebase_info(&info);
+
+    _glfw.timer.macos.frequency = (info.denom * 1e9) / info.numer;
+}
+
+uint64_t _glfwPlatformGetTimerValue(void)
+{
+    return mach_absolute_time();
+}
+
+uint64_t _glfwPlatformGetTimerFrequency(void)
+{
+    return _glfw.timer.macos.frequency;
+}
+
+#endif // GLFW_BUILD_MACOS_TIMER
+
diff --git a/raylib/src/external/glfw/src/macos_time.h b/raylib/src/external/glfw/src/macos_time.h
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/glfw/src/macos_time.h
@@ -0,0 +1,35 @@
+//========================================================================
+// GLFW 3.5 macOS - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2009-2021 Camilla Löwy <elmindreda@glfw.org>
+//
+// 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 GLFW_MACOS_LIBRARY_TIMER_STATE _GLFWtimerMacOS macos;
+
+// macOS-specific global timer data
+//
+typedef struct _GLFWtimerMacOS
+{
+    uint64_t        frequency;
+} _GLFWtimerMacOS;
+
diff --git a/raylib/src/external/glfw/src/mappings.h b/raylib/src/external/glfw/src/mappings.h
--- a/raylib/src/external/glfw/src/mappings.h
+++ b/raylib/src/external/glfw/src/mappings.h
@@ -1,1909 +1,1001 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
-//
-// 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.
-//
-//========================================================================
-// As mappings.h.in, this file is used by CMake to produce the mappings.h
-// header file.  If you are adding a GLFW specific gamepad mapping, this is
-// where to put it.
-//========================================================================
-// As mappings.h, this provides all pre-defined gamepad mappings, including
-// all available in SDL_GameControllerDB.  Do not edit this file.  Any gamepad
-// mappings not specific to GLFW should be submitted to SDL_GameControllerDB.
-// This file can be re-generated from mappings.h.in and the upstream
-// gamecontrollerdb.txt with the 'update_mappings' CMake target.
-//========================================================================
-
-// All gamepad mappings not labeled GLFW are copied from the
-// SDL_GameControllerDB project under the following license:
-//
-// Simple DirectMedia Layer
-// Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
-//
-// 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.
-
-const char* _glfwDefaultMappings[] =
-{
-#if defined(_GLFW_WIN32)
-"03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000fa190000918d000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
-"03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,",
-"03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,",
-"03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,",
-"03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,",
-"03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,",
-"03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,",
-"03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows,",
-"03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,",
-"03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows,",
-"03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,",
-"03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,",
-"03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows,",
-"03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows,",
-"03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001b30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001d30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
-"03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
-"030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows,",
-"030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,",
-"0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000020500000913000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000373500000710000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000373500004610000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000190e00000110000000000000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Windows,",
-"03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,",
-"03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows,",
-"03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000380800001889000000000000,AtGames Legends Gamer Pro,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b14,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,",
-"030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,",
-"030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,",
-"030000008a3500000402000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,",
-"03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",
-"030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows,",
-"030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000790000000700000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000808300000300000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,",
-"030000005a1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,",
-"030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,",
-"030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,",
-"030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,",
-"030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,",
-"030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows,",
-"030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows,",
-"030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows,",
-"030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,",
-"03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
-"03000095090000010000000000000000,Elecom JC-U609,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,",
-"0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,",
-"03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,platform:Windows,",
-"030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
-"03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
-"030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
-"030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
-"030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
-"030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",
-"030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
-"030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000062000001801000000000000,EMS TrioLinker Plus II,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Windows,",
-"03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
-"0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,",
-"03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows,",
-"03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,",
-"03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,",
-"03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,",
-"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,",
-"03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,",
-"0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",
-"03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows,",
-"03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows,",
-"03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000ac0500001a06000000000000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000373500009410000000000000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,",
-"030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000c9110000f055000000000000,GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",
-"030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,",
-"030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000008a2e0000dd10000000000000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Windows,",
-"030000008a2e0000df10000000000000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Windows,",
-"030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,",
-"030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00008800000000000000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
-"030000000d0f00008700000000000000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,",
-"030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows,",
-"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows,",
-"030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,",
-"030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000000d0f00000202000000000000,Horipad O Nintendo Switch 2 Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
-"030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,",
-"03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,",
-"03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,",
-"03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows,",
-"03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,",
-"03000000f00300008d04000000000000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:-a2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:+a5,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,",
-"03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows,",
-"03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,platform:Windows,",
-"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",
-"03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,",
-"03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,",
-"03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,",
-"03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,",
-"03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,",
-"03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,",
-"03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,",
-"030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,",
-"030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows,",
-"03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
-"03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,",
-"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,",
-"030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,",
-"030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,",
-"03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",
-"030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,",
-"030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
-"0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000242f0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,",
-"03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,",
-"03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,",
-"030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows,",
-"030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows,",
-"030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,",
-"030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,",
-"030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows,",
-"03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows,",
-"03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,",
-"03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,",
-"030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows,",
-"0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,",
-"03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,",
-"03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,",
-"03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows,",
-"03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
-"030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows,",
-"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,",
-"030000007e0500007320000000000000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Windows,",
-"030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows,",
-"030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,",
-"03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,",
-"030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000004b120000014d000000000000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,",
-"030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
-"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,",
-"03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,",
-"03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d62000003340000000000000,PowerA OPS Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000d62000002640000000000000,PowerA OPS Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
-"030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,",
-"030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
-"030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows,",
-"03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,",
-"03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
-"03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,",
-"03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows,",
-"03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,",
-"030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,",
-"030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,",
-"030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,",
-"030000009b280000d000000000000000,Raphnet Dreamcast Adapter,a:b1,b:b0,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,lefttrigger:+a5,leftx:a0,lefty:a1,righttrigger:+a2,start:b3,x:b5,y:b4,platform:Windows,",
-"030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,",
-"030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,",
-"030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,",
-"030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,",
-"030000009b2800003c00000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,",
-"030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,",
-"030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,",
-"030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,",
-"030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,",
-"030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,",
-"030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,",
-"030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,",
-"030000009b2800002600000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800002e00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800002f00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,",
-"030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,",
-"030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,",
-"03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"0300000032150000a602000000000000,Razer Huntsman V3 Pro,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows,",
-"03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,",
-"03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,",
-"03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,",
-"03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows,",
-"0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
-"0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
-"03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,",
-"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,platform:Windows,",
-"03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,",
-"030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows,",
-"030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows,",
-"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,",
-"03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,",
-"03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
-"03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
-"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows,",
-"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,",
-"03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,",
-"03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows,",
-"03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,",
-"03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,",
-"03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,",
-"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,",
-"0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
-"0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,",
-"03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,",
-"03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,",
-"030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,",
-"03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,",
-"03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,",
-"030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,",
-"03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,",
-"030000008f0e00000910000000000000,Sony DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000fe1400002a23000000000000,Sony PlayStation Adapter,a:b0,b:b1,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,x:b2,y:b3,platform:Windows,",
-"030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000d9040000160f000000000000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"030000004c0500003713000000000000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,",
-"030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,",
-"030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows,",
-"03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,",
-"030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,",
-"03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,",
-"03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows,",
-"03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,",
-"03000000790000001c18000000000000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000790000002601000000000000,TGZ Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,",
-"030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f0400000ed0000000000000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f04000008d0000000000000,Thrustmaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,",
-"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
-"030000004f04000003d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000004f04000009d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows,",
-"03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,",
-"03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,",
-"03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows,",
-"03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
-"030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
-"03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows,",
-"03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,",
-"0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,",
-"03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
-"0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,platform:Windows,",
-"03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000a102000000000000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows,",
-"03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,",
-"030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
-"03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
-"030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
-"03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows,",
-"03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,",
-"030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,",
-"030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows,",
-"03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
-"03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,",
-"03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
-"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
-#endif // _GLFW_WIN32
-
-#if defined(_GLFW_COCOA)
-"030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,",
-"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Mac OS X,",
-"03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,",
-"03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,",
-"03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,",
-"03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00002690000000010000,8BitDo NEOGEO,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00003028000000010000,8Bitdo SFC30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001d30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001330000000020000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,",
-"0300000008100000e501000019040000,Anbernic Handheld,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"03000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,",
-"03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,",
-"03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,",
-"03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,",
-"03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,",
-"030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,",
-"030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,",
-"03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,",
-"03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X,",
-"030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Mac OS X,",
-"03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,",
-"03000000ac0500001a06000002020000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000373500000411000023000000,GameSir X4A Xbox Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X,",
-"03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,",
-"030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00008800000000010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00008700000000010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,",
-"030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X,",
-"03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X,",
-"03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
-"03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,",
-"03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X,",
-"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,",
-"03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,",
-"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,",
-"0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X,",
-"0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,",
-"03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,",
-"03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
-"03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
-"030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X,",
-"030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X,",
-"030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X,",
-"030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,",
-"030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,",
-"03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000853200008906000000010000,Nacon Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,",
-"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000007e0500006920000001010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Mac OS X,",
-"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,",
-"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,",
-"030000007e0500007320000001010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Mac OS X,",
-"030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,",
-"030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,",
-"030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
-"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
-"030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
-"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"03000000222c00000225000000010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X,",
-"030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X,",
-"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000632500002305000000010000,Redragon Saturn,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X,",
-"03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X,",
-"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X,",
-"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X,",
-"030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X,",
-"03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,",
-"03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,",
-"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,",
-"03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,",
-"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
-"0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,",
-"030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,",
-"030000004c050000da0c000000010000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"030000004c0500003713000000010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
-"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
-"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
-"05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,",
-"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,",
-"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
-"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
-"030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
-"03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,",
-"03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,",
-"03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,",
-"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,",
-"030000004f0400000ed0000000020000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,",
-"03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X,",
-"03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
-"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,",
-"03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X,",
-"030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,",
-"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,",
-"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,",
-"030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4~,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,",
-"03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
-"030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
-"03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-"03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
-#endif // _GLFW_COCOA
-
-#if defined(GLFW_BUILD_LINUX_JOYSTICK)
-"03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,",
-"03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Linux,",
-"03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000a20000000020000,8BitDo M30 Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,",
-"03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00006928000011010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,",
-"05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,",
-"05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000060000011010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,",
-"030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000a31000014010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00000631000014010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
-"05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
-"05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
-"0300000008100000e501000001010000,Anbernic Handheld,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux,",
-"03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
-"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
-"03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,",
-"03000000503200000110000011010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,",
-"05000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,",
-"05000000503200000110000044010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,",
-"05000000503200000110000046010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,",
-"03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,",
-"03000000503200000210000011010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"05000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"05000000503200000210000045010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"05000000503200000210000046010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,",
-"030000008a3500000201000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000008a3500000202000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d81d00000b00000010010000,Buffalo BSGP1601,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Linux,",
-"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,",
-"030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,",
-"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
-"030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
-"030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,",
-"030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
-"03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
-"19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000373500009410000010010000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000f0250000c283000010010000,Gioteck VX2 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux,",
-"190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux,",
-"190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,platform:Linux,",
-"03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000001010000,GPD Win Max 2 6800U Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,",
-"030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux,",
-"030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux,",
-"06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,",
-"03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000000d0f00005001000009040000,Hori Fighting Commander Octa Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux,",
-"030000000d0f00008800000011010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00008700000011010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,",
-"030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,",
-"030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,",
-"030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f0000ab01000011010000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000000d0f00009601000091000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
-"05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,",
-"03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux,",
-"03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux,",
-"03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
-"030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,",
-"050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,",
-"03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",
-"03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",
-"03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Linux,",
-"03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
-"0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000300f00001101000010010000,Jess Tech Colour Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,",
-"050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,",
-"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,",
-"050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,",
-"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",
-"030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,",
-"05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000120c00000500000000010000,Manta DualShock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,",
-"0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,",
-"0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,",
-"030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,",
-"030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,",
-"030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
-"030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux,",
-"030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
-"030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
-"030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000017050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
-"03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
-"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
-"05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
-"03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
-"030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux,",
-"030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000853200000503000000010000,Nacon MG-X Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,",
-"060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
-"030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,",
-"03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,",
-"030000007e0500006920000011010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Linux,",
-"060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
-"060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
-"060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
-"050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,",
-"030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux,",
-"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
-"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
-"050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,",
-"05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
-"050000005a1d00000218000003000000,Nokia GC 5000,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,",
-"030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux,",
-"030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux,",
-"050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,",
-"050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux,",
-"030000007e0500001e20000011810000,NSO Sega Genesis Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,platform:Linux,",
-"030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
-"050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,",
-"050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,",
-"05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,",
-"030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,",
-"19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,",
-"05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
-"05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
-"05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux,",
-"03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,",
-"03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
-"03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,",
-"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
-"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000004c050000f20d000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"050000004c050000f20d000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,",
-"03000000222c00000225000011010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000222c00000025000011010000,Qanba Dragon Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick PS5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
-"030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,",
-"0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
-"0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
-"030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
-"030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
-"030000009b2800006100000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux,",
-"030000009b2800006400000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux,",
-"030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,",
-"030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,",
-"03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
-"030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,",
-"03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,",
-"0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
-"190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,",
-"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
-"00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux,",
-"03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux,",
-"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Linux,",
-"03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,",
-"03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,",
-"03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,",
-"03000000a30600000d5f000010010000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
-"03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,",
-"03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
-"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
-"03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
-"03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
-"05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,",
-"03000000952e00004b43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000952e00004d43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,",
-"03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,",
-"03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,",
-"03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"03000000666600006706000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,",
-"030000004c050000da0c000011010000,Sony PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000d9040000160f000000010000,Sony PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,",
-"030000004c0500003713000011010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
-"030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",
-"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",
-"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",
-"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,",
-"03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,",
-"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,",
-"03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,",
-"030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
-"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
-"030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,",
-"03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,",
-"03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,",
-"03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,",
-"030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
-"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
-"030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
-"030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,",
-"030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,",
-"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,",
-"030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
-"030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
-"03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
-"030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,",
-"03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,",
-"03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,",
-"03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,",
-"030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
-"06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
-"03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",
-"03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,",
-"05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
-"05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
-"030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
-"030000005e0400008e02000072050000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
-"030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
-"030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000dd02000003020000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000ea02000017050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"060000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000200b000023050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
-"05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,",
-"03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
-"030000005e0400008e02000020010000,XInput Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
-"03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
-"03000000120c0000182e000011010000,Zeroplus PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+// GLFW 3.5 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
+//
+// 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.
+//
+//========================================================================
+// As mappings.h.in, this file is used by CMake to produce the mappings.h
+// header file.  If you are adding a GLFW specific gamepad mapping, this is
+// where to put it.
+//========================================================================
+// As mappings.h, this provides all pre-defined gamepad mappings, including
+// all available in SDL_GameControllerDB.  Do not edit this file.  Any gamepad
+// mappings not specific to GLFW should be submitted to SDL_GameControllerDB.
+// This file can be re-generated from mappings.h.in and the upstream
+// gamecontrollerdb.txt with the 'update_mappings' CMake target.
+//========================================================================
+
+// All gamepad mappings not labeled GLFW are copied from the
+// SDL_GameControllerDB project under the following license:
+//
+// Simple DirectMedia Layer
+// Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+//
+// 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.
+
+const char* _glfwDefaultMappings[] =
+{
+#if defined(_GLFW_WIN32)
+"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
+"03000000c82d00002038000000000000,8bitdo,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,",
+"03000000c82d000011ab000000000000,8BitDo F30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000151000000000000,8BitDo M30 ModKit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,",
+"03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00003028000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,",
+"03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"030000006f0e00001413000000000000,Afterglow,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d62000001d57000000000000,Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,",
+"03000000ef0500000300000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",
+"03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",
+"030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bc2000006321000000000000,BETOP CONTROLLER,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
+"03000000120c0000210e000000000000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,",
+"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"030000005e040000a102000000000000,Controller (Xbox 360 Wireless Receiver for Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"030000005e040000ff02000000000000,Controller (Xbox One For Windows) - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"030000005e040000ea02000000000000,Controller (Xbox One For Windows) - Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,",
+"03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,",
+"030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,",
+"030000006f0e00003001000000000000,EA SPORTS PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
+"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
+"03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
+"03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
+"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,",
+"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,",
+"030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,",
+"030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000f0250000c283000000000000,Gioteck,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000f0250000c383000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000f0250000c483000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"030000007d0400000540000000000000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000001008000001e1000000000000,Havit HV-G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000632500002605000000000000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00001600000000007803,HORI Real Arcade Pro EX-SE (Xbox 360),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
+"030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,",
+"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,",
+"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
+"030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000ac0500002c02000000000000,IPEGA,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000491900000304000000000000,Ipega PG-9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,",
+"030000006e0500000a20000000000000,JC-DUX60 ELECOM MMO Gamepad,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,",
+"030000006e0500000520000000000000,JC-P301U,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
+"030000006e0500000320000000000000,JC-U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,",
+"030000006e0500000720000000000000,JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,",
+"030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,",
+"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,",
+"030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
+"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000bd12000003c0000000000000,JY-P70UR,a:b1,b:b0,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b4,x:b3,y:b2,platform:Windows,",
+"03000000242f00002d00000000000000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000242f00008a00000000000000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
+"03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,",
+"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,",
+"03000000380700006652000000000000,Mad Catz C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008433000000000000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008483000000000000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700006252000000000000,Mad Catz Micro C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",
+"030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
+"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,",
+"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
+"0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,",
+"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
+"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,",
+"03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c62400002b89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c62400001a89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000c62400001b89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
+"030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000921200004b46000000000000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,",
+"03000000790000004518000000000000,NEXILUX GAMECUBE Controller Adapter,platform:Windows,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,",
+"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,",
+"03000000550900001472000000000000,NVIDIA Controller v01.04,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,",
+"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000d620000013a7000000000000,NSW wired controller,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
+"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,",
+"03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,",
+"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
+"03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
+"03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,",
+"030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
+"030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,",
+"03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
+"030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000003807000056a8000000000000,PS3 RF pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000ff000000cb01000000000000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,",
+"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
+"03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,",
+"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000bd12000013d0000000000000,Retrolink USB SEGA Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,",
+"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
+"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
+"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
+"03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,",
+"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,",
+"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
+"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
+"03000000a30600002106000000000000,Saitek PS1000,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000a306000020f6000000000000,Saitek PS2700,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
+"03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,",
+"0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,",
+"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000008f0e00000800000000000000,SpeedLink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000790000001c18000000000000,STK-7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,",
+"03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000457500002211000000000000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,",
+"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
+"030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
+"030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,",
+"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
+"03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
+"03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,",
+"03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"030000006e0500001320000000000000,U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000300f00000701000000000000,USB 4-Axis 12-Button Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000341a00002308000000000000,USB gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"030000005509000000b4000000000000,USB gamepad,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows,",
+"030000006b1400000203000000000000,USB gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000790000000a00000000000000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000f0250000c183000000000000,USB gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000ff1100004133000000000000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+"03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
+"0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,",
+"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+"03000000ac0500005b05000000000000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
+"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
+"03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
+"03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
+#endif // _GLFW_WIN32
+
+#if defined(_GLFW_COCOA)
+"030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00004028000000010000,8Bitdo SN30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Mac OS X,",
+"03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"03000000ef0500000300000000020000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,",
+"03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,",
+"03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,",
+"03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000120c0000200e000000010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000120c0000210e000000010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,",
+"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000280400000140000000020000,Gravis Gamepad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000008f0e00000300000007010000,GreenAsia Inc. USB Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,",
+"030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000000d0f0000ee00000000010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,",
+"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
+"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
+"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"03000000242f00002d00000007010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000006d04000018c2000000010000,Logitech RumblePad 2 USB,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,",
+"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,",
+"0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,",
+"03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
+"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
+"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,",
+"03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,",
+"03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,",
+"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000d620000011a7000010050000,Nintendo Switch PowerA Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
+"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,",
+"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"030000004c050000da0c000000010000,Playstation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
+"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
+"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,",
+"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,",
+"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,",
+"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
+"0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,",
+"030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,",
+"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
+"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
+"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,",
+"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
+"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
+"03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,",
+"030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,",
+"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,",
+"030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
+"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,",
+"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,",
+"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000006f0e00000104000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000c62400003a54000000000000,Xbox One PowerA Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
+"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
+"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+"03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
+#endif // _GLFW_COCOA
+
+#if defined(GLFW_BUILD_LINUX_JOYSTICK)
+"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00000061000000010000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
+"030000003512000012ab000010010000,8Bitdo SFC30 GamePad,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,",
+"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
+"03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
+"05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
+"050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
+"05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
+"03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
+"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
+"03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,",
+"05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,",
+"03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
+"05000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,",
+"03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",
+"03000000ef0500000300000000010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,",
+"03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,",
+"03000000120c0000200e000011010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000120c0000210e000011010000,Brook Mars,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
+"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,",
+"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
+"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
+"030000004f04000004b3000010010000,Dual Power 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
+"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,",
+"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
+"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,",
+"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000632500002605000010010000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,",
+"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00008500000010010000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000000d0f0000d800000072056800,HORI Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
+"030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,",
+"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f0000ee00000011010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
+"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
+"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,",
+"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,",
+"0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000632500007505000011010000,Ipega PG-9099 - Bluetooth Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
+"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
+"03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
+"030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,",
+"050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,",
+"030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,",
+"050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,",
+"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d0400001ec2000019200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,",
+"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",
+"050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700008433000011010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700008483000011010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000242f0000f700000001010000,Magic-S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,",
+"0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
+"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
+"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"050000005e040000050b000003090000,Microsoft X-Box One Elite 2 pad,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e040000e302000003020000,Microsoft X-Box One Elite pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000dd02000003020000,Microsoft X-Box One pad (Firmware 2015),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
+"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
+"030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000ea02000008040000,Microsoft Xbox One S pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c62400001a53000000010000,Mini PE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
+"05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
+"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
+"05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
+"03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000c62400001a89000000010000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
+"030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000790000004518000010010000,NEXILUX GAMECUBE Controller Adapter,a:b1,b:b0,x:b2,y:b3,start:b9,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,platform:Linux,",
+"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,",
+"060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
+"060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
+"030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,",
+"03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,",
+"050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,back:b5,leftshoulder:b2,leftstick:b6,leftx:a1,lefty:a0~,rightshoulder:b4,start:b0,x:b7,y:b10,platform:Linux,",
+"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
+"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,",
+"050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0~,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,",
+"050000007e0500001720000001000000,Nintendo Switch SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,",
+"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
+"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,",
+"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,",
+"05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,",
+"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,",
+"19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,",
+"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
+"03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,",
+"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
+"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
+"03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,",
+"03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e0000b802000013020000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000491900000204000000000000,PG-9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000d62000000228000001010000,PowerA Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c62400001a54000001010000,PowerA Xbox One Mini Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
+"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000ff000000cb01000010010000,PSP,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,",
+"030000009b2800004200000001010000,Raphnet Technologies Dual NES to USB v2.0,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,",
+"030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
+"030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,",
+"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
+"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,",
+"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
+"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,",
+"03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,",
+"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,",
+"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,",
+"03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
+"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
+"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
+"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,",
+"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000bc2000000055000010010000,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005f140000c501000010010000,SHANWAN Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000004c050000e60c000011810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"050000004c050000e60c000000810000,Sony DualSense ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
+"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
+"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",
+"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,",
+"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,",
+"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
+"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
+"03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
+"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
+"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,",
+"030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,",
+"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,",
+"030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
+"030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
+"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
+"030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
+"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",
+"030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
+"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
+"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
+"030000005e040000120b000005050000,XBox Series pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
+"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
+"03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
+"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,",
+"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
+"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
 #endif // GLFW_BUILD_LINUX_JOYSTICK
 };
 
diff --git a/raylib/src/external/glfw/src/monitor.c b/raylib/src/external/glfw/src/monitor.c
--- a/raylib/src/external/glfw/src/monitor.c
+++ b/raylib/src/external/glfw/src/monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -325,9 +325,6 @@
 
 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
-
     if (xpos)
         *xpos = 0;
     if (ypos)
@@ -335,6 +332,9 @@
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     _glfw.platform.getMonitorPos(monitor, xpos, ypos);
 }
 
@@ -342,9 +342,6 @@
                                     int* xpos, int* ypos,
                                     int* width, int* height)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
-
     if (xpos)
         *xpos = 0;
     if (ypos)
@@ -356,14 +353,14 @@
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     _glfw.platform.getMonitorWorkarea(monitor, xpos, ypos, width, height);
 }
 
 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
-
     if (widthMM)
         *widthMM = 0;
     if (heightMM)
@@ -371,6 +368,9 @@
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     if (widthMM)
         *widthMM = monitor->widthMM;
     if (heightMM)
@@ -380,42 +380,46 @@
 GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
                                         float* xscale, float* yscale)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
-
     if (xscale)
         *xscale = 0.f;
     if (yscale)
         *yscale = 0.f;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     _glfw.platform.getMonitorContentScale(monitor, xscale, yscale);
 }
 
 GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     assert(monitor != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return monitor->name;
 }
 
 GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     assert(monitor != NULL);
 
-    _GLFW_REQUIRE_INIT();
     monitor->userPointer = pointer;
 }
 
 GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     assert(monitor != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return monitor->userPointer;
 }
 
@@ -428,14 +432,15 @@
 
 GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
     assert(count != NULL);
 
     *count = 0;
 
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     if (!refreshVideoModes(monitor))
         return NULL;
 
@@ -445,11 +450,11 @@
 
 GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     assert(monitor != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-
     if (!_glfw.platform.getVideoMode(monitor, &monitor->currentMode))
         return NULL;
 
@@ -462,13 +467,15 @@
     unsigned short* values;
     GLFWgammaramp ramp;
     const GLFWgammaramp* original;
-    assert(handle != NULL);
+
     assert(gamma > 0.f);
-    assert(gamma <= FLT_MAX);
+    assert(isfinite(gamma));
 
     _GLFW_REQUIRE_INIT();
 
-    if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
+    assert(handle != NULL);
+
+    if (!isfinite(gamma) || gamma <= 0.f)
     {
         _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
         return;
@@ -505,11 +512,11 @@
 
 GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     assert(monitor != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-
     _glfwFreeGammaArrays(&monitor->currentRamp);
     if (!_glfw.platform.getGammaRamp(monitor, &monitor->currentRamp))
         return NULL;
@@ -519,8 +526,6 @@
 
 GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
-    assert(monitor != NULL);
     assert(ramp != NULL);
     assert(ramp->size > 0);
     assert(ramp->red != NULL);
@@ -528,6 +533,9 @@
     assert(ramp->blue != NULL);
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     if (ramp->size <= 0)
     {
diff --git a/raylib/src/external/glfw/src/nsgl_context.m b/raylib/src/external/glfw/src/nsgl_context.m
--- a/raylib/src/external/glfw/src/nsgl_context.m
+++ b/raylib/src/external/glfw/src/nsgl_context.m
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 macOS - www.glfw.org
+// GLFW 3.5 macOS - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
 //
@@ -30,6 +30,7 @@
 
 #include <unistd.h>
 #include <math.h>
+#include <assert.h>
 
 static void makeContextCurrentNSGL(_GLFWwindow* window)
 {
@@ -127,8 +128,6 @@
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-// Initialize OpenGL support
-//
 GLFWbool _glfwInitNSGL(void)
 {
     if (_glfw.nsgl.framework)
@@ -146,14 +145,10 @@
     return GLFW_TRUE;
 }
 
-// Terminate OpenGL support
-//
 void _glfwTerminateNSGL(void)
 {
 }
 
-// Create the OpenGL context
-//
 GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
                                 const _GLFWctxconfig* ctxconfig,
                                 const _GLFWfbconfig* fbconfig)
@@ -182,16 +177,16 @@
         return GLFW_FALSE;
     }
 
-    // Context robustness modes (GL_KHR_robustness) are not yet supported by
+    // Context robustness modes (GL_KHR_robustness) are not supported by
     // macOS but are not a hard constraint, so ignore and continue
 
-    // Context release behaviors (GL_KHR_context_flush_control) are not yet
+    // Context release behaviors (GL_KHR_context_flush_control) are not 
     // supported by macOS but are not a hard constraint, so ignore and continue
 
-    // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not
+    // Debug contexts (GL_KHR_debug) are not supported by macOS but are not
     // a hard constraint, so ignore and continue
 
-    // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
+    // No-error contexts (GL_KHR_no_error) are not supported by macOS but
     // are not a hard constraint, so ignore and continue
 
 #define ADD_ATTRIB(a) \
@@ -217,14 +212,11 @@
         ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching);
     }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
     if (ctxconfig->major >= 4)
     {
         SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
     }
-    else
-#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
-    if (ctxconfig->major >= 3)
+    else if (ctxconfig->major >= 3)
     {
         SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
     }
@@ -361,7 +353,6 @@
 
 GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
@@ -370,6 +361,9 @@
                         "NSGL: Platform not initialized");
         return nil;
     }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (window->context.source != GLFW_NATIVE_CONTEXT_API)
     {
diff --git a/raylib/src/external/glfw/src/null_init.c b/raylib/src/external/glfw/src/null_init.c
--- a/raylib/src/external/glfw/src/null_init.c
+++ b/raylib/src/external/glfw/src/null_init.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016 Google Inc.
 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -260,5 +260,6 @@
     free(_glfw.null.clipboardString);
     _glfwTerminateOSMesa();
     _glfwTerminateEGL();
+    memset(&_glfw.null, 0, sizeof(_glfw.null));
 }
 
diff --git a/raylib/src/external/glfw/src/null_joystick.c b/raylib/src/external/glfw/src/null_joystick.c
--- a/raylib/src/external/glfw/src/null_joystick.c
+++ b/raylib/src/external/glfw/src/null_joystick.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/null_joystick.h b/raylib/src/external/glfw/src/null_joystick.h
--- a/raylib/src/external/glfw/src/null_joystick.h
+++ b/raylib/src/external/glfw/src/null_joystick.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/null_monitor.c b/raylib/src/external/glfw/src/null_monitor.c
--- a/raylib/src/external/glfw/src/null_monitor.c
+++ b/raylib/src/external/glfw/src/null_monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016 Google Inc.
 // Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/null_platform.h b/raylib/src/external/glfw/src/null_platform.h
--- a/raylib/src/external/glfw/src/null_platform.h
+++ b/raylib/src/external/glfw/src/null_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016 Google Inc.
 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -155,6 +155,17 @@
 #define GLFW_NULL_SC_RIGHT_SUPER    119
 #define GLFW_NULL_SC_MENU           120
 #define GLFW_NULL_SC_LAST           GLFW_NULL_SC_MENU
+
+typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT;
+
+typedef struct VkHeadlessSurfaceCreateInfoEXT
+{
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkHeadlessSurfaceCreateFlagsEXT flags;
+} VkHeadlessSurfaceCreateInfoEXT;
+
+typedef VkResult (APIENTRY *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance,const VkHeadlessSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
 
 // Null-specific per-window data
 //
diff --git a/raylib/src/external/glfw/src/null_window.c b/raylib/src/external/glfw/src/null_window.c
--- a/raylib/src/external/glfw/src/null_window.c
+++ b/raylib/src/external/glfw/src/null_window.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016 Google Inc.
 // Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -29,6 +28,7 @@
 #include "internal.h"
 
 #include <stdlib.h>
+#include <string.h>
 
 static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
 {
@@ -60,12 +60,12 @@
     window->null.height = mode.height;
 }
 
-static void acquireMonitorNull(_GLFWwindow* window)
+static void acquireMonitor(_GLFWwindow* window)
 {
     _glfwInputMonitorWindow(window->monitor, window);
 }
 
-static void releaseMonitorNull(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
     if (window->monitor->window != window)
         return;
@@ -148,7 +148,7 @@
     {
         _glfwShowWindowNull(window);
         _glfwFocusWindowNull(window);
-        acquireMonitorNull(window);
+        acquireMonitor(window);
 
         if (wndconfig->centerCursor)
             _glfwCenterCursorInContentArea(window);
@@ -169,7 +169,7 @@
 void _glfwDestroyWindowNull(_GLFWwindow* window)
 {
     if (window->monitor)
-        releaseMonitorNull(window);
+        releaseMonitor(window);
 
     if (_glfw.null.focusedWindow == window)
         _glfw.null.focusedWindow = NULL;
@@ -204,14 +204,14 @@
     }
 
     if (window->monitor)
-        releaseMonitorNull(window);
+        releaseMonitor(window);
 
     _glfwInputWindowMonitor(window, monitor);
 
     if (window->monitor)
     {
         window->null.visible = GLFW_TRUE;
-        acquireMonitorNull(window);
+        acquireMonitor(window);
         fitToMonitor(window);
     }
     else
@@ -341,7 +341,7 @@
         _glfwInputWindowIconify(window, GLFW_TRUE);
 
         if (window->monitor)
-            releaseMonitorNull(window);
+            releaseMonitor(window);
     }
 }
 
@@ -353,7 +353,7 @@
         _glfwInputWindowIconify(window, GLFW_FALSE);
 
         if (window->monitor)
-            acquireMonitorNull(window);
+            acquireMonitor(window);
     }
     else if (window->null.maximized)
     {
@@ -553,12 +553,15 @@
 
 EGLenum _glfwGetEGLPlatformNull(EGLint** attribs)
 {
-    return 0;
+    if (_glfw.egl.EXT_platform_base && _glfw.egl.MESA_platform_surfaceless)
+        return EGL_PLATFORM_SURFACELESS_MESA;
+    else
+        return 0;
 }
 
 EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void)
 {
-    return 0;
+    return EGL_DEFAULT_DISPLAY;
 }
 
 EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window)
@@ -700,13 +703,18 @@
 
 void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
 {
+    if (!_glfw.vk.KHR_surface || !_glfw.vk.EXT_headless_surface)
+        return;
+
+    extensions[0] = "VK_KHR_surface";
+    extensions[1] = "VK_EXT_headless_surface";
 }
 
 GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
                                                        VkPhysicalDevice device,
                                                        uint32_t queuefamily)
 {
-    return GLFW_FALSE;
+    return GLFW_TRUE;
 }
 
 VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
@@ -714,7 +722,28 @@
                                       const VkAllocationCallbacks* allocator,
                                       VkSurfaceKHR* surface)
 {
-    // This seems like the most appropriate error to return here
-    return VK_ERROR_EXTENSION_NOT_PRESENT;
+    PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT =
+        (PFN_vkCreateHeadlessSurfaceEXT)
+        vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
+    if (!vkCreateHeadlessSurfaceEXT)
+    {
+        _glfwInputError(GLFW_API_UNAVAILABLE,
+                        "Null: Vulkan instance missing VK_EXT_headless_surface extension");
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+
+    VkHeadlessSurfaceCreateInfoEXT sci;
+    memset(&sci, 0, sizeof(sci));
+    sci.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
+
+    const VkResult err = vkCreateHeadlessSurfaceEXT(instance, &sci, allocator, surface);
+    if (err)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Null: Failed to create Vulkan surface: %s",
+                        _glfwGetVulkanResultString(err));
+    }
+
+    return err;
 }
 
diff --git a/raylib/src/external/glfw/src/osmesa_context.c b/raylib/src/external/glfw/src/osmesa_context.c
--- a/raylib/src/external/glfw/src/osmesa_context.c
+++ b/raylib/src/external/glfw/src/osmesa_context.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 OSMesa - www.glfw.org
+// GLFW 3.5 OSMesa - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2016 Google Inc.
 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -180,11 +180,8 @@
 
 void _glfwTerminateOSMesa(void)
 {
-    if (_glfw.osmesa.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.osmesa.handle);
-        _glfw.osmesa.handle = NULL;
-    }
+    _glfwPlatformFreeModule(_glfw.osmesa.handle);
+    _glfw.osmesa.handle = NULL;
 }
 
 #define SET_ATTRIB(a, v) \
@@ -296,11 +293,12 @@
 {
     void* mesaBuffer;
     GLint mesaWidth, mesaHeight, mesaFormat;
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
@@ -335,11 +333,12 @@
 {
     void* mesaBuffer;
     GLint mesaWidth, mesaHeight, mesaBytes;
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
 
     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
@@ -369,8 +368,10 @@
 
 GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
     {
diff --git a/raylib/src/external/glfw/src/platform.c b/raylib/src/external/glfw/src/platform.c
--- a/raylib/src/external/glfw/src/platform.c
+++ b/raylib/src/external/glfw/src/platform.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -75,6 +74,15 @@
         return GLFW_FALSE;
     }
 
+    // Only allow the Null platform if specifically requested
+    if (desiredID == GLFW_PLATFORM_NULL)
+        return _glfwConnectNull(desiredID, platform);
+    else if (count == 0)
+    {
+        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "This binary only supports the Null platform");
+        return GLFW_FALSE;
+    }
+
 #if defined(_GLFW_WAYLAND) && defined(_GLFW_X11)
     if (desiredID == GLFW_ANY_PLATFORM)
     {
@@ -179,8 +187,6 @@
         " OSMesa"
 #if defined(__MINGW64_VERSION_MAJOR)
         " MinGW-w64"
-#elif defined(__MINGW32__)
-        " MinGW"
 #elif defined(_MSC_VER)
         " VisualC"
 #endif
diff --git a/raylib/src/external/glfw/src/platform.h b/raylib/src/external/glfw/src/platform.h
--- a/raylib/src/external/glfw/src/platform.h
+++ b/raylib/src/external/glfw/src/platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@@ -28,7 +28,7 @@
 #if defined(GLFW_BUILD_WIN32_TIMER) || \
     defined(GLFW_BUILD_WIN32_MODULE) || \
     defined(GLFW_BUILD_WIN32_THREAD) || \
-    defined(GLFW_BUILD_COCOA_TIMER) || \
+    defined(GLFW_BUILD_MACOS_TIMER) || \
     defined(GLFW_BUILD_POSIX_TIMER) || \
     defined(GLFW_BUILD_POSIX_MODULE) || \
     defined(GLFW_BUILD_POSIX_THREAD) || \
@@ -184,7 +184,7 @@
 #if defined(_WIN32)
  #define GLFW_BUILD_WIN32_TIMER
 #elif defined(__APPLE__)
- #define GLFW_BUILD_COCOA_TIMER
+ #define GLFW_BUILD_MACOS_TIMER
 #else
  #define GLFW_BUILD_POSIX_TIMER
 #endif
@@ -192,9 +192,9 @@
 #if defined(GLFW_BUILD_WIN32_TIMER)
  #include "win32_time.h"
  #define GLFW_PLATFORM_LIBRARY_TIMER_STATE  GLFW_WIN32_LIBRARY_TIMER_STATE
-#elif defined(GLFW_BUILD_COCOA_TIMER)
- #include "cocoa_time.h"
- #define GLFW_PLATFORM_LIBRARY_TIMER_STATE  GLFW_COCOA_LIBRARY_TIMER_STATE
+#elif defined(GLFW_BUILD_MACOS_TIMER)
+ #include "macos_time.h"
+ #define GLFW_PLATFORM_LIBRARY_TIMER_STATE  GLFW_MACOS_LIBRARY_TIMER_STATE
 #elif defined(GLFW_BUILD_POSIX_TIMER)
  #include "posix_time.h"
  #define GLFW_PLATFORM_LIBRARY_TIMER_STATE  GLFW_POSIX_LIBRARY_TIMER_STATE
@@ -207,6 +207,7 @@
 #endif
 
 #if defined(_GLFW_WAYLAND) || defined(_GLFW_X11)
+ #include "posix_poll.h"
  #define GLFW_BUILD_POSIX_POLL
 #endif
 
diff --git a/raylib/src/external/glfw/src/posix_module.c b/raylib/src/external/glfw/src/posix_module.c
--- a/raylib/src/external/glfw/src/posix_module.c
+++ b/raylib/src/external/glfw/src/posix_module.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2021 Camilla Löwy <elmindreda@glfw.org>
 //
@@ -41,7 +41,8 @@
 
 void _glfwPlatformFreeModule(void* module)
 {
-    dlclose(module);
+    if (module)
+        dlclose(module);
 }
 
 GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
diff --git a/raylib/src/external/glfw/src/posix_poll.c b/raylib/src/external/glfw/src/posix_poll.c
--- a/raylib/src/external/glfw/src/posix_poll.c
+++ b/raylib/src/external/glfw/src/posix_poll.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/posix_poll.h b/raylib/src/external/glfw/src/posix_poll.h
--- a/raylib/src/external/glfw/src/posix_poll.h
+++ b/raylib/src/external/glfw/src/posix_poll.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/posix_thread.c b/raylib/src/external/glfw/src/posix_thread.c
--- a/raylib/src/external/glfw/src/posix_thread.c
+++ b/raylib/src/external/glfw/src/posix_thread.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/posix_thread.h b/raylib/src/external/glfw/src/posix_thread.h
--- a/raylib/src/external/glfw/src/posix_thread.h
+++ b/raylib/src/external/glfw/src/posix_thread.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/posix_time.c b/raylib/src/external/glfw/src/posix_time.c
--- a/raylib/src/external/glfw/src/posix_time.c
+++ b/raylib/src/external/glfw/src/posix_time.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/posix_time.h b/raylib/src/external/glfw/src/posix_time.h
--- a/raylib/src/external/glfw/src/posix_time.h
+++ b/raylib/src/external/glfw/src/posix_time.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 POSIX - www.glfw.org
+// GLFW 3.5 POSIX - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/vulkan.c b/raylib/src/external/glfw/src/vulkan.c
--- a/raylib/src/external/glfw/src/vulkan.c
+++ b/raylib/src/external/glfw/src/vulkan.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@@ -34,7 +34,41 @@
 #define _GLFW_FIND_LOADER    1
 #define _GLFW_REQUIRE_LOADER 2
 
+#if defined(__APPLE__)
 
+#include <CoreFoundation/CoreFoundation.h>
+
+static void* loadLocalVulkanLoaderMacOS(void)
+{
+    CFBundleRef bundle = CFBundleGetMainBundle();
+    if (!bundle)
+        return NULL;
+
+    CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);
+    if (!frameworksUrl)
+        return NULL;
+
+    CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(
+        kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);
+    if (!loaderUrl)
+    {
+        CFRelease(frameworksUrl);
+        return NULL;
+    }
+
+    char path[PATH_MAX];
+    void* handle = NULL;
+
+    if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1))
+        handle = _glfwPlatformLoadModule(path);
+
+    CFRelease(loaderUrl);
+    CFRelease(frameworksUrl);
+    return handle;
+}
+
+#endif // __APPLE__
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -55,12 +89,12 @@
     {
 #if defined(_GLFW_VULKAN_LIBRARY)
         _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
-#elif defined(_GLFW_WIN32)
+#elif defined(_WIN32)
         _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
-#elif defined(_GLFW_COCOA)
+#elif defined(__APPLE__)
         _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
         if (!_glfw.vk.handle)
-            _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
+            _glfw.vk.handle = loadLocalVulkanLoaderMacOS();
 #elif defined(__OpenBSD__) || defined(__NetBSD__)
         _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
 #else
@@ -129,19 +163,21 @@
     for (i = 0;  i < count;  i++)
     {
         if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
-            _glfw.vk.KHR_surface = GLFW_TRUE;
+            _glfw.vk.KHR_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
-            _glfw.vk.KHR_win32_surface = GLFW_TRUE;
+            _glfw.vk.KHR_win32_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
-            _glfw.vk.MVK_macos_surface = GLFW_TRUE;
+            _glfw.vk.MVK_macos_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
-            _glfw.vk.EXT_metal_surface = GLFW_TRUE;
+            _glfw.vk.EXT_metal_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
-            _glfw.vk.KHR_xlib_surface = GLFW_TRUE;
+            _glfw.vk.KHR_xlib_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
-            _glfw.vk.KHR_xcb_surface = GLFW_TRUE;
+            _glfw.vk.KHR_xcb_surface = true;
         else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
-            _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
+            _glfw.vk.KHR_wayland_surface = true;
+        else if (strcmp(ep[i].extensionName, "VK_EXT_headless_surface") == 0)
+            _glfw.vk.EXT_headless_surface = true;
     }
 
     _glfw_free(ep);
@@ -155,8 +191,8 @@
 
 void _glfwTerminateVulkan(void)
 {
-    if (_glfw.vk.handle)
-        _glfwPlatformFreeModule(_glfw.vk.handle);
+    _glfwPlatformFreeModule(_glfw.vk.handle);
+    _glfw.vk.handle = NULL;
 }
 
 const char* _glfwGetVulkanResultString(VkResult result)
@@ -272,11 +308,11 @@
                                                      VkPhysicalDevice device,
                                                      uint32_t queuefamily)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
+
     assert(instance != VK_NULL_HANDLE);
     assert(device != VK_NULL_HANDLE);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
-
     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
         return GLFW_FALSE;
 
@@ -297,14 +333,15 @@
                                          const VkAllocationCallbacks* allocator,
                                          VkSurfaceKHR* surface)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(instance != VK_NULL_HANDLE);
-    assert(window != NULL);
     assert(surface != NULL);
 
     *surface = VK_NULL_HANDLE;
 
     _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+    assert(instance != VK_NULL_HANDLE);
 
     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
         return VK_ERROR_INITIALIZATION_FAILED;
diff --git a/raylib/src/external/glfw/src/wgl_context.c b/raylib/src/external/glfw/src/wgl_context.c
--- a/raylib/src/external/glfw/src/wgl_context.c
+++ b/raylib/src/external/glfw/src/wgl_context.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 WGL - www.glfw.org
+// GLFW 3.5 WGL - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -186,28 +186,22 @@
             u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB);
 
             u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB);
-
-            if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB))
-                u->stereo = GLFW_TRUE;
+            u->stereo = FIND_ATTRIB_VALUE(WGL_STEREO_ARB);
 
             if (_glfw.wgl.ARB_multisample)
                 u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB);
 
             if (ctxconfig->client == GLFW_OPENGL_API)
             {
-                if (_glfw.wgl.ARB_framebuffer_sRGB ||
-                    _glfw.wgl.EXT_framebuffer_sRGB)
-                {
-                    if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
-                        u->sRGB = GLFW_TRUE;
-                }
+                if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
+                    u->sRGB = FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
             }
             else
             {
                 if (_glfw.wgl.EXT_colorspace)
                 {
                     if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
-                        u->sRGB = GLFW_TRUE;
+                        u->sRGB = true;
                 }
             }
         }
@@ -261,9 +255,7 @@
             u->accumAlphaBits = pfd.cAccumAlphaBits;
 
             u->auxBuffers = pfd.cAuxBuffers;
-
-            if (pfd.dwFlags & PFD_STEREO)
-                u->stereo = GLFW_TRUE;
+            u->stereo = (pfd.dwFlags & PFD_STEREO);
         }
 
         u->handle = pixelFormat;
@@ -327,8 +319,8 @@
 {
     if (!window->monitor)
     {
-        // HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7
-        if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
+        // HACK: Use DwmFlush when desktop composition is enabled on Windows 7
+        if (!IsWindows8OrGreater())
         {
             BOOL enabled = FALSE;
 
@@ -353,9 +345,9 @@
 
     if (!window->monitor)
     {
-        // HACK: Disable WGL swap interval when desktop composition is enabled on Windows
-        //       Vista and 7 to avoid interfering with DWM vsync
-        if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
+        // HACK: Disable WGL swap interval when desktop composition is enabled on
+        //       Windows 7 to avoid interfering with DWM vsync
+        if (!IsWindows8OrGreater())
         {
             BOOL enabled = FALSE;
 
@@ -401,8 +393,6 @@
     }
 }
 
-// Initialize WGL
-//
 GLFWbool _glfwInitWGL(void)
 {
     PIXELFORMATDESCRIPTOR pfd;
@@ -521,12 +511,10 @@
     return GLFW_TRUE;
 }
 
-// Terminate WGL
-//
 void _glfwTerminateWGL(void)
 {
-    if (_glfw.wgl.instance)
-        _glfwPlatformFreeModule(_glfw.wgl.instance);
+    _glfwPlatformFreeModule(_glfw.wgl.instance);
+    _glfw.wgl.instance = NULL;
 }
 
 #define SET_ATTRIB(a, v) \
@@ -536,8 +524,6 @@
     attribs[index++] = v; \
 }
 
-// Create the OpenGL or OpenGL ES context
-//
 GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                                const _GLFWctxconfig* ctxconfig,
                                const _GLFWfbconfig* fbconfig)
@@ -670,7 +656,7 @@
         if (ctxconfig->noerror)
         {
             if (_glfw.wgl.ARB_create_context_no_error)
-                SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
+                SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, true);
         }
 
         // NOTE: Only request an explicitly versioned context when necessary, as
@@ -775,7 +761,6 @@
 
 GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
@@ -784,6 +769,9 @@
                         "WGL: Platform not initialized");
         return NULL;
     }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     if (window->context.source != GLFW_NATIVE_CONTEXT_API)
     {
diff --git a/raylib/src/external/glfw/src/win32_init.c b/raylib/src/external/glfw/src/win32_init.c
--- a/raylib/src/external/glfw/src/win32_init.c
+++ b/raylib/src/external/glfw/src/win32_init.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -90,10 +89,6 @@
         return GLFW_FALSE;
     }
 
-    _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware)
-        _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDPIAware");
-    _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
-        _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
     _glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling)
         _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
     _glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext)
@@ -171,32 +166,9 @@
     return GLFW_TRUE;
 }
 
-// Unload used libraries (DLLs)
-//
-static void freeLibraries(void)
-{
-    if (_glfw.win32.xinput.instance)
-        _glfwPlatformFreeModule(_glfw.win32.xinput.instance);
-
-    if (_glfw.win32.dinput8.instance)
-        _glfwPlatformFreeModule(_glfw.win32.dinput8.instance);
-
-    if (_glfw.win32.user32.instance)
-        _glfwPlatformFreeModule(_glfw.win32.user32.instance);
-
-    if (_glfw.win32.dwmapi.instance)
-        _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance);
-
-    if (_glfw.win32.shcore.instance)
-        _glfwPlatformFreeModule(_glfw.win32.shcore.instance);
-
-    if (_glfw.win32.ntdll.instance)
-        _glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
-}
-
 // Create key code translation tables
 //
-static void createKeyTablesWin32(void)
+static void createKeyTables(void)
 {
     int scancode;
 
@@ -533,7 +505,8 @@
 
         if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
         {
-            const UINT vks[] = {
+            const UINT vks[] =
+            {
                 VK_NUMPAD0,  VK_NUMPAD1,  VK_NUMPAD2, VK_NUMPAD3,
                 VK_NUMPAD4,  VK_NUMPAD5,  VK_NUMPAD6, VK_NUMPAD7,
                 VK_NUMPAD8,  VK_NUMPAD9,  VK_DECIMAL, VK_DIVIDE,
@@ -686,14 +659,14 @@
     if (!loadLibraries())
         return GLFW_FALSE;
 
-    createKeyTablesWin32();
+    createKeyTables();
     _glfwUpdateKeyNamesWin32();
 
     if (_glfwIsWindows10Version1703OrGreaterWin32())
         SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
     else if (IsWindows8Point1OrGreater())
         SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
-    else if (IsWindowsVistaOrGreater())
+    else
         SetProcessDPIAware();
 
     if (!createHelperWindow())
@@ -725,7 +698,14 @@
     _glfwTerminateEGL();
     _glfwTerminateOSMesa();
 
-    freeLibraries();
+    _glfwPlatformFreeModule(_glfw.win32.xinput.instance);
+    _glfwPlatformFreeModule(_glfw.win32.dinput8.instance);
+    _glfwPlatformFreeModule(_glfw.win32.user32.instance);
+    _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance);
+    _glfwPlatformFreeModule(_glfw.win32.shcore.instance);
+    _glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
+
+    memset(&_glfw.win32, 0, sizeof(_glfw.win32));
 }
 
 #endif // _GLFW_WIN32
diff --git a/raylib/src/external/glfw/src/win32_joystick.c b/raylib/src/external/glfw/src/win32_joystick.c
--- a/raylib/src/external/glfw/src/win32_joystick.c
+++ b/raylib/src/external/glfw/src/win32_joystick.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/win32_joystick.h b/raylib/src/external/glfw/src/win32_joystick.h
--- a/raylib/src/external/glfw/src/win32_joystick.h
+++ b/raylib/src/external/glfw/src/win32_joystick.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
 //
diff --git a/raylib/src/external/glfw/src/win32_module.c b/raylib/src/external/glfw/src/win32_module.c
--- a/raylib/src/external/glfw/src/win32_module.c
+++ b/raylib/src/external/glfw/src/win32_module.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2021 Camilla Löwy <elmindreda@glfw.org>
 //
@@ -39,7 +39,8 @@
 
 void _glfwPlatformFreeModule(void* module)
 {
-    FreeLibrary((HMODULE) module);
+    if (module)
+        FreeLibrary((HMODULE) module);
 }
 
 GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
diff --git a/raylib/src/external/glfw/src/win32_monitor.c b/raylib/src/external/glfw/src/win32_monitor.c
--- a/raylib/src/external/glfw/src/win32_monitor.c
+++ b/raylib/src/external/glfw/src/win32_monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <limits.h>
 #include <wchar.h>
+#include <assert.h>
 
 
 // Callback for EnumDisplayMonitors in createMonitor
@@ -539,7 +540,6 @@
 
 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
@@ -548,12 +548,14 @@
         return NULL;
     }
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     return monitor->win32.publicAdapterName;
 }
 
 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
@@ -561,6 +563,9 @@
         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized");
         return NULL;
     }
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     return monitor->win32.publicDisplayName;
 }
diff --git a/raylib/src/external/glfw/src/win32_platform.h b/raylib/src/external/glfw/src/win32_platform.h
--- a/raylib/src/external/glfw/src/win32_platform.h
+++ b/raylib/src/external/glfw/src/win32_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -48,14 +48,14 @@
  #define UNICODE
 #endif
 
-// GLFW requires Windows XP or later
-#if WINVER < 0x0501
+// GLFW requires Windows 7 or later
+#if WINVER < 0x0601
  #undef WINVER
- #define WINVER 0x0501
+ #define WINVER 0x0601
 #endif
-#if _WIN32_WINNT < 0x0501
+#if _WIN32_WINNT < 0x0601
  #undef _WIN32_WINNT
- #define _WIN32_WINNT 0x0501
+ #define _WIN32_WINNT 0x0601
 #endif
 
 // GLFW uses DirectInput8 interfaces
@@ -66,41 +66,21 @@
 
 #include <wctype.h>
 #include <windows.h>
+#include <dwmapi.h>
 #include <dinput.h>
 #include <xinput.h>
 #include <dbt.h>
 
 // HACK: Define macros that some windows.h variants don't
-#ifndef WM_MOUSEHWHEEL
- #define WM_MOUSEHWHEEL 0x020E
-#endif
-#ifndef WM_DWMCOMPOSITIONCHANGED
- #define WM_DWMCOMPOSITIONCHANGED 0x031E
-#endif
-#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
- #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
-#endif
 #ifndef WM_COPYGLOBALDATA
  #define WM_COPYGLOBALDATA 0x0049
 #endif
-#ifndef WM_UNICHAR
- #define WM_UNICHAR 0x0109
-#endif
-#ifndef UNICODE_NOCHAR
- #define UNICODE_NOCHAR 0xFFFF
-#endif
 #ifndef WM_DPICHANGED
  #define WM_DPICHANGED 0x02E0
 #endif
-#ifndef GET_XBUTTON_WPARAM
- #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
-#endif
 #ifndef EDS_ROTATEDMODE
  #define EDS_ROTATEDMODE 0x00000004
 #endif
-#ifndef DISPLAY_DEVICE_ACTIVE
- #define DISPLAY_DEVICE_ACTIVE 0x00000001
-#endif
 #ifndef _WIN32_WINNT_WINBLUE
  #define _WIN32_WINNT_WINBLUE 0x0603
 #endif
@@ -113,35 +93,7 @@
 #ifndef USER_DEFAULT_SCREEN_DPI
  #define USER_DEFAULT_SCREEN_DPI 96
 #endif
-#ifndef OCR_HAND
- #define OCR_HAND 32649
-#endif
 
-#if WINVER < 0x0601
-typedef struct
-{
-    DWORD cbSize;
-    DWORD ExtStatus;
-} CHANGEFILTERSTRUCT;
-#ifndef MSGFLT_ALLOW
- #define MSGFLT_ALLOW 1
-#endif
-#endif /*Windows 7*/
-
-#if WINVER < 0x0600
-#define DWM_BB_ENABLE 0x00000001
-#define DWM_BB_BLURREGION 0x00000002
-typedef struct
-{
-    DWORD dwFlags;
-    BOOL fEnable;
-    HRGN hRgnBlur;
-    BOOL fTransitionOnMaximized;
-} DWM_BLURBEHIND;
-#else
- #include <dwmapi.h>
-#endif /*Windows Vista*/
-
 #ifndef DPI_ENUMS_DECLARED
 typedef enum
 {
@@ -165,12 +117,6 @@
 // Replacement for versionhelpers.h macros, as we cannot rely on the
 // application having a correct embedded manifest
 //
-#define IsWindowsVistaOrGreater()                                     \
-    _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA),   \
-                                        LOBYTE(_WIN32_WINNT_VISTA), 0)
-#define IsWindows7OrGreater()                                         \
-    _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7),    \
-                                        LOBYTE(_WIN32_WINNT_WIN7), 0)
 #define IsWindows8OrGreater()                                         \
     _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8),    \
                                         LOBYTE(_WIN32_WINNT_WIN8), 0)
@@ -281,15 +227,11 @@
 #define DirectInput8Create _glfw.win32.dinput8.Create
 
 // user32.dll function pointer typedefs
-typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
-typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
 typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
 typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
 typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
 typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
 typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
-#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
-#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
 #define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
 #define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
 #define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
@@ -394,18 +336,18 @@
     PFNWGLGETEXTENSIONSSTRINGEXTPROC    GetExtensionsStringEXT;
     PFNWGLGETEXTENSIONSSTRINGARBPROC    GetExtensionsStringARB;
     PFNWGLCREATECONTEXTATTRIBSARBPROC   CreateContextAttribsARB;
-    GLFWbool                            EXT_swap_control;
-    GLFWbool                            EXT_colorspace;
-    GLFWbool                            ARB_multisample;
-    GLFWbool                            ARB_framebuffer_sRGB;
-    GLFWbool                            EXT_framebuffer_sRGB;
-    GLFWbool                            ARB_pixel_format;
-    GLFWbool                            ARB_create_context;
-    GLFWbool                            ARB_create_context_profile;
-    GLFWbool                            EXT_create_context_es2_profile;
-    GLFWbool                            ARB_create_context_robustness;
-    GLFWbool                            ARB_create_context_no_error;
-    GLFWbool                            ARB_context_flush_control;
+    bool                                EXT_swap_control;
+    bool                                EXT_colorspace;
+    bool                                ARB_multisample;
+    bool                                ARB_framebuffer_sRGB;
+    bool                                EXT_framebuffer_sRGB;
+    bool                                ARB_pixel_format;
+    bool                                ARB_create_context;
+    bool                                ARB_create_context_profile;
+    bool                                EXT_create_context_es2_profile;
+    bool                                ARB_create_context_robustness;
+    bool                                ARB_create_context_no_error;
+    bool                                ARB_context_flush_control;
 } _GLFWlibraryWGL;
 
 // Win32-specific per-window data
@@ -475,8 +417,6 @@
 
     struct {
         HINSTANCE                       instance;
-        PFN_SetProcessDPIAware          SetProcessDPIAware_;
-        PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_;
         PFN_EnableNonClientDpiScaling   EnableNonClientDpiScaling_;
         PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
         PFN_GetDpiForWindow             GetDpiForWindow_;
diff --git a/raylib/src/external/glfw/src/win32_thread.c b/raylib/src/external/glfw/src/win32_thread.c
--- a/raylib/src/external/glfw/src/win32_thread.c
+++ b/raylib/src/external/glfw/src/win32_thread.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/win32_thread.h b/raylib/src/external/glfw/src/win32_thread.h
--- a/raylib/src/external/glfw/src/win32_thread.h
+++ b/raylib/src/external/glfw/src/win32_thread.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/win32_time.c b/raylib/src/external/glfw/src/win32_time.c
--- a/raylib/src/external/glfw/src/win32_time.c
+++ b/raylib/src/external/glfw/src/win32_time.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/win32_time.h b/raylib/src/external/glfw/src/win32_time.h
--- a/raylib/src/external/glfw/src/win32_time.h
+++ b/raylib/src/external/glfw/src/win32_time.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Win32 - www.glfw.org
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
diff --git a/raylib/src/external/glfw/src/win32_window.c b/raylib/src/external/glfw/src/win32_window.c
--- a/raylib/src/external/glfw/src/win32_window.c
+++ b/raylib/src/external/glfw/src/win32_window.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Win32 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -33,6 +32,7 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 #include <windowsx.h>
 #include <shellapi.h>
 
@@ -374,9 +374,6 @@
     BOOL composition, opaque;
     DWORD color;
 
-    if (!IsWindowsVistaOrGreater())
-        return;
-
     if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
        return;
 
@@ -440,7 +437,7 @@
 
 // Make the specified window and its video mode active on its monitor
 //
-static void acquireMonitorWin32(_GLFWwindow* window)
+static void acquireMonitor(_GLFWwindow* window)
 {
     if (!_glfw.win32.acquiredMonitorCount)
     {
@@ -461,7 +458,7 @@
 
 // Remove the window and restore the original video mode
 //
-static void releaseMonitorWin32(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
     if (window->monitor->window != window)
         return;
@@ -471,7 +468,7 @@
     {
         SetThreadExecutionState(ES_CONTINUOUS);
 
-        // HACK: Restore mouse trail length saved in acquireMonitorWin32
+        // HACK: Restore mouse trail length saved in acquireMonitor
         SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
     }
 
@@ -714,11 +711,12 @@
             const int mods = getKeyMods();
 
             scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
-            if (!scancode)
+            if (!(scancode & 0xff))
             {
-                // NOTE: Some synthetic key messages have a scancode of zero
-                // HACK: Map the virtual key back to a usable scancode
-                scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
+                // NOTE: Both media keys and the synthetic key messages from Windows
+                //       Clipboard History are reported with a scancode of zero
+                // HACK: Map the virtual key to a scancode but preserve extended bit
+                scancode |= MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
             }
 
             // HACK: Alt+PrtSc has a different scancode than just PrtSc
@@ -983,7 +981,6 @@
 
         case WM_MOUSEHWHEEL:
         {
-            // This message is only sent on Windows Vista and later
             // NOTE: The X-axis is inverted for consistency with macOS and X11
             _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
             return 0;
@@ -1051,10 +1048,10 @@
             if (window->monitor && window->win32.iconified != iconified)
             {
                 if (iconified)
-                    releaseMonitorWin32(window);
+                    releaseMonitor(window);
                 else
                 {
-                    acquireMonitorWin32(window);
+                    acquireMonitor(window);
                     fitToMonitor(window);
                 }
             }
@@ -1381,7 +1378,7 @@
         frameHeight = rect.bottom - rect.top;
     }
 
-    wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
+    wideTitle = _glfwCreateWideStringFromUTF8Win32(window->title);
     if (!wideTitle)
         return GLFW_FALSE;
 
@@ -1407,15 +1404,9 @@
 
     SetPropW(window->win32.handle, L"GLFW", window);
 
-    if (IsWindows7OrGreater())
-    {
-        ChangeWindowMessageFilterEx(window->win32.handle,
-                                    WM_DROPFILES, MSGFLT_ALLOW, NULL);
-        ChangeWindowMessageFilterEx(window->win32.handle,
-                                    WM_COPYDATA, MSGFLT_ALLOW, NULL);
-        ChangeWindowMessageFilterEx(window->win32.handle,
-                                    WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
-    }
+    ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL);
+    ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL);
+    ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
 
     window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
     window->win32.keymenu = wndconfig->win32.keymenu;
@@ -1535,7 +1526,7 @@
     {
         _glfwShowWindowWin32(window);
         _glfwFocusWindowWin32(window);
-        acquireMonitorWin32(window);
+        acquireMonitor(window);
         fitToMonitor(window);
 
         if (wndconfig->centerCursor)
@@ -1557,7 +1548,7 @@
 void _glfwDestroyWindowWin32(_GLFWwindow* window)
 {
     if (window->monitor)
-        releaseMonitorWin32(window);
+        releaseMonitor(window);
 
     if (window->context.destroy)
         window->context.destroy(window);
@@ -1678,7 +1669,7 @@
     {
         if (window->monitor->window == window)
         {
-            acquireMonitorWin32(window);
+            acquireMonitor(window);
             fitToMonitor(window);
         }
     }
@@ -1850,7 +1841,7 @@
         {
             if (monitor->window == window)
             {
-                acquireMonitorWin32(window);
+                acquireMonitor(window);
                 fitToMonitor(window);
             }
         }
@@ -1880,7 +1871,7 @@
     }
 
     if (window->monitor)
-        releaseMonitorWin32(window);
+        releaseMonitor(window);
 
     _glfwInputWindowMonitor(window, monitor);
 
@@ -1898,7 +1889,7 @@
             flags |= SWP_FRAMECHANGED;
         }
 
-        acquireMonitorWin32(window);
+        acquireMonitor(window);
 
         GetMonitorInfoW(window->monitor->win32.handle, &mi);
         SetWindowPos(window->win32.handle, HWND_TOPMOST,
@@ -1981,9 +1972,6 @@
     if (!window->win32.transparent)
         return GLFW_FALSE;
 
-    if (!IsWindowsVistaOrGreater())
-        return GLFW_FALSE;
-
     if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
         return GLFW_FALSE;
 
@@ -2577,7 +2565,6 @@
 
 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
@@ -2586,6 +2573,9 @@
                         "Win32: Platform not initialized");
         return NULL;
     }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     return window->win32.handle;
 }
diff --git a/raylib/src/external/glfw/src/window.c b/raylib/src/external/glfw/src/window.c
--- a/raylib/src/external/glfw/src/window.c
+++ b/raylib/src/external/glfw/src/window.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 - www.glfw.org
+// GLFW 3.5 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -32,7 +32,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <float.h>
-
+#include <math.h>
 
 //////////////////////////////////////////////////////////////////////////
 //////                         GLFW event API                       //////
@@ -135,9 +135,9 @@
 {
     assert(window != NULL);
     assert(xscale > 0.f);
-    assert(xscale < FLT_MAX);
+    assert(isfinite(xscale));
     assert(yscale > 0.f);
-    assert(yscale < FLT_MAX);
+    assert(isfinite(yscale));
 
     if (window->callbacks.scale)
         window->callbacks.scale((GLFWwindow*) window, xscale, yscale);
@@ -208,7 +208,6 @@
 
     wndconfig.width   = width;
     wndconfig.height  = height;
-    wndconfig.title   = title;
     ctxconfig.share   = (_GLFWwindow*) share;
 
     if (!_glfwIsValidContextConfig(&ctxconfig))
@@ -266,16 +265,16 @@
 
     // The default is a focused, visible, resizable window with decorations
     memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window));
-    _glfw.hints.window.resizable    = GLFW_TRUE;
-    _glfw.hints.window.visible      = GLFW_TRUE;
-    _glfw.hints.window.decorated    = GLFW_TRUE;
-    _glfw.hints.window.focused      = GLFW_TRUE;
-    _glfw.hints.window.autoIconify  = GLFW_TRUE;
-    _glfw.hints.window.centerCursor = GLFW_TRUE;
-    _glfw.hints.window.focusOnShow  = GLFW_TRUE;
+    _glfw.hints.window.resizable    = true;
+    _glfw.hints.window.visible      = true;
+    _glfw.hints.window.decorated    = true;
+    _glfw.hints.window.focused      = true;
+    _glfw.hints.window.autoIconify  = true;
+    _glfw.hints.window.centerCursor = true;
+    _glfw.hints.window.focusOnShow  = true;
     _glfw.hints.window.xpos         = GLFW_ANY_POSITION;
     _glfw.hints.window.ypos         = GLFW_ANY_POSITION;
-    _glfw.hints.window.scaleFramebuffer = GLFW_TRUE;
+    _glfw.hints.window.scaleFramebuffer = true;
 
     // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
     // double buffered
@@ -286,7 +285,7 @@
     _glfw.hints.framebuffer.alphaBits    = 8;
     _glfw.hints.framebuffer.depthBits    = 24;
     _glfw.hints.framebuffer.stencilBits  = 8;
-    _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE;
+    _glfw.hints.framebuffer.doublebuffer = true;
 
     // The default is to select the highest available refresh rate
     _glfw.hints.refreshRate = GLFW_DONT_CARE;
@@ -332,40 +331,40 @@
             _glfw.hints.framebuffer.auxBuffers = value;
             return;
         case GLFW_STEREO:
-            _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.framebuffer.stereo = value;
             return;
         case GLFW_DOUBLEBUFFER:
-            _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.framebuffer.doublebuffer = value;
             return;
         case GLFW_TRANSPARENT_FRAMEBUFFER:
-            _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.framebuffer.transparent = value;
             return;
         case GLFW_SAMPLES:
             _glfw.hints.framebuffer.samples = value;
             return;
         case GLFW_SRGB_CAPABLE:
-            _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.framebuffer.sRGB = value;
             return;
         case GLFW_RESIZABLE:
-            _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.resizable = value;
             return;
         case GLFW_DECORATED:
-            _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.decorated = value;
             return;
         case GLFW_FOCUSED:
-            _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.focused = value;
             return;
         case GLFW_AUTO_ICONIFY:
-            _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.autoIconify = value;
             return;
         case GLFW_FLOATING:
-            _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.floating = value;
             return;
         case GLFW_MAXIMIZED:
-            _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.maximized = value;
             return;
         case GLFW_VISIBLE:
-            _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.visible = value;
             return;
         case GLFW_POSITION_X:
             _glfw.hints.window.xpos = value;
@@ -374,29 +373,29 @@
             _glfw.hints.window.ypos = value;
             return;
         case GLFW_WIN32_KEYBOARD_MENU:
-            _glfw.hints.window.win32.keymenu = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.win32.keymenu = value;
             return;
         case GLFW_WIN32_SHOWDEFAULT:
-            _glfw.hints.window.win32.showDefault = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.win32.showDefault = value;
             return;
         case GLFW_COCOA_GRAPHICS_SWITCHING:
-            _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.context.nsgl.offline = value;
             return;
         case GLFW_SCALE_TO_MONITOR:
-            _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.scaleToMonitor = value;
             return;
         case GLFW_SCALE_FRAMEBUFFER:
         case GLFW_COCOA_RETINA_FRAMEBUFFER:
-            _glfw.hints.window.scaleFramebuffer = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.scaleFramebuffer = value;
             return;
         case GLFW_CENTER_CURSOR:
-            _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.centerCursor = value;
             return;
         case GLFW_FOCUS_ON_SHOW:
-            _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.focusOnShow = value;
             return;
         case GLFW_MOUSE_PASSTHROUGH:
-            _glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.window.mousePassthrough = value;
             return;
         case GLFW_CLIENT_API:
             _glfw.hints.context.client = value;
@@ -414,13 +413,13 @@
             _glfw.hints.context.robustness = value;
             return;
         case GLFW_OPENGL_FORWARD_COMPAT:
-            _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.context.forward = value;
             return;
         case GLFW_CONTEXT_DEBUG:
-            _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.context.debug = value;
             return;
         case GLFW_CONTEXT_NO_ERROR:
-            _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE;
+            _glfw.hints.context.noerror = value;
             return;
         case GLFW_OPENGL_PROFILE:
             _glfw.hints.context.profile = value;
@@ -467,10 +466,10 @@
 
 GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+
     // Allow closing of NULL (to match the behavior of free)
     if (window == NULL)
         return;
@@ -501,40 +500,43 @@
 
 GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(0);
     return window->shouldClose;
 }
 
 GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
     window->shouldClose = value;
 }
 
 GLFWAPI const char* glfwGetWindowTitle(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
-
     return window->title;
 }
 
 GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
     assert(title != NULL);
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     char* prev = window->title;
     window->title = _glfw_strdup(title);
 
@@ -546,14 +548,15 @@
                                int count, const GLFWimage* images)
 {
     int i;
-    _GLFWwindow* window = (_GLFWwindow*) handle;
 
-    assert(window != NULL);
     assert(count >= 0);
     assert(count == 0 || images != NULL);
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (count < 0)
     {
         _glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon");
@@ -577,25 +580,26 @@
 
 GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (xpos)
         *xpos = 0;
     if (ypos)
         *ypos = 0;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _glfw.platform.getWindowPos(window, xpos, ypos);
 }
 
 GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     if (window->monitor)
         return;
 
@@ -604,27 +608,29 @@
 
 GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (width)
         *width = 0;
     if (height)
         *height = 0;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _glfw.platform.getWindowSize(window, width, height);
 }
 
 GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
     assert(width >= 0);
     assert(height >= 0);
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     window->videoMode.width  = width;
     window->videoMode.height = height;
 
@@ -635,11 +641,11 @@
                                      int minwidth, int minheight,
                                      int maxwidth, int maxheight)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE)
     {
         if (minwidth < 0 || minheight < 0)
@@ -678,13 +684,14 @@
 
 GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
     assert(numer != 0);
     assert(denom != 0);
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
     {
         if (numer <= 0 || denom <= 0)
@@ -707,15 +714,16 @@
 
 GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (width)
         *width = 0;
     if (height)
         *height = 0;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _glfw.platform.getFramebufferSize(window, width, height);
 }
 
@@ -723,9 +731,6 @@
                                     int* left, int* top,
                                     int* right, int* bottom)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (left)
         *left = 0;
     if (top)
@@ -736,44 +741,51 @@
         *bottom = 0;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _glfw.platform.getWindowFrameSize(window, left, top, right, bottom);
 }
 
 GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle,
                                        float* xscale, float* yscale)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-
     if (xscale)
         *xscale = 0.f;
     if (yscale)
         *yscale = 0.f;
 
     _GLFW_REQUIRE_INIT();
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     _glfw.platform.getWindowContentScale(window, xscale, yscale);
 }
 
 GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(0.f);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(0.f);
     return _glfw.platform.getWindowOpacity(window);
 }
 
 GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
-    assert(window != NULL);
-    assert(opacity == opacity);
+    assert(isfinite(opacity));
     assert(opacity >= 0.f);
     assert(opacity <= 1.f);
 
     _GLFW_REQUIRE_INIT();
 
-    if (opacity != opacity || opacity < 0.f || opacity > 1.f)
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    if (!isfinite(opacity) || opacity < 0.f || opacity > 1.f)
     {
         _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity);
         return;
@@ -784,29 +796,31 @@
 
 GLFWAPI void glfwIconifyWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
     _glfw.platform.iconifyWindow(window);
 }
 
 GLFWAPI void glfwRestoreWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
     _glfw.platform.restoreWindow(window);
 }
 
 GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     if (window->monitor)
         return;
 
@@ -815,11 +829,11 @@
 
 GLFWAPI void glfwShowWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     if (window->monitor)
         return;
 
@@ -831,21 +845,21 @@
 
 GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     _glfw.platform.requestWindowAttention(window);
 }
 
 GLFWAPI void glfwHideWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     if (window->monitor)
         return;
 
@@ -854,21 +868,21 @@
 
 GLFWAPI void glfwFocusWindow(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     _glfw.platform.focusWindow(window);
 }
 
 GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(0);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(0);
-
     switch (attrib)
     {
         case GLFW_FOCUSED:
@@ -927,11 +941,11 @@
 
 GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
-
     value = value ? GLFW_TRUE : GLFW_FALSE;
 
     switch (attrib)
@@ -973,10 +987,11 @@
 
 GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return (GLFWmonitor*) window->monitor;
 }
 
@@ -986,14 +1001,15 @@
                                   int width, int height,
                                   int refreshRate)
 {
-    _GLFWwindow* window = (_GLFWwindow*) wh;
-    _GLFWmonitor* monitor = (_GLFWmonitor*) mh;
-    assert(window != NULL);
     assert(width >= 0);
     assert(height >= 0);
 
     _GLFW_REQUIRE_INIT();
 
+    _GLFWwindow* window = (_GLFWwindow*) wh;
+    _GLFWmonitor* monitor = (_GLFWmonitor*) mh;
+    assert(window != NULL);
+
     if (width <= 0 || height <= 0)
     {
         _glfwInputError(GLFW_INVALID_VALUE,
@@ -1021,29 +1037,32 @@
 
 GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
 {
+    _GLFW_REQUIRE_INIT();
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT();
     window->userPointer = pointer;
 }
 
 GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     return window->userPointer;
 }
 
 GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle,
                                                   GLFWwindowposfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowposfun, window->callbacks.pos, cbfun);
     return cbfun;
 }
@@ -1051,10 +1070,11 @@
 GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle,
                                                     GLFWwindowsizefun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowsizefun, window->callbacks.size, cbfun);
     return cbfun;
 }
@@ -1062,10 +1082,11 @@
 GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle,
                                                       GLFWwindowclosefun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowclosefun, window->callbacks.close, cbfun);
     return cbfun;
 }
@@ -1073,10 +1094,11 @@
 GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle,
                                                           GLFWwindowrefreshfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowrefreshfun, window->callbacks.refresh, cbfun);
     return cbfun;
 }
@@ -1084,10 +1106,11 @@
 GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle,
                                                       GLFWwindowfocusfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowfocusfun, window->callbacks.focus, cbfun);
     return cbfun;
 }
@@ -1095,10 +1118,11 @@
 GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle,
                                                           GLFWwindowiconifyfun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowiconifyfun, window->callbacks.iconify, cbfun);
     return cbfun;
 }
@@ -1106,10 +1130,11 @@
 GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle,
                                                             GLFWwindowmaximizefun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowmaximizefun, window->callbacks.maximize, cbfun);
     return cbfun;
 }
@@ -1117,10 +1142,11 @@
 GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle,
                                                               GLFWframebuffersizefun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWframebuffersizefun, window->callbacks.fbsize, cbfun);
     return cbfun;
 }
@@ -1128,10 +1154,11 @@
 GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle,
                                                                     GLFWwindowcontentscalefun cbfun)
 {
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+
     _GLFWwindow* window = (_GLFWwindow*) handle;
     assert(window != NULL);
 
-    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
     _GLFW_SWAP(GLFWwindowcontentscalefun, window->callbacks.scale, cbfun);
     return cbfun;
 }
@@ -1151,11 +1178,10 @@
 GLFWAPI void glfwWaitEventsTimeout(double timeout)
 {
     _GLFW_REQUIRE_INIT();
-    assert(timeout == timeout);
+    assert(isfinite(timeout));
     assert(timeout >= 0.0);
-    assert(timeout <= DBL_MAX);
 
-    if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX)
+    if (!isfinite(timeout) || timeout < 0.0)
     {
         _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout);
         return;
diff --git a/raylib/src/external/glfw/src/wl_init.c b/raylib/src/external/glfw/src/wl_init.c
--- a/raylib/src/external/glfw/src/wl_init.c
+++ b/raylib/src/external/glfw/src/wl_init.c
@@ -1,8 +1,7 @@
 //========================================================================
-// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -136,7 +135,7 @@
         {
             _glfw.wl.seat =
                 wl_registry_bind(registry, name, &wl_seat_interface,
-                                 _glfw_min(4, version));
+                                 _glfw_min(8, version));
             _glfwAddSeatListenerWayland(_glfw.wl.seat);
         }
     }
@@ -245,10 +244,7 @@
                                   uint32_t time)
 {
     _glfw.wl.libdecor.ready = GLFW_TRUE;
-
-    assert(_glfw.wl.libdecor.callback == callback);
-    wl_callback_destroy(_glfw.wl.libdecor.callback);
-    _glfw.wl.libdecor.callback = NULL;
+    wl_callback_destroy(callback);
 }
 
 static const struct wl_callback_listener libdecorReadyListener =
@@ -258,7 +254,7 @@
 
 // Create key code translation tables
 //
-static void createKeyTablesWayland(void)
+static void createKeyTables(void)
 {
     memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes));
     memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes));
@@ -579,6 +575,14 @@
         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_get_fd");
     _glfw.wl.client.display_prepare_read = (PFN_wl_display_prepare_read)
         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read");
+    _glfw.wl.client.display_create_queue = (PFN_wl_display_create_queue)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_create_queue");
+    _glfw.wl.client.display_prepare_read_queue = (PFN_wl_display_prepare_read_queue)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_prepare_read_queue");
+    _glfw.wl.client.display_dispatch_queue_pending = (PFN_wl_display_dispatch_queue_pending)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_dispatch_queue_pending");
+    _glfw.wl.client.event_queue_destroy = (PFN_wl_event_queue_destroy)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_event_queue_destroy");
     _glfw.wl.client.proxy_marshal = (PFN_wl_proxy_marshal)
         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal");
     _glfw.wl.client.proxy_add_listener = (PFN_wl_proxy_add_listener)
@@ -601,6 +605,12 @@
         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version");
     _glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags)
         _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_marshal_flags");
+    _glfw.wl.client.proxy_create_wrapper = (PFN_wl_proxy_create_wrapper)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_create_wrapper");
+    _glfw.wl.client.proxy_wrapper_destroy = (PFN_wl_proxy_wrapper_destroy)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_wrapper_destroy");
+    _glfw.wl.client.proxy_set_queue = (PFN_wl_proxy_set_queue)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_queue");
 
     if (!_glfw.wl.client.display_flush ||
         !_glfw.wl.client.display_cancel_read ||
@@ -610,6 +620,10 @@
         !_glfw.wl.client.display_roundtrip ||
         !_glfw.wl.client.display_get_fd ||
         !_glfw.wl.client.display_prepare_read ||
+        !_glfw.wl.client.display_create_queue ||
+        !_glfw.wl.client.display_prepare_read_queue ||
+        !_glfw.wl.client.display_dispatch_queue_pending ||
+        !_glfw.wl.client.event_queue_destroy ||
         !_glfw.wl.client.proxy_marshal ||
         !_glfw.wl.client.proxy_add_listener ||
         !_glfw.wl.client.proxy_destroy ||
@@ -618,7 +632,10 @@
         !_glfw.wl.client.proxy_get_user_data ||
         !_glfw.wl.client.proxy_set_user_data ||
         !_glfw.wl.client.proxy_get_tag ||
-        !_glfw.wl.client.proxy_set_tag)
+        !_glfw.wl.client.proxy_set_tag ||
+        !_glfw.wl.client.proxy_create_wrapper ||
+        !_glfw.wl.client.proxy_wrapper_destroy ||
+        !_glfw.wl.client.proxy_set_queue)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
                         "Wayland: Failed to load libwayland-client entry point");
@@ -705,6 +722,10 @@
         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_status");
     _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
         _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
+    _glfw.wl.xkb.keysym_to_utf32 = (PFN_xkb_keysym_to_utf32)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keysym_to_utf32");
+    _glfw.wl.xkb.keysym_to_utf8 = (PFN_xkb_keysym_to_utf8)
+        _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keysym_to_utf8");
 
     if (!_glfw.wl.xkb.context_new ||
         !_glfw.wl.xkb.context_unref ||
@@ -777,6 +798,8 @@
             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_capabilities");
         _glfw.wl.libdecor.libdecor_frame_set_visibility_ = (PFN_libdecor_frame_set_visibility)
             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_visibility");
+        _glfw.wl.libdecor.libdecor_frame_is_visible_ = (PFN_libdecor_frame_is_visible)
+            _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_is_visible");
         _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ = (PFN_libdecor_frame_get_xdg_toplevel)
             _glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_get_xdg_toplevel");
         _glfw.wl.libdecor.libdecor_configuration_get_content_size_ = (PFN_libdecor_configuration_get_content_size)
@@ -808,6 +831,7 @@
             !_glfw.wl.libdecor.libdecor_frame_set_capabilities_ ||
             !_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ ||
             !_glfw.wl.libdecor.libdecor_frame_set_visibility_ ||
+            !_glfw.wl.libdecor.libdecor_frame_is_visible_ ||
             !_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ ||
             !_glfw.wl.libdecor.libdecor_configuration_get_content_size_ ||
             !_glfw.wl.libdecor.libdecor_configuration_get_window_state_ ||
@@ -822,9 +846,19 @@
     _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
     wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
 
-    createKeyTablesWayland();
+    createKeyTables();
 
-    _glfw.wl.xkb.context = xkb_context_new(0);
+    _glfw.wl.keyRepeatTimerfd =
+        timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+    if (_glfw.wl.keyRepeatTimerfd == -1)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: Failed to create timerfd: %s",
+                        strerror(errno));
+        return GLFW_FALSE;
+    }
+
+    _glfw.wl.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
     if (!_glfw.wl.xkb.context)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
@@ -847,19 +881,11 @@
             libdecor_dispatch(_glfw.wl.libdecor.context, 0);
 
             // Create sync point to "know" when libdecor is ready for use
-            _glfw.wl.libdecor.callback = wl_display_sync(_glfw.wl.display);
-            wl_callback_add_listener(_glfw.wl.libdecor.callback,
-                                     &libdecorReadyListener,
-                                     NULL);
+            struct wl_callback* callback = wl_display_sync(_glfw.wl.display);
+            wl_callback_add_listener(callback, &libdecorReadyListener, NULL);
         }
     }
 
-    if (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
-    {
-        _glfw.wl.keyRepeatTimerfd =
-            timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
-    }
-
     if (!_glfw.wl.wmBase)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
@@ -903,18 +929,6 @@
         libdecor_unref(_glfw.wl.libdecor.context);
     }
 
-    if (_glfw.wl.libdecor.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
-        _glfw.wl.libdecor.handle = NULL;
-    }
-
-    if (_glfw.wl.egl.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.wl.egl.handle);
-        _glfw.wl.egl.handle = NULL;
-    }
-
     if (_glfw.wl.xkb.composeState)
         xkb_compose_state_unref(_glfw.wl.xkb.composeState);
     if (_glfw.wl.xkb.keymap)
@@ -923,21 +937,11 @@
         xkb_state_unref(_glfw.wl.xkb.state);
     if (_glfw.wl.xkb.context)
         xkb_context_unref(_glfw.wl.xkb.context);
-    if (_glfw.wl.xkb.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.wl.xkb.handle);
-        _glfw.wl.xkb.handle = NULL;
-    }
 
     if (_glfw.wl.cursorTheme)
         wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
     if (_glfw.wl.cursorThemeHiDPI)
         wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
-    if (_glfw.wl.cursor.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.wl.cursor.handle);
-        _glfw.wl.cursor.handle = NULL;
-    }
 
     for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
         wl_data_offer_destroy(_glfw.wl.offers[i].offer);
@@ -997,7 +1001,18 @@
     if (_glfw.wl.cursorTimerfd >= 0)
         close(_glfw.wl.cursorTimerfd);
 
+    // Free modules only after all Wayland termination functions are called
+
+    _glfwPlatformFreeModule(_glfw.egl.handle);
+    _glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
+    _glfwPlatformFreeModule(_glfw.wl.egl.handle);
+    _glfwPlatformFreeModule(_glfw.wl.xkb.handle);
+    _glfwPlatformFreeModule(_glfw.wl.cursor.handle);
+    _glfwPlatformFreeModule(_glfw.wl.client.handle);
+
     _glfw_free(_glfw.wl.clipboardString);
+
+    memset(&_glfw.wl, 0, sizeof(_glfw.wl));
 }
 
 #endif // _GLFW_WAYLAND
diff --git a/raylib/src/external/glfw/src/wl_monitor.c b/raylib/src/external/glfw/src/wl_monitor.c
--- a/raylib/src/external/glfw/src/wl_monitor.c
+++ b/raylib/src/external/glfw/src/wl_monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Wayland - www.glfw.org
+// GLFW 3.5 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <errno.h>
 #include <math.h>
+#include <assert.h>
 
 #include "wayland-client-protocol.h"
 
@@ -258,7 +259,6 @@
 
 GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
@@ -266,6 +266,9 @@
         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Wayland: Platform not initialized");
         return NULL;
     }
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     return monitor->wl.output;
 }
diff --git a/raylib/src/external/glfw/src/wl_platform.h b/raylib/src/external/glfw/src/wl_platform.h
--- a/raylib/src/external/glfw/src/wl_platform.h
+++ b/raylib/src/external/glfw/src/wl_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 Wayland - www.glfw.org
+// GLFW 3.5 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
 //
@@ -28,8 +28,6 @@
 #include <xkbcommon/xkbcommon.h>
 #include <xkbcommon/xkbcommon-compose.h>
 
-#include <stdbool.h>
-
 typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
 
 typedef struct VkWaylandSurfaceCreateInfoKHR
@@ -44,9 +42,6 @@
 typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
 typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
 
-#include "xkb_unicode.h"
-#include "posix_poll.h"
-
 typedef int (* PFN_wl_display_flush)(struct wl_display* display);
 typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display);
 typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display* display);
@@ -56,6 +51,10 @@
 typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
 typedef int (* PFN_wl_display_get_fd)(struct wl_display*);
 typedef int (* PFN_wl_display_prepare_read)(struct wl_display*);
+typedef struct wl_event_queue* (* PFN_wl_display_create_queue)(struct wl_display*);
+typedef void (* PFN_wl_event_queue_destroy)(struct wl_event_queue*);
+typedef int (* PFN_wl_display_prepare_read_queue)(struct wl_display*,struct wl_event_queue*);
+typedef int (* PFN_wl_display_dispatch_queue_pending)(struct wl_display*,struct wl_event_queue*);
 typedef void (* PFN_wl_proxy_marshal)(struct wl_proxy*,uint32_t,...);
 typedef int (* PFN_wl_proxy_add_listener)(struct wl_proxy*,void(**)(void),void*);
 typedef void (* PFN_wl_proxy_destroy)(struct wl_proxy*);
@@ -67,6 +66,9 @@
 typedef const char* const* (* PFN_wl_proxy_get_tag)(struct wl_proxy*);
 typedef uint32_t (* PFN_wl_proxy_get_version)(struct wl_proxy*);
 typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,uint32_t,...);
+typedef void* (* PFN_wl_proxy_create_wrapper)(void*);
+typedef void (* PFN_wl_proxy_wrapper_destroy)(void*);
+typedef void (* PFN_wl_proxy_set_queue)(struct wl_proxy*,struct wl_event_queue*);
 #define wl_display_flush _glfw.wl.client.display_flush
 #define wl_display_cancel_read _glfw.wl.client.display_cancel_read
 #define wl_display_dispatch_pending _glfw.wl.client.display_dispatch_pending
@@ -75,6 +77,10 @@
 #define wl_display_roundtrip _glfw.wl.client.display_roundtrip
 #define wl_display_get_fd _glfw.wl.client.display_get_fd
 #define wl_display_prepare_read _glfw.wl.client.display_prepare_read
+#define wl_display_create_queue _glfw.wl.client.display_create_queue
+#define wl_display_prepare_read_queue _glfw.wl.client.display_prepare_read_queue
+#define wl_display_dispatch_queue_pending _glfw.wl.client.display_dispatch_queue_pending
+#define wl_event_queue_destroy _glfw.wl.client.event_queue_destroy
 #define wl_proxy_marshal _glfw.wl.client.proxy_marshal
 #define wl_proxy_add_listener _glfw.wl.client.proxy_add_listener
 #define wl_proxy_destroy _glfw.wl.client.proxy_destroy
@@ -86,6 +92,9 @@
 #define wl_proxy_set_tag _glfw.wl.client.proxy_set_tag
 #define wl_proxy_get_version _glfw.wl.client.proxy_get_version
 #define wl_proxy_marshal_flags _glfw.wl.client.proxy_marshal_flags
+#define wl_proxy_create_wrapper _glfw.wl.client.proxy_create_wrapper
+#define wl_proxy_wrapper_destroy _glfw.wl.client.proxy_wrapper_destroy
+#define wl_proxy_set_queue _glfw.wl.client.proxy_set_queue
 
 struct wl_shm;
 struct wl_output;
@@ -139,18 +148,22 @@
 #define GLFW_WAYLAND_MONITOR_STATE        _GLFWmonitorWayland wl;
 #define GLFW_WAYLAND_CURSOR_STATE         _GLFWcursorWayland  wl;
 
-struct wl_cursor_image {
+struct wl_cursor_image
+{
     uint32_t width;
     uint32_t height;
     uint32_t hotspot_x;
     uint32_t hotspot_y;
     uint32_t delay;
 };
-struct wl_cursor {
+
+struct wl_cursor
+{
     unsigned int image_count;
     struct wl_cursor_image** images;
     char* name;
 };
+
 typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
 typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
 typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
@@ -180,6 +193,8 @@
 typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
 typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t);
 typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component);
+typedef uint32_t (* PFN_xkb_keysym_to_utf32)(xkb_keysym_t);
+typedef int (* PFN_xkb_keysym_to_utf8)(xkb_keysym_t, char*, size_t);
 #define xkb_context_new _glfw.wl.xkb.context_new
 #define xkb_context_unref _glfw.wl.xkb.context_unref
 #define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string
@@ -193,6 +208,8 @@
 #define xkb_state_update_mask _glfw.wl.xkb.state_update_mask
 #define xkb_state_key_get_layout _glfw.wl.xkb.state_key_get_layout
 #define xkb_state_mod_index_is_active _glfw.wl.xkb.state_mod_index_is_active
+#define xkb_keysym_to_utf32 _glfw.wl.xkb.keysym_to_utf32
+#define xkb_keysym_to_utf8 _glfw.wl.xkb.keysym_to_utf8
 
 typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
 typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*);
@@ -216,62 +233,62 @@
 
 enum libdecor_error
 {
-	LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
-	LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,
+    LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
+    LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,
 };
 
 enum libdecor_window_state
 {
-	LIBDECOR_WINDOW_STATE_NONE = 0,
-	LIBDECOR_WINDOW_STATE_ACTIVE = 1,
-	LIBDECOR_WINDOW_STATE_MAXIMIZED = 2,
-	LIBDECOR_WINDOW_STATE_FULLSCREEN = 4,
-	LIBDECOR_WINDOW_STATE_TILED_LEFT = 8,
-	LIBDECOR_WINDOW_STATE_TILED_RIGHT = 16,
-	LIBDECOR_WINDOW_STATE_TILED_TOP = 32,
-	LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 64
+    LIBDECOR_WINDOW_STATE_NONE = 0,
+    LIBDECOR_WINDOW_STATE_ACTIVE = 1,
+    LIBDECOR_WINDOW_STATE_MAXIMIZED = 2,
+    LIBDECOR_WINDOW_STATE_FULLSCREEN = 4,
+    LIBDECOR_WINDOW_STATE_TILED_LEFT = 8,
+    LIBDECOR_WINDOW_STATE_TILED_RIGHT = 16,
+    LIBDECOR_WINDOW_STATE_TILED_TOP = 32,
+    LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 64
 };
 
 enum libdecor_capabilities
 {
-	LIBDECOR_ACTION_MOVE = 1,
-	LIBDECOR_ACTION_RESIZE = 2,
-	LIBDECOR_ACTION_MINIMIZE = 4,
-	LIBDECOR_ACTION_FULLSCREEN = 8,
-	LIBDECOR_ACTION_CLOSE = 16
+    LIBDECOR_ACTION_MOVE = 1,
+    LIBDECOR_ACTION_RESIZE = 2,
+    LIBDECOR_ACTION_MINIMIZE = 4,
+    LIBDECOR_ACTION_FULLSCREEN = 8,
+    LIBDECOR_ACTION_CLOSE = 16
 };
 
 struct libdecor_interface
 {
-	void (* error)(struct libdecor*,enum libdecor_error,const char*);
-	void (* reserved0)(void);
-	void (* reserved1)(void);
-	void (* reserved2)(void);
-	void (* reserved3)(void);
-	void (* reserved4)(void);
-	void (* reserved5)(void);
-	void (* reserved6)(void);
-	void (* reserved7)(void);
-	void (* reserved8)(void);
-	void (* reserved9)(void);
+    void (* error)(struct libdecor*,enum libdecor_error,const char*);
+    void (* reserved0)(void);
+    void (* reserved1)(void);
+    void (* reserved2)(void);
+    void (* reserved3)(void);
+    void (* reserved4)(void);
+    void (* reserved5)(void);
+    void (* reserved6)(void);
+    void (* reserved7)(void);
+    void (* reserved8)(void);
+    void (* reserved9)(void);
 };
 
 struct libdecor_frame_interface
 {
-	void (* configure)(struct libdecor_frame*,struct libdecor_configuration*,void*);
-	void (* close)(struct libdecor_frame*,void*);
-	void (* commit)(struct libdecor_frame*,void*);
-	void (* dismiss_popup)(struct libdecor_frame*,const char*,void*);
-	void (* reserved0)(void);
-	void (* reserved1)(void);
-	void (* reserved2)(void);
-	void (* reserved3)(void);
-	void (* reserved4)(void);
-	void (* reserved5)(void);
-	void (* reserved6)(void);
-	void (* reserved7)(void);
-	void (* reserved8)(void);
-	void (* reserved9)(void);
+    void (* configure)(struct libdecor_frame*,struct libdecor_configuration*,void*);
+    void (* close)(struct libdecor_frame*,void*);
+    void (* commit)(struct libdecor_frame*,void*);
+    void (* dismiss_popup)(struct libdecor_frame*,const char*,void*);
+    void (* reserved0)(void);
+    void (* reserved1)(void);
+    void (* reserved2)(void);
+    void (* reserved3)(void);
+    void (* reserved4)(void);
+    void (* reserved5)(void);
+    void (* reserved6)(void);
+    void (* reserved7)(void);
+    void (* reserved8)(void);
+    void (* reserved9)(void);
 };
 
 typedef struct libdecor* (* PFN_libdecor_new)(struct wl_display*,const struct libdecor_interface*);
@@ -294,6 +311,7 @@
 typedef void (* PFN_libdecor_frame_set_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);
 typedef void (* PFN_libdecor_frame_unset_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);
 typedef void (* PFN_libdecor_frame_set_visibility)(struct libdecor_frame*,bool visible);
+typedef bool (* PFN_libdecor_frame_is_visible)(struct libdecor_frame*);
 typedef struct xdg_toplevel* (* PFN_libdecor_frame_get_xdg_toplevel)(struct libdecor_frame*);
 typedef bool (* PFN_libdecor_configuration_get_content_size)(struct libdecor_configuration*,struct libdecor_frame*,int*,int*);
 typedef bool (* PFN_libdecor_configuration_get_window_state)(struct libdecor_configuration*,enum libdecor_window_state*);
@@ -319,6 +337,7 @@
 #define libdecor_frame_set_capabilities _glfw.wl.libdecor.libdecor_frame_set_capabilities_
 #define libdecor_frame_unset_capabilities _glfw.wl.libdecor.libdecor_frame_unset_capabilities_
 #define libdecor_frame_set_visibility _glfw.wl.libdecor.libdecor_frame_set_visibility_
+#define libdecor_frame_is_visible _glfw.wl.libdecor.libdecor_frame_is_visible_
 #define libdecor_frame_get_xdg_toplevel _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_
 #define libdecor_configuration_get_content_size _glfw.wl.libdecor.libdecor_configuration_get_content_size_
 #define libdecor_configuration_get_window_state _glfw.wl.libdecor.libdecor_configuration_get_window_state_
@@ -355,14 +374,16 @@
     GLFWbool                    maximized;
     GLFWbool                    activated;
     GLFWbool                    fullscreen;
-    GLFWbool                    hovered;
     GLFWbool                    transparent;
     GLFWbool                    scaleFramebuffer;
     struct wl_surface*          surface;
-    struct wl_callback*         callback;
 
     struct {
+        struct wl_event_queue*  queue;
         struct wl_egl_window*   window;
+        struct wl_callback*     callback;
+        struct wl_surface*      wrapper;
+        int                     interval;
     } egl;
 
     struct {
@@ -384,7 +405,6 @@
         struct libdecor_frame*  frame;
     } libdecor;
 
-    _GLFWcursor*                currentCursor;
     double                      cursorPosX, cursorPosY;
 
     char*                       appId;
@@ -411,7 +431,9 @@
         GLFWbool                    decorations;
         struct wl_buffer*           buffer;
         _GLFWfallbackEdgeWayland    top, left, right, bottom;
-        struct wl_surface*          focus;
+        double                      pointerX, pointerY;
+        uint32_t                    buttonPressSerial;
+        const char*                 cursorName;
     } fallback;
 } _GLFWwindowWayland;
 
@@ -450,10 +472,10 @@
 
     const char*                 tag;
 
+    struct wl_surface*          pointerSurface;
     struct wl_cursor_theme*     cursorTheme;
     struct wl_cursor_theme*     cursorThemeHiDPI;
     struct wl_surface*          cursorSurface;
-    const char*                 cursorPreviousName;
     int                         cursorTimerfd;
     uint32_t                    serial;
     uint32_t                    pointerEnterSerial;
@@ -469,6 +491,19 @@
     char                        keynames[GLFW_KEY_LAST + 1][5];
 
     struct {
+        struct wl_surface*      pointerSurface;
+        unsigned int            events;
+        double                  pointerX;
+        double                  pointerY;
+        double                  scrollX;
+        double                  scrollY;
+        double                  discreteX;
+        double                  discreteY;
+        int                     button;
+        int                     action;
+    } pending;
+
+    struct {
         void*                   handle;
         struct xkb_context*     context;
         struct xkb_keymap*      keymap;
@@ -497,6 +532,8 @@
         PFN_xkb_state_update_mask state_update_mask;
         PFN_xkb_state_key_get_layout state_key_get_layout;
         PFN_xkb_state_mod_index_is_active state_mod_index_is_active;
+        PFN_xkb_keysym_to_utf32 keysym_to_utf32;
+        PFN_xkb_keysym_to_utf8 keysym_to_utf8;
 
         PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
         PFN_xkb_compose_table_unref compose_table_unref;
@@ -507,7 +544,6 @@
         PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym;
     } xkb;
 
-    _GLFWwindow*                pointerFocus;
     _GLFWwindow*                keyboardFocus;
 
     struct {
@@ -520,6 +556,10 @@
         PFN_wl_display_roundtrip                    display_roundtrip;
         PFN_wl_display_get_fd                       display_get_fd;
         PFN_wl_display_prepare_read                 display_prepare_read;
+        PFN_wl_display_create_queue                 display_create_queue;
+        PFN_wl_display_prepare_read_queue           display_prepare_read_queue;
+        PFN_wl_display_dispatch_queue_pending       display_dispatch_queue_pending;
+        PFN_wl_event_queue_destroy                  event_queue_destroy;
         PFN_wl_proxy_marshal                        proxy_marshal;
         PFN_wl_proxy_add_listener                   proxy_add_listener;
         PFN_wl_proxy_destroy                        proxy_destroy;
@@ -531,6 +571,9 @@
         PFN_wl_proxy_set_tag                        proxy_set_tag;
         PFN_wl_proxy_get_version                    proxy_get_version;
         PFN_wl_proxy_marshal_flags                  proxy_marshal_flags;
+        PFN_wl_proxy_create_wrapper                 proxy_create_wrapper;
+        PFN_wl_proxy_wrapper_destroy                proxy_wrapper_destroy;
+        PFN_wl_proxy_set_queue                      proxy_set_queue;
     } client;
 
     struct {
@@ -553,7 +596,6 @@
     struct {
         void*                   handle;
         struct libdecor*        context;
-        struct wl_callback*     callback;
         GLFWbool                ready;
         PFN_libdecor_new        libdecor_new_;
         PFN_libdecor_unref      libdecor_unref_;
@@ -575,6 +617,7 @@
         PFN_libdecor_frame_set_capabilities libdecor_frame_set_capabilities_;
         PFN_libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_;
         PFN_libdecor_frame_set_visibility libdecor_frame_set_visibility_;
+        PFN_libdecor_frame_is_visible libdecor_frame_is_visible_;
         PFN_libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_;
         PFN_libdecor_configuration_get_content_size libdecor_configuration_get_content_size_;
         PFN_libdecor_configuration_get_window_state libdecor_configuration_get_window_state_;
@@ -688,4 +731,6 @@
 
 void _glfwAddSeatListenerWayland(struct wl_seat* seat);
 void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
+
+GLFWbool _glfwWaitForEGLFrameWayland(_GLFWwindow* window);
 
diff --git a/raylib/src/external/glfw/src/wl_window.c b/raylib/src/external/glfw/src/wl_window.c
--- a/raylib/src/external/glfw/src/wl_window.c
+++ b/raylib/src/external/glfw/src/wl_window.c
@@ -1,8 +1,7 @@
 //========================================================================
-// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 Wayland - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -25,7 +24,9 @@
 //
 //========================================================================
 
-#define _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
+ #define _GNU_SOURCE
+#endif
 
 #include "internal.h"
 
@@ -56,6 +57,12 @@
 #define GLFW_BORDER_SIZE    4
 #define GLFW_CAPTION_HEIGHT 24
 
+#define GLFW_PENDING_SURFACE    1
+#define GLFW_PENDING_BUTTON     2
+#define GLFW_PENDING_MOTION     4
+#define GLFW_PENDING_SCROLL     8
+#define GLFW_PENDING_DISCRETE   16
+
 static int createTmpfileCloexec(char* tmpname)
 {
     int fd;
@@ -194,6 +201,16 @@
     return buffer;
 }
 
+static void callbackHandleDone(void* userData, struct wl_callback* callback, uint32_t data)
+{
+    wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener noopCallbackListener =
+{
+    callbackHandleDone
+};
+
 static void createFallbackEdge(_GLFWwindow* window,
                                _GLFWfallbackEdgeWayland* edge,
                                struct wl_surface* parent,
@@ -254,6 +271,9 @@
 
 static void destroyFallbackEdge(_GLFWfallbackEdgeWayland* edge)
 {
+    if (edge->surface == _glfw.wl.pointerSurface)
+        _glfw.wl.pointerSurface = NULL;
+
     if (edge->subsurface)
         wl_subsurface_destroy(edge->subsurface);
     if (edge->surface)
@@ -276,6 +296,148 @@
     destroyFallbackEdge(&window->wl.fallback.bottom);
 }
 
+static void updateFallbackDecorationCursor(_GLFWwindow* window, double xpos, double ypos)
+{
+    window->wl.fallback.pointerX = xpos;
+    window->wl.fallback.pointerY = ypos;
+
+    const char* cursorName = "left_ptr";
+
+    if (window->resizable)
+    {
+        if (_glfw.wl.pointerSurface == window->wl.fallback.top.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                cursorName = "n-resize";
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.left.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                cursorName = "nw-resize";
+            else
+                cursorName = "w-resize";
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.right.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                cursorName = "ne-resize";
+            else
+                cursorName = "e-resize";
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.bottom.surface)
+        {
+            if (xpos < GLFW_BORDER_SIZE)
+                cursorName = "sw-resize";
+            else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
+                cursorName = "se-resize";
+            else
+                cursorName = "s-resize";
+        }
+    }
+
+    if (window->wl.fallback.cursorName != cursorName)
+    {
+        struct wl_surface* surface = _glfw.wl.cursorSurface;
+        struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
+        int scale = 1;
+
+        if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
+        {
+            // We only support up to scale=2 for now, since libwayland-cursor
+            // requires us to load a different theme for each size.
+            scale = 2;
+            theme = _glfw.wl.cursorThemeHiDPI;
+        }
+
+        struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
+        if (!cursor)
+            return;
+
+        // TODO: handle animated cursors too.
+        struct wl_cursor_image* image = cursor->images[0];
+        if (!image)
+            return;
+
+        struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
+        if (!buffer)
+            return;
+
+        wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
+                              surface,
+                              image->hotspot_x / scale,
+                              image->hotspot_y / scale);
+        wl_surface_set_buffer_scale(surface, scale);
+        wl_surface_attach(surface, buffer, 0, 0);
+        wl_surface_damage(surface, 0, 0, image->width, image->height);
+        wl_surface_commit(surface);
+
+        window->wl.fallback.cursorName = cursorName;
+    }
+}
+
+static void handleFallbackDecorationButton(_GLFWwindow* window, int button, int action)
+{
+    if (action != GLFW_PRESS)
+        return;
+
+    const double xpos = window->wl.fallback.pointerX;
+    const double ypos = window->wl.fallback.pointerY;
+    const uint32_t serial = window->wl.fallback.buttonPressSerial;
+
+    if (button == GLFW_MOUSE_BUTTON_LEFT)
+    {
+        uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
+
+        if (_glfw.wl.pointerSurface == window->wl.fallback.top.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
+            else
+                xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.left.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
+            else
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.right.surface)
+        {
+            if (ypos < GLFW_BORDER_SIZE)
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
+            else
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
+        }
+        else if (_glfw.wl.pointerSurface == window->wl.fallback.bottom.surface)
+        {
+            if (xpos < GLFW_BORDER_SIZE)
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
+            else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
+            else
+                edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
+        }
+
+        if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
+            xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges);
+    }
+    else if (button == GLFW_MOUSE_BUTTON_RIGHT)
+    {
+        if (!window->wl.xdg.toplevel)
+            return;
+
+        if (_glfw.wl.pointerSurface != window->wl.fallback.top.surface)
+            return;
+
+        if (ypos < GLFW_BORDER_SIZE)
+            return;
+
+        xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, _glfw.wl.seat, serial,
+                                      xpos, ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE);
+    }
+}
+
 static void xdgDecorationHandleConfigure(void* userData,
                                          struct zxdg_toplevel_decoration_v1* decoration,
                                          uint32_t mode)
@@ -316,8 +478,9 @@
 {
     if (window->wl.fractionalScale)
     {
-        window->wl.fbWidth = (window->wl.width * window->wl.scalingNumerator) / 120;
-        window->wl.fbHeight = (window->wl.height * window->wl.scalingNumerator) / 120;
+        // Round halfway away from zero per fractional-scale-v1 protocol spec
+        window->wl.fbWidth = (window->wl.width * window->wl.scalingNumerator + 60) / 120;
+        window->wl.fbHeight = (window->wl.height * window->wl.scalingNumerator + 60) / 120;
     }
     else
     {
@@ -499,7 +662,7 @@
 
 // Make the specified window and its video mode active on its monitor
 //
-static void acquireMonitorWayland(_GLFWwindow* window)
+static void acquireMonitor(_GLFWwindow* window)
 {
     if (window->wl.libdecor.frame)
     {
@@ -520,7 +683,7 @@
 
 // Remove the window and restore the original video mode
 //
-static void releaseMonitorWayland(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
     if (window->wl.libdecor.frame)
         libdecor_frame_unset_fullscreen(window->wl.libdecor.frame);
@@ -734,6 +897,10 @@
     libdecor_frame_commit(frame, frameState, config);
     libdecor_state_free(frameState);
 
+    // NOTE: Frame visibility must only be set after a frame state has been committed
+    if (window->decorated != libdecor_frame_is_visible(window->wl.libdecor.frame))
+        libdecor_frame_set_visibility(window->wl.libdecor.frame, window->decorated);
+
     if (window->wl.activated != activated)
     {
         window->wl.activated = activated;
@@ -815,36 +982,39 @@
         return GLFW_FALSE;
     }
 
-    struct libdecor_state* frameState =
-        libdecor_state_new(window->wl.width, window->wl.height);
-    libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
-    libdecor_state_free(frameState);
-
     if (strlen(window->wl.appId))
         libdecor_frame_set_app_id(window->wl.libdecor.frame, window->wl.appId);
 
     libdecor_frame_set_title(window->wl.libdecor.frame, window->title);
 
-    if (window->minwidth != GLFW_DONT_CARE &&
-        window->minheight != GLFW_DONT_CARE)
+    if (window->resizable)
     {
-        libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
-                                            window->minwidth,
-                                            window->minheight);
-    }
+        if (window->minwidth != GLFW_DONT_CARE &&
+            window->minheight != GLFW_DONT_CARE)
+        {
+            libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
+                                                window->minwidth,
+                                                window->minheight);
+        }
 
-    if (window->maxwidth != GLFW_DONT_CARE &&
-        window->maxheight != GLFW_DONT_CARE)
-    {
-        libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
-                                            window->maxwidth,
-                                            window->maxheight);
+        if (window->maxwidth != GLFW_DONT_CARE &&
+            window->maxheight != GLFW_DONT_CARE)
+        {
+            libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
+                                                window->maxwidth,
+                                                window->maxheight);
+        }
     }
-
-    if (!window->resizable)
+    else
     {
         libdecor_frame_unset_capabilities(window->wl.libdecor.frame,
                                           LIBDECOR_ACTION_RESIZE);
+        libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
+                                            window->wl.width,
+                                            window->wl.height);
+        libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
+                                            window->wl.width,
+                                            window->wl.height);
     }
 
     if (window->monitor)
@@ -855,12 +1025,11 @@
     }
     else
     {
+        // Frame visibility is applied in libdecorFrameHandleConfigure
+
         if (window->wl.maximized)
             libdecor_frame_set_maximized(window->wl.libdecor.frame);
 
-        if (!window->decorated)
-            libdecor_frame_set_visibility(window->wl.libdecor.frame, false);
-
         setIdleInhibitor(window, GLFW_FALSE);
     }
 
@@ -1122,14 +1291,16 @@
     wl_surface_commit(surface);
 }
 
-static void incrementCursorImage(_GLFWwindow* window)
+static void incrementCursorImage(void)
 {
-    _GLFWcursor* cursor;
+    if (!_glfw.wl.pointerSurface)
+        return;
 
-    if (!window || !window->wl.hovered)
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
+    if (window->wl.surface != _glfw.wl.pointerSurface)
         return;
 
-    cursor = window->wl.currentCursor;
+    _GLFWcursor* cursor = window->cursor;
     if (cursor && cursor->wl.cursor)
     {
         cursor->wl.currentImage += 1;
@@ -1157,7 +1328,7 @@
     return GLFW_TRUE;
 }
 
-static int translateKeyWayland(uint32_t scancode)
+static int translateKey(uint32_t scancode)
 {
     if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
         return _glfw.wl.keycodes[scancode];
@@ -1193,8 +1364,8 @@
     if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)
     {
         const xkb_keysym_t keysym = composeSymbol(keysyms[0]);
-        const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
-        if (codepoint != GLFW_INVALID_CODEPOINT)
+        const uint32_t codepoint = xkb_keysym_to_utf32(keysym);
+        if (codepoint != 0)
         {
             const int mods = _glfw.wl.xkb.modifiers;
             const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
@@ -1211,24 +1382,27 @@
 #endif
 
     GLFWbool event = GLFW_FALSE;
-    enum { DISPLAY_FD, KEYREPEAT_FD, CURSOR_FD, LIBDECOR_FD };
+    enum { DISPLAY_FD, KEYREPEAT_FD, CURSOR_FD };
     struct pollfd fds[] =
     {
         [DISPLAY_FD] = { wl_display_get_fd(_glfw.wl.display), POLLIN },
         [KEYREPEAT_FD] = { _glfw.wl.keyRepeatTimerfd, POLLIN },
-        [CURSOR_FD] = { _glfw.wl.cursorTimerfd, POLLIN },
-        [LIBDECOR_FD] = { -1, POLLIN }
+        [CURSOR_FD] = { _glfw.wl.cursorTimerfd, POLLIN }
     };
 
-    if (_glfw.wl.libdecor.context)
-        fds[LIBDECOR_FD].fd = libdecor_get_fd(_glfw.wl.libdecor.context);
-
     while (!event)
     {
+        if (_glfw.wl.libdecor.context)
+        {
+            // Dispatch unconditionally because it also processes non-Wayland events
+            if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0)
+                event = GLFW_TRUE;
+        }
+
         while (wl_display_prepare_read(_glfw.wl.display) != 0)
         {
             if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
-                return;
+                event = GLFW_TRUE;
         }
 
         // If an error other than EAGAIN happens, we have likely been disconnected
@@ -1247,6 +1421,11 @@
             return;
         }
 
+        double immediate = 0.0;
+
+        if (event)
+            timeout = &immediate;
+
         if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout))
         {
             wl_display_cancel_read(_glfw.wl.display);
@@ -1268,17 +1447,21 @@
 
             if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8)
             {
-                for (uint64_t i = 0; i < repeats; i++)
+                if (_glfw.wl.keyboardFocus)
                 {
-                    _glfwInputKey(_glfw.wl.keyboardFocus,
-                                  translateKeyWayland(_glfw.wl.keyRepeatScancode),
-                                  _glfw.wl.keyRepeatScancode,
-                                  GLFW_PRESS,
-                                  _glfw.wl.xkb.modifiers);
-                    inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode);
+                    for (uint64_t i = 0; i < repeats; i++)
+                    {
+                        _glfwInputKey(_glfw.wl.keyboardFocus,
+                                      translateKey(_glfw.wl.keyRepeatScancode),
+                                      _glfw.wl.keyRepeatScancode,
+                                      GLFW_PRESS,
+                                      _glfw.wl.xkb.modifiers);
+                        inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode);
+                    }
+
+                    event = GLFW_TRUE;
                 }
 
-                event = GLFW_TRUE;
             }
         }
 
@@ -1287,13 +1470,7 @@
             uint64_t repeats;
 
             if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
-                incrementCursorImage(_glfw.wl.pointerFocus);
-        }
-
-        if (fds[LIBDECOR_FD].revents & POLLIN)
-        {
-            if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0)
-                event = GLFW_TRUE;
+                incrementCursorImage();
         }
     }
 }
@@ -1330,6 +1507,7 @@
             if (!longer)
             {
                 _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
+                _glfw_free(string);
                 close(fds[0]);
                 return NULL;
             }
@@ -1349,6 +1527,7 @@
             _glfwInputError(GLFW_PLATFORM_ERROR,
                             "Wayland: Failed to read from data offer pipe: %s",
                             strerror(errno));
+            _glfw_free(string);
             close(fds[0]);
             return NULL;
         }
@@ -1362,6 +1541,70 @@
     return string;
 }
 
+static void processPointerEnterSurface(struct wl_surface* surface)
+{
+    _glfw.wl.pointerSurface = surface;
+
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
+    if (window->wl.surface == _glfw.wl.pointerSurface)
+    {
+        _glfwSetCursorWayland(window, window->cursor);
+        _glfwInputCursorEnter(window, GLFW_TRUE);
+    }
+}
+
+static void processPointerLeaveSurface(struct wl_surface* surface)
+{
+    _glfw.wl.pointerSurface = NULL;
+
+    _GLFWwindow* window = wl_surface_get_user_data(surface);
+    if (window->wl.surface == surface)
+        _glfwInputCursorEnter(window, GLFW_FALSE);
+    else
+    {
+        if (window->wl.fallback.decorations)
+            window->wl.fallback.cursorName = NULL;
+    }
+}
+
+static void processPointerMotion(double xpos, double ypos)
+{
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
+    if (window->wl.surface == _glfw.wl.pointerSurface)
+    {
+        if (window->cursorMode != GLFW_CURSOR_DISABLED)
+        {
+            window->wl.cursorPosX = xpos;
+            window->wl.cursorPosY = ypos;
+            _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
+        }
+    }
+    else
+    {
+        if (window->wl.fallback.decorations)
+            updateFallbackDecorationCursor(window, xpos, ypos);
+    }
+}
+
+static void processPointerButton(int button, int action)
+{
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
+    if (window->wl.surface == _glfw.wl.pointerSurface)
+        _glfwInputMouseClick(window, button, action, _glfw.wl.xkb.modifiers);
+    else
+    {
+        if (window->wl.fallback.decorations)
+            handleFallbackDecorationButton(window, button, action);
+    }
+}
+
+static void processPointerScroll(double xoffset, double yoffset)
+{
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
+    if (window->wl.surface == _glfw.wl.pointerSurface)
+        _glfwInputScroll(window, xoffset, yoffset);
+}
+
 static void pointerHandleEnter(void* userData,
                                struct wl_pointer* pointer,
                                uint32_t serial,
@@ -1376,22 +1619,23 @@
     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
         return;
 
-    _GLFWwindow* window = wl_surface_get_user_data(surface);
-
     _glfw.wl.serial = serial;
     _glfw.wl.pointerEnterSerial = serial;
-    _glfw.wl.pointerFocus = window;
 
-    if (surface == window->wl.surface)
+    const double xpos = wl_fixed_to_double(sx);
+    const double ypos = wl_fixed_to_double(sy);
+
+    if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
     {
-        window->wl.hovered = GLFW_TRUE;
-        _glfwSetCursorWayland(window, window->wl.currentCursor);
-        _glfwInputCursorEnter(window, GLFW_TRUE);
+        _glfw.wl.pending.events |= (GLFW_PENDING_SURFACE | GLFW_PENDING_MOTION);
+        _glfw.wl.pending.pointerSurface = surface;
+        _glfw.wl.pending.pointerX = xpos;
+        _glfw.wl.pending.pointerY = ypos;
     }
     else
     {
-        if (window->wl.fallback.decorations)
-            window->wl.fallback.focus = surface;
+        processPointerEnterSurface(surface);
+        processPointerMotion(xpos, ypos);
     }
 }
 
@@ -1406,24 +1650,15 @@
     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
         return;
 
-    _GLFWwindow* window = _glfw.wl.pointerFocus;
-    if (!window)
-        return;
-
     _glfw.wl.serial = serial;
-    _glfw.wl.pointerFocus = NULL;
-    _glfw.wl.cursorPreviousName = NULL;
 
-    if (window->wl.hovered)
+    if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
     {
-        window->wl.hovered = GLFW_FALSE;
-        _glfwInputCursorEnter(window, GLFW_FALSE);
+        _glfw.wl.pending.events |= GLFW_PENDING_SURFACE;
+        _glfw.wl.pending.pointerSurface = NULL;
     }
     else
-    {
-        if (window->wl.fallback.decorations)
-            window->wl.fallback.focus = NULL;
-    }
+        processPointerLeaveSurface(surface);
 }
 
 static void pointerHandleMotion(void* userData,
@@ -1432,178 +1667,52 @@
                                 wl_fixed_t sx,
                                 wl_fixed_t sy)
 {
-    _GLFWwindow* window = _glfw.wl.pointerFocus;
-    if (!window)
-        return;
-
-    if (window->cursorMode == GLFW_CURSOR_DISABLED)
+    if (!_glfw.wl.pointerSurface)
         return;
 
     const double xpos = wl_fixed_to_double(sx);
     const double ypos = wl_fixed_to_double(sy);
-    window->wl.cursorPosX = xpos;
-    window->wl.cursorPosY = ypos;
 
-    if (window->wl.hovered)
-    {
-        _glfw.wl.cursorPreviousName = NULL;
-        _glfwInputCursorPos(window, xpos, ypos);
-        return;
-    }
-
-    if (window->wl.fallback.decorations)
+    if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
     {
-        const char* cursorName = "left_ptr";
-
-        if (window->resizable)
-        {
-            if (window->wl.fallback.focus == window->wl.fallback.top.surface)
-            {
-                if (ypos < GLFW_BORDER_SIZE)
-                    cursorName = "n-resize";
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
-            {
-                if (ypos < GLFW_BORDER_SIZE)
-                    cursorName = "nw-resize";
-                else
-                    cursorName = "w-resize";
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
-            {
-                if (ypos < GLFW_BORDER_SIZE)
-                    cursorName = "ne-resize";
-                else
-                    cursorName = "e-resize";
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
-            {
-                if (xpos < GLFW_BORDER_SIZE)
-                    cursorName = "sw-resize";
-                else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
-                    cursorName = "se-resize";
-                else
-                    cursorName = "s-resize";
-            }
-        }
-
-        if (_glfw.wl.cursorPreviousName != cursorName)
-        {
-            struct wl_surface* surface = _glfw.wl.cursorSurface;
-            struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
-            int scale = 1;
-
-            if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
-            {
-                // We only support up to scale=2 for now, since libwayland-cursor
-                // requires us to load a different theme for each size.
-                scale = 2;
-                theme = _glfw.wl.cursorThemeHiDPI;
-            }
-
-            struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
-            if (!cursor)
-                return;
-
-            // TODO: handle animated cursors too.
-            struct wl_cursor_image* image = cursor->images[0];
-            if (!image)
-                return;
-
-            struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
-            if (!buffer)
-                return;
-
-            wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
-                                  surface,
-                                  image->hotspot_x / scale,
-                                  image->hotspot_y / scale);
-            wl_surface_set_buffer_scale(surface, scale);
-            wl_surface_attach(surface, buffer, 0, 0);
-            wl_surface_damage(surface, 0, 0, image->width, image->height);
-            wl_surface_commit(surface);
-
-            _glfw.wl.cursorPreviousName = cursorName;
-        }
+        _glfw.wl.pending.events |= GLFW_PENDING_MOTION;
+        _glfw.wl.pending.pointerX = xpos;
+        _glfw.wl.pending.pointerY = ypos;
     }
+    else
+        processPointerMotion(xpos, ypos);
 }
 
 static void pointerHandleButton(void* userData,
                                 struct wl_pointer* pointer,
                                 uint32_t serial,
                                 uint32_t time,
-                                uint32_t button,
+                                uint32_t buttonID,
                                 uint32_t state)
 {
-    _GLFWwindow* window = _glfw.wl.pointerFocus;
-    if (!window)
+    if (!_glfw.wl.pointerSurface)
         return;
 
-    if (window->wl.hovered)
-    {
-        _glfw.wl.serial = serial;
+    _glfw.wl.serial = serial;
 
-        _glfwInputMouseClick(window,
-                             button - BTN_LEFT,
-                             state == WL_POINTER_BUTTON_STATE_PRESSED,
-                             _glfw.wl.xkb.modifiers);
-        return;
-    }
+    const int button = buttonID - BTN_LEFT;
+    const int action = (state == WL_POINTER_BUTTON_STATE_PRESSED);
 
+    _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface);
     if (window->wl.fallback.decorations)
     {
-        if (button == BTN_LEFT)
-        {
-            uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
-
-            if (window->wl.fallback.focus == window->wl.fallback.top.surface)
-            {
-                if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
-                else
-                    xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
-            {
-                if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
-                else
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
-            {
-                if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
-                else
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
-            }
-            else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
-            {
-                if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
-                else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
-                else
-                    edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
-            }
+        if (action == GLFW_PRESS)
+            window->wl.fallback.buttonPressSerial = serial;
+    }
 
-            if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
-            {
-                xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
-                                    serial, edges);
-            }
-        }
-        else if (button == BTN_RIGHT)
-        {
-            if (window->wl.xdg.toplevel)
-            {
-                xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
-                                              _glfw.wl.seat, serial,
-                                              window->wl.cursorPosX,
-                                              window->wl.cursorPosY);
-            }
-        }
+    if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
+    {
+        _glfw.wl.pending.events |= GLFW_PENDING_BUTTON;
+        _glfw.wl.pending.button = button;
+        _glfw.wl.pending.action = action;
     }
+    else
+        processPointerButton(button, action);
 }
 
 static void pointerHandleAxis(void* userData,
@@ -1612,15 +1721,88 @@
                               uint32_t axis,
                               wl_fixed_t value)
 {
-    _GLFWwindow* window = _glfw.wl.pointerFocus;
-    if (!window)
+    if (!_glfw.wl.pointerSurface)
         return;
 
-    // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
+    if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION)
+    {
+        _glfw.wl.pending.events |= GLFW_PENDING_SCROLL;
+        if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
+            _glfw.wl.pending.scrollX = -wl_fixed_to_double(value) / 10.0;
+        else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+            _glfw.wl.pending.scrollY = -wl_fixed_to_double(value) / 10.0;
+    }
+    else
+    {
+        // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
+        if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
+            processPointerScroll(-wl_fixed_to_double(value) / 10.0, 0.0);
+        else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+            processPointerScroll(0.0, -wl_fixed_to_double(value) / 10.0);
+    }
+}
+
+static void pointerHandleFrame(void* userData, struct wl_pointer* pointer)
+{
+    if (_glfw.wl.pending.events & GLFW_PENDING_SURFACE)
+    {
+        if (_glfw.wl.pointerSurface)
+            processPointerLeaveSurface(_glfw.wl.pointerSurface);
+
+        if (_glfw.wl.pending.pointerSurface)
+            processPointerEnterSurface(_glfw.wl.pending.pointerSurface);
+    }
+
+    if (!_glfw.wl.pointerSurface)
+        return;
+
+    if (_glfw.wl.pending.events & GLFW_PENDING_MOTION)
+        processPointerMotion(_glfw.wl.pending.pointerX, _glfw.wl.pending.pointerY);
+
+    if (_glfw.wl.pending.events & GLFW_PENDING_BUTTON)
+        processPointerButton(_glfw.wl.pending.button, _glfw.wl.pending.action);
+
+    if (_glfw.wl.pending.events & GLFW_PENDING_DISCRETE)
+        processPointerScroll(_glfw.wl.pending.discreteX, _glfw.wl.pending.discreteY);
+    else if (_glfw.wl.pending.events & GLFW_PENDING_SCROLL)
+        processPointerScroll(_glfw.wl.pending.scrollX, _glfw.wl.pending.scrollY);
+
+    memset(&_glfw.wl.pending, 0, sizeof(_glfw.wl.pending));
+}
+
+static void pointerHandleAxisSource(void* userData,
+                                    struct wl_pointer* pointer,
+                                    uint32_t axisSource)
+{
+}
+
+static void pointerHandleAxisStop(void* userData,
+                                  struct wl_pointer* pointer,
+                                  uint32_t time,
+                                  uint32_t axis)
+{
+}
+
+static void pointerHandleAxisDiscrete(void* userData,
+                                      struct wl_pointer* pointer,
+                                      uint32_t axis,
+                                      int32_t discrete)
+{
+}
+
+static void pointerHandleAxisValue120(void* data,
+                                      struct wl_pointer* pointer,
+                                      uint32_t axis,
+                                      int32_t value120)
+{
+    if (!_glfw.wl.pointerSurface)
+        return;
+
+    _glfw.wl.pending.events |= GLFW_PENDING_DISCRETE;
     if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
-        _glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0);
+        _glfw.wl.pending.discreteX = -(value120 / 120.0);
     else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
-        _glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0);
+        _glfw.wl.pending.discreteY = -(value120 / 120.0);
 }
 
 static const struct wl_pointer_listener pointerListener =
@@ -1630,6 +1812,11 @@
     pointerHandleMotion,
     pointerHandleButton,
     pointerHandleAxis,
+    pointerHandleFrame,
+    pointerHandleAxisSource,
+    pointerHandleAxisStop,
+    pointerHandleAxisDiscrete,
+    pointerHandleAxisValue120
 };
 
 static void keyboardHandleKeymap(void* userData,
@@ -1652,8 +1839,9 @@
         return;
     }
 
-    mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
-    if (mapStr == MAP_FAILED) {
+    mapStr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (mapStr == MAP_FAILED)
+    {
         close(fd);
         return;
     }
@@ -1661,7 +1849,7 @@
     keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
                                         mapStr,
                                         XKB_KEYMAP_FORMAT_TEXT_V1,
-                                        0);
+                                        XKB_KEYMAP_COMPILE_NO_FLAGS);
     munmap(mapStr, size);
     close(fd);
 
@@ -1774,7 +1962,7 @@
     if (!window)
         return;
 
-    const int key = translateKeyWayland(scancode);
+    const int key = translateKey(scancode);
     const int action =
         state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
 
@@ -1797,10 +1985,13 @@
 
             timer.it_value.tv_sec = _glfw.wl.keyRepeatDelay / 1000;
             timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;
+            timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
         }
     }
-
-    timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
+    else if (scancode == _glfw.wl.keyRepeatScancode)
+    {
+        timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
+    }
 
     _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);
 
@@ -1889,7 +2080,11 @@
     }
     else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
     {
-        wl_pointer_destroy(_glfw.wl.pointer);
+        if (wl_pointer_get_version(_glfw.wl.pointer) >= WL_POINTER_RELEASE_SINCE_VERSION)
+            wl_pointer_release(_glfw.wl.pointer);
+        else
+            wl_pointer_destroy(_glfw.wl.pointer);
+
         _glfw.wl.pointer = NULL;
     }
 
@@ -1897,10 +2092,21 @@
     {
         _glfw.wl.keyboard = wl_seat_get_keyboard(seat);
         wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
+
+        if (wl_keyboard_get_version(_glfw.wl.keyboard) <
+            WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
+        {
+            _glfw.wl.keyRepeatRate = 4;
+            _glfw.wl.keyRepeatDelay = 500;
+        }
     }
     else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
     {
-        wl_keyboard_destroy(_glfw.wl.keyboard);
+        if (wl_keyboard_get_version(_glfw.wl.keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
+            wl_keyboard_release(_glfw.wl.keyboard);
+        else
+            wl_keyboard_destroy(_glfw.wl.keyboard);
+
         _glfw.wl.keyboard = NULL;
     }
 }
@@ -1975,41 +2181,41 @@
         _glfw.wl.dragFocus = NULL;
     }
 
-    for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
+    unsigned int i;
+
+    for (i = 0; i < _glfw.wl.offerCount; i++)
     {
         if (_glfw.wl.offers[i].offer == offer)
-        {
-            _GLFWwindow* window = NULL;
+            break;
+    }
 
-            if (surface)
-            {
-                if (wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag)
-                    window = wl_surface_get_user_data(surface);
-            }
+    if (i == _glfw.wl.offerCount)
+        return;
 
-            if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)
+    if (surface && wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag)
+    {
+        _GLFWwindow* window = wl_surface_get_user_data(surface);
+        if (window->wl.surface == surface)
+        {
+            if (_glfw.wl.offers[i].text_uri_list)
             {
                 _glfw.wl.dragOffer = offer;
                 _glfw.wl.dragFocus = window;
                 _glfw.wl.dragSerial = serial;
-            }
 
-            _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
-            _glfw.wl.offerCount--;
-            break;
+                wl_data_offer_accept(offer, serial, "text/uri-list");
+            }
         }
     }
 
-    if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
-        return;
-
-    if (_glfw.wl.dragOffer)
-        wl_data_offer_accept(offer, serial, "text/uri-list");
-    else
+    if (!_glfw.wl.dragOffer)
     {
         wl_data_offer_accept(offer, serial, NULL);
         wl_data_offer_destroy(offer);
     }
+
+    _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
+    _glfw.wl.offerCount--;
 }
 
 static void dataDeviceHandleLeave(void* userData,
@@ -2043,15 +2249,17 @@
         int count;
         char** paths = _glfwParseUriList(string, &count);
         if (paths)
+        {
             _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths);
 
-        for (int i = 0; i < count; i++)
-            _glfw_free(paths[i]);
+            for (int i = 0; i < count; i++)
+                _glfw_free(paths[i]);
 
-        _glfw_free(paths);
-    }
+            _glfw_free(paths);
+        }
 
-    _glfw_free(string);
+        _glfw_free(string);
+    }
 }
 
 static void dataDeviceHandleSelection(void* userData,
@@ -2109,6 +2317,18 @@
     xdgActivationHandleDone
 };
 
+static void callbackHandleFrame(void* userData, struct wl_callback* callback, uint32_t data)
+{
+    _GLFWwindow* window = userData;
+    wl_callback_destroy(callback);
+    window->wl.egl.callback = NULL;
+}
+
+static const struct wl_callback_listener frameCallbackListener =
+{
+    callbackHandleFrame
+};
+
 void _glfwAddSeatListenerWayland(struct wl_seat* seat)
 {
     wl_seat_add_listener(seat, &seatListener, NULL);
@@ -2119,7 +2339,43 @@
     wl_data_device_add_listener(device, &dataDeviceListener, NULL);
 }
 
+GLFWbool _glfwWaitForEGLFrameWayland(_GLFWwindow* window)
+{
+    double timeout = 0.02;
 
+    while (window->wl.egl.callback)
+    {
+        if (wl_display_prepare_read_queue(_glfw.wl.display, window->wl.egl.queue) != 0)
+        {
+            wl_display_dispatch_queue_pending(_glfw.wl.display, window->wl.egl.queue);
+            continue;
+        }
+
+        if (!flushDisplay())
+        {
+            wl_display_cancel_read(_glfw.wl.display);
+            return GLFW_FALSE;
+        }
+
+        struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLIN };
+
+        if (!_glfwPollPOSIX(&fd, 1, &timeout))
+        {
+            wl_display_cancel_read(_glfw.wl.display);
+            return GLFW_FALSE;
+        }
+
+        wl_display_read_events(_glfw.wl.display);
+        wl_display_dispatch_queue_pending(_glfw.wl.display, window->wl.egl.queue);
+    }
+
+    window->wl.egl.callback = wl_surface_frame(window->wl.egl.wrapper);
+    wl_callback_add_listener(window->wl.egl.callback, &frameCallbackListener, window);
+
+    // If the window is hidden when the wait is over then don't swap
+    return window->wl.visible;
+}
+
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
@@ -2147,6 +2403,27 @@
                 return GLFW_FALSE;
             }
 
+            window->wl.egl.queue = wl_display_create_queue(_glfw.wl.display);
+            if (!window->wl.egl.queue)
+            {
+                _glfwInputError(GLFW_PLATFORM_ERROR,
+                                "Wayland: Failed to create EGL frame queue");
+                return GLFW_FALSE;
+            }
+
+            window->wl.egl.wrapper = wl_proxy_create_wrapper(window->wl.surface);
+            if (!window->wl.egl.wrapper)
+            {
+                _glfwInputError(GLFW_PLATFORM_ERROR,
+                                "Wayland: Failed to create surface wrapper");
+                return GLFW_FALSE;
+            }
+
+            wl_proxy_set_queue((struct wl_proxy*) window->wl.egl.wrapper,
+                               window->wl.egl.queue);
+
+            window->wl.egl.interval = 1;
+
             if (!_glfwInitEGL())
                 return GLFW_FALSE;
             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
@@ -2178,12 +2455,23 @@
 
 void _glfwDestroyWindowWayland(_GLFWwindow* window)
 {
-    if (window == _glfw.wl.pointerFocus)
-        _glfw.wl.pointerFocus = NULL;
+    if (window->wl.surface == _glfw.wl.pointerSurface)
+        _glfw.wl.pointerSurface = NULL;
 
     if (window == _glfw.wl.keyboardFocus)
+    {
+        struct itimerspec timer = {0};
+        timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
+
         _glfw.wl.keyboardFocus = NULL;
+    }
 
+    if (window->wl.fractionalScale)
+        wp_fractional_scale_v1_destroy(window->wl.fractionalScale);
+
+    if (window->wl.scalingViewport)
+        wp_viewport_destroy(window->wl.scalingViewport);
+
     if (window->wl.activationToken)
         xdg_activation_token_v1_destroy(window->wl.activationToken);
 
@@ -2207,6 +2495,15 @@
     if (window->wl.fallback.buffer)
         wl_buffer_destroy(window->wl.fallback.buffer);
 
+    if (window->wl.egl.callback)
+        wl_callback_destroy(window->wl.egl.callback);
+
+    if (window->wl.egl.wrapper)
+        wl_proxy_wrapper_destroy(window->wl.egl.wrapper);
+
+    if (window->wl.egl.queue)
+        wl_event_queue_destroy(window->wl.egl.queue);
+
     if (window->wl.egl.window)
         wl_egl_window_destroy(window->wl.egl.window);
 
@@ -2440,6 +2737,8 @@
 
         wl_surface_attach(window->wl.surface, NULL, 0, 0);
         wl_surface_commit(window->wl.surface);
+
+        flushDisplay();
     }
 }
 
@@ -2510,12 +2809,12 @@
     }
 
     if (window->monitor)
-        releaseMonitorWayland(window);
+        releaseMonitor(window);
 
     _glfwInputWindowMonitor(window, monitor);
 
     if (window->monitor)
-        acquireMonitorWayland(window);
+        acquireMonitor(window);
     else
         _glfwSetWindowSizeWayland(window, width, height);
 }
@@ -2544,7 +2843,7 @@
 
 GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window)
 {
-    return window->wl.hovered;
+    return window->wl.surface == _glfw.wl.pointerSurface;
 }
 
 GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window)
@@ -2654,7 +2953,9 @@
 
 void _glfwPostEmptyEventWayland(void)
 {
-    wl_display_sync(_glfw.wl.display);
+    struct wl_callback* callback = wl_display_sync(_glfw.wl.display);
+    wl_callback_add_listener(callback, &noopCallbackListener, NULL);
+
     flushDisplay();
 }
 
@@ -2674,7 +2975,7 @@
 
 void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
 {
-    _glfwSetCursorWayland(window, window->wl.currentCursor);
+    _glfwSetCursorWayland(window, window->cursor);
 }
 
 const char* _glfwGetScancodeNameWayland(int scancode)
@@ -2714,23 +3015,23 @@
         return NULL;
     }
 
-    const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]);
-    if (codepoint == GLFW_INVALID_CODEPOINT)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to retrieve codepoint for key name");
-        return NULL;
-    }
-
-    const size_t count = _glfwEncodeUTF8(_glfw.wl.keynames[key],  codepoint);
-    if (count == 0)
+    // WORKAROUND: xkb_keysym_to_utf8() requires the third parameter (size of the output buffer)
+    // to be at least 7 (6 bytes + a null terminator), because it was written when UTF-8
+    // sequences could be up to 6 bytes long. The _glfw.wl.keynames buffers are only 5 bytes
+    // long, because UTF-8 sequences are now limited to 4 bytes and no codepoints were ever assigned
+    // that needed more than that. To work around this, we first copy to a temporary buffer.
+    //
+    // See: https://github.com/xkbcommon/libxkbcommon/issues/418
+    char temp_buffer[7];
+    const int bytes_written = xkb_keysym_to_utf8(keysyms[0], temp_buffer, sizeof(temp_buffer));
+    if (bytes_written <= 0 || bytes_written > 5)
     {
         _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: Failed to encode codepoint for key name");
+                        "Wayland: Failed to encode keysym as UTF-8");
         return NULL;
     }
+    memcpy(_glfw.wl.keynames[key], temp_buffer, bytes_written);
 
-    _glfw.wl.keynames[key][count] = '\0';
     return _glfw.wl.keynames[key];
 }
 
@@ -2921,10 +3222,16 @@
     if (!_glfw.wl.relativePointerManager)
     {
         _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                        "Wayland: The compositor does not support pointer locking");
+                        "Wayland: The compositor does not support relative pointer motion");
         return;
     }
 
+    if (!_glfw.wl.pointerConstraints)
+    {
+        _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+                        "Wayland: The compositor does not support locking the pointer");
+    }
+
     window->wl.relativePointer =
         zwp_relative_pointer_manager_v1_get_relative_pointer(
             _glfw.wl.relativePointerManager,
@@ -2972,6 +3279,12 @@
 
 static void confinePointer(_GLFWwindow* window)
 {
+    if (!_glfw.wl.pointerConstraints)
+    {
+        _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+                        "Wayland: The compositor does not support confining the pointer");
+    }
+
     window->wl.confinedPointer =
         zwp_pointer_constraints_v1_confine_pointer(
             _glfw.wl.pointerConstraints,
@@ -2996,11 +3309,7 @@
     if (!_glfw.wl.pointer)
         return;
 
-    window->wl.currentCursor = cursor;
-
-    // If we're not in the correct window just save the cursor
-    // the next time the pointer enters the window the cursor will change
-    if (!window->wl.hovered)
+    if (window->wl.surface != _glfw.wl.pointerSurface)
         return;
 
     // Update pointer lock to match cursor mode
@@ -3292,7 +3601,6 @@
 
 GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
@@ -3301,6 +3609,9 @@
                         "Wayland: Platform not initialized");
         return NULL;
     }
+
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
 
     return window->wl.surface;
 }
diff --git a/raylib/src/external/glfw/src/x11_init.c b/raylib/src/external/glfw/src/x11_init.c
--- a/raylib/src/external/glfw/src/x11_init.c
+++ b/raylib/src/external/glfw/src/x11_init.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -211,7 +210,7 @@
 
 // Create key code translation tables
 //
-static void createKeyTablesX11(void)
+static void createKeyTables(void)
 {
     int scancodeMin, scancodeMax;
 
@@ -536,6 +535,7 @@
                                    XA_WINDOW,
                                    (unsigned char**) &windowFromChild))
     {
+        _glfwReleaseErrorHandlerX11();
         XFree(windowFromRoot);
         return;
     }
@@ -909,7 +909,7 @@
     // Update the key code LUT
     // FIXME: We should listen to XkbMapNotify events to track changes to
     // the keyboard mapping.
-    createKeyTablesX11();
+    createKeyTables();
 
     // String format atoms
     _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
@@ -1592,65 +1592,29 @@
         _glfw.x11.display = NULL;
     }
 
-    if (_glfw.x11.x11xcb.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
-        _glfw.x11.x11xcb.handle = NULL;
-    }
-
-    if (_glfw.x11.xcursor.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
-        _glfw.x11.xcursor.handle = NULL;
-    }
-
-    if (_glfw.x11.randr.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.randr.handle);
-        _glfw.x11.randr.handle = NULL;
-    }
-
-    if (_glfw.x11.xinerama.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
-        _glfw.x11.xinerama.handle = NULL;
-    }
-
-    if (_glfw.x11.xrender.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.xrender.handle);
-        _glfw.x11.xrender.handle = NULL;
-    }
-
-    if (_glfw.x11.vidmode.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
-        _glfw.x11.vidmode.handle = NULL;
-    }
-
-    if (_glfw.x11.xi.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.xi.handle);
-        _glfw.x11.xi.handle = NULL;
-    }
-
     _glfwTerminateOSMesa();
     // NOTE: These need to be unloaded after XCloseDisplay, as they register
     //       cleanup callbacks that get called by that function
     _glfwTerminateEGL();
     _glfwTerminateGLX();
 
-    if (_glfw.x11.xlib.handle)
-    {
-        _glfwPlatformFreeModule(_glfw.x11.xlib.handle);
-        _glfw.x11.xlib.handle = NULL;
-    }
+    _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
+    _glfwPlatformFreeModule(_glfw.x11.randr.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xrender.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xshape.handle);
+    _glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xi.handle);
+    _glfwPlatformFreeModule(_glfw.x11.xlib.handle);
 
     if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
     {
         close(_glfw.x11.emptyEventPipe[0]);
         close(_glfw.x11.emptyEventPipe[1]);
     }
+
+    memset(&_glfw.x11, 0, sizeof(_glfw.x11));
 }
 
 #endif // _GLFW_X11
diff --git a/raylib/src/external/glfw/src/x11_monitor.c b/raylib/src/external/glfw/src/x11_monitor.c
--- a/raylib/src/external/glfw/src/x11_monitor.c
+++ b/raylib/src/external/glfw/src/x11_monitor.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 X11 - www.glfw.org
+// GLFW 3.5 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <assert.h>
 
 
 // Check whether the display mode should be included in enumeration
@@ -150,6 +151,12 @@
             }
 
             XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
+            if (!ci)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
             if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
             {
                 widthMM  = oi->mm_height;
@@ -611,7 +618,6 @@
 
 GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(None);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
@@ -620,12 +626,14 @@
         return None;
     }
 
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
     return monitor->x11.crtc;
 }
 
 GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
 {
-    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(None);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
@@ -633,6 +641,9 @@
         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
         return None;
     }
+
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
 
     return monitor->x11.output;
 }
diff --git a/raylib/src/external/glfw/src/x11_platform.h b/raylib/src/external/glfw/src/x11_platform.h
--- a/raylib/src/external/glfw/src/x11_platform.h
+++ b/raylib/src/external/glfw/src/x11_platform.h
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 X11 - www.glfw.org
+// GLFW 3.5 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -452,9 +452,6 @@
 typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
 typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
 
-#include "xkb_unicode.h"
-#include "posix_poll.h"
-
 #define GLFW_X11_WINDOW_STATE           _GLFWwindowX11 x11;
 #define GLFW_X11_LIBRARY_WINDOW_STATE   _GLFWlibraryX11 x11;
 #define GLFW_X11_MONITOR_STATE          _GLFWmonitorX11 x11;
@@ -463,6 +460,7 @@
 #define GLFW_GLX_CONTEXT_STATE          _GLFWcontextGLX glx;
 #define GLFW_GLX_LIBRARY_CONTEXT_STATE  _GLFWlibraryGLX glx;
 
+#define GLFW_INVALID_CODEPOINT 0xffffffffu
 
 // GLX-specific per-context data
 //
@@ -470,6 +468,7 @@
 {
     GLXContext      handle;
     GLXWindow       window;
+    GLXFBConfig     fbconfig;
 } _GLFWcontextGLX;
 
 // GLX-specific global data
@@ -504,18 +503,18 @@
     PFNGLXSWAPINTERVALEXTPROC           SwapIntervalEXT;
     PFNGLXSWAPINTERVALMESAPROC          SwapIntervalMESA;
     PFNGLXCREATECONTEXTATTRIBSARBPROC   CreateContextAttribsARB;
-    GLFWbool        SGI_swap_control;
-    GLFWbool        EXT_swap_control;
-    GLFWbool        MESA_swap_control;
-    GLFWbool        ARB_multisample;
-    GLFWbool        ARB_framebuffer_sRGB;
-    GLFWbool        EXT_framebuffer_sRGB;
-    GLFWbool        ARB_create_context;
-    GLFWbool        ARB_create_context_profile;
-    GLFWbool        ARB_create_context_robustness;
-    GLFWbool        EXT_create_context_es2_profile;
-    GLFWbool        ARB_create_context_no_error;
-    GLFWbool        ARB_context_flush_control;
+    bool            SGI_swap_control;
+    bool            EXT_swap_control;
+    bool            MESA_swap_control;
+    bool            ARB_multisample;
+    bool            ARB_framebuffer_sRGB;
+    bool            EXT_framebuffer_sRGB;
+    bool            ARB_create_context;
+    bool            ARB_create_context_profile;
+    bool            ARB_create_context_robustness;
+    bool            EXT_create_context_es2_profile;
+    bool            ARB_create_context_no_error;
+    bool            ARB_context_flush_control;
 } _GLFWlibraryGLX;
 
 // X11-specific per-window data
@@ -983,6 +982,8 @@
                                         Atom type,
                                         unsigned char** value);
 GLFWbool _glfwIsVisualTransparentX11(Visual* visual);
+
+uint32_t _glfwKeySym2UnicodeX11(unsigned int keysym);
 
 void _glfwGrabErrorHandlerX11(void);
 void _glfwReleaseErrorHandlerX11(void);
diff --git a/raylib/src/external/glfw/src/x11_window.c b/raylib/src/external/glfw/src/x11_window.c
--- a/raylib/src/external/glfw/src/x11_window.c
+++ b/raylib/src/external/glfw/src/x11_window.c
@@ -1,9 +1,8 @@
 //========================================================================
-// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com
+// GLFW 3.5 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
-// Copyright (c) 2024 M374LX <wilsalx@gmail.com>
 //
 // This software is provided 'as-is', without any express or implied
 // warranty. In no event will the authors be held liable for any damages
@@ -236,9 +235,9 @@
 
 // Translates an X11 key code to a GLFW key token
 //
-static int translateKeyX11(int scancode)
+static int translateKey(int scancode)
 {
-    // Use the pre-filled LUT (see createKeyTablesX11() in x11_init.c)
+    // Use the pre-filled LUT (see createKeyTables() in x11_init.c)
     if (scancode < 0 || scancode > 255)
         return GLFW_KEY_UNKNOWN;
 
@@ -577,6 +576,10 @@
         height *= _glfw.x11.contentScaleY;
     }
 
+    // The dimensions must be nonzero, or a BadValue error results.
+    width = _glfw_max(1, width);
+    height = _glfw_max(1, height);
+
     int xpos = 0, ypos = 0;
 
     if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
@@ -755,13 +758,13 @@
             const char* resourceName = getenv("RESOURCE_NAME");
             if (resourceName && strlen(resourceName))
                 hint->res_name = (char*) resourceName;
-            else if (strlen(wndconfig->title))
-                hint->res_name = (char*) wndconfig->title;
+            else if (strlen(window->title))
+                hint->res_name = (char*) window->title;
             else
                 hint->res_name = (char*) "glfw-application";
 
-            if (strlen(wndconfig->title))
-                hint->res_class = (char*) wndconfig->title;
+            if (strlen(window->title))
+                hint->res_class = (char*) window->title;
             else
                 hint->res_class = (char*) "GLFW-Application";
         }
@@ -781,7 +784,7 @@
     if (_glfw.x11.im)
         _glfwCreateInputContextX11(window);
 
-    _glfwSetWindowTitleX11(window, wndconfig->title);
+    _glfwSetWindowTitleX11(window, window->title);
     _glfwGetWindowPosX11(window, &window->x11.xpos, &window->x11.ypos);
     _glfwGetWindowSizeX11(window, &window->x11.width, &window->x11.height);
 
@@ -1082,7 +1085,7 @@
 
 // Make the specified window and its video mode active on its monitor
 //
-static void acquireMonitorX11(_GLFWwindow* window)
+static void acquireMonitor(_GLFWwindow* window)
 {
     if (_glfw.x11.saver.count == 0)
     {
@@ -1121,7 +1124,7 @@
 
 // Remove the window and restore the original video mode
 //
-static void releaseMonitorX11(_GLFWwindow* window)
+static void releaseMonitor(_GLFWwindow* window)
 {
     if (window->monitor->window != window)
         return;
@@ -1243,7 +1246,7 @@
 
         case KeyPress:
         {
-            const int key = translateKeyX11(keycode);
+            const int key = translateKey(keycode);
             const int mods = translateState(event->xkey.state);
             const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
 
@@ -1305,7 +1308,7 @@
 
                 _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
 
-                const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
+                const uint32_t codepoint = _glfwKeySym2UnicodeX11(keysym);
                 if (codepoint != GLFW_INVALID_CODEPOINT)
                     _glfwInputChar(window, codepoint, mods, plain);
             }
@@ -1315,7 +1318,7 @@
 
         case KeyRelease:
         {
-            const int key = translateKeyX11(keycode);
+            const int key = translateKey(keycode);
             const int mods = translateState(event->xkey.state);
 
             if (!_glfw.x11.xkb.detectable)
@@ -1807,9 +1810,9 @@
                     if (window->monitor)
                     {
                         if (iconified)
-                            releaseMonitorX11(window);
+                            releaseMonitor(window);
                         else
-                            acquireMonitorX11(window);
+                            acquireMonitor(window);
                     }
 
                     window->x11.iconified = iconified;
@@ -2026,7 +2029,7 @@
     {
         _glfwShowWindowX11(window);
         updateWindowMode(window);
-        acquireMonitorX11(window);
+        acquireMonitor(window);
 
         if (wndconfig->centerCursor)
             _glfwCenterCursorInContentArea(window);
@@ -2051,7 +2054,7 @@
         enableCursor(window);
 
     if (window->monitor)
-        releaseMonitorX11(window);
+        releaseMonitor(window);
 
     if (window->x11.ic)
     {
@@ -2204,10 +2207,14 @@
 
 void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
 {
+    // The dimensions must be nonzero, or a BadValue error results
+    width = _glfw_max(1, width);
+    height = _glfw_max(1, height);
+
     if (window->monitor)
     {
         if (window->monitor->window == window)
-            acquireMonitorX11(window);
+            acquireMonitor(window);
     }
     else
     {
@@ -2431,6 +2438,38 @@
     if (_glfwWindowVisibleX11(window))
         return;
 
+    if (window->floating && _glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
+    {
+        Atom* states = NULL;
+        const unsigned long count =
+            _glfwGetWindowPropertyX11(window->x11.handle,
+                                      _glfw.x11.NET_WM_STATE,
+                                      XA_ATOM, (unsigned char**) &states);
+
+        // NOTE: We don't check for failure as this property may not exist yet
+        //       and that's fine (and we'll create it implicitly with append)
+
+        unsigned long i;
+
+        for (i = 0;  i < count;  i++)
+        {
+            if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
+                break;
+        }
+
+        if (i == count)
+        {
+            XChangeProperty(_glfw.x11.display, window->x11.handle,
+                            _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
+                            PropModeAppend,
+                            (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
+                            1);
+        }
+
+        if (states)
+            XFree(states);
+    }
+
     XMapWindow(_glfw.x11.display, window->x11.handle);
     waitForVisibilityNotify(window);
 }
@@ -2478,7 +2517,7 @@
         if (monitor)
         {
             if (monitor->window == window)
-                acquireMonitorX11(window);
+                acquireMonitor(window);
         }
         else
         {
@@ -2497,7 +2536,7 @@
     {
         _glfwSetWindowDecoratedX11(window, window->decorated);
         _glfwSetWindowFloatingX11(window, window->floating);
-        releaseMonitorX11(window);
+        releaseMonitor(window);
     }
 
     _glfwInputWindowMonitor(window, monitor);
@@ -2512,7 +2551,7 @@
         }
 
         updateWindowMode(window);
-        acquireMonitorX11(window);
+        acquireMonitor(window);
     }
     else
     {
@@ -2660,6 +2699,10 @@
     }
     else
     {
+        // NOTE: _NET_WM_STATE_ABOVE is added when the window is shown
+        if (enabled)
+            return;
+
         Atom* states = NULL;
         const unsigned long count =
             _glfwGetWindowPropertyX11(window->x11.handle,
@@ -2670,38 +2713,20 @@
         // NOTE: We don't check for failure as this property may not exist yet
         //       and that's fine (and we'll create it implicitly with append)
 
-        if (enabled)
-        {
-            unsigned long i;
-
-            for (i = 0;  i < count;  i++)
-            {
-                if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
-                    break;
-            }
+        unsigned long i;
 
-            if (i == count)
-            {
-                XChangeProperty(_glfw.x11.display, window->x11.handle,
-                                _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
-                                PropModeAppend,
-                                (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
-                                1);
-            }
+        for (i = 0;  i < count;  i++)
+        {
+            if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
+                break;
         }
-        else if (states)
+
+        if (i < count)
         {
-            for (unsigned long i = 0;  i < count;  i++)
-            {
-                if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
-                {
-                    states[i] = states[count - 1];
-                    XChangeProperty(_glfw.x11.display, window->x11.handle,
-                                    _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
-                                    PropModeReplace, (unsigned char*) states, count - 1);
-                    break;
-                }
-            }
+            states[i] = states[count - 1];
+            XChangeProperty(_glfw.x11.display, window->x11.handle,
+                            _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
+                            PropModeReplace, (unsigned char*) states, count - 1);
         }
 
         if (states)
@@ -2919,7 +2944,7 @@
     if (keysym == NoSymbol)
         return NULL;
 
-    const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
+    const uint32_t codepoint = _glfwKeySym2UnicodeX11(keysym);
     if (codepoint == GLFW_INVALID_CODEPOINT)
         return NULL;
 
@@ -3303,7 +3328,6 @@
 
 GLFWAPI Window glfwGetX11Window(GLFWwindow* handle)
 {
-    _GLFWwindow* window = (_GLFWwindow*) handle;
     _GLFW_REQUIRE_INIT_OR_RETURN(None);
 
     if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
@@ -3312,6 +3336,9 @@
         return None;
     }
 
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
     return window->x11.handle;
 }
 
@@ -3324,6 +3351,8 @@
         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
         return;
     }
+
+    assert(string != NULL);
 
     _glfw_free(_glfw.x11.primarySelectionString);
     _glfw.x11.primarySelectionString = _glfw_strdup(string);
diff --git a/raylib/src/external/glfw/src/xkb_unicode.c b/raylib/src/external/glfw/src/xkb_unicode.c
--- a/raylib/src/external/glfw/src/xkb_unicode.c
+++ b/raylib/src/external/glfw/src/xkb_unicode.c
@@ -1,5 +1,5 @@
 //========================================================================
-// GLFW 3.4 X11 - www.glfw.org
+// GLFW 3.5 X11 - www.glfw.org
 //------------------------------------------------------------------------
 // Copyright (c) 2002-2006 Marcus Geelnard
 // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -27,7 +27,7 @@
 
 #include "internal.h"
 
-#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
+#if defined(_GLFW_X11)
 
 /*
  * Marcus: This code was originally written by Markus G. Kuhn.
@@ -906,7 +906,7 @@
 
 // Convert XKB KeySym to Unicode
 //
-uint32_t _glfwKeySym2Unicode(unsigned int keysym)
+uint32_t _glfwKeySym2UnicodeX11(unsigned int keysym)
 {
     int min = 0;
     int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
@@ -939,5 +939,5 @@
     return GLFW_INVALID_CODEPOINT;
 }
 
-#endif // _GLFW_WAYLAND or _GLFW_X11
+#endif // _GLFW_X11
 
diff --git a/raylib/src/external/glfw/src/xkb_unicode.h b/raylib/src/external/glfw/src/xkb_unicode.h
deleted file mode 100644
--- a/raylib/src/external/glfw/src/xkb_unicode.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//========================================================================
-// GLFW 3.4 Linux - www.glfw.org
-//------------------------------------------------------------------------
-// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
-//
-// 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 GLFW_INVALID_CODEPOINT 0xffffffffu
-
-uint32_t _glfwKeySym2Unicode(unsigned int keysym);
-
diff --git a/raylib/src/external/jar_mod.h b/raylib/src/external/jar_mod.h
--- a/raylib/src/external/jar_mod.h
+++ b/raylib/src/external/jar_mod.h
@@ -1538,10 +1538,10 @@
             modctx->modfile = (muchar *) JARMOD_MALLOC(fsize);
             modctx->modfilesize = fsize;
             memset(modctx->modfile, 0, fsize);
-            fread(modctx->modfile, fsize, 1, f);
+            if(fread(modctx->modfile, fsize, 1, f) != 1) fsize = 0;
             fclose(f);
 
-            if(!jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0;
+            if(fsize && !jar_mod_load(modctx, (void *)modctx->modfile, fsize)) fsize = 0;
         } else fsize = 0;
     }
     return fsize;
diff --git a/raylib/src/external/m3d.h b/raylib/src/external/m3d.h
--- a/raylib/src/external/m3d.h
+++ b/raylib/src/external/m3d.h
@@ -236,7 +236,8 @@
 #ifdef M3D_ASCII
 #define M3D_PROPERTYDEF(f,i,n) { (f), (i), (char*)(n) }
     char *key;
-#else
+#endif
+#ifndef M3D_ASCII
 #define M3D_PROPERTYDEF(f,i,n) { (f), (i) }
 #endif
 } m3dpd_t;
@@ -414,7 +415,8 @@
 #ifdef M3D_ASCII
 #define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
     char *key;
-#else
+#endif
+#ifndef M3D_ASCII
 #define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
 #endif
     uint8_t p;
@@ -674,6 +676,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* we'll need this with M3D_NOTEXTURE */
+char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+
+#ifndef M3D_NOTEXTURE
 #if !defined(M3D_NOIMPORTER) && !defined(STBI_INCLUDE_STB_IMAGE_H)
 /* PNG decompressor from
 
@@ -1868,6 +1874,11 @@
 #if !defined(M3D_NOIMPORTER) && defined(STBI_INCLUDE_STB_IMAGE_H) && !defined(STB_IMAGE_IMPLEMENTATION)
 #error "stb_image.h included without STB_IMAGE_IMPLEMENTATION. Sorry, we need some stuff defined inside the ifguard for proper integration"
 #endif
+#else
+#if !defined(STBI_INCLUDE_STB_IMAGE_H) || defined(STBI_NO_ZLIB)
+#error "stb_image.h not included or STBI_NO_ZLIB defined. Sorry, we need its zlib implementation for proper integration"
+#endif
+#endif /* M3D_NOTEXTURE */
 
 #if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H)
 /* zlib_compressor from
@@ -2168,9 +2179,11 @@
     unsigned int i, len = 0;
     unsigned char *buff = NULL;
     char *fn2;
+#ifndef M3D_NOTEXTURE
     unsigned int w, h;
     stbi__context s;
     stbi__result_info ri;
+#endif
 
     /* failsafe */
     if(!fn || !*fn) return M3D_UNDEF;
@@ -2209,13 +2222,17 @@
     if(!model->texture) {
         if(buff && freecb) (*freecb)(buff);
         model->errcode = M3D_ERR_ALLOC;
+        model->numtexture = 0;
         return M3D_UNDEF;
     }
+    memset(&model->texture[i], 0, sizeof(m3dtx_t));
     model->texture[i].name = fn;
-    model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL;
     if(buff) {
         if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') {
-            s.read_from_callbacks = 0;
+#ifndef M3D_NOTEXTURE
+            /* return pixel buffer of the decoded texture */
+            memset(&s, 0, sizeof(s));
+            memset(&ri, 0, sizeof(ri));
             s.img_buffer = s.img_buffer_original = (unsigned char *) buff;
             s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len;
             /* don't use model->texture[i].w directly, it's a uint16_t */
@@ -2225,6 +2242,16 @@
             model->texture[i].w = w;
             model->texture[i].h = h;
             model->texture[i].f = (uint8_t)len;
+#else
+            /* return only the raw undecoded texture */
+            if((model->texture[i].d = (uint8_t*)M3D_MALLOC(len))) {
+                memcpy(model->texture[i].d, buff, len);
+                model->texture[i].w = len & 0xffff;
+                model->texture[i].h = (len >> 16) & 0xffff;
+                model->texture[i].f = 0;
+            } else
+                model->errcode = M3D_ERR_ALLOC;
+#endif
         } else {
 #ifdef M3D_TX_INTERP
             if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) {
@@ -4280,7 +4307,7 @@
     if(l != msec) {
         model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, (model->numvertex + 2 * model->numbone) * sizeof(m3dv_t));
         if(!model->vertex) {
-            free(ret);
+            M3D_FREE(ret);
             model->errcode = M3D_ERR_ALLOC;
             return NULL;
         }
@@ -4492,7 +4519,7 @@
     if(model->label) M3D_FREE(model->label);
     if(model->inlined) M3D_FREE(model->inlined);
     if(model->extra) M3D_FREE(model->extra);
-    free(model);
+    M3D_FREE(model);
 }
 #endif
 
@@ -4568,15 +4595,15 @@
         safe = _m3d_safestr(s, 0);
         if(!safe) return 0;
         if(!*safe) {
-            free(safe);
+            M3D_FREE(safe);
             return 0;
         }
         for(i = 0; i < numstr; i++)
             if(!strcmp(str[i].str, s)) {
-                free(safe);
+                M3D_FREE(safe);
                 return str[i].offs;
             }
-        free(safe);
+        M3D_FREE(safe);
     }
     return 0;
 }
@@ -4889,7 +4916,7 @@
                     if(cmd->type == m3dc_mesh) {
                         if(numgrp + 2 < maxgrp) {
                             maxgrp += 1024;
-                            grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t));
+                            grpidx = (uint32_t*)M3D_REALLOC(grpidx, maxgrp * sizeof(uint32_t));
                             if(!grpidx) goto memerr;
                             if(!numgrp) {
                                 grpidx[0] = 0;
@@ -5194,7 +5221,7 @@
         if(sa) M3D_FREE(sa);
         if(sd) M3D_FREE(sd);
         if(out) M3D_FREE(out);
-        if(opa) free(opa);
+        if(opa) M3D_FREE(opa);
         if(h) M3D_FREE(h);
         M3D_LOG("Out of memory");
         model->errcode = M3D_ERR_ALLOC;
@@ -6285,7 +6312,7 @@
     if(skin) M3D_FREE(skin);
     if(str) M3D_FREE(str);
     if(vrtx) M3D_FREE(vrtx);
-    if(opa) free(opa);
+    if(opa) M3D_FREE(opa);
     if(h) M3D_FREE(h);
     return out;
 }
@@ -6310,7 +6337,7 @@
 
         public:
             Model() {
-                this->model = (m3d_t*)malloc(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t));
+                this->model = (m3d_t*)M3D_MALLOC(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t));
             }
             Model(_unused const std::string &data, _unused m3dread_t ReadFileCB,
                 _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) {
diff --git a/raylib/src/external/miniaudio.h b/raylib/src/external/miniaudio.h
# file too large to diff: raylib/src/external/miniaudio.h
diff --git a/raylib/src/external/pep.h b/raylib/src/external/pep.h
new file mode 100644
--- /dev/null
+++ b/raylib/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 <stdint.h> // uint*_t
+#include <stdlib.h> // mem-alloc
+#include <stdio.h> // FILE
+#include <string.h> // 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 <intrin.h> // __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/raylib/src/external/qoa.h b/raylib/src/external/qoa.h
--- a/raylib/src/external/qoa.h
+++ b/raylib/src/external/qoa.h
@@ -31,7 +31,7 @@
 	struct {
 		char     magic[4];         // magic bytes "qoaf"
 		uint32_t samples;          // samples per channel in this file
-	} file_header;             
+	} file_header;
 
 	struct {
 		struct {
@@ -39,12 +39,12 @@
 			uint24_t samplerate;   // samplerate in hz
 			uint16_t fsamples;     // samples per channel in this frame
 			uint16_t fsize;        // frame size (includes this header)
-		} frame_header;          
+		} frame_header;
 
 		struct {
 			int16_t history[4];    // most recent last
 			int16_t weights[4];    // most recent last
-		} lms_state[num_channels]; 
+		} lms_state[num_channels];
 
 		qoa_slice_t slices[256][num_channels];
 
@@ -66,7 +66,7 @@
 slice (for each channel) in the last frame may contain less than 20 samples; the
 slice still must be 8 bytes wide, with the unused samples zeroed out.
 
-Channels are interleaved per slice. E.g. for 2 channel stereo: 
+Channels are interleaved per slice. E.g. for 2 channel stereo:
 slice[0] = L, slice[1] = R, slice[2] = L, slice[3] = R ...
 
 A valid QOA file or stream must have at least one frame. Each frame must contain
@@ -74,7 +74,7 @@
 (inclusive).
 
 If the total number of samples is not known by the encoder, the samples in the
-file header may be set to 0x00000000 to indicate that the encoder is 
+file header may be set to 0x00000000 to indicate that the encoder is
 "streaming". In a streaming context, the samplerate and number of channels may
 differ from frame to frame. For static files (those with samples set to a
 non-zero value), each frame must have the same number of channels and same
@@ -88,15 +88,15 @@
 
 	1. Mono
 	2. L, R
-	3. L, R, C 
-	4. FL, FR, B/SL, B/SR 
-	5. FL, FR, C, B/SL, B/SR 
+	3. L, R, C
+	4. FL, FR, B/SL, B/SR
+	5. FL, FR, C, B/SL, B/SR
 	6. FL, FR, C, LFE, B/SL, B/SR
-	7. FL, FR, C, LFE, B, SL, SR 
+	7. FL, FR, C, LFE, B, SL, SR
 	8. FL, FR, C, LFE, BL, BR, SL, SR
 
 QOA predicts each audio sample based on the previously decoded ones using a
-"Sign-Sign Least Mean Squares Filter" (LMS). This prediction plus the 
+"Sign-Sign Least Mean Squares Filter" (LMS). This prediction plus the
 dequantized residual forms the final output sample.
 
 */
@@ -178,9 +178,9 @@
 
 
 /* The quant_tab provides an index into the dequant_tab for residuals in the
-range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at 
-the higher end. Note that the residual zero is identical to the lowest positive 
-value. This is mostly fine, since the qoa_div() function always rounds away 
+range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at
+the higher end. Note that the residual zero is identical to the lowest positive
+value. This is mostly fine, since the qoa_div() function always rounds away
 from zero. */
 
 static const int qoa_quant_tab[17] = {
@@ -193,8 +193,8 @@
 /* We have 16 different scalefactors. Like the quantized residuals these become
 less accurate at the higher end. In theory, the highest scalefactor that we
 would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we
-rely on the LMS filter to predict samples accurately enough that a maximum 
-residual of one quarter of the 16 bit range is sufficient. I.e. with the 
+rely on the LMS filter to predict samples accurately enough that a maximum
+residual of one quarter of the 16 bit range is sufficient. I.e. with the
 scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14.
 
 The scalefactor values are computed as:
@@ -205,9 +205,9 @@
 };
 
 
-/* The reciprocal_tab maps each of the 16 scalefactors to their rounded 
-reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in 
-the encoder with just one multiplication instead of an expensive division. We 
+/* The reciprocal_tab maps each of the 16 scalefactors to their rounded
+reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in
+the encoder with just one multiplication instead of an expensive division. We
 do this in .16 fixed point with integers, instead of floats.
 
 The reciprocal_tab is computed as:
@@ -218,11 +218,11 @@
 };
 
 
-/* The dequant_tab maps each of the scalefactors and quantized residuals to 
+/* The dequant_tab maps each of the scalefactors and quantized residuals to
 their unscaled & dequantized version.
 
 Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4
-instead of 1. The dequant_tab assumes the following dequantized values for each 
+instead of 1. The dequant_tab assumes the following dequantized values for each
 of the quant_tab indices and is computed as:
 float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
 dequant_tab[s][q] <- round_ties_away_from_zero(scalefactor_tab[s] * dqt[q])
@@ -258,7 +258,7 @@
 The next sample is predicted as the sum of (weight[i] * history[i]).
 
 The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or
-subtracts the residual to each weight, based on the corresponding sample from 
+subtracts the residual to each weight, based on the corresponding sample from
 the history. This, surprisingly, is sufficient to get worthwhile predictions.
 
 This is all done with fixed point integers. Hence the right-shifts when updating
@@ -285,8 +285,8 @@
 }
 
 
-/* qoa_div() implements a rounding division, but avoids rounding to zero for 
-small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still 
+/* qoa_div() implements a rounding division, but avoids rounding to zero for
+small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still
 returns as 0, which is handled in the qoa_quant_tab[].
 qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an
 argument, so it can do the division with a cheaper integer multiplication. */
@@ -385,10 +385,10 @@
 		for (unsigned int c = 0; c < channels; c++) {
 			int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
 			int slice_start = sample_index * channels + c;
-			int slice_end = (sample_index + slice_len) * channels + c;			
+			int slice_end = (sample_index + slice_len) * channels + c;
 
-			/* Brute for search for the best scalefactor. Just go through all
-			16 scalefactors, encode all samples for the current slice and 
+			/* Brute force search for the best scalefactor. Just go through all
+			16 scalefactors, encode all samples for the current slice and
 			meassure the total squared error. */
 			qoa_uint64_t best_rank = -1;
 			#ifdef QOA_RECORD_TOTAL_ERROR
@@ -402,7 +402,7 @@
 				/* There is a strong correlation between the scalefactors of
 				neighboring slices. As an optimization, start testing
 				the best scalefactor of the previous slice first. */
-				int scalefactor = (sfi + prev_scalefactor[c]) % 16;
+				int scalefactor = (sfi + prev_scalefactor[c]) & (16 - 1);
 
 				/* We have to reset the LMS state to the last known good one
 				before trying each scalefactor, as each pass updates the LMS
@@ -500,7 +500,7 @@
 		num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
 		num_slices * 8 * qoa->channels;                /* 8 byte slices */
 
-	unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size);
+	unsigned char *bytes = QOA_MALLOC(encoded_size);
 
 	for (unsigned int c = 0; c < qoa->channels; c++) {
 		/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the 
@@ -657,7 +657,7 @@
 
 	/* Calculate the required size of the sample buffer and allocate */
 	int total_samples = qoa->samples * qoa->channels;
-	short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short));
+	short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
 
 	unsigned int sample_index = 0;
 	unsigned int frame_len;
@@ -733,7 +733,7 @@
 	bytes_read = fread(data, 1, size, f);
 	fclose(f);
 
-	sample_data = qoa_decode((const unsigned char *)data, bytes_read, qoa);
+	sample_data = qoa_decode(data, bytes_read, qoa);
 	QOA_FREE(data);
 	return sample_data;
 }
diff --git a/raylib/src/external/qoi.h b/raylib/src/external/qoi.h
--- a/raylib/src/external/qoi.h
+++ b/raylib/src/external/qoi.h
@@ -427,7 +427,7 @@
 				run = 0;
 			}
 
-			index_pos = QOI_COLOR_HASH(px) % 64;
+			index_pos = QOI_COLOR_HASH(px) & (64 - 1);
 
 			if (index[index_pos].v == px.v) {
 				bytes[p++] = QOI_OP_INDEX | index_pos;
@@ -574,7 +574,7 @@
 				run = (b1 & 0x3f);
 			}
 
-			index[QOI_COLOR_HASH(px) % 64] = px;
+			index[QOI_COLOR_HASH(px) & (64 - 1)] = px;
 		}
 
 		pixels[px_pos + 0] = px.rgba.r;
diff --git a/raylib/src/external/rl_gputex.h b/raylib/src/external/rl_gputex.h
deleted file mode 100644
--- a/raylib/src/external/rl_gputex.h
+++ /dev/null
@@ -1,1550 +0,0 @@
-/**********************************************************************************************
-*
-*   rl_gputex v1.1 - GPU compressed textures loading and saving
-*
-*   DESCRIPTION:
-*
-*     Load GPU compressed image data from image files provided as memory data arrays,
-*     data is loaded compressed, ready to be loaded into GPU
-*
-*     Note that some file formats (DDS, PVR, KTX) also support uncompressed data storage.
-*     In those cases data is loaded uncompressed and format is returned
-*
-*   FIXME: This library still depends on Raylib due to the following reasons:
-*     - rl_save_ktx_to_memory() requires rlGetGlTextureFormats() from rlgl.h
-*         though this is not a problem, if you don't need KTX support
-*
-*   TODO:
-*     - Review rl_load_ktx_from_memory() to support KTX v2.2 specs
-*
-*   CONFIGURATION:
-*
-*   #define RL_GPUTEX_SUPPORT_DDS
-*   #define RL_GPUTEX_SUPPORT_PKM
-*   #define RL_GPUTEX_SUPPORT_KTX
-*   #define RL_GPUTEX_SUPPORT_PVR
-*   #define RL_GPUTEX_SUPPORT_ASTC
-*       Define desired file formats to be supported
-*
-*   #define RL_GPUTEX_SHOW_LOG_INFO
-*       Define, if you wish to see warnings generated by the library
-*       This will include <stdio.h> unless you provide your own RL_GPUTEX_LOG
-*   #define RL_GPUTEX_LOG
-*       Define, if you wish to provide your own warning function
-*       Make sure that this macro puts newline character '\n' at the end
-*
-*   #define RL_GPUTEX_MALLOC
-*   #define RL_GPUTEX_FREE
-*       Define those macros in order to provide your own libc-compliant allocator;
-*       not doing so will include <stdlib.h>
-*       If you're providing any of those, you must provide ALL of them,
-*       otherwise the code will (most likely) crash...
-*
-*   #define RL_GPUTEX_NULL
-*       Define in order to provide your own libc-compliant NULL pointer;
-*       not doing so will include <stdlib.h>
-*
-*   #define RL_GPUTEX_MEMCPY
-*       Define in order to provide your own libc-compliant 'memcpy' function;
-*       not doing so will include <string.h>
-*
-*   #define RLGPUTEXAPI
-*       Define to compiler-specific intrinsic, if you wish to export public functions
-*       There is no need to do so when statically linking
-*
-*   VERSIONS HISTORY:
-*       1.1 (15-Jul-2025) Several minor fixes related to specific image formats; some work has been done
-*           in order to decouple the library from Raylib by introducing few new macros; library still
-*           requires Raylib in order to function properly
-*
-*       1.0 (17-Sep-2022) First version has been created by migrating part of compressed-texture-loading
-*           functionality from Raylib src/rtextures.c into self-contained library
-*
-*   LICENSE: zlib/libpng
-*
-*   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.
-*
-**********************************************************************************************/
-
-#ifndef RL_GPUTEX_H
-#define RL_GPUTEX_H
-
-#ifndef RLGPUTEXAPI
-    #define RLGPUTEXAPI  // Functions defined as 'extern' by default (implicit specifiers)
-#endif
-
-// Texture pixel formats
-// NOTE: Support depends on OpenGL version
-// WARNING: Enum values aligned with raylib/rlgl equivalent PixelFormat/rlPixelFormat enum,
-// to avoid value mapping between the 3 libraries format values
-typedef enum {
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1,     // 8 bit per pixel (no alpha)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,        // 8*2 bpp (2 channels)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5,            // 16 bpp
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8,            // 24 bpp
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1,          // 16 bpp (1 bit alpha)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4,          // 16 bpp (4 bit alpha)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,          // 32 bpp
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32,               // 32 bpp (1 channel - float)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32,         // 32*3 bpp (3 channels - float)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32,      // 32*4 bpp (4 channels - float)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16,               // 16 bpp (1 channel - half float)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16,         // 16*3 bpp (3 channels - half float)
-    RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16,      // 16*4 bpp (4 channels - half float)
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB,            // 4 bpp (no alpha)
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA,           // 4 bpp (1 bit alpha)
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA,           // 8 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA,           // 8 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB,            // 4 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB,            // 4 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA,       // 8 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB,            // 4 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA,           // 4 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA,       // 8 bpp
-    RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA        // 2 bpp
-} rlGpuTexPixelFormat;
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-#if defined(__cplusplus)
-extern "C" {            // Prevents name mangling of functions
-#endif
-
-// Load image data from memory data files
-RLGPUTEXAPI void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
-RLGPUTEXAPI void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
-RLGPUTEXAPI void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
-RLGPUTEXAPI void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
-RLGPUTEXAPI void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
-
-RLGPUTEXAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int width, int height, int format, int mipmaps);  // Save image data as KTX file
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif // RL_GPUTEX_H
-
-/***********************************************************************************
-*
-*   RL_GPUTEX IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RL_GPUTEX_IMPLEMENTATION)
-
-#if defined(RL_GPUTEX_SHOW_LOG_INFO) && !defined(RL_GPUTEX_LOG)
-    #include <stdio.h>          // Required for: printf()
-#endif
-#if !defined(RL_GPUTEX_MALLOC) || !defined(RL_GPUTEX_NULL)
-    #include <stdlib.h>         // Required for: NULL, malloc(), calloc(), free()
-#endif
-#if !defined(RL_GPUTEX_MEMCPY)
-    #include <string.h>         // Required for: memcpy()
-#endif
-
-#if defined(RL_GPUTEX_MALLOC) || defined(RL_GPUTEX_FREE)
-    #if !defined(RL_GPUTEX_MALLOC) || !defined(RL_GPUTEX_FREE)
-        #warning "RL_GPUTEX_MALLOC and RL_GPUTEX_FREE allocation functions are required to be provided"
-    #endif
-#endif
-#if !defined(RL_GPUTEX_MALLOC)
-    #define RL_GPUTEX_MALLOC(sz)        malloc(sz)
-    #define RL_GPUTEX_FREE(ptr)         free(ptr)
-#endif
-
-#if !defined(RL_GPUTEX_NULL)
-    #define RL_GPUTEX_NULL NULL
-#endif
-#if !defined(RL_GPUTEX_MEMCPY)
-    #define RL_GPUTEX_MEMCPY(dest, src, num)  memcpy(dest, src, num)
-#endif
-
-// Simple warning logging system to avoid LOG() calls if required
-// NOTE: Avoiding those calls, also avoids const strings memory usage
-// WARN: This macro expects that newline character is added automatically
-//       in order to match the functionality of Raylib's TRACELOG()
-#if defined(RL_GPUTEX_SHOW_LOG_INFO)
-    #if !defined(RL_GPUTEX_LOG)
-        #define RL_GPUTEX_LOG(...) (void)(printf("RL_GPUTEX: WARNING: " __VA_ARGS__), printf("\n"))
-    #endif
-#else
-    #if defined(RL_GPUTEX_LOG)
-        // Undefine it first in order to supress warnings about macro redefinition
-        #undef RL_GPUTEX_LOG
-    #endif
-    #define RL_GPUTEX_LOG(...)
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-// Get pixel data size in bytes for certain pixel format
-static int get_pixel_data_size(int width, int height, int format);
-
-// Get OpenGL internal formats and data type from rlGpuTexPixelFormat
-void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsigned int *gl_format, unsigned int *gl_type);
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-#if defined(RL_GPUTEX_SUPPORT_DDS)
-// Loading DDS from memory image data (compressed or uncompressed)
-void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
-{
-    void *image_data = RL_GPUTEX_NULL;  // Image data pointer
-    int image_pixel_size = 0;           // Image pixel size
-
-    unsigned char *file_data_ptr = (unsigned char *)file_data;
-
-    // Required extension:
-    // GL_EXT_texture_compression_s3tc
-
-    // Supported tokens (defined by extensions)
-    // GL_COMPRESSED_RGB_S3TC_DXT1_EXT      0x83F0
-    // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT     0x83F1
-    // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT     0x83F2
-    // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT     0x83F3
-
-    #define FOURCC_DXT1 0x31545844  // Equivalent to "DXT1" in ASCII
-    #define FOURCC_DXT3 0x33545844  // Equivalent to "DXT3" in ASCII
-    #define FOURCC_DXT5 0x35545844  // Equivalent to "DXT5" in ASCII
-
-    // DDS Pixel Format
-    typedef struct {
-        unsigned int size;
-        unsigned int flags;
-        unsigned int fourcc;
-        unsigned int rgb_bit_count;
-        unsigned int r_bit_mask;
-        unsigned int g_bit_mask;
-        unsigned int b_bit_mask;
-        unsigned int a_bit_mask;
-    } dds_pixel_format;
-
-    // DDS Header (124 bytes)
-    typedef struct {
-        unsigned int size;
-        unsigned int flags;
-        unsigned int height;
-        unsigned int width;
-        unsigned int pitch_or_linear_size;
-        unsigned int depth;
-        unsigned int mipmap_count;
-        unsigned int reserved1[11];
-        dds_pixel_format ddspf;
-        unsigned int caps;
-        unsigned int caps2;
-        unsigned int caps3;
-        unsigned int caps4;
-        unsigned int reserved2;
-    } dds_header;
-
-    if (file_data_ptr != RL_GPUTEX_NULL)
-    {
-        // Verify the type of file
-        unsigned char *dds_header_id = file_data_ptr;
-        file_data_ptr += 4;
-
-        if ((dds_header_id[0] != 'D') || (dds_header_id[1] != 'D') || (dds_header_id[2] != 'S') || (dds_header_id[3] != ' '))
-        {
-            RL_GPUTEX_LOG("DDS file data not valid");
-        }
-        else
-        {
-            dds_header *header = (dds_header *)file_data_ptr;
-
-            file_data_ptr += sizeof(dds_header);        // Skip header
-
-            *width = header->width;
-            *height = header->height;
-
-            if (*width % 4 != 0) RL_GPUTEX_LOG("DDS file width must be multiple of 4. Image will not display correctly");
-            if (*height % 4 != 0) RL_GPUTEX_LOG("DDS file height must be multiple of 4. Image will not display correctly");
-
-            image_pixel_size = header->width*header->height;
-
-            if (header->mipmap_count == 0) *mips = 1;   // Parameter not used
-            else *mips = header->mipmap_count;
-
-            if (header->ddspf.rgb_bit_count == 16)      // 16bit mode, no compressed
-            {
-                if (header->ddspf.flags == 0x40)        // No alpha channel
-                {
-                    int data_size = image_pixel_size*sizeof(unsigned short);
-                    if (header->mipmap_count > 1) data_size = data_size + data_size/3;
-                    image_data = RL_GPUTEX_MALLOC(data_size);
-
-                    RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                    *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5;
-                }
-                else if (header->ddspf.flags == 0x41)           // With alpha channel
-                {
-                    if (header->ddspf.a_bit_mask == 0x8000)     // 1bit alpha
-                    {
-                        int data_size = image_pixel_size*sizeof(unsigned short);
-                        if (header->mipmap_count > 1) data_size = data_size + data_size/3;
-                        image_data = RL_GPUTEX_MALLOC(data_size);
-
-                        RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                        unsigned char alpha = 0;
-
-                        // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1
-                        for (int i = 0; i < data_size/sizeof(unsigned short); i++)
-                        {
-                            alpha = ((unsigned short *)image_data)[i] >> 15;
-                            ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1;
-                            ((unsigned short *)image_data)[i] += alpha;
-                        }
-
-                        *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
-                    }
-                    else if (header->ddspf.a_bit_mask == 0xf000)   // 4bit alpha
-                    {
-                        int data_size = image_pixel_size*sizeof(unsigned short);
-                        if (header->mipmap_count > 1) data_size = data_size + data_size/3;
-                        image_data = RL_GPUTEX_MALLOC(data_size);
-
-                        RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                        unsigned char alpha = 0;
-
-                        // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4
-                        for (int i = 0; i < data_size/sizeof(unsigned short); i++)
-                        {
-                            alpha = ((unsigned short *)image_data)[i] >> 12;
-                            ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4;
-                            ((unsigned short *)image_data)[i] += alpha;
-                        }
-
-                        *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
-                    }
-                }
-            }
-            else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
-            {
-                int data_size = image_pixel_size*3*sizeof(unsigned char);
-                if (header->mipmap_count > 1) data_size = data_size + data_size/3;
-                image_data = RL_GPUTEX_MALLOC(data_size);
-
-                RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8;
-            }
-            else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed
-            {
-                int data_size = image_pixel_size*4*sizeof(unsigned char);
-                if (header->mipmap_count > 1) data_size = data_size + data_size/3;
-                image_data = RL_GPUTEX_MALLOC(data_size);
-
-                RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                unsigned char blue = 0;
-
-                // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment)
-                // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA
-                // So, we must realign B8G8R8A8 to R8G8B8A8
-                for (int i = 0; i < data_size; i += 4)
-                {
-                    blue = ((unsigned char *)image_data)[i];
-                    ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];
-                    ((unsigned char *)image_data)[i + 2] = blue;
-                }
-
-                *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-            }
-            else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed
-            {
-                int data_size = 0;
-
-                // Calculate data size, including all mipmaps
-                if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size/3;
-                else data_size = header->pitch_or_linear_size;
-
-                image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char));
-
-                RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                switch (header->ddspf.fourcc)
-                {
-                    case FOURCC_DXT1:
-                    {
-                        if (header->ddspf.flags == 0x04) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB;
-                        else *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA;
-                    } break;
-                    case FOURCC_DXT3: *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA; break;
-                    case FOURCC_DXT5: *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA; break;
-                    default: break;
-                }
-            }
-        }
-    }
-
-    return image_data;
-}
-#endif
-
-#if defined(RL_GPUTEX_SUPPORT_PKM)
-// Loading PKM image data (ETC1/ETC2 compression)
-// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
-// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
-void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
-{
-    void *image_data = RL_GPUTEX_NULL;        // Image data pointer
-
-    unsigned char *file_data_ptr = (unsigned char *)file_data;
-
-    // Required extensions:
-    // GL_OES_compressed_ETC1_RGB8_texture  (ETC1) (OpenGL ES 2.0)
-    // GL_ARB_ES3_compatibility  (ETC2/EAC) (OpenGL ES 3.0)
-
-    // Supported tokens (defined by extensions)
-    // GL_ETC1_RGB8_OES                 0x8D64
-    // GL_COMPRESSED_RGB8_ETC2          0x9274
-    // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
-
-    // PKM file (ETC1) Header (16 bytes)
-    typedef struct {
-        char id[4];                 // "PKM "
-        char version[2];            // "10" or "20"
-        unsigned short format;      // Data format (big-endian) (Check list below)
-        unsigned short width;       // Texture width (big-endian) (orig_width rounded to multiple of 4)
-        unsigned short height;      // Texture height (big-endian) (orig_height rounded to multiple of 4)
-        unsigned short orig_width;   // Original width (big-endian)
-        unsigned short orig_height;  // Original height (big-endian)
-    } pkm_header;
-
-    // Formats list
-    // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
-    // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R
-
-    // NOTE: The extended width and height are the widths rounded up to a multiple of 4
-    // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels)
-
-    if (file_data_ptr != RL_GPUTEX_NULL)
-    {
-        pkm_header *header = (pkm_header *)file_data_ptr;
-
-        if ((header->id[0] != 'P') || (header->id[1] != 'K') || (header->id[2] != 'M') || (header->id[3] != ' '))
-        {
-            RL_GPUTEX_LOG("PKM file data not valid");
-        }
-        else
-        {
-            file_data_ptr += sizeof(pkm_header);   // Skip header
-
-            // NOTE: format, width and height come as big-endian, data must be swapped to little-endian
-            header->format = ((header->format & 0x00FF) << 8) | ((header->format & 0xFF00) >> 8);
-            header->width = ((header->width & 0x00FF) << 8) | ((header->width & 0xFF00) >> 8);
-            header->height = ((header->height & 0x00FF) << 8) | ((header->height & 0xFF00) >> 8);
-
-            *width = header->width;
-            *height = header->height;
-            *mips = 1;
-
-            int bpp = 4;
-            if (header->format == 3) bpp = 8;
-
-            int data_size = (*width)*(*height)*bpp/8;  // Total data size in bytes
-
-            image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char));
-
-            RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-            if (header->format == 0) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB;
-            else if (header->format == 1) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB;
-            else if (header->format == 3) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
-        }
-    }
-
-    return image_data;
-}
-#endif
-
-#if defined(RL_GPUTEX_SUPPORT_KTX)
-// Load KTX compressed image data (ETC1/ETC2 compression)
-// TODO: Review KTX loading, many things changed!
-void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
-{
-    void *image_data = RL_GPUTEX_NULL;        // Image data pointer
-
-    unsigned char *file_data_ptr = (unsigned char *)file_data;
-
-    // Required extensions:
-    // GL_OES_compressed_ETC1_RGB8_texture  (ETC1)
-    // GL_ARB_ES3_compatibility  (ETC2/EAC)
-
-    // Supported tokens (defined by extensions)
-    // GL_ETC1_RGB8_OES                 0x8D64
-    // GL_COMPRESSED_RGB8_ETC2          0x9274
-    // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
-
-    // KTX file Header (64 bytes)
-    // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
-    // v2.0 - http://github.khronos.org/KTX-Specification/
-
-    // KTX 1.1 Header
-    // TODO: Support KTX 2.2 specs!
-    typedef struct {
-        char id[12];                            // Identifier: "«KTX 11»\r\n\x1A\n"
-        unsigned int endianness;                // Little endian: 0x01 0x02 0x03 0x04
-        unsigned int gl_type;                   // For compressed textures, glType must equal 0
-        unsigned int gl_type_size;              // For compressed texture data, usually 1
-        unsigned int gl_format;                 // For compressed textures is 0
-        unsigned int gl_internal_format;        // Compressed internal format
-        unsigned int gl_base_internal_format;   // Same as glFormat (RGB, RGBA, ALPHA...)
-        unsigned int width;                     // Texture image width in pixels
-        unsigned int height;                    // Texture image height in pixels
-        unsigned int depth;                     // For 2D textures is 0
-        unsigned int elements;                  // Number of array elements, usually 0
-        unsigned int faces;                     // Cubemap faces, for no-cubemap = 1
-        unsigned int mipmap_levels;             // Non-mipmapped textures = 1
-        unsigned int key_value_data_size;       // Used to encode any arbitrary data...
-    } ktx_header;
-
-    // NOTE: Before start of every mipmap data block, we have: unsigned int data_size
-
-    if (file_data_ptr != RL_GPUTEX_NULL)
-    {
-        ktx_header *header = (ktx_header *)file_data_ptr;
-
-        if ((header->id[1] != 'K') || (header->id[2] != 'T') || (header->id[3] != 'X') ||
-            (header->id[4] != ' ') || (header->id[5] != '1') || (header->id[6] != '1'))
-        {
-            RL_GPUTEX_LOG("KTX file data not valid");
-        }
-        else
-        {
-            file_data_ptr += sizeof(ktx_header);           // Move file data pointer
-
-            *width = header->width;
-            *height = header->height;
-            *mips = header->mipmap_levels;
-
-            file_data_ptr += header->key_value_data_size; // Skip value data size
-
-            int data_size = ((int *)file_data_ptr)[0];
-            file_data_ptr += sizeof(int);
-
-            image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char));
-
-            RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-            if (header->gl_internal_format == 0x8D64) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB;
-            else if (header->gl_internal_format == 0x9274) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB;
-            else if (header->gl_internal_format == 0x9278) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
-
-            // TODO: Support uncompressed data formats? Right now it returns format = 0!
-        }
-    }
-
-    return image_data;
-}
-
-// Save image data as KTX file
-// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
-// TODO: Review KTX saving, many things changed!
-int rl_save_ktx(const char *file_name, void *data, int width, int height, int format, int mipmaps)
-{
-    // KTX file Header (64 bytes)
-    // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
-    // v2.0 - https://github.khronos.org/KTX-Specification/ktxspec.v2.html
-    typedef struct {
-        char id[12];                            // Identifier: "«KTX 11»\r\n\x1A\n"         // KTX 2.0: "«KTX 20»\r\n\x1A\n"
-        unsigned int endianness;                // Little endian: 0x01 0x02 0x03 0x04
-        unsigned int gl_type;                   // For compressed textures, glType must equal 0
-        unsigned int gl_type_size;              // For compressed texture data, usually 1
-        unsigned int gl_format;                 // For compressed textures is 0
-        unsigned int gl_internal_format;        // Compressed internal format
-        unsigned int gl_base_internal_format;   // Same as glFormat (RGB, RGBA, ALPHA...)   // KTX 2.0: UInt32 vkFormat
-        unsigned int width;                     // Texture image width in pixels
-        unsigned int height;                    // Texture image height in pixels
-        unsigned int depth;                     // For 2D textures is 0
-        unsigned int elements;                  // Number of array elements, usually 0
-        unsigned int faces;                     // Cubemap faces, for no-cubemap = 1
-        unsigned int mipmap_levels;             // Non-mipmapped textures = 1
-        unsigned int key_value_data_size;       // Used to encode any arbitrary data...     // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0
-                                                                                            // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)...
-        // KTX 2.0 defines additional header elements...
-    } ktx_header;
-
-    /*
-    Byte[12] identifier
-    UInt32 vkFormat
-    UInt32 typeSize
-    UInt32 pixelWidth
-    UInt32 pixelHeight
-    UInt32 pixelDepth
-    UInt32 layerCount
-    UInt32 faceCount
-    UInt32 levelCount
-    UInt32 supercompressionScheme
-    */
-
-    // Calculate file data_size required
-    int data_size = sizeof(ktx_header);
-
-    for (int i = 0, w = width, h = height; i < mipmaps; i++)
-    {
-        data_size += get_pixel_data_size(w, h, format);
-        w /= 2; h /= 2;
-    }
-
-    unsigned char *file_data = RL_GPUTEX_MALLOC(data_size);
-    unsigned char *file_data_ptr = file_data;
-
-    ktx_header header = { 0 };
-
-    // KTX identifier (v1.1)
-    //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
-    //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
-
-    const char ktx_identifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
-
-    // Get the image header
-    RL_GPUTEX_MEMCPY(header.id, ktx_identifier, 12);  // KTX 1.1 signature
-    header.endianness = 0;
-    header.gl_type = 0;                     // Obtained from format
-    header.gl_type_size = 1;
-    header.gl_format = 0;                   // Obtained from format
-    header.gl_internal_format = 0;          // Obtained from format
-    header.gl_base_internal_format = 0;
-    header.width = width;
-    header.height = height;
-    header.depth = 0;
-    header.elements = 0;
-    header.faces = 1;
-    header.mipmap_levels = mipmaps;         // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
-    header.key_value_data_size = 0;         // No extra data after the header
-
-    // TODO: WARNING: Function dependant on rlgl library!
-    rlGetGlTextureFormats(format, &header.gl_internal_format, &header.gl_format, &header.gl_type); // rlgl module function
-
-    header.gl_base_internal_format = header.gl_format; // TODO: WARNING: KTX 1.1 only
-
-    // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
-
-    if (header.gl_format == -1) RL_GPUTEX_LOG("RL_GPUTEX: GL format not supported for KTX export (%i)", header.gl_format);
-    else
-    {
-        RL_GPUTEX_MEMCPY(file_data_ptr, &header, sizeof(ktx_header));
-        file_data_ptr += sizeof(ktx_header);
-
-        int temp_width = width;
-        int temp_height = height;
-        int data_offset = 0;
-
-        // Save all mipmaps data
-        for (int i = 0; i < mipmaps; i++)
-        {
-            unsigned int data_size = get_pixel_data_size(temp_width, temp_height, format);
-
-            RL_GPUTEX_MEMCPY(file_data_ptr, &data_size, sizeof(unsigned int));
-            RL_GPUTEX_MEMCPY(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size);
-
-            temp_width /= 2;
-            temp_height /= 2;
-            data_offset += data_size;
-            file_data_ptr += (4 + data_size);
-        }
-    }
-
-    // Save file data to file
-    int success = false;
-    FILE *file = fopen(file_name, "wb");
-
-    if (file != RL_GPUTEX_NULL)
-    {
-        unsigned int count = (unsigned int)fwrite(file_data, sizeof(unsigned char), data_size, file);
-
-        if (count == 0) RL_GPUTEX_LOG("FILEIO: [%s] Failed to write file", file_name);
-        else if (count != data_size) RL_GPUTEX_LOG("FILEIO: [%s] File partially written", file_name);
-        else (void)0; // WARN: this branch is handled by Raylib, since rl_gputex only prints warnings
-
-        int result = fclose(file);
-        if (result != 0) RL_GPUTEX_LOG("FILEIO: [%s] Failed to close file", file_name);
-
-        if (result == 0 && count == data_size) success = true;
-    }
-    else RL_GPUTEX_LOG("FILEIO: [%s] Failed to open file", file_name);
-
-    RL_GPUTEX_FREE(file_data);    // Free file data buffer
-
-    // If all data has been written correctly to file, success = 1
-    return success;
-}
-#endif
-
-#if defined(RL_GPUTEX_SUPPORT_PVR)
-// Loading PVR image data (uncompressed or PVRT compression)
-// NOTE: PVR v2 not supported, use PVR v3 instead
-void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
-{
-    void *image_data = RL_GPUTEX_NULL;        // Image data pointer
-
-    unsigned char *file_data_ptr = (unsigned char *)file_data;
-
-    // Required extension:
-    // GL_IMG_texture_compression_pvrtc
-
-    // Supported tokens (defined by extensions)
-    // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG       0x8C00
-    // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG      0x8C02
-
-#if 0   // Not used...
-    // PVR file v2 Header (52 bytes)
-    typedef struct {
-        unsigned int headerLength;
-        unsigned int height;
-        unsigned int width;
-        unsigned int numMipmaps;
-        unsigned int flags;
-        unsigned int dataLength;
-        unsigned int bpp;
-        unsigned int bitmaskRed;
-        unsigned int bitmaskGreen;
-        unsigned int bitmaskBlue;
-        unsigned int bitmaskAlpha;
-        unsigned int pvrTag;
-        unsigned int numSurfs;
-    } PVRHeaderV2;
-#endif
-
-    // PVR file v3 Header (52 bytes)
-    // NOTE: After it could be metadata (15 bytes?)
-    typedef struct {
-        char id[4];
-        unsigned int flags;
-        unsigned char channels[4];      // pixelFormat high part
-        unsigned char channel_depth[4];  // pixelFormat low part
-        unsigned int color_space;
-        unsigned int channel_type;
-        unsigned int height;
-        unsigned int width;
-        unsigned int depth;
-        unsigned int num_surfaces;
-        unsigned int num_faces;
-        unsigned int num_mipmaps;
-        unsigned int metadata_size;
-    } pvr_header;
-
-#if 0   // Not used...
-    // Metadata (usually 15 bytes)
-    typedef struct {
-        unsigned int devFOURCC;
-        unsigned int key;
-        unsigned int data_size;      // Not used?
-        unsigned char *data;        // Not used?
-    } PVRMetadata;
-#endif
-
-    if (file_data_ptr != RL_GPUTEX_NULL)
-    {
-        // Check PVR image version
-        unsigned char pvr_version = file_data_ptr[0];
-
-        // Load different PVR data formats
-        if (pvr_version == 0x50)
-        {
-            pvr_header *header = (pvr_header *)file_data_ptr;
-
-            if ((header->id[0] != 'P') || (header->id[1] != 'V') || (header->id[2] != 'R') || (header->id[3] != 3))
-            {
-                RL_GPUTEX_LOG("PVR file data not valid");
-            }
-            else
-            {
-                file_data_ptr += sizeof(pvr_header);   // Skip header
-
-                *width = header->width;
-                *height = header->height;
-                *mips = header->num_mipmaps;
-
-                // Check data format
-                if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-                else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
-                else if ((header->channels[0] == 'r') && (header->channels[1] == 'g') && (header->channels[2] == 'b'))
-                {
-                    if (header->channels[3] == 'a')
-                    {
-                        if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
-                        else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
-                        else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-                    }
-                    else if (header->channels[3] == 0)
-                    {
-                        if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5;
-                        else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8;
-                    }
-                }
-                else if (header->channels[0] == 2) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB;
-                else if (header->channels[0] == 3) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA;
-
-                file_data_ptr += header->metadata_size;    // Skip meta data header
-
-                // Calculate data size (depends on format)
-                int bpp = 0;
-                switch (*format)
-                {
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
-                    case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
-                    case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB:
-                    case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
-                    default: break;
-                }
-
-                int data_size = (*width)*(*height)*bpp/8;  // Total data size in bytes
-                image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char));
-
-                RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-            }
-        }
-        else if (pvr_version == 52) RL_GPUTEX_LOG("PVRv2 format not supported, update your files to PVRv3");
-    }
-
-    return image_data;
-}
-#endif
-
-#if defined(RL_GPUTEX_SUPPORT_ASTC)
-// Load ASTC compressed image data (ASTC compression)
-void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
-{
-    void *image_data = RL_GPUTEX_NULL;        // Image data pointer
-
-    unsigned char *file_data_ptr = (unsigned char *)file_data;
-
-    // Required extensions:
-    // GL_KHR_texture_compression_astc_hdr
-    // GL_KHR_texture_compression_astc_ldr
-
-    // Supported tokens (defined by extensions)
-    // GL_COMPRESSED_RGBA_ASTC_4x4_KHR      0x93b0
-    // GL_COMPRESSED_RGBA_ASTC_8x8_KHR      0x93b7
-
-    // ASTC file Header (16 bytes)
-    typedef struct {
-        unsigned char id[4];        // Signature: 0x13 0xAB 0xA1 0x5C
-        unsigned char blockX;       // Block X dimensions
-        unsigned char blockY;       // Block Y dimensions
-        unsigned char blockZ;       // Block Z dimensions (1 for 2D images)
-        unsigned char width[3];     // void *width in pixels (24bit value)
-        unsigned char height[3];    // void *height in pixels (24bit value)
-        unsigned char length[3];    // void *Z-size (1 for 2D images)
-    } astc_header;
-
-    if (file_data_ptr != RL_GPUTEX_NULL)
-    {
-        astc_header *header = (astc_header *)file_data_ptr;
-
-        if ((header->id[3] != 0x5c) || (header->id[2] != 0xa1) || (header->id[1] != 0xab) || (header->id[0] != 0x13))
-        {
-            RL_GPUTEX_LOG("ASTC file data not valid");
-        }
-        else
-        {
-            file_data_ptr += sizeof(astc_header);   // Skip header
-
-            // NOTE: Assuming Little Endian (could it be wrong?)
-            *width = 0x00000000 | ((int)header->width[2] << 16) | ((int)header->width[1] << 8) | ((int)header->width[0]);
-            *height = 0x00000000 | ((int)header->height[2] << 16) | ((int)header->height[1] << 8) | ((int)header->height[0]);
-            *mips = 1;      // NOTE: ASTC format only contains one mipmap level
-
-            // NOTE: Each block is always stored in 128bit so we can calculate the bpp
-            int bpp = 128/(header->blockX*header->blockY);
-
-            // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
-            if ((bpp == 8) || (bpp == 2))
-            {
-                int data_size = (*width)*(*height)*bpp/8;  // Data size in bytes
-
-                image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char));
-
-                RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size);
-
-                if (bpp == 8) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA;
-                else if (bpp == 2) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA;
-            }
-            else RL_GPUTEX_LOG("ASTC block size configuration not supported");
-        }
-    }
-
-    return image_data;
-}
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-// Get pixel data size in bytes for certain pixel format
-static int get_pixel_data_size(int width, int height, int format)
-{
-    int data_size = 0;       // Size in bytes
-    int bpp = 0;            // Bits per pixel
-
-    switch (format)
-    {
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
-        default: break;
-    }
-
-    data_size = width*height*bpp/8;  // 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 ((format >= RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8;
-        else if ((format >= RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16;
-    }
-
-    return data_size;
-}
-
-// Get OpenGL internal formats and data type from rlGpuTexPixelFormat
-void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsigned int *gl_format, unsigned int *gl_type)
-{
-    // KTX 1.1 uses OpenGL formats on header info but KTX 2.0 uses Vulkan texture formats,
-    // if this library is being improved to support KTX 2.0, it requires those formats to be provided -> View list at the end!
-
-    /*
-    *gl_internal_format = 0;
-    *gl_format = 0;
-    *gl_type = 0;
-
-    switch (format)
-    {
-    #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
-        // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_LUMINANCE_ALPHA; *gl_format = GL_LUMINANCE_ALPHA; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break;
-        #if !defined(GRAPHICS_API_OPENGL_11)
-        #if defined(GRAPHICS_API_OPENGL_ES3)
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F_EXT; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F_EXT; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_HALF_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F_EXT; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F_EXT; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break;
-        #else
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_FLOAT; break;            // NOTE: Requires extension OES_texture_float
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;                  // NOTE: Requires extension OES_texture_float
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;             // NOTE: Requires extension OES_texture_float
-        #if defined(GRAPHICS_API_OPENGL_21)
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_ARB; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_ARB; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_ARB; break;
-        #else // defined(GRAPHICS_API_OPENGL_ES2)
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_OES; break;   // NOTE: Requires extension OES_texture_half_float
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_OES; break;         // NOTE: Requires extension OES_texture_half_float
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_OES; break;    // NOTE: Requires extension OES_texture_half_float
-        #endif
-        #endif
-        #endif
-    #elif defined(GRAPHICS_API_OPENGL_33)
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_R8; *gl_format = GL_RED; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_RG8; *gl_format = GL_RG; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB565; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB8; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGB5_A1; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA4; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA8; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F; *gl_format = GL_RED; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F; *gl_format = GL_RED; *gl_type = GL_HALF_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break;
-        case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break;
-    #endif
-    #if !defined(GRAPHICS_API_OPENGL_11)
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB: *gl_internal_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB: *gl_internal_format = GL_ETC1_RGB8_OES; break;                      // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB: *gl_internal_format = GL_COMPRESSED_RGB8_ETC2; break;               // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA8_ETC2_EAC; break;     // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB: *gl_internal_format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break;    // NOTE: Requires PowerVR GPU
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break;  // NOTE: Requires PowerVR GPU
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break;  // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
-        case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break;  // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
-    #endif
-        default: RL_GPUTEX_LOG("GPUTEX: Current format not supported (%i)", format); break;
-    }
-    */
-}
-#endif // RL_GPUTEX_IMPLEMENTATION
-
-/*
-// OpenGL texture data formats
-// NOTE: Those values can be useful for KTX 1.1 saving,
-// probably only the latest OpenGL ones, not the extensions ones
-// So, there is no need to include full OpenGL headers
-#define GL_UNSIGNED_BYTE                      0x1401
-#define GL_UNSIGNED_SHORT_5_6_5               0x8363
-#define GL_UNSIGNED_SHORT_4_4_4_4             0x8033
-#define GL_UNSIGNED_SHORT_5_5_5_1             0x8034
-#define GL_FLOAT                              0x1406
-#define GL_HALF_FLOAT                         0x140b
-#define GL_HALF_FLOAT_ARB                     0x140b
-#define GL_HALF_FLOAT_OES                     0x8d61
-
-#define GL_RED_EXT                            0x1903
-#define GL_RGB                                0x1907
-#define GL_RGBA                               0x1908
-#define GL_LUMINANCE                          0x1909
-#define GL_R8                                 0x8229
-#define GL_RG8                                0x822b
-#define GL_RGB565                             0x8d62
-#define GL_RGB8                               0x8051
-#define GL_RGB5_A1                            0x8057
-#define GL_RGBA4                              0x8056
-#define GL_RGBA8                              0x8058
-#define GL_R16F                               0x822d
-#define GL_RGB16F                             0x881b
-#define GL_RGBA16F                            0x881a
-#define GL_R32F                               0x822e
-#define GL_RGB32F                             0x8815
-#define GL_RGBA32F                            0x8814
-
-#define GL_R32F_EXT                           0x822e
-#define GL_RGB32F_EXT                         0x8815
-#define GL_RGBA32F_EXT                        0x8814
-#define GL_R16F_EXT                           0x822d
-#define GL_RGB16F_EXT                         0x881b
-#define GL_RGBA16F_EXT                        0x881a
-
-// S3TC (DXT) compression
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT       0x83f0
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      0x83f1
-#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      0x83f2
-#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      0x83f3
-
-// ETC formats
-#define GL_ETC1_RGB8_OES                      0x8d64
-#define GL_COMPRESSED_RGB8_ETC2               0x9274
-#define GL_COMPRESSED_RGBA8_ETC2_EAC          0x9278
-
-// PVRTC
-#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG    0x8c00
-#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG   0x8c02
-
-// ASTC
-#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR       0x93b0
-#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR       0x93b7
-*/
-
-/*
-// Vulkan texture formats
-typedef enum VkFormat {
-    // Provided by VK_VERSION_1_0
-    VK_FORMAT_UNDEFINED = 0,
-    VK_FORMAT_R4G4_UNORM_PACK8 = 1,
-    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
-    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
-    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
-    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
-    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
-    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
-    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
-    VK_FORMAT_R8_UNORM = 9,
-    VK_FORMAT_R8_SNORM = 10,
-    VK_FORMAT_R8_USCALED = 11,
-    VK_FORMAT_R8_SSCALED = 12,
-    VK_FORMAT_R8_UINT = 13,
-    VK_FORMAT_R8_SINT = 14,
-    VK_FORMAT_R8_SRGB = 15,
-    VK_FORMAT_R8G8_UNORM = 16,
-    VK_FORMAT_R8G8_SNORM = 17,
-    VK_FORMAT_R8G8_USCALED = 18,
-    VK_FORMAT_R8G8_SSCALED = 19,
-    VK_FORMAT_R8G8_UINT = 20,
-    VK_FORMAT_R8G8_SINT = 21,
-    VK_FORMAT_R8G8_SRGB = 22,
-    VK_FORMAT_R8G8B8_UNORM = 23,
-    VK_FORMAT_R8G8B8_SNORM = 24,
-    VK_FORMAT_R8G8B8_USCALED = 25,
-    VK_FORMAT_R8G8B8_SSCALED = 26,
-    VK_FORMAT_R8G8B8_UINT = 27,
-    VK_FORMAT_R8G8B8_SINT = 28,
-    VK_FORMAT_R8G8B8_SRGB = 29,
-    VK_FORMAT_B8G8R8_UNORM = 30,
-    VK_FORMAT_B8G8R8_SNORM = 31,
-    VK_FORMAT_B8G8R8_USCALED = 32,
-    VK_FORMAT_B8G8R8_SSCALED = 33,
-    VK_FORMAT_B8G8R8_UINT = 34,
-    VK_FORMAT_B8G8R8_SINT = 35,
-    VK_FORMAT_B8G8R8_SRGB = 36,
-    VK_FORMAT_R8G8B8A8_UNORM = 37,
-    VK_FORMAT_R8G8B8A8_SNORM = 38,
-    VK_FORMAT_R8G8B8A8_USCALED = 39,
-    VK_FORMAT_R8G8B8A8_SSCALED = 40,
-    VK_FORMAT_R8G8B8A8_UINT = 41,
-    VK_FORMAT_R8G8B8A8_SINT = 42,
-    VK_FORMAT_R8G8B8A8_SRGB = 43,
-    VK_FORMAT_B8G8R8A8_UNORM = 44,
-    VK_FORMAT_B8G8R8A8_SNORM = 45,
-    VK_FORMAT_B8G8R8A8_USCALED = 46,
-    VK_FORMAT_B8G8R8A8_SSCALED = 47,
-    VK_FORMAT_B8G8R8A8_UINT = 48,
-    VK_FORMAT_B8G8R8A8_SINT = 49,
-    VK_FORMAT_B8G8R8A8_SRGB = 50,
-    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
-    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
-    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
-    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
-    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
-    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
-    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
-    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
-    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
-    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
-    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
-    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
-    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
-    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
-    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
-    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
-    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
-    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
-    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
-    VK_FORMAT_R16_UNORM = 70,
-    VK_FORMAT_R16_SNORM = 71,
-    VK_FORMAT_R16_USCALED = 72,
-    VK_FORMAT_R16_SSCALED = 73,
-    VK_FORMAT_R16_UINT = 74,
-    VK_FORMAT_R16_SINT = 75,
-    VK_FORMAT_R16_SFLOAT = 76,
-    VK_FORMAT_R16G16_UNORM = 77,
-    VK_FORMAT_R16G16_SNORM = 78,
-    VK_FORMAT_R16G16_USCALED = 79,
-    VK_FORMAT_R16G16_SSCALED = 80,
-    VK_FORMAT_R16G16_UINT = 81,
-    VK_FORMAT_R16G16_SINT = 82,
-    VK_FORMAT_R16G16_SFLOAT = 83,
-    VK_FORMAT_R16G16B16_UNORM = 84,
-    VK_FORMAT_R16G16B16_SNORM = 85,
-    VK_FORMAT_R16G16B16_USCALED = 86,
-    VK_FORMAT_R16G16B16_SSCALED = 87,
-    VK_FORMAT_R16G16B16_UINT = 88,
-    VK_FORMAT_R16G16B16_SINT = 89,
-    VK_FORMAT_R16G16B16_SFLOAT = 90,
-    VK_FORMAT_R16G16B16A16_UNORM = 91,
-    VK_FORMAT_R16G16B16A16_SNORM = 92,
-    VK_FORMAT_R16G16B16A16_USCALED = 93,
-    VK_FORMAT_R16G16B16A16_SSCALED = 94,
-    VK_FORMAT_R16G16B16A16_UINT = 95,
-    VK_FORMAT_R16G16B16A16_SINT = 96,
-    VK_FORMAT_R16G16B16A16_SFLOAT = 97,
-    VK_FORMAT_R32_UINT = 98,
-    VK_FORMAT_R32_SINT = 99,
-    VK_FORMAT_R32_SFLOAT = 100,
-    VK_FORMAT_R32G32_UINT = 101,
-    VK_FORMAT_R32G32_SINT = 102,
-    VK_FORMAT_R32G32_SFLOAT = 103,
-    VK_FORMAT_R32G32B32_UINT = 104,
-    VK_FORMAT_R32G32B32_SINT = 105,
-    VK_FORMAT_R32G32B32_SFLOAT = 106,
-    VK_FORMAT_R32G32B32A32_UINT = 107,
-    VK_FORMAT_R32G32B32A32_SINT = 108,
-    VK_FORMAT_R32G32B32A32_SFLOAT = 109,
-    VK_FORMAT_R64_UINT = 110,
-    VK_FORMAT_R64_SINT = 111,
-    VK_FORMAT_R64_SFLOAT = 112,
-    VK_FORMAT_R64G64_UINT = 113,
-    VK_FORMAT_R64G64_SINT = 114,
-    VK_FORMAT_R64G64_SFLOAT = 115,
-    VK_FORMAT_R64G64B64_UINT = 116,
-    VK_FORMAT_R64G64B64_SINT = 117,
-    VK_FORMAT_R64G64B64_SFLOAT = 118,
-    VK_FORMAT_R64G64B64A64_UINT = 119,
-    VK_FORMAT_R64G64B64A64_SINT = 120,
-    VK_FORMAT_R64G64B64A64_SFLOAT = 121,
-    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
-    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
-    VK_FORMAT_D16_UNORM = 124,
-    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
-    VK_FORMAT_D32_SFLOAT = 126,
-    VK_FORMAT_S8_UINT = 127,
-    VK_FORMAT_D16_UNORM_S8_UINT = 128,
-    VK_FORMAT_D24_UNORM_S8_UINT = 129,
-    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
-    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
-    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
-    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
-    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
-    VK_FORMAT_BC2_UNORM_BLOCK = 135,
-    VK_FORMAT_BC2_SRGB_BLOCK = 136,
-    VK_FORMAT_BC3_UNORM_BLOCK = 137,
-    VK_FORMAT_BC3_SRGB_BLOCK = 138,
-    VK_FORMAT_BC4_UNORM_BLOCK = 139,
-    VK_FORMAT_BC4_SNORM_BLOCK = 140,
-    VK_FORMAT_BC5_UNORM_BLOCK = 141,
-    VK_FORMAT_BC5_SNORM_BLOCK = 142,
-    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
-    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
-    VK_FORMAT_BC7_UNORM_BLOCK = 145,
-    VK_FORMAT_BC7_SRGB_BLOCK = 146,
-    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
-    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
-    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
-    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
-    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
-    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
-    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
-    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
-    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
-    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
-    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
-    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
-    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
-    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
-    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
-    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
-    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
-    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
-    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
-    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
-    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
-    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
-    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
-    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
-    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
-    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
-    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
-    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
-    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
-    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
-    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
-    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
-    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
-    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
-    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
-    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
-    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
-    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
-    // Provided by VK_VERSION_1_1
-    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012,
-    // Provided by VK_VERSION_1_3
-    VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013,
-    // Provided by VK_VERSION_1_4
-    VK_FORMAT_A1B5G5R5_UNORM_PACK16 = 1000470000,
-    // Provided by VK_VERSION_1_4
-    VK_FORMAT_A8_UNORM = 1000470001,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
-    // Provided by VK_IMG_format_pvrtc
-    VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
-    // Provided by VK_ARM_tensors
-    VK_FORMAT_R8_BOOL_ARM = 1000460000,
-    // Provided by VK_NV_optical_flow
-    VK_FORMAT_R16G16_SFIXED5_NV = 1000464000,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R10X6_UINT_PACK16_ARM = 1000609000,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R10X6G10X6_UINT_2PACK16_ARM = 1000609001,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R10X6G10X6B10X6A10X6_UINT_4PACK16_ARM = 1000609002,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R12X4_UINT_PACK16_ARM = 1000609003,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R12X4G12X4_UINT_2PACK16_ARM = 1000609004,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R12X4G12X4B12X4A12X4_UINT_4PACK16_ARM = 1000609005,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2_UINT_PACK16_ARM = 1000609006,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2G14X2_UINT_2PACK16_ARM = 1000609007,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2G14X2B14X2A14X2_UINT_4PACK16_ARM = 1000609008,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2_UNORM_PACK16_ARM = 1000609009,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2G14X2_UNORM_2PACK16_ARM = 1000609010,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_R14X2G14X2B14X2A14X2_UNORM_4PACK16_ARM = 1000609011,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_G14X2_B14X2R14X2_2PLANE_420_UNORM_3PACK16_ARM = 1000609012,
-    // Provided by VK_ARM_format_pack
-    VK_FORMAT_G14X2_B14X2R14X2_2PLANE_422_UNORM_3PACK16_ARM = 1000609013,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK,
-    // Provided by VK_EXT_texture_compression_astc_hdr
-    VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
-    // Provided by VK_KHR_sampler_ycbcr_conversion
-    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
-    // Provided by VK_EXT_ycbcr_2plane_444_formats
-    VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
-    // Provided by VK_EXT_ycbcr_2plane_444_formats
-    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16,
-    // Provided by VK_EXT_ycbcr_2plane_444_formats
-    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16,
-    // Provided by VK_EXT_ycbcr_2plane_444_formats
-    VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM,
-    // Provided by VK_EXT_4444_formats
-    VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16,
-    // Provided by VK_EXT_4444_formats
-    VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16,
-    // Provided by VK_NV_optical_flow
-    // VK_FORMAT_R16G16_S10_5_NV is a deprecated alias
-    VK_FORMAT_R16G16_S10_5_NV = VK_FORMAT_R16G16_SFIXED5_NV,
-    // Provided by VK_KHR_maintenance5
-    VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = VK_FORMAT_A1B5G5R5_UNORM_PACK16,
-    // Provided by VK_KHR_maintenance5
-    VK_FORMAT_A8_UNORM_KHR = VK_FORMAT_A8_UNORM,
-} VkFormat;
-*/
diff --git a/raylib/src/external/rlsw.h b/raylib/src/external/rlsw.h
--- a/raylib/src/external/rlsw.h
+++ b/raylib/src/external/rlsw.h
@@ -1,4801 +1,6025 @@
 /**********************************************************************************************
 *
-*   rlsw v1.0 - An OpenGL 1.1-style software renderer implementation
-*
-*   DESCRIPTION:
-*       rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all
-*       functionality available on rlgl.h library used by raylib, becoming a direct software
-*       rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less
-*       devices when required
-*
-*   FEATURES:
-*       - Rendering to custom internal framebuffer with multiple color modes supported:
-*           - Color buffer: RGB - 8-bit (3:3:2) | RGB - 16-bit (5:6:5) | RGB - 24-bit (8:8:8)
-*           - Depth buffer: D - 8-bit (unorm) | D - 16-bit (unorm) | D - 24-bit (unorm)
-*       - Rendering modes supported: POINT, LINES, TRIANGLE, QUADS
-*           - Additional features: Polygon modes, Point width, Line width
-*       - Clipping support for all rendering modes
-*       - Texture features supported:
-*           - All uncompressed texture formats supported by raylib
-*           - Texture Minification/Magnification checks
-*           - Point and Bilinear filtering
-*           - Texture Wrap Modes with separate checks for S/T coordinates
-*       - Vertex Arrays support with direct primitive drawing mode
-*       - Matrix Stack support (Matrix Push/Pop)
-*       - Other GL misc features:
-*           - GL-style getter functions
-*           - Framebuffer resizing
-*           - Perspective correction
-*           - Scissor clipping
-*           - Depth testing
-*           - Blend modes
-*           - Face culling
-*
-*   ADDITIONAL NOTES:
-*       Check PR for more info: https://github.com/raysan5/raylib/pull/4832
-*
-*   CONFIGURATION:
-*       #define RLSW_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 RLSW_USE_SIMD_INTRINSICS
-*           Detect and use SIMD intrinsics on the host compilation platform
-*           SIMD could improve rendering considerable vectorizing some raster operations
-*           but the target platforms running the compiled program with SIMD enabled
-*           must support the SIMD the program has been built for, making them only
-*           recommended under specific situations and only if the developers know
-*           what are they doing; this flag is not defined by default
-*
-*       rlsw capabilities could be customized just defining some internal
-*       values before library inclusion (default values listed):
-*
-*           #define SW_GL_FRAMEBUFFER_COPY_BGRA     true
-*           #define SW_GL_BINDING_COPY_TEXTURE      true
-*           #define SW_COLOR_BUFFER_BITS            24
-*           #define SW_DEPTH_BUFFER_BITS            16
-*           #define SW_MAX_PROJECTION_STACK_SIZE    2
-*           #define SW_MAX_MODELVIEW_STACK_SIZE     8
-*           #define SW_MAX_TEXTURE_STACK_SIZE       2
-*           #define SW_MAX_TEXTURES                 128
-*
-*
-*   LICENSE: MIT
-*
-*   Copyright (c) 2025-2026 Le Juez Victor (@Bigfoot71), reviewed by Ramon Santamaria (@raysan5)
-*
-*   Permission is hereby granted, free of charge, to any person obtaining a copy
-*   of this software and associated documentation files (the "Software"), to deal
-*   in the Software without restriction, including without limitation the rights
-*   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-*   copies of the Software, and to permit persons to whom the Software is
-*   furnished to do so, subject to the following conditions:
-*
-*   The above copyright notice and this permission notice shall be included in all
-*   copies or substantial portions of the Software.
-*
-*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-*   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-*   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-*   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-*   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-*   SOFTWARE.
-*
-**********************************************************************************************/
-
-#ifndef RLSW_H
-#define RLSW_H
-
-#include <stdbool.h>
-#include <stdint.h>
-
-//----------------------------------------------------------------------------------
-// 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_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_GL_FRAMEBUFFER_COPY_BGRA
-    #define SW_GL_FRAMEBUFFER_COPY_BGRA     true
-#endif
-
-#ifndef SW_COLOR_BUFFER_BITS
-    #define SW_COLOR_BUFFER_BITS            32  //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed)
-#endif
-
-#ifndef SW_DEPTH_BUFFER_BITS
-    #define SW_DEPTH_BUFFER_BITS            16  //< 32, 24 or 16
-#endif
-
-#ifndef SW_MAX_PROJECTION_STACK_SIZE
-    #define SW_MAX_PROJECTION_STACK_SIZE    2
-#endif
-
-#ifndef SW_MAX_MODELVIEW_STACK_SIZE
-    #define SW_MAX_MODELVIEW_STACK_SIZE     8
-#endif
-
-#ifndef SW_MAX_TEXTURE_STACK_SIZE
-    #define SW_MAX_TEXTURE_STACK_SIZE       2
-#endif
-
-#ifndef SW_MAX_TEXTURES
-    #define SW_MAX_TEXTURES                 128
-#endif
-
-// Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane
-// Considering the largest polygon involved is a quadrilateral (4 vertices),
-// and that clipping occurs against both the frustum (6 planes) and the scissors (4 planes),
-// the maximum number of vertices after clipping is:
-// 4 (original vertices) + 6 (frustum planes) + 4 (scissors planes) = 14
-#ifndef SW_MAX_CLIPPED_POLYGON_VERTICES
-    #define SW_MAX_CLIPPED_POLYGON_VERTICES 14
-#endif
-
-#ifndef SW_CLIP_EPSILON
-    #define SW_CLIP_EPSILON                 1e-4f
-#endif
-
-//----------------------------------------------------------------------------------
-// OpenGL Compatibility Types
-//----------------------------------------------------------------------------------
-typedef unsigned int        GLenum;
-typedef unsigned char       GLboolean;
-typedef unsigned int        GLbitfield;
-typedef void                GLvoid;
-typedef signed char         GLbyte;
-typedef short               GLshort;
-typedef int                 GLint;
-typedef unsigned char       GLubyte;
-typedef unsigned short      GLushort;
-typedef unsigned int        GLuint;
-typedef int                 GLsizei;
-typedef float               GLfloat;
-typedef float               GLclampf;
-typedef double              GLdouble;
-typedef double              GLclampd;
-
-//----------------------------------------------------------------------------------
-// OpenGL Definitions
-// NOTE: Not used/supported definitions are commented
-//----------------------------------------------------------------------------------
-#define GL_FALSE                            0
-#define GL_TRUE                             1
-
-#define GL_SCISSOR_TEST                     0x0C11
-#define GL_TEXTURE_2D                       0x0DE1
-#define GL_DEPTH_TEST                       0x0B71
-#define GL_CULL_FACE                        0x0B44
-#define GL_BLEND                            0x0BE2
-
-#define GL_VENDOR                           0x1F00
-#define GL_RENDERER                         0x1F01
-#define GL_VERSION                          0x1F02
-#define GL_EXTENSIONS                       0x1F03
-
-//#define GL_ATTRIB_STACK_DEPTH             0x0BB0
-//#define GL_CLIENT_ATTRIB_STACK_DEPTH      0x0BB1
-#define GL_COLOR_CLEAR_VALUE                0x0C22
-#define GL_DEPTH_CLEAR_VALUE                0x0B73
-//#define GL_COLOR_WRITEMASK                0x0C23
-//#define GL_CURRENT_INDEX                  0x0B01
-#define GL_CURRENT_COLOR                    0x0B00
-//#define GL_CURRENT_NORMAL                 0x0B02
-//#define GL_CURRENT_RASTER_COLOR           0x0B04
-//#define GL_CURRENT_RASTER_DISTANCE        0x0B09
-//#define GL_CURRENT_RASTER_INDEX           0x0B05
-//#define GL_CURRENT_RASTER_POSITION        0x0B07
-//#define GL_CURRENT_RASTER_TEXTURE_COORDS  0x0B06
-//#define GL_CURRENT_RASTER_POSITION_VALID  0x0B08
-#define GL_CURRENT_TEXTURE_COORDS           0x0B03
-#define GL_POINT_SIZE                       0x0B11
-#define GL_LINE_WIDTH                       0x0B21
-//#define GL_INDEX_CLEAR_VALUE              0x0C20
-//#define GL_INDEX_MODE                     0x0C30
-//#define GL_INDEX_WRITEMASK                0x0C21
-#define GL_MODELVIEW_MATRIX                 0x0BA6
-#define GL_MODELVIEW_STACK_DEPTH            0x0BA3
-//#define GL_NAME_STACK_DEPTH               0x0D70
-#define GL_PROJECTION_MATRIX                0x0BA7
-#define GL_PROJECTION_STACK_DEPTH           0x0BA4
-//#define GL_RENDER_MODE                    0x0C40
-//#define GL_RGBA_MODE                      0x0C31
-#define GL_TEXTURE_MATRIX                   0x0BA8
-#define GL_TEXTURE_STACK_DEPTH              0x0BA5
-#define GL_VIEWPORT                         0x0BA2
-
-#define GL_COLOR_BUFFER_BIT                 0x00004000
-#define GL_DEPTH_BUFFER_BIT                 0x00000100
-
-#define GL_MODELVIEW                        0x1700
-#define GL_PROJECTION                       0x1701
-#define GL_TEXTURE                          0x1702
-
-#define GL_VERTEX_ARRAY                     0x8074
-#define GL_NORMAL_ARRAY                     0x8075      // WARNING: Not implemented (defined for RLGL)
-#define GL_COLOR_ARRAY                      0x8076
-//#define GL_INDEX_ARRAY                    0x8077
-#define GL_TEXTURE_COORD_ARRAY              0x8078
-
-#define GL_POINTS                           0x0000
-#define GL_LINES                            0x0001
-//#define GL_LINE_LOOP                      0x0002
-//#define GL_LINE_STRIP                     0x0003
-#define GL_TRIANGLES                        0x0004
-//#define GL_TRIANGLE_STRIP                 0x0005
-//#define GL_TRIANGLE_FAN                   0x0006
-#define GL_QUADS                            0x0007
-//#define GL_QUAD_STRIP                     0x0008
-//#define GL_POLYGON                        0x0009
-
-#define GL_POINT                            0x1B00
-#define GL_LINE                             0x1B01
-#define GL_FILL                             0x1B02
-
-#define GL_FRONT                            0x0404
-#define GL_BACK                             0x0405
-
-#define GL_ZERO                             0
-#define GL_ONE                              1
-#define GL_SRC_COLOR                        0x0300
-#define GL_ONE_MINUS_SRC_COLOR              0x0301
-#define GL_SRC_ALPHA                        0x0302
-#define GL_ONE_MINUS_SRC_ALPHA              0x0303
-#define GL_DST_ALPHA                        0x0304
-#define GL_ONE_MINUS_DST_ALPHA              0x0305
-#define GL_DST_COLOR                        0x0306
-#define GL_ONE_MINUS_DST_COLOR              0x0307
-#define GL_SRC_ALPHA_SATURATE               0x0308
-
-#define GL_NEAREST                          0x2600
-#define GL_LINEAR                           0x2601
-
-#define GL_REPEAT                           0x2901
-#define GL_CLAMP                            0x2900
-
-#define GL_TEXTURE_MAG_FILTER               0x2800
-#define GL_TEXTURE_MIN_FILTER               0x2801
-
-#define GL_TEXTURE_WRAP_S                   0x2802
-#define GL_TEXTURE_WRAP_T                   0x2803
-
-#define GL_NO_ERROR                         0
-#define GL_INVALID_ENUM                     0x0500
-#define GL_INVALID_VALUE                    0x0501
-#define GL_INVALID_OPERATION                0x0502
-#define GL_STACK_OVERFLOW                   0x0503
-#define GL_STACK_UNDERFLOW                  0x0504
-#define GL_OUT_OF_MEMORY                    0x0505
-
-#define GL_ALPHA                            0x1906
-#define GL_LUMINANCE                        0x1909
-#define GL_LUMINANCE_ALPHA                  0x190A
-#define GL_RGB                              0x1907
-#define GL_RGBA                             0x1908
-
-#define GL_BYTE                             0x1400
-#define GL_UNSIGNED_BYTE                    0x1401
-#define GL_SHORT                            0x1402
-#define GL_UNSIGNED_SHORT                   0x1403
-#define GL_INT                              0x1404
-#define GL_UNSIGNED_INT                     0x1405
-#define GL_FLOAT                            0x1406
-
-// OpenGL Definitions NOT USED
-#define GL_PERSPECTIVE_CORRECTION_HINT      0x0C50
-#define GL_PACK_ALIGNMENT                   0x0D05
-#define GL_UNPACK_ALIGNMENT                 0x0CF5
-#define GL_LINE_SMOOTH                      0x0B20
-#define GL_SMOOTH                           0x1D01
-#define GL_NICEST                           0x1102
-#define GL_CCW                              0x0901
-#define GL_CW                               0x0900
-#define GL_NEVER                            0x0200
-#define GL_LESS                             0x0201
-#define GL_EQUAL                            0x0202
-#define GL_LEQUAL                           0x0203
-#define GL_GREATER                          0x0204
-#define GL_NOTEQUAL                         0x0205
-#define GL_GEQUAL                           0x0206
-#define GL_ALWAYS                           0x0207
-
-//----------------------------------------------------------------------------------
-// OpenGL Bindings to rlsw
-//----------------------------------------------------------------------------------
-#define glReadPixels(x, y, w, h, f, t, p)           swCopyFramebuffer((x), (y), (w), (h), (f), (t), (p))
-#define glEnable(state)                             swEnable((state))
-#define glDisable(state)                            swDisable((state))
-#define glGetFloatv(pname, params)                  swGetFloatv((pname), (params))
-#define glGetString(pname)                          swGetString((pname))
-#define glGetError()                                swGetError()
-#define glViewport(x, y, w, h)                      swViewport((x), (y), (w), (h))
-#define glScissor(x, y, w, h)                       swScissor((x), (y), (w), (h))
-#define glClearColor(r, g, b, a)                    swClearColor((r), (g), (b), (a))
-#define glClearDepth(d)                             swClearDepth((d))
-#define glClear(bitmask)                            swClear((bitmask))
-#define glBlendFunc(sfactor, dfactor)               swBlendFunc((sfactor), (dfactor))
-#define glPolygonMode(face, mode)                   swPolygonMode((mode))
-#define glCullFace(face)                            swCullFace((face))
-#define glPointSize(size)                           swPointSize((size))
-#define glLineWidth(width)                          swLineWidth((width))
-#define glMatrixMode(mode)                          swMatrixMode((mode))
-#define glPushMatrix()                              swPushMatrix()
-#define glPopMatrix()                               swPopMatrix()
-#define glLoadIdentity()                            swLoadIdentity()
-#define glTranslatef(x, y, z)                       swTranslatef((x), (y), (z))
-#define glRotatef(a, x, y, z)                       swRotatef((a), (x), (y), (z))
-#define glScalef(x, y, z)                           swScalef((x), (y), (z))
-#define glMultMatrixf(v)                            swMultMatrixf((v))
-#define glFrustum(l, r, b, t, n, f)                 swFrustum((l), (r), (b), (t), (n), (f))
-#define glOrtho(l, r, b, t, n, f)                   swOrtho((l), (r), (b), (t), (n), (f))
-#define glBegin(mode)                               swBegin((mode))
-#define glEnd()                                     swEnd()
-#define glVertex2i(x, y)                            swVertex2i((x), (y))
-#define glVertex2f(x, y)                            swVertex2f((x), (y))
-#define glVertex2fv(v)                              swVertex2fv((v))
-#define glVertex3i(x, y, z)                         swVertex3i((x), (y), (z))
-#define glVertex3f(x, y, z)                         swVertex3f((x), (y), (z))
-#define glvertex3fv(v)                              swVertex3fv((v))
-#define glVertex4i(x, y, z, w)                      swVertex4i((x), (y), (z), (w))
-#define glVertex4f(x, y, z, w)                      swVertex4f((x), (y), (z), (w))
-#define glVertex4fv(v)                              swVertex4fv((v))
-#define glColor3ub(r, g, b)                         swColor3ub((r), (g), (b))
-#define glColor3ubv(v)                              swColor3ubv((v))
-#define glColor3f(r, g, b)                          swColor3f((r), (g), (b))
-#define glColor3fv(v)                               swColor3fv((v))
-#define glColor4ub(r, g, b, a)                      swColor4ub((r), (g), (b), (a))
-#define glColor4ubv(v)                              swColor4ubv((v))
-#define glColor4f(r, g, b, a)                       swColor4f((r), (g), (b), (a))
-#define glColor4fv(v)                               swColor4fv((v))
-#define glTexCoord2f(u, v)                          swTexCoord2f((u), (v))
-#define glTexCoord2fv(v)                            swTexCoord2fv((v))
-
-#define glEnableClientState(t)                      ((void)(t))
-#define glDisableClientState(t)                     swBindArray((t), 0)
-#define glVertexPointer(sz, t, s, p)                swBindArray(SW_VERTEX_ARRAY, (p))
-#define glTexCoordPointer(sz, t, s, p)              swBindArray(SW_TEXTURE_COORD_ARRAY, (p))
-#define glColorPointer(sz, t, s, p)                 swBindArray(SW_COLOR_ARRAY, (p))
-#define glDrawArrays(m, o, c)                       swDrawArrays((m), (o), (c))
-#define glDrawElements(m,c,t,i)                     swDrawElements((m),(c),(t),(i))
-#define glGenTextures(c, v)                         swGenTextures((c), (v))
-#define glDeleteTextures(c, v)                      swDeleteTextures((c), (v))
-#define glTexImage2D(tr, l, if, w, h, b, f, t, p)   swTexImage2D((w), (h), (f), (t), (p))
-#define glTexParameteri(tr, pname, param)           swTexParameteri((pname), (param))
-#define glBindTexture(tr, id)                       swBindTexture((id))
-
-// OpenGL functions NOT IMPLEMENTED by rlsw
-#define glDepthMask(X)                          ((void)(X))
-#define glColorMask(X,Y,Z,W)                    ((void)(X),(void)(Y),(void)(Z),(void)(W))
-#define glPixelStorei(X,Y)                      ((void)(X),(void)(Y))
-#define glHint(X,Y)                             ((void)(X),(void)(Y))
-#define glShadeModel(X)                         ((void)(X))
-#define glFrontFace(X)                          ((void)(X))
-#define glDepthFunc(X)                          ((void)(X))
-#define glTexSubImage2D(X,Y,Z,W,A,B,C,D,E)      ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A),(void)(B),(void)(C),(void)(D),(void)(E))
-#define glGetTexImage(X,Y,Z,W,A)                ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A))
-#define glNormal3f(X,Y,Z)                       ((void)(X),(void)(Y),(void)(Z))
-#define glNormal3fv(X)                          ((void)(X))
-#define glNormalPointer(X,Y,Z)                  ((void)(X),(void)(Y),(void)(Z))
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-typedef enum {
-    SW_SCISSOR_TEST = GL_SCISSOR_TEST,
-    SW_TEXTURE_2D = GL_TEXTURE_2D,
-    SW_DEPTH_TEST = GL_DEPTH_TEST,
-    SW_CULL_FACE = GL_CULL_FACE,
-    SW_BLEND = GL_BLEND
-} SWstate;
-
-typedef enum {
-    SW_VENDOR = GL_VENDOR,
-    SW_RENDERER = GL_RENDERER,
-    SW_VERSION = GL_VERSION,
-    SW_EXTENSIONS = GL_EXTENSIONS,
-    SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
-    SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
-    SW_CURRENT_COLOR = GL_CURRENT_COLOR,
-    SW_CURRENT_TEXTURE_COORDS = GL_CURRENT_TEXTURE_COORDS,
-    SW_POINT_SIZE = GL_POINT_SIZE,
-    SW_LINE_WIDTH = GL_LINE_WIDTH,
-    SW_MODELVIEW_MATRIX = GL_MODELVIEW_MATRIX,
-    SW_MODELVIEW_STACK_DEPTH = GL_MODELVIEW_STACK_DEPTH,
-    SW_PROJECTION_MATRIX = GL_PROJECTION_MATRIX,
-    SW_PROJECTION_STACK_DEPTH = GL_PROJECTION_STACK_DEPTH,
-    SW_TEXTURE_MATRIX = GL_TEXTURE_MATRIX,
-    SW_TEXTURE_STACK_DEPTH = GL_TEXTURE_STACK_DEPTH,
-    SW_VIEWPORT = GL_VIEWPORT
-} SWget;
-
-typedef enum {
-    SW_COLOR_BUFFER_BIT = GL_COLOR_BUFFER_BIT,
-    SW_DEPTH_BUFFER_BIT = GL_DEPTH_BUFFER_BIT
-} SWbuffer;
-
-typedef enum {
-    SW_PROJECTION = GL_PROJECTION,
-    SW_MODELVIEW = GL_MODELVIEW,
-    SW_TEXTURE = GL_TEXTURE
-} SWmatrix;
-
-typedef enum {
-    SW_VERTEX_ARRAY = GL_VERTEX_ARRAY,
-    SW_TEXTURE_COORD_ARRAY = GL_TEXTURE_COORD_ARRAY,
-    SW_COLOR_ARRAY = GL_COLOR_ARRAY
-} SWarray;
-
-typedef enum {
-    SW_POINTS = GL_POINTS,
-    SW_LINES = GL_LINES,
-    SW_TRIANGLES = GL_TRIANGLES,
-    SW_QUADS = GL_QUADS
-} SWdraw;
-
-typedef enum {
-    SW_POINT = GL_POINT,
-    SW_LINE = GL_LINE,
-    SW_FILL = GL_FILL
-} SWpoly;
-
-typedef enum {
-    SW_FRONT = GL_FRONT,
-    SW_BACK = GL_BACK,
-} SWface;
-
-typedef enum {
-    SW_ZERO = GL_ZERO,
-    SW_ONE = GL_ONE,
-    SW_SRC_COLOR = GL_SRC_COLOR,
-    SW_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
-    SW_SRC_ALPHA = GL_SRC_ALPHA,
-    SW_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,
-    SW_DST_ALPHA = GL_DST_ALPHA,
-    SW_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,
-    SW_DST_COLOR = GL_DST_COLOR,
-    SW_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,
-    SW_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE
-} SWfactor;
-
-typedef enum {
-    SW_LUMINANCE = GL_LUMINANCE,
-    SW_LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA,
-    SW_RGB = GL_RGB,
-    SW_RGBA = GL_RGBA,
-} SWformat;
-
-typedef enum {
-    SW_UNSIGNED_BYTE = GL_UNSIGNED_BYTE,
-    SW_BYTE = GL_BYTE,
-    SW_UNSIGNED_SHORT = GL_UNSIGNED_SHORT,
-    SW_SHORT = GL_SHORT,
-    SW_UNSIGNED_INT = GL_UNSIGNED_INT,
-    SW_INT = GL_INT,
-    SW_FLOAT = GL_FLOAT
-} SWtype;
-
-typedef enum {
-    SW_NEAREST = GL_NEAREST,
-    SW_LINEAR = GL_LINEAR
-} SWfilter;
-
-typedef enum {
-    SW_REPEAT = GL_REPEAT,
-    SW_CLAMP = GL_CLAMP,
-} SWwrap;
-
-typedef enum {
-    SW_TEXTURE_MIN_FILTER = GL_TEXTURE_MIN_FILTER,
-    SW_TEXTURE_MAG_FILTER = GL_TEXTURE_MAG_FILTER,
-    SW_TEXTURE_WRAP_S = GL_TEXTURE_WRAP_S,
-    SW_TEXTURE_WRAP_T = GL_TEXTURE_WRAP_T
-} SWtexparam;
-
-typedef enum {
-    SW_NO_ERROR = GL_NO_ERROR,
-    SW_INVALID_ENUM = GL_INVALID_ENUM,
-    SW_INVALID_VALUE = GL_INVALID_VALUE,
-    SW_STACK_OVERFLOW = GL_STACK_OVERFLOW,
-    SW_STACK_UNDERFLOW = GL_STACK_UNDERFLOW,
-    SW_INVALID_OPERATION = GL_INVALID_OPERATION,
-} SWerrcode;
-
-//------------------------------------------------------------------------------------
-// Functions Declaration - Public API
-//------------------------------------------------------------------------------------
-SWAPI bool swInit(int w, int h);
-SWAPI void swClose(void);
-
-SWAPI bool swResizeFramebuffer(int w, int h);
-SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels);
-SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels);
-
-SWAPI void swEnable(SWstate state);
-SWAPI void swDisable(SWstate state);
-
-SWAPI void swGetFloatv(SWget name, float *v);
-SWAPI const char *swGetString(SWget name);
-SWAPI SWerrcode swGetError(void);
-
-SWAPI void swViewport(int x, int y, int width, int height);
-SWAPI void swScissor(int x, int y, int width, int height);
-
-SWAPI void swClearColor(float r, float g, float b, float a);
-SWAPI void swClearDepth(float depth);
-SWAPI void swClear(uint32_t bitmask);
-
-SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor);
-SWAPI void swPolygonMode(SWpoly mode);
-SWAPI void swCullFace(SWface face);
-
-SWAPI void swPointSize(float size);
-SWAPI void swLineWidth(float width);
-
-SWAPI void swMatrixMode(SWmatrix mode);
-SWAPI void swPushMatrix(void);
-SWAPI void swPopMatrix(void);
-SWAPI void swLoadIdentity(void);
-SWAPI void swTranslatef(float x, float y, float z);
-SWAPI void swRotatef(float angle, float x, float y, float z);
-SWAPI void swScalef(float x, float y, float z);
-SWAPI void swMultMatrixf(const float *mat);
-SWAPI void swFrustum(double left, double right, double bottom, double top, double znear, double zfar);
-SWAPI void swOrtho(double left, double right, double bottom, double top, double znear, double zfar);
-
-SWAPI void swBegin(SWdraw mode);
-SWAPI void swEnd(void);
-
-SWAPI void swVertex2i(int x, int y);
-SWAPI void swVertex2f(float x, float y);
-SWAPI void swVertex2fv(const float *v);
-SWAPI void swVertex3i(int x, int y, int z);
-SWAPI void swVertex3f(float x, float y, float z);
-SWAPI void swVertex3fv(const float *v);
-SWAPI void swVertex4i(int x, int y, int z, int w);
-SWAPI void swVertex4f(float x, float y, float z, float w);
-SWAPI void swVertex4fv(const float *v);
-
-SWAPI void swColor3ub(uint8_t r, uint8_t g, uint8_t b);
-SWAPI void swColor3ubv(const uint8_t *v);
-SWAPI void swColor3f(float r, float g, float b);
-SWAPI void swColor3fv(const float *v);
-SWAPI void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
-SWAPI void swColor4ubv(const uint8_t *v);
-SWAPI void swColor4f(float r, float g, float b, float a);
-SWAPI void swColor4fv(const float *v);
-
-SWAPI void swTexCoord2f(float u, float v);
-SWAPI void swTexCoord2fv(const float *v);
-
-SWAPI void swBindArray(SWarray type, void *buffer);
-SWAPI void swDrawArrays(SWdraw mode, int offset, int count);
-SWAPI void swDrawElements(SWdraw mode, int count, int type, const void *indices);
-
-SWAPI void swGenTextures(int count, uint32_t *textures);
-SWAPI void swDeleteTextures(int count, uint32_t *textures);
-
-SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data);
-SWAPI void swTexParameteri(int param, int value);
-SWAPI void swBindTexture(uint32_t id);
-
-#endif // RLSW_H
-
-/***********************************************************************************
-*
-*   RLSW IMPLEMENTATION
-*
-************************************************************************************/
-#define RLSW_IMPLEMENTATION
-#if defined(RLSW_IMPLEMENTATION)
-
-#include <stdlib.h>         // Required for: malloc(), free()
-#include <stddef.h>         // Required for: NULL, size_t, uint8_t, uint16_t, uint32_t...
-#include <math.h>           // Required for: sinf(), cosf(), floorf(), fabsf(), sqrtf(), roundf()
-
-// Simple log system to avoid printf() calls if required
-// NOTE: Avoiding those calls, also avoids const strings memory usage
-#define SW_SUPPORT_LOG_INFO
-#if defined(SW_SUPPORT_LOG_INFO) //&& defined(_DEBUG)      // WARNING: LOG() output required for this tool
-    #include <stdio.h>
-    #define SW_LOG(...) printf(__VA_ARGS__)
-#else
-    #define SW_LOG(...)
-#endif
-
-#if defined(_MSC_VER)
-    #define SW_ALIGN(x) __declspec(align(x))
-#elif defined(__GNUC__) || defined(__clang__)
-    #define SW_ALIGN(x) __attribute__((aligned(x)))
-#else
-    #define SW_ALIGN(x) // Do nothing if not available
-#endif
-
-#if defined(_M_X64) || defined(__x86_64__)
-    #define SW_ARCH_X86_64
-#elif defined(_M_IX86) || defined(__i386__)
-    #define SW_ARCH_X86
-#elif defined(_M_ARM) || defined(__arm__)
-    #define SW_ARCH_ARM32
-#elif defined(_M_ARM64) || defined(__aarch64__)
-    #define SW_ARCH_ARM64
-#elif defined(__riscv)
-    #define SW_ARCH_RISCV
-#endif
-
-#if defined(RLSW_USE_SIMD_INTRINSICS)
-    // Check for SIMD vector instructions
-    // NOTE: Compiler is responsible to enable required flags for host device,
-    // supported features are detected at compiler init but varies depending on compiler
-    // TODO: This logic must be reviewed to avoid the inclusion of multiple headers
-    // and enable the higher level of SIMD available
-    #if defined(__FMA__) && defined(__AVX2__)
-        #define SW_HAS_FMA_AVX2
-        #include <immintrin.h>
-    #elif defined(__FMA__) && defined(__AVX__)
-        #define SW_HAS_FMA_AVX
-        #include <immintrin.h>
-    #elif defined(__AVX2__)
-        #define SW_HAS_AVX2
-        #include <immintrin.h>
-    #elif defined(__AVX__)
-        #define SW_HAS_AVX
-        #include <immintrin.h>
-    #endif
-    #if defined(__SSE4_2__)
-        #define SW_HAS_SSE42
-        #include <nmmintrin.h>
-    #elif defined(__SSE4_1__)
-        #define SW_HAS_SSE41
-        #include <smmintrin.h>
-    #elif defined(__SSSE3__)
-        #define SW_HAS_SSSE3
-        #include <tmmintrin.h>
-    #elif defined(__SSE3__)
-        #define SW_HAS_SSE3
-        #include <pmmintrin.h>
-    #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64
-        #define SW_HAS_SSE2
-        #include <emmintrin.h>
-    #elif defined(__SSE__)
-        #define SW_HAS_SSE
-        #include <xmmintrin.h>
-    #endif
-    #if defined(__ARM_NEON) || defined(__aarch64__)
-        #if defined(__ARM_FEATURE_FMA)
-            #define SW_HAS_NEON_FMA
-        #else
-            #define SW_HAS_NEON
-        #endif
-        #include <arm_neon.h>
-    #endif
-    #if defined(__riscv_vector)
-        // NOTE: Requires compilation flags: -march=rv64gcv -mabi=lp64d
-        #define SW_HAS_RVV
-        #include <riscv_vector.h>
-    #endif
-#endif  // RLSW_USE_SIMD_INTRINSICS
-
-#ifdef __cplusplus
-    #define SW_CURLY_INIT(name) name
-#else
-    #define SW_CURLY_INIT(name) (name)
-#endif
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#define SW_PI       3.14159265358979323846f
-#define SW_INV_255  0.00392156862745098f            // 1.0f/255.0f
-#define SW_DEG2RAD  (SW_PI/180.0f)
-#define SW_RAD2DEG  (180.0f/SW_PI)
-
-#define SW_COLOR_PIXEL_SIZE     (SW_COLOR_BUFFER_BITS >> 3)
-#define SW_DEPTH_PIXEL_SIZE     (SW_DEPTH_BUFFER_BITS >> 3)
-#define SW_PIXEL_SIZE           (SW_COLOR_PIXEL_SIZE + SW_DEPTH_PIXEL_SIZE)
-
-#if (SW_PIXEL_SIZE <= 4)
-    #define SW_PIXEL_ALIGNMENT 4
-#else // if (SW_PIXEL_SIZE <= 8)
-    #define SW_PIXEL_ALIGNMENT 8
-#endif
-
-#if (SW_COLOR_BUFFER_BITS == 8)
-    #define SW_COLOR_TYPE       uint8_t
-    #define SW_COLOR_IS_PACKED  1
-    #define SW_COLOR_PACK_COMP  1
-    #define SW_PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03)
-    #define SW_UNPACK_R(p)      (((p)>>5)&0x07)
-    #define SW_UNPACK_G(p)      (((p)>>2)&0x07)
-    #define SW_UNPACK_B(p)      ((p)&0x03)
-    #define SW_SCALE_R(v)       ((v)*255+3)/7
-    #define SW_SCALE_G(v)       ((v)*255+3)/7
-    #define SW_SCALE_B(v)       ((v)*255+1)/3
-    #define SW_TO_FLOAT_R(v)    ((v)*(1.0f/7.0f))
-    #define SW_TO_FLOAT_G(v)    ((v)*(1.0f/7.0f))
-    #define SW_TO_FLOAT_B(v)    ((v)*(1.0f/3.0f))
-#elif (SW_COLOR_BUFFER_BITS == 16)
-    #define SW_COLOR_TYPE       uint16_t
-    #define SW_COLOR_IS_PACKED  1
-    #define SW_COLOR_PACK_COMP  1
-    #define SW_PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F)
-    #define SW_UNPACK_R(p)      (((p)>>11)&0x1F)
-    #define SW_UNPACK_G(p)      (((p)>>5)&0x3F)
-    #define SW_UNPACK_B(p)      ((p)&0x1F)
-    #define SW_SCALE_R(v)       ((v)*255+15)/31
-    #define SW_SCALE_G(v)       ((v)*255+31)/63
-    #define SW_SCALE_B(v)       ((v)*255+15)/31
-    #define SW_TO_FLOAT_R(v)    ((v)*(1.0f/31.0f))
-    #define SW_TO_FLOAT_G(v)    ((v)*(1.0f/63.0f))
-    #define SW_TO_FLOAT_B(v)    ((v)*(1.0f/31.0f))
-#else // 32 bits
-    #define SW_COLOR_TYPE       uint8_t
-    #define SW_COLOR_IS_PACKED  0
-    #define SW_COLOR_PACK_COMP  4
-#endif
-
-#if (SW_DEPTH_BUFFER_BITS == 16)
-    #define SW_DEPTH_TYPE       uint16_t
-    #define SW_DEPTH_IS_PACKED  1
-    #define SW_DEPTH_PACK_COMP  1
-    #define SW_DEPTH_MAX        UINT16_MAX
-    #define SW_DEPTH_SCALE      (1.0f/UINT16_MAX)
-    #define SW_PACK_DEPTH(d)    ((SW_DEPTH_TYPE)((d)*SW_DEPTH_MAX))
-    #define SW_UNPACK_DEPTH(p)  (p)
-#elif (SW_DEPTH_BUFFER_BITS == 24)
-    #define SW_DEPTH_TYPE       uint8_t
-    #define SW_DEPTH_IS_PACKED  0
-    #define SW_DEPTH_PACK_COMP  3
-    #define SW_DEPTH_MAX        0xFFFFFFU
-    #define SW_DEPTH_SCALE      (1.0f/0xFFFFFFU)
-    #define SW_PACK_DEPTH_0(d)  ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>16)&0xFFU))
-    #define SW_PACK_DEPTH_1(d)  ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>8)&0xFFU))
-    #define SW_PACK_DEPTH_2(d)  ((uint8_t)((uint32_t)((d)*SW_DEPTH_MAX)&0xFFU))
-    #define SW_UNPACK_DEPTH(p)  ((((uint32_t)(p)[0]<<16)|((uint32_t)(p)[1]<<8)|(uint32_t)(p)[2]))
-#else // 32 bits
-    #define SW_DEPTH_TYPE       float
-    #define SW_DEPTH_IS_PACKED  1
-    #define SW_DEPTH_PACK_COMP  1
-    #define SW_DEPTH_MAX        1.0f
-    #define SW_DEPTH_SCALE      1.0f
-    #define SW_PACK_DEPTH(d)    ((SW_DEPTH_TYPE)(d))
-    #define SW_UNPACK_DEPTH(p)  (p)
-#endif
-
-#define SW_STATE_CHECK(flags)   (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags)))
-#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags))
-
-#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)
-
-//----------------------------------------------------------------------------------
-// Module Types and Structures Definition
-//----------------------------------------------------------------------------------
-// Pixel data format type
-// NOTE: Enum aligned with raylib PixelFormat
-typedef enum {
-    SW_PIXELFORMAT_UNKNOWN = 0,
-    SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE,         // 8 bit per pixel (no alpha)
-    SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,        // 8*2 bpp (2 channels)
-    SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5,            // 16 bpp
-    SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8,            // 24 bpp
-    SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1,          // 16 bpp (1 bit alpha)
-    SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4,          // 16 bpp (4 bit alpha)
-    SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,          // 32 bpp
-    SW_PIXELFORMAT_UNCOMPRESSED_R32,               // 32 bpp (1 channel - float)
-    SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32,         // 32*3 bpp (3 channels - float)
-    SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32,      // 32*4 bpp (4 channels - float)
-    SW_PIXELFORMAT_UNCOMPRESSED_R16,               // 16 bpp (1 channel - half float)
-    SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16,         // 16*3 bpp (3 channels - half float)
-    SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16,      // 16*4 bpp (4 channels - half float)
-} sw_pixelformat_t;
-
-typedef void (*sw_factor_f)(
-    float *SW_RESTRICT factor,
-    const float *SW_RESTRICT src,
-    const float *SW_RESTRICT dst
-);
-
-typedef float sw_matrix_t[4*4];
-typedef uint16_t sw_half_t;
-
-typedef struct {
-    float position[4];          // Position coordinates
-    float texcoord[2];          // Texture coordinates
-    float color[4];             // Color value (RGBA)
-
-    float homogeneous[4];       // Homogeneous coordinates
-    float screen[2];            // Screen coordinates
-} sw_vertex_t;
-
-typedef struct {
-    uint8_t *pixels;            // Texture pixels (RGBA32)
-
-    int width, height;          // Dimensions of the texture
-    int wMinus1, hMinus1;       // Dimensions minus one
-
-    SWfilter minFilter;         // Minification filter
-    SWfilter magFilter;         // Magnification filter
-
-    SWwrap sWrap;               // texcoord.x wrap mode
-    SWwrap tWrap;               // texcoord.y wrap mode
-
-    float tx;                   // Texel width
-    float ty;                   // Texel height
-} sw_texture_t;
-
-// Pixel data type
-typedef SW_ALIGN(SW_PIXEL_ALIGNMENT) struct {
-    SW_COLOR_TYPE color[SW_COLOR_PACK_COMP];
-    SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP];
-#if (SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT != 0)
-    uint8_t padding[SW_PIXEL_ALIGNMENT - SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT];
-#endif
-} sw_pixel_t;
-
-typedef struct {
-    sw_pixel_t *pixels;
-    int width;
-    int height;
-    int allocSz;
-} sw_framebuffer_t;
-
-typedef struct {
-    sw_framebuffer_t framebuffer;   // Main framebuffer
-    sw_pixel_t clearValue;          // Clear value of the framebuffer
-
-    float vpCenter[2];              // Viewport center
-    float vpHalf[2];                // Viewport half dimensions
-    int vpSize[2];                  // Viewport dimensions (minus one)
-    int vpMin[2];                   // Viewport minimum renderable point (top-left)
-    int vpMax[2];                   // Viewport maximum renderable point (bottom-right)
-
-    int scMin[2];                   // Scissor rectangle minimum renderable point (top-left)
-    int scMax[2];                   // Scissor rectangle maximum renderable point (bottom-right)
-    float scClipMin[2];             // Scissor rectangle minimum renderable point in clip space
-    float scClipMax[2];             // Scissor rectangle maximum renderable point in clip space
-
-    uint32_t currentTexture;        // Current active texture id
-
-    struct {
-        float *positions;
-        float *texcoords;
-        uint8_t *colors;
-    } array;
-
-    struct {
-        float texcoord[2];
-        float color[4];
-    } current;
-
-    sw_vertex_t vertexBuffer[SW_MAX_CLIPPED_POLYGON_VERTICES];  // Buffer used for storing primitive vertices, used for processing and rendering
-    int vertexCounter;                                          // Number of vertices in 'ctx.vertexBuffer'
-
-    SWdraw drawMode;                                            // Current primitive mode (e.g., lines, triangles)
-    SWpoly polyMode;                                            // Current polygon filling mode (e.g., lines, triangles)
-    int reqVertices;                                            // Number of vertices required for the primitive being drawn
-    float pointRadius;                                          // Rasterized point radius
-    float lineWidth;                                            // Rasterized line width
-
-    sw_matrix_t stackProjection[SW_MAX_PROJECTION_STACK_SIZE];  // Projection matrix stack for push/pop operations
-    sw_matrix_t stackModelview[SW_MAX_MODELVIEW_STACK_SIZE];    // Modelview matrix stack for push/pop operations
-    sw_matrix_t stackTexture[SW_MAX_TEXTURE_STACK_SIZE];        // Texture matrix stack for push/pop operations
-    uint32_t stackProjectionCounter;                            // Counter for matrix stack operations
-    uint32_t stackModelviewCounter;                             // Counter for matrix stack operations
-    uint32_t stackTextureCounter;                               // Counter for matrix stack operations
-    SWmatrix currentMatrixMode;                                 // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
-    sw_matrix_t *currentMatrix;                                 // Pointer to the currently used matrix according to the mode
-    sw_matrix_t matMVP;                                         // Model view projection matrix, calculated and used internally
-    bool isDirtyMVP;                                            // Indicates if the MVP matrix should be rebuilt
-
-    SWfactor srcFactor;
-    SWfactor dstFactor;
-
-    sw_factor_f srcFactorFunc;
-    sw_factor_f dstFactorFunc;
-
-    SWface cullFace;                                            // Faces to cull
-    SWerrcode errCode;                                          // Last error code
-
-    sw_texture_t *loadedTextures;
-    int loadedTextureCount;
-
-    uint32_t *freeTextureIds;
-    int freeTextureIdCount;
-
-    uint32_t stateFlags;
-} sw_context_t;
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static sw_context_t RLSW = { 0 };
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-static inline void sw_matrix_id(sw_matrix_t dst)
-{
-    dst[0]  = 1, dst[1]  = 0, dst[2]  = 0, dst[3]  = 0;
-    dst[4]  = 0, dst[5]  = 1, dst[6]  = 0, dst[7]  = 0;
-    dst[8]  = 0, dst[9]  = 0, dst[10] = 1, dst[11] = 0;
-    dst[12] = 0, dst[13] = 0, dst[14] = 0, dst[15] = 1;
-}
-
-static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right)
-{
-    float l00 = left[0],  l01 = left[1],  l02 = left[2],  l03 = left[3];
-    float l10 = left[4],  l11 = left[5],  l12 = left[6],  l13 = left[7];
-    float l20 = left[8],  l21 = left[9],  l22 = left[10], l23 = left[11];
-    float l30 = left[12], l31 = left[13], l32 = left[14], l33 = left[15];
-
-    dst[0]  = l00*right[0] + l01*right[4] + l02*right[8]  + l03*right[12];
-    dst[4]  = l10*right[0] + l11*right[4] + l12*right[8]  + l13*right[12];
-    dst[8]  = l20*right[0] + l21*right[4] + l22*right[8]  + l23*right[12];
-    dst[12] = l30*right[0] + l31*right[4] + l32*right[8]  + l33*right[12];
-
-    dst[1]  = l00*right[1] + l01*right[5] + l02*right[9]  + l03*right[13];
-    dst[5]  = l10*right[1] + l11*right[5] + l12*right[9]  + l13*right[13];
-    dst[9]  = l20*right[1] + l21*right[5] + l22*right[9]  + l23*right[13];
-    dst[13] = l30*right[1] + l31*right[5] + l32*right[9]  + l33*right[13];
-
-    dst[2]  = l00*right[2] + l01*right[6] + l02*right[10] + l03*right[14];
-    dst[6]  = l10*right[2] + l11*right[6] + l12*right[10] + l13*right[14];
-    dst[10] = l20*right[2] + l21*right[6] + l22*right[10] + l23*right[14];
-    dst[14] = l30*right[2] + l31*right[6] + l32*right[10] + l33*right[14];
-
-    dst[3]  = l00*right[3] + l01*right[7] + l02*right[11] + l03*right[15];
-    dst[7]  = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15];
-    dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15];
-    dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15];
-}
-
-static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right)
-{
-    float result[16];
-
-    sw_matrix_mul_rst(result, left, right);
-
-    for (int i = 0; i < 16; i++) dst[i] = result[i];
-}
-
-static inline float sw_saturate(float x)
-{
-    union { float f; uint32_t u; } fb;
-    fb.f = x;
-
-    // Check if x < 0.0f
-    // If sign bit is set (MSB), x is negative
-    if ((fb.u & 0x80000000) != 0) return 0.0f;
-
-    // Check if x > 1.0f
-    // Works for positive floats: IEEE 754 ordering matches integer ordering
-    if (fb.u > 0x3F800000) return 1.0f;
-
-    // x is in [0.0f, 1.0f]
-    return x;
-}
-
-static inline float sw_fract(float x)
-{
-    return (x - floorf(x));
-}
-
-static inline int sw_clampi(int v, int min, int max)
-{
-    if (v < min) return min;
-    if (v > max) return max;
-    return v;
-}
-
-static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t)
-{
-    const float tInv = 1.0f - t;
-
-    // Position interpolation (4 components)
-    out->position[0] = a->position[0]*tInv + b->position[0]*t;
-    out->position[1] = a->position[1]*tInv + b->position[1]*t;
-    out->position[2] = a->position[2]*tInv + b->position[2]*t;
-    out->position[3] = a->position[3]*tInv + b->position[3]*t;
-
-    // Texture coordinate interpolation (2 components)
-    out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t;
-    out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t;
-
-    // Color interpolation (4 components)
-    out->color[0] = a->color[0]*tInv + b->color[0]*t;
-    out->color[1] = a->color[1]*tInv + b->color[1]*t;
-    out->color[2] = a->color[2]*tInv + b->color[2]*t;
-    out->color[3] = a->color[3]*tInv + b->color[3]*t;
-
-    // Homogeneous coordinate interpolation (4 components)
-    out->homogeneous[0] = a->homogeneous[0]*tInv + b->homogeneous[0]*t;
-    out->homogeneous[1] = a->homogeneous[1]*tInv + b->homogeneous[1]*t;
-    out->homogeneous[2] = a->homogeneous[2]*tInv + b->homogeneous[2]*t;
-    out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t;
-}
-
-static inline void sw_get_vertex_grad_PTCH(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 Texture coordinates
-    out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale;
-    out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*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 Homogeneous coordinates
-    out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0])*scale;
-    out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1])*scale;
-    out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2])*scale;
-    out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale;
-}
-
-static inline void sw_add_vertex_grad_PTCH(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 Texture coordinates
-    out->texcoord[0] += gradients->texcoord[0];
-    out->texcoord[1] += gradients->texcoord[1];
-
-    // 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 Homogeneous coordinates
-    out->homogeneous[0] += gradients->homogeneous[0];
-    out->homogeneous[1] += gradients->homogeneous[1];
-    out->homogeneous[2] += gradients->homogeneous[2];
-    out->homogeneous[3] += gradients->homogeneous[3];
-}
-
-static inline void sw_add_vertex_grad_scaled_PTCH(
-    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 Texture coordinates
-    out->texcoord[0] += gradients->texcoord[0]*scale;
-    out->texcoord[1] += gradients->texcoord[1]*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 Homogeneous coordinates
-    out->homogeneous[0] += gradients->homogeneous[0]*scale;
-    out->homogeneous[1] += gradients->homogeneous[1]*scale;
-    out->homogeneous[2] += gradients->homogeneous[2]*scale;
-    out->homogeneous[3] += gradients->homogeneous[3]*scale;
-}
-
-static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4])
-{
-#if defined(SW_HAS_NEON)
-    float32x4_t values = vld1q_f32(src);
-    float32x4_t scaled = vmulq_n_f32(values, 255.0f);
-    int32x4_t clamped_s32 = vcvtq_s32_f32(scaled);  // f32 -> s32 (truncated)
-    int16x4_t narrow16_s = vqmovn_s32(clamped_s32);
-    int16x8_t combined16_s = vcombine_s16(narrow16_s, narrow16_s);
-    uint8x8_t narrow8_u = vqmovun_s16(combined16_s);
-    vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8_u), 0);
-#elif defined(SW_HAS_SSE41)
-    __m128 values = _mm_loadu_ps(src);
-    __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
-    __m128i clamped = _mm_cvtps_epi32(scaled);      // f32 -> s32 (truncated)
-    clamped = _mm_packus_epi32(clamped, clamped);   // s32 -> u16 (saturated < 0 to 0)
-    clamped = _mm_packus_epi16(clamped, clamped);   // u16 -> u8 (saturated > 255 to 255)
-    *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
-#elif defined(SW_HAS_SSE2)
-    __m128 values = _mm_loadu_ps(src);
-    __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
-    __m128i clamped = _mm_cvtps_epi32(scaled);      // f32 -> s32 (truncated)
-    clamped = _mm_packs_epi32(clamped, clamped);    // s32 -> s16 (saturated)
-    clamped = _mm_packus_epi16(clamped, clamped);   // s16 -> u8 (saturated < 0 to 0)
-    *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
-#elif defined(SW_HAS_RVV)
-    // TODO: Sample code generated by AI, needs testing and review
-    // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions
-    size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register
-    vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values
-
-    // Clamp to [0.0f, 1.0f]
-    vfloat32m1_t vzero = __riscv_vfmv_v_f_f32m1(0.0f, vl);
-    vfloat32m1_t vone  = __riscv_vfmv_v_f_f32m1(1.0f, vl);
-    vsrc = __riscv_vfmin_vv_f32m1(vsrc, vone, vl);
-    vsrc = __riscv_vfmax_vv_f32m1(vsrc, vzero, vl);
-
-    // Multiply by 255.0f and add 0.5f for rounding
-    vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl);
-    vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl);
-
-    // Convert to unsigned integer (truncate toward zero)
-    vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl);
-
-    // Narrow from u32 -> u8
-    vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero
-    __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result
-#else
-    for (int i = 0; i < 4; i++)
-    {
-        float val = src[i]*255.0f;
-        val = (val > 255.0f)? 255.0f : val;
-        val = (val < 0.0f)? 0.0f : val;
-        dst[i] = (uint8_t)val;
-    }
-#endif
-}
-
-static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4])
-{
-#if defined(SW_HAS_NEON)
-    uint8x8_t bytes8 = vld1_u8(src); //< Read 8 bytes, faster, but let's hope we're not at the end of the page (unlikely)...
-    uint16x8_t bytes16 = vmovl_u8(bytes8);
-    uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16));
-    float32x4_t floats = vcvtq_f32_u32(ints);
-    floats = vmulq_n_f32(floats, SW_INV_255);
-    vst1q_f32(dst, floats);
-#elif defined(SW_HAS_SSE41)
-    __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
-    __m128i ints = _mm_cvtepu8_epi32(bytes);
-    __m128 floats = _mm_cvtepi32_ps(ints);
-    floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
-    _mm_storeu_ps(dst, floats);
-#elif defined(SW_HAS_SSE2)
-    __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
-    bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128());
-    __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128());
-    __m128 floats = _mm_cvtepi32_ps(ints);
-    floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
-    _mm_storeu_ps(dst, floats);
-#elif defined(SW_HAS_RVV)
-    // TODO: Sample code generated by AI, needs testing and review
-    size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements
-    vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers
-    vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers
-    vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32
-    vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize
-    __riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result
-#else
-    dst[0] = (float)src[0]*SW_INV_255;
-    dst[1] = (float)src[1]*SW_INV_255;
-    dst[2] = (float)src[2]*SW_INV_255;
-    dst[3] = (float)src[3]*SW_INV_255;
-#endif
-}
-
-// Half conversion functions
-static inline uint32_t sw_half_to_float_ui(uint16_t h)
-{
-    uint32_t s = (uint32_t)(h & 0x8000) << 16;
-    int32_t em = h & 0x7fff;
-
-    // bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15)
-    int32_t r = (em + (112 << 10)) << 13;
-
-    // denormal: flush to zero
-    r = (em < (1 << 10))? 0 : r;
-
-    // infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases
-    // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255
-    r += (em >= (31 << 10))? (112 << 23) : 0;
-
-    return s | r;
-}
-
-static inline float sw_half_to_float(sw_half_t y)
-{
-    union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) };
-
-    return v.f;
-}
-
-static inline uint16_t sw_half_from_float_ui(uint32_t ui)
-{
-    int32_t s = (ui >> 16) & 0x8000;
-    int32_t em = ui & 0x7fffffff;
-
-    // Bias exponent and round to nearest; 112 is relative exponent bias (127-15)
-    int32_t h = (em - (112 << 23) + (1 << 12)) >> 13;
-
-    // Underflow: flush to zero; 113 encodes exponent -14
-    h = (em < (113 << 23))? 0 : h;
-
-    // Overflow: infinity; 143 encodes exponent 16
-    h = (em >= (143 << 23))? 0x7c00 : h;
-
-    // NaN; note that we convert all types of NaN to qNaN
-    h = (em > (255 << 23))? 0x7e00 : h;
-
-    return (uint16_t)(s | h);
-}
-
-static inline sw_half_t sw_half_from_float(float i)
-{
-    union { float f; uint32_t i; } v;
-    v.f = i;
-    return sw_half_from_float_ui(v.i);
-}
-
-// Framebuffer management functions
-//-------------------------------------------------------------------------------------------
-static inline bool sw_framebuffer_load(int w, int h)
-{
-    int size = w*h;
-
-    RLSW.framebuffer.pixels = SW_MALLOC(sizeof(sw_pixel_t)*size);
-    if (RLSW.framebuffer.pixels == NULL) return false;
-
-    RLSW.framebuffer.width = w;
-    RLSW.framebuffer.height = h;
-    RLSW.framebuffer.allocSz = size;
-
-    return true;
-}
-
-static inline bool sw_framebuffer_resize(int w, int h)
-{
-    int newSize = w*h;
-
-    if (newSize <= RLSW.framebuffer.allocSz)
-    {
-        RLSW.framebuffer.width = w;
-        RLSW.framebuffer.height = h;
-        return true;
-    }
-
-    void *newPixels = SW_REALLOC(RLSW.framebuffer.pixels, sizeof(sw_pixel_t)*newSize);
-    if (newPixels == NULL) return false;
-
-    RLSW.framebuffer.pixels = newPixels;
-
-    RLSW.framebuffer.width = w;
-    RLSW.framebuffer.height = h;
-    RLSW.framebuffer.allocSz = newSize;
-
-    return true;
-}
-
-static inline void sw_framebuffer_read_color(float dst[4], const sw_pixel_t *src)
-{
-#if SW_COLOR_IS_PACKED
-    SW_COLOR_TYPE pixel = src->color[0];
-    dst[0] = SW_TO_FLOAT_R(SW_UNPACK_R(pixel));
-    dst[1] = SW_TO_FLOAT_G(SW_UNPACK_G(pixel));
-    dst[2] = SW_TO_FLOAT_B(SW_UNPACK_B(pixel));
-    dst[3] = 1.0f;
-#else
-    sw_float_from_unorm8_simd(dst, src->color);
-#endif
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const sw_pixel_t *src)
-{
-#if SW_COLOR_IS_PACKED
-    SW_COLOR_TYPE pixel = src->color[0];
-    dst[0] = SW_SCALE_R(SW_UNPACK_R(pixel));
-    dst[1] = SW_SCALE_G(SW_UNPACK_G(pixel));
-    dst[2] = SW_SCALE_B(SW_UNPACK_B(pixel));
-    dst[3] = 255;
-#else
-    const SW_COLOR_TYPE *p = src->color;
-    dst[0] = p[0];
-    dst[1] = p[1];
-    dst[2] = p[2];
-    dst[3] = p[3];
-#endif
-}
-
-static inline float sw_framebuffer_read_depth(const sw_pixel_t *src)
-{
-#if SW_DEPTH_IS_PACKED
-    return src->depth[0]*SW_DEPTH_SCALE;
-#else
-    return SW_UNPACK_DEPTH(src->depth)*SW_DEPTH_SCALE;
-#endif
-}
-
-static inline void sw_framebuffer_write_color(sw_pixel_t *dst, const float src[4])
-{
-#if SW_COLOR_IS_PACKED
-    dst->color[0] = SW_PACK_COLOR(src[0], src[1], src[2]);
-#else
-    sw_float_to_unorm8_simd(dst->color, src);
-#endif
-}
-
-static inline void sw_framebuffer_write_depth(sw_pixel_t *dst, float depth)
-{
-    depth = sw_saturate(depth); // REVIEW: An overflow can occur in certain circumstances with clipping, and needs to be reviewed...
-
-#if SW_DEPTH_IS_PACKED
-    dst->depth[0] = SW_PACK_DEPTH(depth);
-#else
-    dst->depth[0] = SW_PACK_DEPTH_0(depth);
-    dst->depth[1] = SW_PACK_DEPTH_1(depth);
-    dst->depth[2] = SW_PACK_DEPTH_2(depth);
-#endif
-}
-
-static inline void sw_framebuffer_fill_color(sw_pixel_t *ptr, int size, const SW_COLOR_TYPE color[SW_COLOR_PACK_COMP])
-{
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
-        for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
-        {
-            sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
-            for (int x = 0; x < w; x++, row++)
-            {
-                for (int i = 0; i < SW_COLOR_PACK_COMP; i++) row->color[i] = color[i];
-            }
-        }
-    }
-    else
-    {
-        for (int i = 0; i < size; i++, ptr++)
-        {
-            for (int j = 0; j < SW_COLOR_PACK_COMP; j++) ptr->color[j] = color[j];
-        }
-    }
-}
-
-static inline void sw_framebuffer_fill_depth(sw_pixel_t *ptr, int size, const SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP])
-{
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
-        for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
-        {
-            sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
-            for (int x = 0; x < w; x++, row++)
-            {
-                for (int i = 0; i < SW_DEPTH_PACK_COMP; i++) row->depth[i] = depth[i];
-            }
-        }
-    }
-    else
-    {
-        for (int i = 0; i < size; i++, ptr++)
-        {
-            for (int j = 0; j < SW_DEPTH_PACK_COMP; j++) ptr->depth[j] = depth[j];
-        }
-    }
-}
-
-static inline void sw_framebuffer_fill(sw_pixel_t *ptr, int size, sw_pixel_t value)
-{
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
-        for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
-        {
-            sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
-            for (int x = 0; x < w; x++, row++) *row = value;
-        }
-    }
-    else
-    {
-        for (int i = 0; i < size; i++, ptr++) *ptr = value;
-    }
-}
-
-static inline void sw_framebuffer_copy_fast(void* dst)
-{
-    int size = RLSW.framebuffer.width*RLSW.framebuffer.height;
-    const sw_pixel_t *pixels = RLSW.framebuffer.pixels;
-
-#if SW_COLOR_BUFFER_BITS == 8
-    uint8_t *dst8 = (uint8_t*)dst;
-    for (int i = 0; i < size; i++) dst8[i] = pixels[i].color[0];
-#elif SW_COLOR_BUFFER_BITS == 16
-    uint16_t *dst16 = (uint16_t*)dst;
-    for (int i = 0; i < size; i++) dst16[i] = *(uint16_t*)pixels[i].color;
-#else // 32 bits
-    uint32_t *dst32 = (uint32_t*)dst;
-    #if SW_GL_FRAMEBUFFER_COPY_BGRA
-        for (int i = 0; i < size; i++)
-        {
-            const uint8_t *c = pixels[i].color;
-            dst32[i] = (uint32_t)c[2] | ((uint32_t)c[1] << 8) | ((uint32_t)c[0] << 16) | ((uint32_t)c[3] << 24);
-        }
-    #else // RGBA
-        for (int i = 0; i < size; i++) dst32[i] = *(uint32_t*)pixels[i].color;
-    #endif
-#endif
-}
-
-#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T)                          \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
-{                                                                               \
-    const int stride = RLSW.framebuffer.width;                                  \
-    const sw_pixel_t *src = RLSW.framebuffer.pixels + (y*stride + x);           \
-                                                                                \
-    for (int iy = 0; iy < h; iy++) {                                            \
-        const sw_pixel_t *line = src;                                           \
-        for (int ix = 0; ix < w; ix++) {                                        \
-            uint8_t color[4];                                                   \
-            sw_framebuffer_read_color8(color, line);                            \
-
-#define DEFINE_FRAMEBUFFER_COPY_END()                                           \
-            ++line;                                                             \
-        }                                                                       \
-        src += stride;                                                          \
-    }                                                                           \
-}
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t)
-{
-    // NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B
-    uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
-    *dst++ = gray;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t)
-{
-    // Convert RGB to grayscale using NTSC formula
-    uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
-
-    dst[0] = gray;
-    dst[1] = color[3]; // alpha
-
-    dst += 2;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t)
-{
-    // Convert 8-bit RGB to 5:6:5 format
-    uint8_t r5 = (color[0]*31 + 127)/255;
-    uint8_t g6 = (color[1]*63 + 127)/255;
-    uint8_t b5 = (color[2]*31 + 127)/255;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5;
-#else // RGBA
-    uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5;
-#endif
-
-    *dst++ = rgb565;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    dst[0] = color[2];
-    dst[1] = color[1];
-    dst[2] = color[0];
-#else // RGBA
-    dst[0] = color[0];
-    dst[1] = color[1];
-    dst[2] = color[2];
-#endif
-
-    dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t)
-{
-    uint8_t r5 = (color[0]*31 + 127)/255;
-    uint8_t g5 = (color[1]*31 + 127)/255;
-    uint8_t b5 = (color[2]*31 + 127)/255;
-    uint8_t a1 = (color[3] >= 128)? 1 : 0;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1;
-#else // RGBA
-    uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1;
-#endif
-
-    *dst++ = pixel;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t)
-{
-    uint8_t r4 = (color[0]*15 + 127)/255;
-    uint8_t g4 = (color[1]*15 + 127)/255;
-    uint8_t b4 = (color[2]*15 + 127)/255;
-    uint8_t a4 = (color[3]*15 + 127)/255;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4;
-#else // RGBA
-    uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4;
-#endif
-
-    *dst++ = pixel;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    dst[0] = color[2];
-    dst[1] = color[1];
-    dst[2] = color[0];
-#else // RGBA
-    dst[0] = color[0];
-    dst[1] = color[1];
-    dst[2] = color[2];
-#endif
-    dst[3] = color[3];
-
-    dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T)                          \
-static inline void sw_framebuffer_blit_to_##name(                               \
-    int xDst, int yDst, int wDst, int hDst,                                     \
-    int xSrc, int ySrc, int wSrc, int hSrc,                                     \
-    DST_PTR_T *dst)                                                             \
-{                                                                               \
-    const sw_pixel_t *srcBase = RLSW.framebuffer.pixels;                        \
-    const int fbWidth = RLSW.framebuffer.width;                                 \
-                                                                                \
-    const uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst;              \
-    const uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst;              \
-                                                                                \
-    for (int dy = 0; dy < hDst; dy++) {                                         \
-        uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale;                     \
-        int sy = yFix >> 16;                                                    \
-        const sw_pixel_t *srcLine = srcBase + sy*fbWidth + xSrc;                \
-                                                                                \
-        const sw_pixel_t *srcPtr = srcLine;                                     \
-        for (int dx = 0; dx < wDst; dx++) {                                     \
-            uint32_t xFix = dx*xScale;                                          \
-            int sx = xFix >> 16;                                                \
-            const sw_pixel_t *pixel = srcPtr + sx;                              \
-            uint8_t color[4];                                                   \
-            sw_framebuffer_read_color8(color, pixel);
-
-#define DEFINE_FRAMEBUFFER_BLIT_END()                                           \
-        }                                                                       \
-    }                                                                           \
-}
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t)
-{
-    uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
-    *dst++ = gray;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t)
-{
-    uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
-
-    dst[0] = gray;
-    dst[1] = color[3]; // alpha
-
-    dst += 2;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t)
-{
-    uint8_t r5 = (color[0]*31 + 127)/255;
-    uint8_t g6 = (color[1]*63 + 127)/255;
-    uint8_t b5 = (color[2]*31 + 127)/255;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5;
-#else // RGBA
-    uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5;
-#endif
-
-    *dst++ = rgb565;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    dst[0] = color[2];
-    dst[1] = color[1];
-    dst[2] = color[0];
-#else // RGBA
-    dst[0] = color[0];
-    dst[1] = color[1];
-    dst[2] = color[2];
-#endif
-
-    dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t)
-{
-    uint8_t r5 = (color[0]*31 + 127)/255;
-    uint8_t g5 = (color[1]*31 + 127)/255;
-    uint8_t b5 = (color[2]*31 + 127)/255;
-    uint8_t a1 = (color[3] >= 128)? 1 : 0;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1;
-#else // RGBA
-    uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1;
-#endif
-
-    *dst++ = pixel;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t)
-{
-    uint8_t r4 = (color[0]*15 + 127)/255;
-    uint8_t g4 = (color[1]*15 + 127)/255;
-    uint8_t b4 = (color[2]*15 + 127)/255;
-    uint8_t a4 = (color[3]*15 + 127)/255;
-
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4;
-#else // RGBA
-    uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4;
-#endif
-
-    *dst++ = pixel;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
-    dst[0] = color[2];
-    dst[1] = color[1];
-    dst[2] = color[0];
-#else // RGBA
-    dst[0] = color[0];
-    dst[1] = color[1];
-    dst[2] = color[2];
-#endif
-    dst[3] = color[3];
-
-    dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-//-------------------------------------------------------------------------------------------
-
-// Pixel format management functions
-//-------------------------------------------------------------------------------------------
-static inline int sw_get_pixel_format(SWformat format, SWtype type)
-{
-    int channels = 0;
-    int bitsPerChannel = 8; // Default: 8 bits per channel
-
-    // Determine the number of channels (format)
-    switch (format)
-    {
-        case SW_LUMINANCE:        channels = 1; break;
-        case SW_LUMINANCE_ALPHA:  channels = 2; break;
-        case SW_RGB:              channels = 3; break;
-        case SW_RGBA:             channels = 4; break;
-        default: return SW_PIXELFORMAT_UNKNOWN;
-    }
-
-    // Determine the depth of each channel (type)
-    switch (type)
-    {
-        case SW_UNSIGNED_BYTE:    bitsPerChannel = 8;  break;
-        case SW_BYTE:             bitsPerChannel = 8;  break;
-        case SW_UNSIGNED_SHORT:   bitsPerChannel = 16; break;
-        case SW_SHORT:            bitsPerChannel = 16; break;
-        case SW_UNSIGNED_INT:     bitsPerChannel = 32; break;
-        case SW_INT:              bitsPerChannel = 32; break;
-        case SW_FLOAT:            bitsPerChannel = 32; break;
-        default: return SW_PIXELFORMAT_UNKNOWN;
-    }
-
-    // Map the format and type to the correct internal format
-    if (bitsPerChannel == 8)
-    {
-        if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-        if (channels == 2) return SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
-        if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8;
-        if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-    }
-    else if (bitsPerChannel == 16)
-    {
-        if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R16;
-        if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16;
-        if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16;
-    }
-    else if (bitsPerChannel == 32)
-    {
-        if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R32;
-        if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32;
-        if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
-    }
-
-    return SW_PIXELFORMAT_UNKNOWN;
-}
-
-static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
-{
-    switch (format)
-    {
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-        {
-            uint8_t gray = ((const uint8_t*)pixels)[offset];
-            color[0] = gray;
-            color[1] = gray;
-            color[2] = gray;
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-        {
-            const uint8_t *src = &((const uint8_t*)pixels)[offset*2];
-            color[0] = src[0];
-            color[1] = src[0];
-            color[2] = src[0];
-            color[3] = src[1];
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        {
-            uint16_t pixel = ((const uint16_t*)pixels)[offset];
-            color[0] = ((pixel >> 11) & 0x1F)*255/31;   // R (5 bits)
-            color[1] = ((pixel >> 5) & 0x3F)*255/63;    // G (6 bits)
-            color[2] = (pixel & 0x1F)*255/31;           // B (5 bits)
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-        {
-            const uint8_t *src = &((const uint8_t*)pixels)[offset*3];
-            color[0] = src[0];
-            color[1] = src[1];
-            color[2] = src[2];
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        {
-            uint16_t pixel = ((const uint16_t*)pixels)[offset];
-            color[0] = ((pixel >> 11) & 0x1F)*255/31;   // R (5 bits)
-            color[1] = ((pixel >> 6) & 0x1F)*255/31;    // G (5 bits)
-            color[2] = ((pixel >> 1) & 0x1F)*255/31;    // B (5 bits)
-            color[3] = (pixel & 0x01)*255;              // A (1 bit)
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-        {
-            uint16_t pixel = ((const uint16_t*)pixels)[offset];
-            color[0] = ((pixel >> 12) & 0x0F)*255/15;   // R (4 bits)
-            color[1] = ((pixel >> 8) & 0x0F)*255/15;    // G (4 bits)
-            color[2] = ((pixel >> 4) & 0x0F)*255/15;    // B (4 bits)
-            color[3] = (pixel & 0x0F)*255/15;           // A (4 bits)
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-        {
-            const uint8_t *src = &((const uint8_t*)pixels)[offset*4];
-            color[0] = src[0];
-            color[1] = src[1];
-            color[2] = src[2];
-            color[3] = src[3];
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32:
-        {
-            float val = ((const float*)pixels)[offset];
-            uint8_t gray = (uint8_t)(val*255.0f);
-            color[0] = gray;
-            color[1] = gray;
-            color[2] = gray;
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-        {
-            const float *src = &((const float*)pixels)[offset*3];
-            color[0] = (uint8_t)(src[0]*255.0f);
-            color[1] = (uint8_t)(src[1]*255.0f);
-            color[2] = (uint8_t)(src[2]*255.0f);
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-        {
-            const float *src = &((const float*)pixels)[offset*4];
-            color[0] = (uint8_t)(src[0]*255.0f);
-            color[1] = (uint8_t)(src[1]*255.0f);
-            color[2] = (uint8_t)(src[2]*255.0f);
-            color[3] = (uint8_t)(src[3]*255.0f);
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16:
-        {
-            uint16_t val = ((const uint16_t*)pixels)[offset];
-            uint8_t gray = sw_half_to_float(val)*SW_INV_255;
-            color[0] = gray;
-            color[1] = gray;
-            color[2] = gray;
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-        {
-            const uint16_t *src = &((const uint16_t*)pixels)[offset*3];
-            color[0] = sw_half_to_float(src[0])*SW_INV_255;
-            color[1] = sw_half_to_float(src[1])*SW_INV_255;
-            color[2] = sw_half_to_float(src[2])*SW_INV_255;
-            color[3] = 255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-        {
-            const uint16_t *src = &((const uint16_t*)pixels)[offset*4];
-            color[0] = sw_half_to_float(src[0])*SW_INV_255;
-            color[1] = sw_half_to_float(src[1])*SW_INV_255;
-            color[2] = sw_half_to_float(src[2])*SW_INV_255;
-            color[3] = sw_half_to_float(src[3])*SW_INV_255;
-            break;
-        }
-        case SW_PIXELFORMAT_UNKNOWN:
-        default:
-        {
-            color[0] = 0;
-            color[1] = 0;
-            color[2] = 0;
-            color[3] = 0;
-            break;
-        }
-    }
-}
-//-------------------------------------------------------------------------------------------
-
-// Texture sampling functionality
-//-------------------------------------------------------------------------------------------
-static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y)
-{
-    sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]);
-}
-
-static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v)
-{
-    u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
-    v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
-
-    int x = u*tex->width;
-    int y = v*tex->height;
-
-    sw_texture_fetch(color, tex, x, y);
-}
-
-static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v)
-{
-    // TODO: With a bit more cleverness we could clearly reduce the
-    // number of operations here, but for now it works fine
-
-    float xf = (u*tex->width) - 0.5f;
-    float yf = (v*tex->height) - 0.5f;
-
-    float fx = sw_fract(xf);
-    float fy = sw_fract(yf);
-
-    int x0 = (int)xf;
-    int y0 = (int)yf;
-
-    int x1 = x0 + 1;
-    int y1 = y0 + 1;
-
-    // NOTE: If the textures are POT we could avoid the division for SW_REPEAT
-
-    if (tex->sWrap == SW_CLAMP)
-    {
-        x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
-        x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1;
-    }
-    else
-    {
-        x0 = (x0%tex->width + tex->width)%tex->width;
-        x1 = (x1%tex->width + tex->width)%tex->width;
-    }
-
-    if (tex->tWrap == SW_CLAMP)
-    {
-        y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0;
-        y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1;
-    }
-    else
-    {
-        y0 = (y0%tex->height + tex->height)%tex->height;
-        y1 = (y1%tex->height + tex->height)%tex->height;
-    }
-
-    float c00[4], c10[4], c01[4], c11[4];
-    sw_texture_fetch(c00, tex, x0, y0);
-    sw_texture_fetch(c10, tex, x1, y0);
-    sw_texture_fetch(c01, tex, x0, y1);
-    sw_texture_fetch(c11, tex, x1, y1);
-
-    for (int i = 0; i < 4; i++)
-    {
-        float t = c00[i] + fx*(c10[i] - c00[i]);
-        float b = c01[i] + fx*(c11[i] - c01[i]);
-        color[i] = t + fy*(b - t);
-    }
-}
-
-static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy)
-{
-    // Previous method: There is no need to compute the square root
-    // because using the squared value, the comparison remains `L2 > 1.0f*1.0f`
-    //float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
-    //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 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;
-    }
-}
-//-------------------------------------------------------------------------------------------
-
-// Color blending functionality
-//-------------------------------------------------------------------------------------------
-static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = factor[1] = factor[2] = factor[3] = 0.0f;
-}
-
-static inline void sw_factor_one(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = factor[1] = factor[2] = factor[3] = 1.0f;
-}
-
-static inline void sw_factor_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3];
-}
-
-static inline void sw_factor_one_minus_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1];
-    factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3];
-}
-
-static inline void sw_factor_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = factor[1] = factor[2] = factor[3] = src[3];
-}
-
-static inline void sw_factor_one_minus_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    float invAlpha = 1.0f - src[3];
-    factor[0] = factor[1] = factor[2] = factor[3] = invAlpha;
-}
-
-static inline void sw_factor_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = factor[1] = factor[2] = factor[3] = dst[3];
-}
-
-static inline void sw_factor_one_minus_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    float invAlpha = 1.0f - dst[3];
-    factor[0] = factor[1] = factor[2] = factor[3] = invAlpha;
-}
-
-static inline void sw_factor_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3];
-}
-
-static inline void sw_factor_one_minus_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1];
-    factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3];
-}
-
-static inline void sw_factor_src_alpha_saturate(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
-{
-    factor[0] = factor[1] = factor[2] = 1.0f;
-    factor[3] = (src[3] < 1.0f)? src[3] : 1.0f;
-}
-
-static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *SW_RESTRICT src/*[4]*/)
-{
-    float srcFactor[4], dstFactor[4];
-
-    RLSW.srcFactorFunc(srcFactor, src, dst);
-    RLSW.dstFactorFunc(dstFactor, src, dst);
-
-    dst[0] = srcFactor[0]*src[0] + dstFactor[0]*dst[0];
-    dst[1] = srcFactor[1]*src[1] + dstFactor[1]*dst[1];
-    dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2];
-    dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3];
-}
-//-------------------------------------------------------------------------------------------
-
-// Projection helper functions
-//-------------------------------------------------------------------------------------------
-static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4])
-{
-    screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f;
-    screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalf[1] + 0.5f;
-}
-//-------------------------------------------------------------------------------------------
-
-// Polygon clipping management
-//-------------------------------------------------------------------------------------------
-#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T)                          \
-static inline int sw_clip_##name(                                                       \
-    sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES],                                \
-    const sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES],                           \
-    int n)                                                                              \
-{                                                                                       \
-    const sw_vertex_t *prev = &input[n - 1];                                            \
-    int prevInside = FUNC_IS_INSIDE(prev->homogeneous);                                 \
-    int outputCount = 0;                                                                \
-                                                                                        \
-    for (int i = 0; i < n; i++) {                                                       \
-        const sw_vertex_t *curr = &input[i];                                            \
-        int currInside = FUNC_IS_INSIDE(curr->homogeneous);                             \
-                                                                                        \
-        /* If transition between interior/exterior, calculate intersection point */     \
-        if (prevInside != currInside) {                                                 \
-            float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous);             \
-            sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t);                 \
-        }                                                                               \
-                                                                                        \
-        /* If current vertex inside, add it */                                          \
-        if (currInside) {                                                               \
-            output[outputCount++] = *curr;                                              \
-        }                                                                               \
-                                                                                        \
-        prev = curr;                                                                    \
-        prevInside = currInside;                                                        \
-    }                                                                                   \
-                                                                                        \
-    return outputCount;                                                                 \
-}
-//-------------------------------------------------------------------------------------------
-
-// Frustum cliping functions
-//-------------------------------------------------------------------------------------------
-#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON)
-#define IS_INSIDE_PLANE_X_POS(h) ( (h)[0] <  (h)[3])        // Exclusive for +X
-#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <  (h)[3])        // Exclusive for -X
-#define IS_INSIDE_PLANE_Y_POS(h) ( (h)[1] <  (h)[3])        // Exclusive for +Y
-#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] <  (h)[3])        // Exclusive for -Y
-#define IS_INSIDE_PLANE_Z_POS(h) ( (h)[2] <= (h)[3])        // Inclusive for +Z
-#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3])        // Inclusive for -Z
-
-#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3]))
-#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0])))
-#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0])/(((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0])))
-#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1])/(((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1])))
-#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1])/(((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1])))
-#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2])/(((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2])))
-#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2])/(((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2])))
-
-DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W)
-DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS)
-DEFINE_CLIP_FUNC(x_neg, IS_INSIDE_PLANE_X_NEG, COMPUTE_T_PLANE_X_NEG)
-DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS)
-DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG)
-DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS)
-DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG)
-//-------------------------------------------------------------------------------------------
-
-// Scissor clip functions
-//-------------------------------------------------------------------------------------------
-#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3])))
-#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3])))
-#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3])))
-#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMax[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1])*(hPrev)[3])))
-
-#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0])*(h)[3])
-#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0])*(h)[3])
-#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1])*(h)[3])
-#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1])*(h)[3])
-
-DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN)
-DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX)
-DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN)
-DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX)
-//-------------------------------------------------------------------------------------------
-
-// Main polygon clip function
-static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter)
-{
-    static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES];
-
-    int n = *vertexCounter;
-
-    #define CLIP_AGAINST_PLANE(FUNC_CLIP)                       \
-    {                                                           \
-        n = FUNC_CLIP(tmp, polygon, n);                         \
-        if (n < 3)                                              \
-        {                                                       \
-            *vertexCounter = 0;                                 \
-            return false;                                       \
-        }                                                       \
-        for (int i = 0; i < n; i++) polygon[i] = tmp[i];        \
-    }
-
-    CLIP_AGAINST_PLANE(sw_clip_w);
-    CLIP_AGAINST_PLANE(sw_clip_x_pos);
-    CLIP_AGAINST_PLANE(sw_clip_x_neg);
-    CLIP_AGAINST_PLANE(sw_clip_y_pos);
-    CLIP_AGAINST_PLANE(sw_clip_y_neg);
-    CLIP_AGAINST_PLANE(sw_clip_z_pos);
-    CLIP_AGAINST_PLANE(sw_clip_z_neg);
-
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        CLIP_AGAINST_PLANE(sw_clip_scissor_x_min);
-        CLIP_AGAINST_PLANE(sw_clip_scissor_x_max);
-        CLIP_AGAINST_PLANE(sw_clip_scissor_y_min);
-        CLIP_AGAINST_PLANE(sw_clip_scissor_y_max);
-    }
-
-    *vertexCounter = n;
-
-    return (n >= 3);
-}
-
-// Triangle rendering logic
-//-------------------------------------------------------------------------------------------
-static inline bool sw_triangle_face_culling(void)
-{
-    // NOTE: Face culling is done before clipping to avoid unnecessary computations
-    //       To handle triangles crossing the w=0 plane correctly,
-    //       we perform the winding order test in homogeneous coordinates directly,
-    //       before the perspective division (division by w)
-    //       This test determines the orientation of the triangle in the (x,y,w) plane,
-    //       which corresponds to the projected 2D winding order sign,
-    //       even with negative w values
-
-    // Preload homogeneous coordinates into local variables
-    const float *h0 = RLSW.vertexBuffer[0].homogeneous;
-    const float *h1 = RLSW.vertexBuffer[1].homogeneous;
-    const float *h2 = RLSW.vertexBuffer[2].homogeneous;
-
-    // Compute a value proportional to the signed area in the projected 2D plane,
-    // calculated directly using homogeneous coordinates BEFORE division by w
-    // This is the determinant of the matrix formed by the (x, y, w) components
-    // of the vertices, which correctly captures the winding order in homogeneous
-    // space and its relationship to the projected 2D winding order, even with
-    // negative w values
-    // The determinant formula used here is:
-    // h0.x*(h1.y*h2.w - h2.y*h1.w) +
-    // h1.x*(h2.y*h0.w - h0.y*h2.w) +
-    // h2.x*(h0.y*h1.w - h1.y*h0.w)
-
-    const float hSgnArea =
-        h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) +
-        h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) +
-        h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]);
-
-    // Discard the triangle if its winding order (determined by the sign
-    // of the homogeneous area/determinant) matches the culled direction
-    // A positive hSgnArea typically corresponds to a counter-clockwise
-    // winding in the projected space when all w > 0
-    // This test is robust for points with w > 0 or w < 0, correctly
-    // capturing the change in orientation when crossing the w=0 plane
-
-    // The culling logic remains the same based on the signed area/determinant
-    // A value of 0 for hSgnArea means the points are collinear in (x, y, w)
-    // space, which corresponds to a degenerate triangle projection
-    // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
-    // and should be handled by the clipper if necessary
-    return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise"
-}
-
-static inline void sw_triangle_clip_and_project(void)
-{
-    sw_vertex_t *polygon = RLSW.vertexBuffer;
-    int *vertexCounter = &RLSW.vertexCounter;
-
-    if (sw_polygon_clip(polygon, vertexCounter))
-    {
-        // Transformation to screen space and normalization
-        for (int i = 0; i < *vertexCounter; i++)
-        {
-            sw_vertex_t *v = &polygon[i];
-
-            // Calculation of the reciprocal of W for normalization
-            // as well as perspective-correct attributes
-            const float wRcp = 1.0f/v->homogeneous[3];
-            v->homogeneous[3] = wRcp;
-
-            // Division of XYZ coordinates by weight
-            v->homogeneous[0] *= wRcp;
-            v->homogeneous[1] *= wRcp;
-            v->homogeneous[2] *= wRcp;
-
-            // Division of texture coordinates (perspective-correct)
-            v->texcoord[0] *= wRcp;
-            v->texcoord[1] *= wRcp;
-
-            // Division of colors (perspective-correct)
-            v->color[0] *= wRcp;
-            v->color[1] *= wRcp;
-            v->color[2] *= wRcp;
-            v->color[3] *= wRcp;
-
-            // Transformation to screen space
-            sw_project_ndc_to_screen(v->screen, v->homogeneous);
-        }
-    }
-}
-
-#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
-static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,     \
-                             const sw_vertex_t *end, float dUdy, float dVdy)        \
-{                                                                                   \
-    /* Gets the start and end coordinates */                                        \
-    int xStart = (int)start->screen[0];                                             \
-    int xEnd   = (int)end->screen[0];                                               \
-                                                                                    \
-    /* Avoid empty lines */                                                         \
-    if (xStart == xEnd) return;                                                     \
-                                                                                    \
-    /* Compute the subpixel distance to traverse before the first pixel */          \
-    float xSubstep = 1.0f - sw_fract(start->screen[0]);                             \
-                                                                                    \
-    /* Compute the inverse horizontal distance along the X axis */                  \
-    float dxRcp = 1.0f/(end->screen[0] - start->screen[0]);                         \
-                                                                                    \
-    /* Compute the interpolation steps along the X axis */                          \
-    float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp;               \
-    float dWdx = (end->homogeneous[3] - start->homogeneous[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                                     \
-    };                                                                              \
-                                                                                    \
-    float dUdx = 0.0f;                                                              \
-    float dVdx = 0.0f;                                                              \
-    if (ENABLE_TEXTURE) {                                                           \
-        dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp;                       \
-        dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp;                       \
-    }                                                                               \
-                                                                                    \
-    /* Initializing the interpolation starting values  */                           \
-    float z = start->homogeneous[2] + dZdx*xSubstep;                                \
-    float w = start->homogeneous[3] + dWdx*xSubstep;                                \
-                                                                                    \
-    float color[4] = {                                                              \
-        start->color[0] + dCdx[0]*xSubstep,                                         \
-        start->color[1] + dCdx[1]*xSubstep,                                         \
-        start->color[2] + dCdx[2]*xSubstep,                                         \
-        start->color[3] + dCdx[3]*xSubstep                                          \
-    };                                                                              \
-                                                                                    \
-    float u = 0.0f;                                                                 \
-    float v = 0.0f;                                                                 \
-    if (ENABLE_TEXTURE) {                                                           \
-        u = start->texcoord[0] + dUdx*xSubstep;                                     \
-        v = start->texcoord[1] + dVdx*xSubstep;                                     \
-    }                                                                               \
-                                                                                    \
-    /* Pre-calculate the starting pointers for the framebuffer row */               \
-    int y = (int)start->screen[1];                                                  \
-    sw_pixel_t *ptr = RLSW.framebuffer.pixels + y*RLSW.framebuffer.width + xStart;  \
-                                                                                    \
-    /* Scanline rasterization */                                                    \
-    for (int x = xStart; x < xEnd; x++)                                             \
-    {                                                                               \
-        float wRcp = 1.0f/w;                                                        \
-        float srcColor[4] = {                                                       \
-            color[0]*wRcp,                                                          \
-            color[1]*wRcp,                                                          \
-            color[2]*wRcp,                                                          \
-            color[3]*wRcp                                                           \
-        };                                                                          \
-                                                                                    \
-        if (ENABLE_DEPTH_TEST)                                                      \
-        {                                                                           \
-            /* TODO: Implement different depth funcs? */                            \
-            float depth =  sw_framebuffer_read_depth(ptr);                          \
-            if (z > depth) goto discard;                                            \
-        }                                                                           \
-                                                                                    \
-        /* TODO: Implement depth mask */                                            \
-        sw_framebuffer_write_depth(ptr, z);                                         \
-                                                                                    \
-        if (ENABLE_TEXTURE)                                                         \
-        {                                                                           \
-            float texColor[4];                                                      \
-            float s = u*wRcp;                                                       \
-            float t = v*wRcp;                                                       \
-            sw_texture_sample(texColor, tex, s, t, dUdx, dUdy, dVdx, dVdy);         \
-            srcColor[0] *= texColor[0];                                             \
-            srcColor[1] *= texColor[1];                                             \
-            srcColor[2] *= texColor[2];                                             \
-            srcColor[3] *= texColor[3];                                             \
-        }                                                                           \
-                                                                                    \
-        if (ENABLE_COLOR_BLEND)                                                     \
-        {                                                                           \
-            float dstColor[4];                                                      \
-            sw_framebuffer_read_color(dstColor, ptr);                               \
-            sw_blend_colors(dstColor, srcColor);                                    \
-            sw_framebuffer_write_color(ptr, dstColor);                              \
-        }                                                                           \
-        else                                                                        \
-        {                                                                           \
-            sw_framebuffer_write_color(ptr, srcColor);                              \
-        }                                                                           \
-                                                                                    \
-        /* Increment the interpolation parameter, UVs, and pointers */              \
-    discard:                                                                        \
-        z += dZdx;                                                                  \
-        w += dWdx;                                                                  \
-        color[0] += dCdx[0];                                                        \
-        color[1] += dCdx[1];                                                        \
-        color[2] += dCdx[2];                                                        \
-        color[3] += dCdx[3];                                                        \
-        if (ENABLE_TEXTURE)                                                         \
-        {                                                                           \
-            u += dUdx;                                                              \
-            v += dVdx;                                                              \
-        }                                                                           \
-        ++ptr;                                                                      \
-    }                                                                               \
-}
-
-#define DEFINE_TRIANGLE_RASTER(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE)            \
-static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1,          \
-                             const sw_vertex_t *v2, const sw_texture_t *tex)        \
-{                                                                                   \
-    /* Swap vertices by increasing y */                                             \
-    if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \
-    if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } \
-    if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \
-                                                                                    \
-    /* Extracting coordinates from the sorted vertices */                           \
-    float x0 = v0->screen[0], y0 = v0->screen[1];                                   \
-    float x1 = v1->screen[0], y1 = v1->screen[1];                                   \
-    float x2 = v2->screen[0], y2 = v2->screen[1];                                   \
-                                                                                    \
-    /* Compute height differences */                                                \
-    float h02 = y2 - y0;                                                            \
-    float h01 = y1 - y0;                                                            \
-    float h12 = y2 - y1;                                                            \
-                                                                                    \
-    if (h02 < 1e-6f) return;                                                        \
-                                                                                    \
-    /* Precompute the inverse values without additional checks */                   \
-    float h02Rcp = 1.0f/h02;                                                        \
-    float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f;                                  \
-    float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f;                                  \
-                                                                                    \
-    /* Pre-calculation of slopes */                                                 \
-    float dXdy02 = (x2 - x0)*h02Rcp;                                                \
-    float dXdy01 = (x1 - x0)*h01Rcp;                                                \
-    float dXdy12 = (x2 - x1)*h12Rcp;                                                \
-                                                                                    \
-    /* Y subpixel correction */                                                     \
-    float y0Substep = 1.0f - sw_fract(y0);                                          \
-    float y1Substep = 1.0f - sw_fract(y1);                                          \
-                                                                                    \
-    /* Y bounds (vertical clipping) */                                              \
-    int yTop = (int)y0;                                                             \
-    int yMid = (int)y1;                                                             \
-    int yBot = (int)y2;                                                             \
-                                                                                    \
-    /* Compute gradients for each side of the triangle */                           \
-    sw_vertex_t dVXdy02, dVXdy01, dVXdy12;                                          \
-    sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp);                              \
-    sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp);                              \
-    sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp);                              \
-                                                                                    \
-    /* Get a copy of vertices for interpolation and apply substep correction */     \
-    sw_vertex_t vLeft = *v0, vRight = *v0;                                          \
-    sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep);                    \
-    sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep);                   \
-                                                                                    \
-    vLeft.screen[0] += dXdy02*y0Substep;                                            \
-    vRight.screen[0] += dXdy01*y0Substep;                                           \
-                                                                                    \
-    /* Scanline for the upper part of the triangle */                               \
-    for (int y = yTop; y < yMid; y++)                                               \
-    {                                                                               \
-        vLeft.screen[1] = vRight.screen[1] = y;                                     \
-                                                                                    \
-        if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
-        else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
-                                                                                    \
-        sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02);                                  \
-        vLeft.screen[0] += dXdy02;                                                  \
-                                                                                    \
-        sw_add_vertex_grad_PTCH(&vRight, &dVXdy01);                                 \
-        vRight.screen[0] += dXdy01;                                                 \
-    }                                                                               \
-                                                                                    \
-    /* Get a copy of next right for interpolation and apply substep correction */   \
-    vRight = *v1;                                                                   \
-    sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep);                   \
-    vRight.screen[0] += dXdy12*y1Substep;                                           \
-                                                                                    \
-    /* Scanline for the lower part of the triangle */                               \
-    for (int y = yMid; y < yBot; y++)                                               \
-    {                                                                               \
-        vLeft.screen[1] = vRight.screen[1] = y;                                     \
-                                                                                    \
-        if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
-        else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
-                                                                                    \
-        sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02);                                  \
-        vLeft.screen[0] += dXdy02;                                                  \
-                                                                                    \
-        sw_add_vertex_grad_PTCH(&vRight, &dVXdy12);                                 \
-        vRight.screen[0] += dXdy12;                                                 \
-    }                                                                               \
-}
-
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline, 0, 0, 0)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX, 1, 0, 0)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH, 0, 1, 0)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_BLEND, 0, 0, 1)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH, 1, 1, 0)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_BLEND, 1, 0, 1)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH_BLEND, 0, 1, 1)
-DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH_BLEND, 1, 1, 1)
-
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster, sw_triangle_raster_scanline, false)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX, sw_triangle_raster_scanline_TEX, true)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH, sw_triangle_raster_scanline_DEPTH, false)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_BLEND, sw_triangle_raster_scanline_BLEND, false)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH, sw_triangle_raster_scanline_TEX_DEPTH, true)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND, sw_triangle_raster_scanline_TEX_BLEND, true)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND, sw_triangle_raster_scanline_DEPTH_BLEND, false)
-DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND, sw_triangle_raster_scanline_TEX_DEPTH_BLEND, true)
-
-static inline void sw_triangle_render(void)
-{
-    if (RLSW.stateFlags & SW_STATE_CULL_FACE)
-    {
-        if (!sw_triangle_face_culling()) return;
-    }
-
-    sw_triangle_clip_and_project();
-
-    if (RLSW.vertexCounter < 3) return;
-
-    #define TRIANGLE_RASTER(RASTER_FUNC)                        \
-    {                                                           \
-        for (int i = 0; i < RLSW.vertexCounter - 2; i++)        \
-        {                                                       \
-            RASTER_FUNC(                                        \
-                &RLSW.vertexBuffer[0],                          \
-                &RLSW.vertexBuffer[i + 1],                      \
-                &RLSW.vertexBuffer[i + 2],                      \
-                &RLSW.loadedTextures[RLSW.currentTexture]       \
-            );                                                  \
-        }                                                       \
-    }
-
-    uint32_t state = RLSW.stateFlags;
-    if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
-    if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
-
-    if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
-    else TRIANGLE_RASTER(sw_triangle_raster)
-
-    #undef TRIANGLE_RASTER
-}
-//-------------------------------------------------------------------------------------------
-
-// Quad rendering logic
-//-------------------------------------------------------------------------------------------
-static inline bool sw_quad_face_culling(void)
-{
-    // NOTE: Face culling is done before clipping to avoid unnecessary computations
-    //       To handle quads crossing the w=0 plane correctly,
-    //       we perform the winding order test in homogeneous coordinates directly,
-    //       before the perspective division (division by w)
-    //       For a convex quad with vertices P0, P1, P2, P3 in sequential order,
-    //       the winding order of the quad is the same as the winding order
-    //       of the triangle P0 P1 P2. We use the homogeneous triangle
-    //       winding test on this first triangle
-
-    // Preload homogeneous coordinates into local variables
-    const float *h0 = RLSW.vertexBuffer[0].homogeneous;
-    const float *h1 = RLSW.vertexBuffer[1].homogeneous;
-    const float *h2 = RLSW.vertexBuffer[2].homogeneous;
-
-    // NOTE: h3 is not needed for this test
-    // const float *h3 = RLSW.vertexBuffer[3].homogeneous;
-
-    // Compute a value proportional to the signed area of the triangle P0 P1 P2
-    // in the projected 2D plane, calculated directly using homogeneous coordinates
-    // BEFORE division by w
-    // This is the determinant of the matrix formed by the (x, y, w) components
-    // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order
-    // in homogeneous space and its relationship to the projected 2D winding order,
-    // even with negative w values
-    // The determinant formula used here is:
-    // h0.x*(h1.y*h2.w - h2.y*h1.w) +
-    // h1.x*(h2.y*h0.w - h0.y*h2.w) +
-    // h2.x*(h0.y*h1.w - h1.y*h0.w)
-
-    const float hSgnArea =
-        h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) +
-        h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) +
-        h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]);
-
-    // Perform face culling based on the winding order determined by the sign
-    // of the homogeneous area/determinant of triangle P0 P1 P2
-    // This test is robust for points with w > 0 or w < 0 within the triangle,
-    // correctly capturing the change in orientation when crossing the w=0 plane
-
-    // A positive hSgnArea typically corresponds to a counter-clockwise
-    // winding in the projected space when all w > 0
-    // A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w)
-    // space, which corresponds to a degenerate triangle projection
-    // Such quads might also be degenerate or non-planar. They are typically
-    // not culled by this test (0 < 0 is false, 0 > 0 is false)
-    // and should be handled by the clipper if necessary
-
-    return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
-}
-
-static inline void sw_quad_clip_and_project(void)
-{
-    sw_vertex_t *polygon = RLSW.vertexBuffer;
-    int *vertexCounter = &RLSW.vertexCounter;
-
-    if (sw_polygon_clip(polygon, vertexCounter))
-    {
-        // Transformation to screen space and normalization
-        for (int i = 0; i < *vertexCounter; i++)
-        {
-            sw_vertex_t *v = &polygon[i];
-
-            // Calculation of the reciprocal of W for normalization
-            // as well as perspective-correct attributes
-            const float wRcp = 1.0f/v->homogeneous[3];
-            v->homogeneous[3] = wRcp;
-
-            // Division of XYZ coordinates by weight
-            v->homogeneous[0] *= wRcp;
-            v->homogeneous[1] *= wRcp;
-            v->homogeneous[2] *= wRcp;
-
-            // Division of texture coordinates (perspective-correct)
-            v->texcoord[0] *= wRcp;
-            v->texcoord[1] *= wRcp;
-
-            // Division of colors (perspective-correct)
-            v->color[0] *= wRcp;
-            v->color[1] *= wRcp;
-            v->color[2] *= wRcp;
-            v->color[3] *= wRcp;
-
-            // Transformation to screen space
-            sw_project_ndc_to_screen(v->screen, v->homogeneous);
-        }
-    }
-}
-
-static inline bool sw_quad_is_axis_aligned(void)
-{
-    // Reject quads with perspective projection
-    // The fast path assumes affine (non-perspective) quads,
-    // so we require all vertices to have homogeneous w = 1.0
-    for (int i = 0; i < 4; i++)
-    {
-        if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false;
-    }
-
-    // Epsilon tolerance in screen space (pixels)
-    const float epsilon = 0.5f;
-
-    // Fetch screen-space positions for the four quad vertices
-    const float *p0 = RLSW.vertexBuffer[0].screen;
-    const float *p1 = RLSW.vertexBuffer[1].screen;
-    const float *p2 = RLSW.vertexBuffer[2].screen;
-    const float *p3 = RLSW.vertexBuffer[3].screen;
-
-    // Compute edge vectors between consecutive vertices
-    // These define the four sides of the quad in screen space
-    float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1];
-    float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1];
-    float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1];
-    float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1];
-
-    // Each edge must be either horizontal or vertical within epsilon tolerance
-    // If any edge deviates significantly from either axis, the quad is not axis-aligned
-    if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false;
-    if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false;
-    if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false;
-    if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false;
-
-    return true;
-}
-
-static inline void sw_quad_sort_cw(const sw_vertex_t* *output)
-{
-    const sw_vertex_t *input = RLSW.vertexBuffer;
-
-    // Calculate the centroid of the quad
-    float cx = (input[0].screen[0] + input[1].screen[0] +
-                input[2].screen[0] + input[3].screen[0])*0.25f;
-    float cy = (input[0].screen[1] + input[1].screen[1] +
-                input[2].screen[1] + input[3].screen[1])*0.25f;
-
-    // Calculate the angle of each vertex relative to the center
-    // and assign them directly to their correct position
-    const sw_vertex_t *corners[4] = { 0 };
-
-    for (int i = 0; i < 4; i++)
-    {
-        float dx = input[i].screen[0] - cx;
-        float dy = input[i].screen[1] - cy;
-
-        // Determine the quadrant (clockwise from top-left)
-        // top-left: dx < 0, dy < 0
-        // top-right: dx >= 0, dy < 0
-        // bottom-right: dx >= 0, dy >= 0
-        // bottom-left: dx < 0, dy >= 0
-
-        int idx;
-        if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row
-        else idx = (dx < 0)? 3 : 2; // Bottom row
-
-        corners[idx] = &input[i];
-    }
-
-    output[0] = corners[0];  // top-left
-    output[1] = corners[1];  // top-right
-    output[2] = corners[2];  // bottom-right
-    output[3] = corners[3];  // bottom-left
-}
-
-// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth,
-// still appear perfectly aligned from a certain point of view?
-// Because in that case, we would still need to perform perspective division for textures and colors...
-#define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
-static inline void FUNC_NAME(void)                                              \
-{                                                                               \
-    const sw_vertex_t *sortedVerts[4];                                          \
-    sw_quad_sort_cw(sortedVerts);                                               \
-                                                                                \
-    const sw_vertex_t *v0 = sortedVerts[0];                                     \
-    const sw_vertex_t *v1 = sortedVerts[1];                                     \
-    const sw_vertex_t *v2 = sortedVerts[2];                                     \
-    const sw_vertex_t *v3 = sortedVerts[3];                                     \
-                                                                                \
-    /* Screen bounds (axis-aligned) */                                          \
-    int xMin = (int)v0->screen[0];                                              \
-    int yMin = (int)v0->screen[1];                                              \
-    int xMax = (int)v2->screen[0];                                              \
-    int yMax = (int)v2->screen[1];                                              \
-                                                                                \
-    float w = v2->screen[0] - v0->screen[0];                                    \
-    float h = v2->screen[1] - v0->screen[1];                                    \
-                                                                                \
-    if ((w == 0) || (h == 0)) return;                                           \
-                                                                                \
-    float wRcp = (w > 0.0f)? 1.0f/w : 0.0f;                                     \
-    float hRcp = (h > 0.0f)? 1.0f/h : 0.0f;                                     \
-                                                                                \
-    /* Subpixel corrections */                                                  \
-    float xSubstep = 1.0f - sw_fract(v0->screen[0]);                            \
-    float ySubstep = 1.0f - sw_fract(v0->screen[1]);                            \
-                                                                                \
-    /* Calculation of vertex gradients in X and Y */                            \
-    float dUdx = 0.0f, dVdx = 0.0f;                                             \
-    float dUdy = 0.0f, dVdy = 0.0f;                                             \
-    if (ENABLE_TEXTURE) {                                                       \
-        dUdx = (v1->texcoord[0] - v0->texcoord[0])*wRcp;                        \
-        dVdx = (v1->texcoord[1] - v0->texcoord[1])*wRcp;                        \
-        dUdy = (v3->texcoord[0] - v0->texcoord[0])*hRcp;                        \
-        dVdy = (v3->texcoord[1] - v0->texcoord[1])*hRcp;                        \
-    }                                                                           \
-                                                                                \
-    float dCdx[4], dCdy[4];                                                     \
-    dCdx[0] = (v1->color[0] - v0->color[0])*wRcp;                               \
-    dCdx[1] = (v1->color[1] - v0->color[1])*wRcp;                               \
-    dCdx[2] = (v1->color[2] - v0->color[2])*wRcp;                               \
-    dCdx[3] = (v1->color[3] - v0->color[3])*wRcp;                               \
-    dCdy[0] = (v3->color[0] - v0->color[0])*hRcp;                               \
-    dCdy[1] = (v3->color[1] - v0->color[1])*hRcp;                               \
-    dCdy[2] = (v3->color[2] - v0->color[2])*hRcp;                               \
-    dCdy[3] = (v3->color[3] - v0->color[3])*hRcp;                               \
-                                                                                \
-    float dZdx, dZdy;                                                           \
-    dZdx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp;                      \
-    dZdy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp;                      \
-                                                                                \
-    /* Start of quad rasterization */                                           \
-    const sw_texture_t *tex;                                                    \
-    if (ENABLE_TEXTURE) tex = &RLSW.loadedTextures[RLSW.currentTexture];        \
-                                                                                \
-    sw_pixel_t *pixels = RLSW.framebuffer.pixels;                               \
-    int wDst = RLSW.framebuffer.width;                                          \
-                                                                                \
-    float zScanline = v0->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep;       \
-    float uScanline = v0->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep;          \
-    float vScanline = v0->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep;          \
-                                                                                \
-    float colorScanline[4] = {                                                  \
-        v0->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep,                     \
-        v0->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep,                     \
-        v0->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep,                     \
-        v0->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep                      \
-    };                                                                          \
-                                                                                \
-    for (int y = yMin; y < yMax; y++)                                           \
-    {                                                                           \
-        sw_pixel_t *ptr = pixels + y*wDst + xMin;                               \
-                                                                                \
-        float z = zScanline;                                                    \
-        float u = uScanline;                                                    \
-        float v = vScanline;                                                    \
-                                                                                \
-        float color[4] = {                                                      \
-            colorScanline[0],                                                   \
-            colorScanline[1],                                                   \
-            colorScanline[2],                                                   \
-            colorScanline[3]                                                    \
-        };                                                                      \
-                                                                                \
-        /* Scanline rasterization */                                            \
-        for (int x = xMin; x < xMax; x++)                                       \
-        {                                                                       \
-            /* Pixel color computation */                                       \
-            float srcColor[4] = {                                               \
-                color[0],                                                       \
-                color[1],                                                       \
-                color[2],                                                       \
-                color[3]                                                        \
-            };                                                                  \
-                                                                                \
-            /* Test and write depth */                                          \
-            if (ENABLE_DEPTH_TEST)                                              \
-            {                                                                   \
-                /* TODO: Implement different depth funcs? */                    \
-                float depth =  sw_framebuffer_read_depth(ptr);                  \
-                if (z > depth) goto discard;                                    \
-            }                                                                   \
-                                                                                \
-            /* TODO: Implement depth mask */                                    \
-            sw_framebuffer_write_depth(ptr, z);                                 \
-                                                                                \
-            if (ENABLE_TEXTURE)                                                 \
-            {                                                                   \
-                float texColor[4];                                              \
-                sw_texture_sample(texColor, tex, u, v, dUdx, dUdy, dVdx, dVdy); \
-                srcColor[0] *= texColor[0];                                     \
-                srcColor[1] *= texColor[1];                                     \
-                srcColor[2] *= texColor[2];                                     \
-                srcColor[3] *= texColor[3];                                     \
-            }                                                                   \
-                                                                                \
-            if (ENABLE_COLOR_BLEND)                                             \
-            {                                                                   \
-                float dstColor[4];                                              \
-                sw_framebuffer_read_color(dstColor, ptr);                       \
-                sw_blend_colors(dstColor, srcColor);                            \
-                sw_framebuffer_write_color(ptr, dstColor);                      \
-            }                                                                   \
-            else sw_framebuffer_write_color(ptr, srcColor);                     \
-                                                                                \
-        discard:                                                                \
-            z += dZdx;                                                          \
-            color[0] += dCdx[0];                                                \
-            color[1] += dCdx[1];                                                \
-            color[2] += dCdx[2];                                                \
-            color[3] += dCdx[3];                                                \
-            if (ENABLE_TEXTURE)                                                 \
-            {                                                                   \
-                u += dUdx;                                                      \
-                v += dVdx;                                                      \
-            }                                                                   \
-            ++ptr;                                                              \
-        }                                                                       \
-                                                                                \
-        zScanline += dZdy;                                                      \
-        colorScanline[0] += dCdy[0];                                            \
-        colorScanline[1] += dCdy[1];                                            \
-        colorScanline[2] += dCdy[2];                                            \
-        colorScanline[3] += dCdy[3];                                            \
-                                                                                \
-        if (ENABLE_TEXTURE)                                                     \
-        {                                                                       \
-            uScanline += dUdy;                                                  \
-            vScanline += dVdy;                                                  \
-        }                                                                       \
-    }                                                                           \
-}
-
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned, 0, 0, 0)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX, 1, 0, 0)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH, 0, 1, 0)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_BLEND, 0, 0, 1)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH, 1, 1, 0)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_BLEND, 1, 0, 1)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH_BLEND, 0, 1, 1)
-DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND, 1, 1, 1)
-
-static inline void sw_quad_render(void)
-{
-    if (RLSW.stateFlags & SW_STATE_CULL_FACE)
-    {
-        if (!sw_quad_face_culling()) return;
-    }
-
-    sw_quad_clip_and_project();
-
-    if (RLSW.vertexCounter < 3) return;
-
-    uint32_t state = RLSW.stateFlags;
-    if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
-    if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
-
-    if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned())
-    {
-        if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
-        else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
-        else sw_quad_raster_axis_aligned();
-        return;
-    }
-
-    #define TRIANGLE_RASTER(RASTER_FUNC)                        \
-    {                                                           \
-        for (int i = 0; i < RLSW.vertexCounter - 2; i++)        \
-        {                                                       \
-            RASTER_FUNC(                                        \
-                &RLSW.vertexBuffer[0],                          \
-                &RLSW.vertexBuffer[i + 1],                      \
-                &RLSW.vertexBuffer[i + 2],                      \
-                &RLSW.loadedTextures[RLSW.currentTexture]       \
-            );                                                  \
-        }                                                       \
-    }
-
-    if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
-    else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
-    else TRIANGLE_RASTER(sw_triangle_raster)
-
-    #undef TRIANGLE_RASTER
-}
-//-------------------------------------------------------------------------------------------
-
-// Line rendering logic
-//-------------------------------------------------------------------------------------------
-static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1)
-{
-    if (fabsf(p) < SW_CLIP_EPSILON)
-    {
-        // Check if the line is entirely outside the window
-        if (q < -SW_CLIP_EPSILON) return 0; // Completely outside
-        return 1; // Completely inside or on the edges
-    }
-
-    const float r = q/p;
-
-    if (p < 0)
-    {
-        if (r > *t1) return 0;
-        if (r > *t0) *t0 = r;
-    }
-    else
-    {
-        if (r < *t0) return 0;
-        if (r < *t1) *t1 = r;
-    }
-
-    return 1;
-}
-
-static inline bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1)
-{
-    float t0 = 0.0f, t1 = 1.0f;
-    float dH[4], dC[4];
-
-    for (int i = 0; i < 4; i++)
-    {
-        dH[i] = v1->homogeneous[i] - v0->homogeneous[i];
-        dC[i] = v1->color[i] - v0->color[i];
-    }
-
-    // Clipping Liang-Barsky
-    if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false;
-    if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false;
-    if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false;
-    if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false;
-    if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false;
-    if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false;
-
-    // Clipping Scissor
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false;
-        if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false;
-        if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false;
-        if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false;
-    }
-
-    // Interpolation of new coordinates
-    if (t1 < 1.0f)
-    {
-        for (int i = 0; i < 4; i++)
-        {
-            v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i];
-            v1->color[i] = v0->color[i] + t1*dC[i];
-        }
-    }
-
-    if (t0 > 0.0f)
-    {
-        for (int i = 0; i < 4; i++)
-        {
-            v0->homogeneous[i] += t0*dH[i];
-            v0->color[i] += t0*dC[i];
-        }
-    }
-
-    return true;
-}
-
-static inline bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
-{
-    if (!sw_line_clip(v0, v1)) return false;
-
-    // Convert homogeneous coordinates to NDC
-    v0->homogeneous[3] = 1.0f/v0->homogeneous[3];
-    v1->homogeneous[3] = 1.0f/v1->homogeneous[3];
-    for (int i = 0; i < 3; i++)
-    {
-        v0->homogeneous[i] *= v0->homogeneous[3];
-        v1->homogeneous[i] *= v1->homogeneous[3];
-    }
-
-    // Convert NDC coordinates to screen space
-    sw_project_ndc_to_screen(v0->screen, v0->homogeneous);
-    sw_project_ndc_to_screen(v1->screen, v1->homogeneous);
-
-    return true;
-}
-
-#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
-static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
-{                                                                       \
-    float x0 = v0->screen[0];                                           \
-    float y0 = v0->screen[1];                                           \
-    float x1 = v1->screen[0];                                           \
-    float y1 = v1->screen[1];                                           \
-                                                                        \
-    float dx = x1 - x0;                                                 \
-    float dy = y1 - y0;                                                 \
-                                                                        \
-    /* Compute dominant axis and subpixel offset */                     \
-    float steps, substep;                                               \
-    if (fabsf(dx) > fabsf(dy))                                          \
-    {                                                                   \
-        steps = fabsf(dx);                                              \
-        if (steps < 1.0f) return;                                       \
-        substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0);   \
-    }                                                                   \
-    else                                                                \
-    {                                                                   \
-        steps = fabsf(dy);                                              \
-        if (steps < 1.0f) return;                                       \
-        substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0);   \
-    }                                                                   \
-                                                                        \
-    /* Compute per pixel increments */                                  \
-    float xInc = dx/steps;                                              \
-    float yInc = dy/steps;                                              \
-    float stepRcp = 1.0f/steps;                                         \
-                                                                        \
-    float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp;     \
-    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;                                        \
-    float z = v0->homogeneous[2] + zInc*substep;                        \
-    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;                              \
-                                                                        \
-    const int fbWidth = RLSW.framebuffer.width;                         \
-    sw_pixel_t *pixels = RLSW.framebuffer.pixels;                       \
-                                                                        \
-    int numPixels = (int)(steps - substep) + 1;                         \
-                                                                        \
-    for (int i = 0; i < numPixels; i++)                                 \
-    {                                                                   \
-        /* REVIEW: May require reviewing projection details */          \
-        int px = (int)(x - 0.5f);                                       \
-        int py = (int)(y - 0.5f);                                       \
-                                                                        \
-        sw_pixel_t *ptr = pixels + py*fbWidth + px;                     \
-                                                                        \
-        if (ENABLE_DEPTH_TEST)                                          \
-        {                                                               \
-            float depth = sw_framebuffer_read_depth(ptr);               \
-            if (z > depth) goto discard;                                \
-        }                                                               \
-                                                                        \
-        sw_framebuffer_write_depth(ptr, z);                             \
-                                                                        \
-        float color[4] = {r, g, b, a};                                  \
-                                                                        \
-        if (ENABLE_COLOR_BLEND)                                         \
-        {                                                               \
-            float dstColor[4];                                          \
-            sw_framebuffer_read_color(dstColor, ptr);                   \
-            sw_blend_colors(dstColor, color);                           \
-            sw_framebuffer_write_color(ptr, dstColor);                  \
-        }                                                               \
-        else sw_framebuffer_write_color(ptr, color);                    \
-                                                                        \
-    discard:                                                            \
-        x += xInc; y += yInc; z += zInc;                                \
-        r += rInc; g += gInc; b += bInc; a += aInc;                     \
-    }                                                                   \
-}
-
-#define DEFINE_LINE_THICK_RASTER(FUNC_NAME, RASTER_FUNC)                \
-void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2)            \
-{                                                                       \
-    sw_vertex_t tv1, tv2;                                               \
-                                                                        \
-    int x1 = (int)v1->screen[0];                                        \
-    int y1 = (int)v1->screen[1];                                        \
-    int x2 = (int)v2->screen[0];                                        \
-    int y2 = (int)v2->screen[1];                                        \
-                                                                        \
-    int dx = x2 - x1;                                                   \
-    int dy = y2 - y1;                                                   \
-                                                                        \
-    RASTER_FUNC(v1, v2);                                                \
-                                                                        \
-    if ((dx != 0) && (abs(dy/dx) < 1))                                  \
-    {                                                                   \
-        int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \
-        wy >>= 1;                                                       \
-        for (int i = 1; i <= wy; i++)                                   \
-        {                                                               \
-            tv1 = *v1, tv2 = *v2;                                       \
-            tv1.screen[1] -= i;                                         \
-            tv2.screen[1] -= i;                                         \
-            RASTER_FUNC(&tv1, &tv2);                                    \
-            tv1 = *v1, tv2 = *v2;                                       \
-            tv1.screen[1] += i;                                         \
-            tv2.screen[1] += i;                                         \
-            RASTER_FUNC(&tv1, &tv2);                                    \
-        }                                                               \
-    }                                                                   \
-    else if (dy != 0)                                                   \
-    {                                                                   \
-        int wx = (int)((RLSW.lineWidth - 1.0f)*abs(dy)/sqrtf(dx*dx + dy*dy)); \
-        wx >>= 1;                                                       \
-        for (int i = 1; i <= wx; i++)                                   \
-        {                                                               \
-            tv1 = *v1, tv2 = *v2;                                       \
-            tv1.screen[0] -= i;                                         \
-            tv2.screen[0] -= i;                                         \
-            RASTER_FUNC(&tv1, &tv2);                                    \
-            tv1 = *v1, tv2 = *v2;                                       \
-            tv1.screen[0] += i;                                         \
-            tv2.screen[0] += i;                                         \
-            RASTER_FUNC(&tv1, &tv2);                                    \
-        }                                                               \
-    }                                                                   \
-}
-
-DEFINE_LINE_RASTER(sw_line_raster, 0, 0)
-DEFINE_LINE_RASTER(sw_line_raster_DEPTH, 1, 0)
-DEFINE_LINE_RASTER(sw_line_raster_BLEND, 0, 1)
-DEFINE_LINE_RASTER(sw_line_raster_DEPTH_BLEND, 1, 1)
-
-DEFINE_LINE_THICK_RASTER(sw_line_thick_raster, sw_line_raster)
-DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH, sw_line_raster_DEPTH)
-DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_BLEND, sw_line_raster_BLEND)
-DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH_BLEND, sw_line_raster_DEPTH_BLEND)
-
-static inline void sw_line_render(sw_vertex_t *vertices)
-{
-    if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) return;
-
-    if (RLSW.lineWidth >= 2.0f)
-    {
-        if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_thick_raster_DEPTH_BLEND(&vertices[0], &vertices[1]);
-        else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_thick_raster_BLEND(&vertices[0], &vertices[1]);
-        else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_thick_raster_DEPTH(&vertices[0], &vertices[1]);
-        else sw_line_thick_raster(&vertices[0], &vertices[1]);
-    }
-    else
-    {
-        if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_raster_DEPTH_BLEND(&vertices[0], &vertices[1]);
-        else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_raster_BLEND(&vertices[0], &vertices[1]);
-        else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_raster_DEPTH(&vertices[0], &vertices[1]);
-        else sw_line_raster(&vertices[0], &vertices[1]);
-    }
-}
-//-------------------------------------------------------------------------------------------
-
-// Point rendering logic
-//-------------------------------------------------------------------------------------------
-static inline bool sw_point_clip_and_project(sw_vertex_t *v)
-{
-    if (v->homogeneous[3] != 1.0f)
-    {
-        for (int_fast8_t i = 0; i < 3; i++)
-        {
-            if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false;
-        }
-
-        v->homogeneous[3] = 1.0f/v->homogeneous[3];
-        v->homogeneous[0] *= v->homogeneous[3];
-        v->homogeneous[1] *= v->homogeneous[3];
-        v->homogeneous[2] *= v->homogeneous[3];
-    }
-
-    sw_project_ndc_to_screen(v->screen, v->homogeneous);
-
-    const int *min = NULL, *max = NULL;
-
-    if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
-    {
-        min = RLSW.scMin;
-        max = RLSW.scMax;
-    }
-    else
-    {
-        min = RLSW.vpMin;
-        max = RLSW.vpMax;
-    }
-
-    bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]);
-    bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]);
-
-    return (insideX && insideY);
-}
-
-#define DEFINE_POINT_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND, CHECK_BOUNDS) \
-static inline void FUNC_NAME(int x, int y, float z, const float color[4])   \
-{                                                                           \
-    if (CHECK_BOUNDS == 1)                                                  \
-    {                                                                       \
-        if ((x < RLSW.vpMin[0]) || (x >= RLSW.vpMax[0])) return;            \
-        if ((y < RLSW.vpMin[1]) || (y >= RLSW.vpMax[1])) return;            \
-    }                                                                       \
-    else if (CHECK_BOUNDS == SW_SCISSOR_TEST)                               \
-    {                                                                       \
-        if ((x < RLSW.scMin[0]) || (x >= RLSW.scMax[0])) return;            \
-        if ((y < RLSW.scMin[1]) || (y >= RLSW.scMax[1])) return;            \
-    }                                                                       \
-                                                                            \
-    int offset = y*RLSW.framebuffer.width + x;                              \
-    sw_pixel_t *ptr = RLSW.framebuffer.pixels + offset;                     \
-                                                                            \
-    if (ENABLE_DEPTH_TEST)                                                  \
-    {                                                                       \
-        float depth = sw_framebuffer_read_depth(ptr);                       \
-        if (z > depth) return;                                              \
-    }                                                                       \
-                                                                            \
-    sw_framebuffer_write_depth(ptr, z);                                     \
-                                                                            \
-    if (ENABLE_COLOR_BLEND)                                                 \
-    {                                                                       \
-        float dstColor[4];                                                  \
-        sw_framebuffer_read_color(dstColor, ptr);                           \
-        sw_blend_colors(dstColor, color);                                   \
-        sw_framebuffer_write_color(ptr, dstColor);                          \
-    }                                                                       \
-    else sw_framebuffer_write_color(ptr, color);                            \
-}
-
-#define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC)                   \
-static inline void FUNC_NAME(sw_vertex_t *v)                                \
-{                                                                           \
-    int cx = v->screen[0];                                                  \
-    int cy = v->screen[1];                                                  \
-    float cz = v->homogeneous[2];                                           \
-    int radius = RLSW.pointRadius;                                          \
-    const float *color = v->color;                                          \
-                                                                            \
-    int x = 0;                                                              \
-    int y = radius;                                                         \
-    int d = 3 - 2*radius;                                                   \
-                                                                            \
-    while (x <= y)                                                          \
-    {                                                                       \
-        for (int i = -x; i <= x; i++)                                       \
-        {                                                                   \
-            RASTER_FUNC(cx + i, cy + y, cz, color);                         \
-            RASTER_FUNC(cx + i, cy - y, cz, color);                         \
-        }                                                                   \
-        for (int i = -y; i <= y; i++)                                       \
-        {                                                                   \
-            RASTER_FUNC(cx + i, cy + x, cz, color);                         \
-            RASTER_FUNC(cx + i, cy - x, cz, color);                         \
-        }                                                                   \
-        if (d > 0)                                                          \
-        {                                                                   \
-            y--;                                                            \
-            d = d + 4*(x - y) + 10;                                         \
-        }                                                                   \
-        else d = d + 4*x + 6;                                               \
-        x++;                                                                \
-    }                                                                       \
-}
-
-DEFINE_POINT_RASTER(sw_point_raster, 0, 0, 0)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH, 1, 0, 0)
-DEFINE_POINT_RASTER(sw_point_raster_BLEND, 0, 1, 0)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND, 1, 1, 0)
-
-DEFINE_POINT_RASTER(sw_point_raster_CHECK, 0, 0, 1)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK, 1, 0, 1)
-DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK, 0, 1, 1)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK, 1, 1, 1)
-
-DEFINE_POINT_RASTER(sw_point_raster_CHECK_SCISSOR, 0, 0, SW_SCISSOR_TEST)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK_SCISSOR, 1, 0, SW_SCISSOR_TEST)
-DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK_SCISSOR, 0, 1, SW_SCISSOR_TEST)
-DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR, 1, 1, SW_SCISSOR_TEST)
-
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster, sw_point_raster_CHECK)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH, sw_point_raster_DEPTH_CHECK)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND, sw_point_raster_BLEND_CHECK)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND, sw_point_raster_DEPTH_BLEND_CHECK)
-
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_SCISSOR, sw_point_raster_CHECK_SCISSOR)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_SCISSOR, sw_point_raster_DEPTH_CHECK_SCISSOR)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND_SCISSOR, sw_point_raster_BLEND_CHECK_SCISSOR)
-DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND_SCISSOR, sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR)
-
-static inline void sw_point_render(sw_vertex_t *v)
-{
-    if (!sw_point_clip_and_project(v)) return;
-
-    if (RLSW.pointRadius >= 1.0f)
-    {
-        if (SW_STATE_CHECK(SW_STATE_SCISSOR_TEST))
-        {
-            if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND_SCISSOR(v);
-            else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND_SCISSOR(v);
-            else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH_SCISSOR(v);
-            else sw_point_thick_raster_SCISSOR(v);
-        }
-        else
-        {
-            if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND(v);
-            else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND(v);
-            else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH(v);
-            else sw_point_thick_raster(v);
-        }
-    }
-    else
-    {
-        if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_raster_DEPTH_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
-        else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_raster_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
-        else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_raster_DEPTH(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
-        else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
-    }
-}
-//-------------------------------------------------------------------------------------------
-
-// Polygon modes rendering logic
-//-------------------------------------------------------------------------------------------
-static inline void sw_poly_point_render(void)
-{
-    for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]);
-}
-
-static inline void sw_poly_line_render(void)
-{
-    const sw_vertex_t *vertices = RLSW.vertexBuffer;
-    int cm1 = RLSW.vertexCounter - 1;
-
-    for (int i = 0; i < cm1; i++)
-    {
-        sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] };
-        sw_line_render(verts);
-    }
-
-    sw_vertex_t verts[2] = { vertices[cm1], vertices[0] };
-    sw_line_render(verts);
-}
-
-static inline void sw_poly_fill_render(void)
-{
-    switch (RLSW.drawMode)
-    {
-        case SW_POINTS: sw_point_render(&RLSW.vertexBuffer[0]); break;
-        case SW_LINES: sw_line_render(RLSW.vertexBuffer); break;
-        case SW_TRIANGLES: sw_triangle_render(); break;
-        case SW_QUADS: sw_quad_render(); break;
-    }
-}
-//-------------------------------------------------------------------------------------------
-
-// Immediate rendering logic
-//-------------------------------------------------------------------------------------------
-void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2])
-{
-    // Copy the attributes in the current vertex
-    sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++];
-    for (int i = 0; i < 4; i++)
-    {
-        vertex->position[i] = position[i];
-        if (i < 2) vertex->texcoord[i] = texcoord[i];
-        vertex->color[i] = color[i];
-    }
-
-    // Calculate homogeneous coordinates
-    const float *m = RLSW.matMVP, *v = vertex->position;
-    vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
-    vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
-    vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
-    vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
-
-    // Immediate rendering of the primitive if the required number is reached
-    if (RLSW.vertexCounter == RLSW.reqVertices)
-    {
-        switch (RLSW.polyMode)
-        {
-            case SW_FILL: sw_poly_fill_render(); break;
-            case SW_LINE: sw_poly_line_render(); break;
-            case SW_POINT: sw_poly_point_render(); break;
-            default: break;
-        }
-
-        RLSW.vertexCounter = 0;
-    }
-}
-
-//-------------------------------------------------------------------------------------------
-
-// Validity check helper functions
-//-------------------------------------------------------------------------------------------
-static inline bool sw_is_texture_valid(uint32_t id)
-{
-    bool valid = true;
-
-    if (id == 0) valid = false;
-    else if (id >= SW_MAX_TEXTURES) valid = false;
-    else if (RLSW.loadedTextures[id].pixels == NULL) valid = false;
-
-    return true;
-}
-
-static inline bool sw_is_texture_filter_valid(int filter)
-{
-    return ((filter == SW_NEAREST) || (filter == SW_LINEAR));
-}
-
-static inline bool sw_is_texture_wrap_valid(int wrap)
-{
-    return ((wrap == SW_REPEAT) || (wrap == SW_CLAMP));
-}
-
-static inline bool sw_is_draw_mode_valid(int mode)
-{
-    bool result = false;
-
-    switch (mode)
-    {
-        case SW_POINTS:
-        case SW_LINES:
-        case SW_TRIANGLES:
-        case SW_QUADS: result = true; break;
-        default: break;
-    }
-
-    return result;
-}
-
-static inline bool sw_is_poly_mode_valid(int mode)
-{
-    bool result = false;
-
-    switch (mode)
-    {
-        case SW_POINT:
-        case SW_LINE:
-        case SW_FILL: result = true; break;
-        default: break;
-    }
-
-    return result;
-}
-
-static inline bool sw_is_face_valid(int face)
-{
-    return (face == SW_FRONT || face == SW_BACK);
-}
-
-static inline bool sw_is_blend_src_factor_valid(int blend)
-{
-    bool result = false;
-
-    switch (blend)
-    {
-        case SW_ZERO:
-        case SW_ONE:
-        case SW_SRC_COLOR:
-        case SW_ONE_MINUS_SRC_COLOR:
-        case SW_SRC_ALPHA:
-        case SW_ONE_MINUS_SRC_ALPHA:
-        case SW_DST_ALPHA:
-        case SW_ONE_MINUS_DST_ALPHA:
-        case SW_DST_COLOR:
-        case SW_ONE_MINUS_DST_COLOR:
-        case SW_SRC_ALPHA_SATURATE: result = true; break;
-        default: break;
-    }
-
-    return result;
-}
-
-static inline bool sw_is_blend_dst_factor_valid(int blend)
-{
-    bool result = false;
-
-    switch (blend)
-    {
-        case SW_ZERO:
-        case SW_ONE:
-        case SW_SRC_COLOR:
-        case SW_ONE_MINUS_SRC_COLOR:
-        case SW_SRC_ALPHA:
-        case SW_ONE_MINUS_SRC_ALPHA:
-        case SW_DST_ALPHA:
-        case SW_ONE_MINUS_DST_ALPHA:
-        case SW_DST_COLOR:
-        case SW_ONE_MINUS_DST_COLOR: result = true; break;
-        default: break;
-    }
-
-    return result;
-}
-//-------------------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-bool swInit(int w, int h)
-{
-    if (!sw_framebuffer_load(w, h)) { swClose(); return false; }
-
-    swViewport(0, 0, w, h);
-    swScissor(0, 0, w, h);
-
-    RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
-    if (RLSW.loadedTextures == NULL) { swClose(); return false; }
-
-    RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
-    if (RLSW.loadedTextures == NULL) { swClose(); return false; }
-
-    const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
-    sw_framebuffer_write_color(&RLSW.clearValue, clearColor);
-    sw_framebuffer_write_depth(&RLSW.clearValue, 1.0f);
-
-    RLSW.currentMatrixMode = SW_MODELVIEW;
-    RLSW.currentMatrix = &RLSW.stackModelview[0];
-
-    sw_matrix_id(RLSW.stackProjection[0]);
-    sw_matrix_id(RLSW.stackModelview[0]);
-    sw_matrix_id(RLSW.stackTexture[0]);
-    sw_matrix_id(RLSW.matMVP);
-
-    RLSW.stackProjectionCounter = 1;
-    RLSW.stackModelviewCounter = 1;
-    RLSW.stackTextureCounter = 1;
-    RLSW.isDirtyMVP = false;
-
-    RLSW.current.texcoord[0] = 0.0f;
-    RLSW.current.texcoord[1] = 0.0f;
-
-    RLSW.current.color[0] = 1.0f;
-    RLSW.current.color[1] = 1.0f;
-    RLSW.current.color[2] = 1.0f;
-    RLSW.current.color[3] = 1.0f;
-
-    RLSW.srcFactor = SW_SRC_ALPHA;
-    RLSW.dstFactor = SW_ONE_MINUS_SRC_ALPHA;
-
-    RLSW.srcFactorFunc = sw_factor_src_alpha;
-    RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha;
-
-    RLSW.polyMode = SW_FILL;
-    RLSW.cullFace = SW_BACK;
-
-    static uint32_t defaultTex[3*2*2] = {
-        0xFFFFFFFF,
-        0xFFFFFFFF,
-        0xFFFFFFFF,
-        0xFFFFFFFF
-    };
-
-    RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex;
-    RLSW.loadedTextures[0].width = 2;
-    RLSW.loadedTextures[0].height = 2;
-    RLSW.loadedTextures[0].wMinus1 = 1;
-    RLSW.loadedTextures[0].hMinus1 = 1;
-    RLSW.loadedTextures[0].minFilter = SW_NEAREST;
-    RLSW.loadedTextures[0].magFilter = SW_NEAREST;
-    RLSW.loadedTextures[0].sWrap = SW_REPEAT;
-    RLSW.loadedTextures[0].tWrap = SW_REPEAT;
-    RLSW.loadedTextures[0].tx = 0.5f;
-    RLSW.loadedTextures[0].ty = 0.5f;
-
-    RLSW.loadedTextureCount = 1;
-
-    SW_LOG("INFO: RLSW: Software renderer initialized successfully\n");
-#if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2)
-    SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n");
-#endif
-#if defined(SW_HAS_AVX) || defined(SW_HAS_AVX2)
-    SW_LOG("INFO: RLSW: Using SIMD instructions: AVX\n");
-#endif
-#if defined(SW_HAS_SSE) || defined(SW_HAS_SSE2) || defined(SW_HAS_SSE3) || defined(SW_HAS_SSSE3) || defined(SW_HAS_SSE41) || defined(SW_HAS_SSE42)
-    SW_LOG("INFO: RLSW: Using SIMD instructions: SSE\n");
-#endif
-#if defined(SW_HAS_NEON_FMA) || defined(SW_HAS_NEON)
-    SW_LOG("INFO: RLSW: Using SIMD instructions: NEON\n");
-#endif
-#if defined(SW_HAS_RVV)
-    SW_LOG("INFO: RLSW: Using SIMD instructions: RVV\n");
-#endif
-
-    return true;
-}
-
-void swClose(void)
-{
-    // NOTE: Starts at texture 1, texture 0 does not have to be freed
-    for (int i = 1; i < RLSW.loadedTextureCount; i++)
-    {
-        if (sw_is_texture_valid(i))
-        {
-            SW_FREE(RLSW.loadedTextures[i].pixels);
-        }
-    }
-
-    SW_FREE(RLSW.framebuffer.pixels);
-    SW_FREE(RLSW.loadedTextures);
-    SW_FREE(RLSW.freeTextureIds);
-
-    RLSW = SW_CURLY_INIT(sw_context_t) { 0 };
-}
-
-bool swResizeFramebuffer(int w, int h)
-{
-    return sw_framebuffer_resize(w, h);
-}
-
-void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels)
-{
-    sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
-
-    if (w <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
-    if (h <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
-
-    if (w > RLSW.framebuffer.width) w = RLSW.framebuffer.width;
-    if (h > RLSW.framebuffer.height) h = RLSW.framebuffer.height;
-
-    x = sw_clampi(x, 0, w);
-    y = sw_clampi(y, 0, h);
-
-    if ((x >= w) || (y >= h)) return;
-
-    if ((x == 0) && (y == 0) && (w == RLSW.framebuffer.width) && (h == RLSW.framebuffer.height))
-    {
-        #if SW_COLOR_BUFFER_BITS == 32
-            if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
-            {
-                sw_framebuffer_copy_fast(pixels);
-                return;
-            }
-        #elif SW_COLOR_BUFFER_BITS == 16
-            if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5)
-            {
-                sw_framebuffer_copy_fast(pixels);
-                return;
-            }
-        #endif
-    }
-
-    switch (pFormat)
-    {
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break;
-        //case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break;
-        // Below: not implemented
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels)
-{
-    sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
-
-    if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
-    if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
-
-    if (wSrc > RLSW.framebuffer.width) wSrc = RLSW.framebuffer.width;
-    if (hSrc > RLSW.framebuffer.height) hSrc = RLSW.framebuffer.height;
-
-    xSrc = sw_clampi(xSrc, 0, wSrc);
-    ySrc = sw_clampi(ySrc, 0, hSrc);
-
-    // Check if the sizes are identical after clamping the source to avoid unexpected issues
-    // REVIEW: This repeats the operations if true, so we could make a copy function without these checks
-    if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc)
-    {
-        swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels);
-    }
-
-    switch (pFormat)
-    {
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
-        case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
-        // Below: not implemented
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-        case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-        default:
-            RLSW.errCode = SW_INVALID_ENUM;
-            break;
-    }
-}
-
-void swEnable(SWstate state)
-{
-    switch (state)
-    {
-        case SW_SCISSOR_TEST: RLSW.stateFlags |= SW_STATE_SCISSOR_TEST; break;
-        case SW_TEXTURE_2D: RLSW.stateFlags |= SW_STATE_TEXTURE_2D; break;
-        case SW_DEPTH_TEST: RLSW.stateFlags |= SW_STATE_DEPTH_TEST; break;
-        case SW_CULL_FACE: RLSW.stateFlags |= SW_STATE_CULL_FACE; break;
-        case SW_BLEND: RLSW.stateFlags |= SW_STATE_BLEND; break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-void swDisable(SWstate state)
-{
-    switch (state)
-    {
-        case SW_SCISSOR_TEST: RLSW.stateFlags &= ~SW_STATE_SCISSOR_TEST; break;
-        case SW_TEXTURE_2D: RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D; break;
-        case SW_DEPTH_TEST: RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST; break;
-        case SW_CULL_FACE: RLSW.stateFlags &= ~SW_STATE_CULL_FACE; break;
-        case SW_BLEND: RLSW.stateFlags &= ~SW_STATE_BLEND; break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-void swGetIntegerv(SWget name, int *v)
-{
-    switch (name)
-    {
-        case SW_MODELVIEW_STACK_DEPTH: *v = SW_MODELVIEW_STACK_DEPTH; break;
-        case SW_PROJECTION_STACK_DEPTH: *v = SW_PROJECTION_STACK_DEPTH; break;
-        case SW_TEXTURE_STACK_DEPTH: *v = SW_TEXTURE_STACK_DEPTH; break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-void swGetFloatv(SWget name, float *v)
-{
-    switch (name)
-    {
-        case SW_COLOR_CLEAR_VALUE:
-        {
-            sw_framebuffer_read_color(v, &RLSW.clearValue);
-        } break;
-        case SW_DEPTH_CLEAR_VALUE:
-        {
-            v[0] = sw_framebuffer_read_depth(&RLSW.clearValue);
-        } break;
-        case SW_CURRENT_COLOR:
-        {
-            v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[0];
-            v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[1];
-            v[2] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[2];
-            v[3] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[3];
-        } break;
-        case SW_CURRENT_TEXTURE_COORDS:
-        {
-            v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[0];
-            v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[1];
-        } break;
-        case SW_POINT_SIZE:
-        {
-            v[0] = 2.0f*RLSW.pointRadius;
-        } break;
-        case SW_LINE_WIDTH:
-        {
-            v[0] = RLSW.lineWidth;
-        } break;
-        case SW_MODELVIEW_MATRIX:
-        {
-            for (int i = 0; i < 16; i++) v[i] = RLSW.stackModelview[RLSW.stackModelviewCounter - 1][i];
-
-        } break;
-        case SW_PROJECTION_MATRIX:
-        {
-            for (int i = 0; i < 16; i++) v[i] = RLSW.stackProjection[RLSW.stackProjectionCounter - 1][i];
-
-        } break;
-        case SW_TEXTURE_MATRIX:
-        {
-            for (int i = 0; i < 16; i++) v[i] = RLSW.stackTexture[RLSW.stackTextureCounter - 1][i];
-
-        } break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-const char *swGetString(SWget name)
-{
-    const char *result = NULL;
-
-    switch (name)
-    {
-        case SW_VENDOR: result = "RLSW Header"; break;
-        case SW_RENDERER: result = "RLSW Software Renderer"; break;
-        case SW_VERSION: result = "RLSW 1.0"; break;
-        case SW_EXTENSIONS: result = "None"; break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-
-    return result;
-}
-
-SWerrcode swGetError(void)
-{
-    SWerrcode ret = RLSW.errCode;
-    RLSW.errCode = SW_NO_ERROR;
-    return ret;
-}
-
-void swViewport(int x, int y, int width, int height)
-{
-    if ((width < 0) || (height < 0))
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    RLSW.vpSize[0] = width;
-    RLSW.vpSize[1] = height;
-
-    RLSW.vpHalf[0] = width/2.0f;
-    RLSW.vpHalf[1] = height/2.0f;
-
-    RLSW.vpCenter[0] = (float)x + RLSW.vpHalf[0];
-    RLSW.vpCenter[1] = (float)y + RLSW.vpHalf[1];
-
-    RLSW.vpMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1);
-    RLSW.vpMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1);
-    RLSW.vpMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1);
-    RLSW.vpMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1);
-}
-
-void swScissor(int x, int y, int width, int height)
-{
-    if ((width < 0) || (height < 0))
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    RLSW.scMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1);
-    RLSW.scMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1);
-    RLSW.scMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1);
-    RLSW.scMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1);
-
-    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]);
-}
-
-void swClearColor(float r, float g, float b, float a)
-{
-    float v[4] = { r, g, b, a };
-    sw_framebuffer_write_color(&RLSW.clearValue, v);
-}
-
-void swClearDepth(float depth)
-{
-    sw_framebuffer_write_depth(&RLSW.clearValue, depth);
-}
-
-void swClear(uint32_t bitmask)
-{
-    int size = RLSW.framebuffer.width*RLSW.framebuffer.height;
-
-    if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT))
-    {
-        sw_framebuffer_fill(RLSW.framebuffer.pixels, size, RLSW.clearValue);
-    }
-    else if (bitmask & (SW_COLOR_BUFFER_BIT))
-    {
-        sw_framebuffer_fill_color(RLSW.framebuffer.pixels, size, RLSW.clearValue.color);
-    }
-    else if (bitmask & SW_DEPTH_BUFFER_BIT)
-    {
-        sw_framebuffer_fill_depth(RLSW.framebuffer.pixels, size, RLSW.clearValue.depth);
-    }
-}
-
-void swBlendFunc(SWfactor sfactor, SWfactor dfactor)
-{
-    if (!sw_is_blend_src_factor_valid(sfactor) ||
-        !sw_is_blend_dst_factor_valid(dfactor))
-    {
-        RLSW.errCode = SW_INVALID_ENUM;
-        return;
-    }
-
-    RLSW.srcFactor = sfactor;
-    RLSW.dstFactor = dfactor;
-
-    switch (sfactor)
-    {
-        case SW_ZERO: RLSW.srcFactorFunc = sw_factor_zero; break;
-        case SW_ONE: RLSW.srcFactorFunc = sw_factor_one; break;
-        case SW_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_src_color; break;
-        case SW_ONE_MINUS_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_src_color; break;
-        case SW_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_src_alpha; break;
-        case SW_ONE_MINUS_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_src_alpha; break;
-        case SW_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_dst_alpha; break;
-        case SW_ONE_MINUS_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_dst_alpha; break;
-        case SW_DST_COLOR: RLSW.srcFactorFunc = sw_factor_dst_color; break;
-        case SW_ONE_MINUS_DST_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_dst_color; break;
-        case SW_SRC_ALPHA_SATURATE: RLSW.srcFactorFunc = sw_factor_src_alpha_saturate; break;
-        default: break;
-    }
-
-    switch (dfactor)
-    {
-        case SW_ZERO: RLSW.dstFactorFunc = sw_factor_zero; break;
-        case SW_ONE: RLSW.dstFactorFunc = sw_factor_one; break;
-        case SW_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_src_color; break;
-        case SW_ONE_MINUS_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_src_color; break;
-        case SW_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_src_alpha; break;
-        case SW_ONE_MINUS_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; break;
-        case SW_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_dst_alpha; break;
-        case SW_ONE_MINUS_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_dst_alpha; break;
-        case SW_DST_COLOR: RLSW.dstFactorFunc = sw_factor_dst_color; break;
-        case SW_ONE_MINUS_DST_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_dst_color; break;
-        case SW_SRC_ALPHA_SATURATE: break;
-        default: break;
-    }
-}
-
-void swPolygonMode(SWpoly mode)
-{
-    if (!sw_is_poly_mode_valid(mode))
-    {
-        RLSW.errCode = SW_INVALID_ENUM;
-        return;
-    }
-
-    RLSW.polyMode = mode;
-}
-
-void swCullFace(SWface face)
-{
-    if (!sw_is_face_valid(face))
-    {
-        RLSW.errCode = SW_INVALID_ENUM;
-        return;
-    }
-
-    RLSW.cullFace = face;
-}
-
-void swPointSize(float size)
-{
-    RLSW.pointRadius = floorf(size*0.5f);
-}
-
-void swLineWidth(float width)
-{
-    RLSW.lineWidth = roundf(width);
-}
-
-void swMatrixMode(SWmatrix mode)
-{
-    switch (mode)
-    {
-        case SW_PROJECTION: RLSW.currentMatrix = &RLSW.stackProjection[RLSW.stackProjectionCounter - 1]; break;
-        case SW_MODELVIEW: RLSW.currentMatrix = &RLSW.stackModelview[RLSW.stackModelviewCounter - 1]; break;
-        case SW_TEXTURE: RLSW.currentMatrix = &RLSW.stackTexture[RLSW.stackTextureCounter - 1]; break;
-        default: RLSW.errCode = SW_INVALID_ENUM; return;
-    }
-
-    RLSW.currentMatrixMode = mode;
-}
-
-void swPushMatrix(void)
-{
-    switch (RLSW.currentMatrixMode)
-    {
-        case SW_PROJECTION:
-        {
-            if (RLSW.stackProjectionCounter >= SW_MAX_PROJECTION_STACK_SIZE)
-            {
-                RLSW.errCode = SW_STACK_OVERFLOW;
-                return;
-            }
-
-            int iOld = RLSW.stackProjectionCounter - 1;
-            int iNew = RLSW.stackProjectionCounter++;
-
-            for (int i = 0; i < 16; i++)
-            {
-                RLSW.stackProjection[iNew][i] = RLSW.stackProjection[iOld][i];
-            }
-
-            RLSW.currentMatrix = &RLSW.stackProjection[iNew];
-        } break;
-        case SW_MODELVIEW:
-        {
-            if (RLSW.stackModelviewCounter >= SW_MAX_MODELVIEW_STACK_SIZE)
-            {
-                RLSW.errCode = SW_STACK_OVERFLOW;
-                return;
-            }
-
-            int iOld = RLSW.stackModelviewCounter - 1;
-            int iNew = RLSW.stackModelviewCounter++;
-
-            for (int i = 0; i < 16; i++)
-            {
-                RLSW.stackModelview[iNew][i] = RLSW.stackModelview[iOld][i];
-            }
-
-            RLSW.currentMatrix = &RLSW.stackModelview[iNew];
-        } break;
-        case SW_TEXTURE:
-        {
-            if (RLSW.stackTextureCounter >= SW_MAX_TEXTURE_STACK_SIZE)
-            {
-                RLSW.errCode = SW_STACK_OVERFLOW;
-                return;
-            }
-
-            int iOld = RLSW.stackTextureCounter - 1;
-            int iNew = RLSW.stackTextureCounter++;
-
-            for (int i = 0; i < 16; i++)
-            {
-                RLSW.stackTexture[iNew][i] = RLSW.stackTexture[iOld][i];
-            }
-
-            RLSW.currentMatrix = &RLSW.stackTexture[iNew];
-        } break;
-        default: break;
-    }
-}
-
-void swPopMatrix(void)
-{
-    switch (RLSW.currentMatrixMode)
-    {
-        case SW_PROJECTION:
-        {
-            if (RLSW.stackProjectionCounter <= 0)
-            {
-                RLSW.errCode = SW_STACK_UNDERFLOW;
-                return;
-            }
-
-            RLSW.currentMatrix = &RLSW.stackProjection[--RLSW.stackProjectionCounter];
-            RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed
-        } break;
-        case SW_MODELVIEW:
-        {
-            if (RLSW.stackModelviewCounter <= 0)
-            {
-                RLSW.errCode = SW_STACK_UNDERFLOW;
-                return;
-            }
-
-            RLSW.currentMatrix = &RLSW.stackModelview[--RLSW.stackModelviewCounter];
-            RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed
-        } break;
-        case SW_TEXTURE:
-        {
-            if (RLSW.stackTextureCounter <= 0)
-            {
-                RLSW.errCode = SW_STACK_UNDERFLOW;
-                return;
-            }
-
-            RLSW.currentMatrix = &RLSW.stackTexture[--RLSW.stackTextureCounter];
-        } break;
-        default: break;
-    }
-}
-
-void swLoadIdentity(void)
-{
-    sw_matrix_id(*RLSW.currentMatrix);
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swTranslatef(float x, float y, float z)
-{
-    sw_matrix_t mat;
-    sw_matrix_id(mat);
-
-    mat[12] = x;
-    mat[13] = y;
-    mat[14] = z;
-
-    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swRotatef(float angle, float x, float y, float z)
-{
-    angle *= SW_DEG2RAD;
-
-    float lengthSq = x*x + y*y + z*z;
-
-    if ((lengthSq != 1.0f) && (lengthSq != 0.0f))
-    {
-        float invLength = 1.0f/sqrtf(lengthSq);
-        x *= invLength;
-        y *= invLength;
-        z *= invLength;
-    }
-
-    float sinres = sinf(angle);
-    float cosres = cosf(angle);
-    float t = 1.0f - cosres;
-
-    sw_matrix_t mat;
-
-    mat[0] = x*x*t + cosres;
-    mat[1] = y*x*t + z*sinres;
-    mat[2] = z*x*t - y*sinres;
-    mat[3] = 0.0f;
-
-    mat[4] = x*y*t - z*sinres;
-    mat[5] = y*y*t + cosres;
-    mat[6] = z*y*t + x*sinres;
-    mat[7] = 0.0f;
-
-    mat[8] = x*z*t + y*sinres;
-    mat[9] = y*z*t - x*sinres;
-    mat[10] = z*z*t + cosres;
-    mat[11] = 0.0f;
-
-    mat[12] = 0.0f;
-    mat[13] = 0.0f;
-    mat[14] = 0.0f;
-    mat[15] = 1.0f;
-
-    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swScalef(float x, float y, float z)
-{
-    sw_matrix_t mat;
-
-    mat[0]  = x, mat[1]  = 0, mat[2]  = 0, mat[3]  = 0;
-    mat[4]  = 0, mat[5]  = y, mat[6]  = 0, mat[7]  = 0;
-    mat[8]  = 0, mat[9]  = 0, mat[10] = z, mat[11] = 0;
-    mat[12] = 0, mat[13] = 0, mat[14] = 0, mat[15] = 1;
-
-    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swMultMatrixf(const float *mat)
-{
-    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swFrustum(double left, double right, double bottom, double top, double znear, double zfar)
-{
-    sw_matrix_t mat;
-
-    double rl = right - left;
-    double tb = top - bottom;
-    double fn = zfar - znear;
-
-    mat[0] = (float)(znear*2.0)/rl;
-    mat[1] = 0.0f;
-    mat[2] = 0.0f;
-    mat[3] = 0.0f;
-
-    mat[4] = 0.0f;
-    mat[5] = (float)(znear*2.0)/tb;
-    mat[6] = 0.0f;
-    mat[7] = 0.0f;
-
-    mat[8] = (float)(right + left)/rl;
-    mat[9] = (float)(top + bottom)/tb;
-    mat[10] = -(float)(zfar + znear)/fn;
-    mat[11] = -1.0f;
-
-    mat[12] = 0.0f;
-    mat[13] = 0.0f;
-    mat[14] = -(zfar*znear*2.0)/fn;
-    mat[15] = 0.0f;
-
-    sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swOrtho(double left, double right, double bottom, double top, double znear, double zfar)
-{
-    sw_matrix_t mat;
-
-    double rl = right - left;
-    double tb = top - bottom;
-    double fn = zfar - znear;
-
-    mat[0] = 2.0f/(float)rl;
-    mat[1] = 0.0f;
-    mat[2] = 0.0f;
-    mat[3] = 0.0f;
-
-    mat[4] = 0.0f;
-    mat[5] = 2.0f/(float)tb;
-    mat[6] = 0.0f;
-    mat[7] = 0.0f;
-
-    mat[8] = 0.0f;
-    mat[9] = 0.0f;
-    mat[10] = -2.0f/(float)fn;
-    mat[11] = 0.0f;
-
-    mat[12] = -(float)(left + right)/rl;
-    mat[13] = -(float)(top + bottom)/tb;
-    mat[14] = -(float)(zfar + znear)/fn;
-    mat[15] = 1.0f;
-
-    sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat);
-
-    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
-}
-
-void swBegin(SWdraw mode)
-{
-    // Check if the draw mode is valid
-    if (!sw_is_draw_mode_valid(mode))
-    {
-        RLSW.errCode = SW_INVALID_ENUM;
-        return;
-    }
-
-    // Recalculate the MVP if this is needed
-    if (RLSW.isDirtyMVP)
-    {
-        sw_matrix_mul_rst(RLSW.matMVP,
-            RLSW.stackModelview[RLSW.stackModelviewCounter - 1],
-            RLSW.stackProjection[RLSW.stackProjectionCounter - 1]);
-
-        RLSW.isDirtyMVP = false;
-    }
-
-    // Obtain the number of vertices needed for this primitive
-    switch (mode)
-    {
-        case SW_POINTS: RLSW.reqVertices = 1; break;
-        case SW_LINES: RLSW.reqVertices = 2; break;
-        case SW_TRIANGLES: RLSW.reqVertices = 3; break;
-        case SW_QUADS: RLSW.reqVertices = 4; break;
-    }
-
-    // Initialize required values
-    RLSW.vertexCounter = 0;
-    RLSW.drawMode = mode;
-}
-
-void swEnd(void)
-{
-    RLSW.drawMode = (SWdraw)0;
-}
-
-void swVertex2i(int x, int y)
-{
-    const float v[4] = { (float)x, (float)y, 0.0f, 1.0f };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex2f(float x, float y)
-{
-    const float v[4] = { x, y, 0.0f, 1.0f };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex2fv(const float *v)
-{
-    const float v4[4] = { v[0], v[1], 0.0f, 1.0f };
-    sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex3i(int x, int y, int z)
-{
-    const float v[4] = { (float)x, (float)y, (float)z, 1.0f };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex3f(float x, float y, float z)
-{
-    const float v[4] = { x, y, z, 1.0f };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex3fv(const float *v)
-{
-    const float v4[4] = { v[0], v[1], v[2], 1.0f };
-    sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex4i(int x, int y, int z, int w)
-{
-    const float v[4] = { (float)x, (float)y, (float)z, (float)w };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex4f(float x, float y, float z, float w)
-{
-    const float v[4] = { x, y, z, w };
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swVertex4fv(const float *v)
-{
-    sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
-}
-
-void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
-{
-    float cv[4];
-    cv[0] = (float)r*SW_INV_255;
-    cv[1] = (float)g*SW_INV_255;
-    cv[2] = (float)b*SW_INV_255;
-    cv[3] = 1.0f;
-
-    swColor4fv(cv);
-}
-
-void swColor3ubv(const uint8_t *v)
-{
-    float cv[4];
-    cv[0] = (float)v[0]*SW_INV_255;
-    cv[1] = (float)v[1]*SW_INV_255;
-    cv[2] = (float)v[2]*SW_INV_255;
-    cv[3] = 1.0f;
-
-    swColor4fv(cv);
-}
-
-void swColor3f(float r, float g, float b)
-{
-    float cv[4];
-    cv[0] = r;
-    cv[1] = g;
-    cv[2] = b;
-    cv[3] = 1.0f;
-
-    swColor4fv(cv);
-}
-
-void swColor3fv(const float *v)
-{
-    float cv[4];
-    cv[0] = v[0];
-    cv[1] = v[1];
-    cv[2] = v[2];
-    cv[3] = 1.0f;
-
-    swColor4fv(cv);
-}
-
-void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
-{
-    float cv[4];
-    cv[0] = (float)r*SW_INV_255;
-    cv[1] = (float)g*SW_INV_255;
-    cv[2] = (float)b*SW_INV_255;
-    cv[3] = (float)a*SW_INV_255;
-
-    swColor4fv(cv);
-}
-
-void swColor4ubv(const uint8_t *v)
-{
-    float cv[4];
-    cv[0] = (float)v[0]*SW_INV_255;
-    cv[1] = (float)v[1]*SW_INV_255;
-    cv[2] = (float)v[2]*SW_INV_255;
-    cv[3] = (float)v[3]*SW_INV_255;
-
-    swColor4fv(cv);
-}
-
-void swColor4f(float r, float g, float b, float a)
-{
-    float cv[4];
-    cv[0] = r;
-    cv[1] = g;
-    cv[2] = b;
-    cv[3] = a;
-
-    swColor4fv(cv);
-}
-
-void swColor4fv(const float *v)
-{
-    for (int i = 0; i < 4; i++) RLSW.current.color[i] = v[i];
-}
-
-void swTexCoord2f(float u, float v)
-{
-    const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
-
-    RLSW.current.texcoord[0] = m[0]*u + m[4]*v + m[12];
-    RLSW.current.texcoord[1] = m[1]*u + m[5]*v + m[13];
-}
-
-void swTexCoord2fv(const float *v)
-{
-    const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
-
-    RLSW.current.texcoord[0] = m[0]*v[0] + m[4]*v[1] + m[12];
-    RLSW.current.texcoord[1] = m[1]*v[0] + m[5]*v[1] + m[13];
-}
-
-void swBindArray(SWarray type, void *buffer)
-{
-    switch (type)
-    {
-        case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break;
-        case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break;
-        case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break;
-        default: break;
-    }
-}
-
-void swDrawArrays(SWdraw mode, int offset, int count)
-{
-    if (RLSW.array.positions == 0)
-    {
-        RLSW.errCode = SW_INVALID_OPERATION;
-        return;
-    }
-
-    swBegin(mode);
-    {
-        const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
-        const float *defaultTexcoord = RLSW.current.texcoord;
-        const float *defaultColor = RLSW.current.color;
-
-        const float *positions = RLSW.array.positions;
-        const float *texcoords = RLSW.array.texcoords;
-        const uint8_t *colors = RLSW.array.colors;
-
-        int end = offset + count;
-
-        for (int i = offset; i < end; i++)
-        {
-            float u, v;
-            if (texcoords)
-            {
-                int idx = 2*i;
-                u = texcoords[idx];
-                v = texcoords[idx + 1];
-            }
-            else
-            {
-                u = defaultTexcoord[0];
-                v = defaultTexcoord[1];
-            }
-
-            float texcoord[2];
-            texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
-            texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
-
-            float color[4] = {
-                defaultColor[0],
-                defaultColor[1],
-                defaultColor[2],
-                defaultColor[3]
-            };
-
-            if (colors)
-            {
-                int idx = 4*i;
-                color[0] *= (float)colors[idx]*SW_INV_255;
-                color[1] *= (float)colors[idx + 1]*SW_INV_255;
-                color[2] *= (float)colors[idx + 2]*SW_INV_255;
-                color[3] *= (float)colors[idx + 3]*SW_INV_255;
-            }
-
-            int idx = 3*i;
-            float position[4] = {
-                positions[idx],
-                positions[idx + 1],
-                positions[idx + 2],
-                1.0f
-            };
-
-            sw_immediate_push_vertex(position, color, texcoord);
-        }
-    }
-    swEnd();
-}
-
-void swDrawElements(SWdraw mode, int count, int type, const void *indices)
-{
-    if (RLSW.array.positions == 0)
-    {
-        RLSW.errCode = SW_INVALID_OPERATION;
-        return;
-    }
-
-    if (count < 0)
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    const uint8_t *indicesUb = NULL;
-    const uint16_t *indicesUs = NULL;
-    const uint32_t *indicesUi = NULL;
-
-    switch (type)
-    {
-        case SW_UNSIGNED_BYTE:
-            indicesUb = (const uint8_t *)indices;
-            break;
-        case SW_UNSIGNED_SHORT:
-            indicesUs = (const uint16_t *)indices;
-            break;
-        case SW_UNSIGNED_INT:
-            indicesUi = (const uint32_t *)indices;
-            break;
-        default:
-            RLSW.errCode = SW_INVALID_ENUM;
-            return;
-    }
-
-    swBegin(mode);
-    {
-        const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
-        const float *defaultTexcoord = RLSW.current.texcoord;
-        const float *defaultColor = RLSW.current.color;
-
-        const float *positions = RLSW.array.positions;
-        const float *texcoords = RLSW.array.texcoords;
-        const uint8_t *colors = RLSW.array.colors;
-
-        for (int i = 0; i < count; i++)
-        {
-            int index = indicesUb? indicesUb[i] :
-                       (indicesUs? indicesUs[i] : indicesUi[i]);
-
-            float u, v;
-            if (texcoords)
-            {
-                int idx = 2*index;
-                u = texcoords[idx];
-                v = texcoords[idx + 1];
-            }
-            else
-            {
-                u = defaultTexcoord[0];
-                v = defaultTexcoord[1];
-            }
-
-            float texcoord[2];
-            texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
-            texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
-
-            float color[4] = {
-                defaultColor[0],
-                defaultColor[1],
-                defaultColor[2],
-                defaultColor[3]
-            };
-
-            if (colors)
-            {
-                int idx = 4*index;
-                color[0] *= (float)colors[idx]*SW_INV_255;
-                color[1] *= (float)colors[idx + 1]*SW_INV_255;
-                color[2] *= (float)colors[idx + 2]*SW_INV_255;
-                color[3] *= (float)colors[idx + 3]*SW_INV_255;
-            }
-
-            int idx = 3*index;
-            float position[4] = {
-                positions[idx],
-                positions[idx + 1],
-                positions[idx + 2],
-                1.0f
-            };
-
-            sw_immediate_push_vertex(position, color, texcoord);
-        }
-    }
-    swEnd();
-}
-
-void swGenTextures(int count, uint32_t *textures)
-{
-    if ((count == 0) || (textures == NULL)) return;
-
-    for (int i = 0; i < count; i++)
-    {
-        if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES)
-        {
-            RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory, not really stack overflow
-            return;
-        }
-
-        uint32_t id = 0;
-        if (RLSW.freeTextureIdCount > 0) id = RLSW.freeTextureIds[--RLSW.freeTextureIdCount];
-        else id = RLSW.loadedTextureCount++;
-
-        RLSW.loadedTextures[id] = RLSW.loadedTextures[0];
-        textures[i] = id;
-    }
-}
-
-void swDeleteTextures(int count, uint32_t *textures)
-{
-    if ((count == 0) || (textures == NULL)) return;
-
-    for (int i = 0; i < count; i++)
-    {
-        if (!sw_is_texture_valid(textures[i]))
-        {
-            RLSW.errCode = SW_INVALID_VALUE;
-            continue;
-        }
-
-        SW_FREE(RLSW.loadedTextures[textures[i]].pixels);
-
-        RLSW.loadedTextures[textures[i]].pixels = NULL;
-        RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i];
-    }
-}
-
-void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data)
-{
-    uint32_t id = RLSW.currentTexture;
-
-    if (!sw_is_texture_valid(id))
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    int pixelFormat = sw_get_pixel_format(format, type);
-
-    if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN)
-    {
-        RLSW.errCode = SW_INVALID_ENUM;
-        return;
-    }
-
-    sw_texture_t *texture = &RLSW.loadedTextures[id];
-
-    int size = width*height;
-    texture->pixels = SW_MALLOC(4*size);
-
-    if (texture->pixels == NULL)
-    {
-        RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory...
-        return;
-    }
-
-    for (int i = 0; i < size; i++)
-    {
-        uint32_t *dst = &((uint32_t*)texture->pixels)[i];
-        sw_get_pixel((uint8_t*)dst, data, i, pixelFormat);
-    }
-
-    texture->width = width;
-    texture->height = height;
-    texture->wMinus1 = width - 1;
-    texture->hMinus1 = height - 1;
-    texture->tx = 1.0f/width;
-    texture->ty = 1.0f/height;
-}
-
-void swTexParameteri(int param, int value)
-{
-    uint32_t id = RLSW.currentTexture;
-
-    if (!sw_is_texture_valid(id))
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    sw_texture_t *texture = &RLSW.loadedTextures[id];
-
-    switch (param)
-    {
-        case SW_TEXTURE_MIN_FILTER:
-        {
-            if (!sw_is_texture_filter_valid(value))
-            {
-                RLSW.errCode = SW_INVALID_ENUM;
-                return;
-            }
-
-            texture->minFilter = (SWfilter)value;
-        } break;
-        case SW_TEXTURE_MAG_FILTER:
-        {
-            if (!sw_is_texture_filter_valid(value))
-            {
-                RLSW.errCode = SW_INVALID_ENUM;
-                return;
-            }
-
-            texture->magFilter = (SWfilter)value;
-        } break;
-        case SW_TEXTURE_WRAP_S:
-        {
-            if (!sw_is_texture_wrap_valid(value))
-            {
-                RLSW.errCode = SW_INVALID_ENUM;
-                return;
-            }
-
-            texture->sWrap = (SWwrap)value;
-        } break;
-        case SW_TEXTURE_WRAP_T:
-        {
-            if (!sw_is_texture_wrap_valid(value))
-            {
-                RLSW.errCode = SW_INVALID_ENUM;
-                return;
-            }
-
-            texture->tWrap = (SWwrap)value;
-        } break;
-        default: RLSW.errCode = SW_INVALID_ENUM; break;
-    }
-}
-
-void swBindTexture(uint32_t id)
-{
-    if (id >= SW_MAX_TEXTURES)
-    {
-        RLSW.errCode = SW_INVALID_VALUE;
-        return;
-    }
-
-    if (RLSW.loadedTextures[id].pixels == NULL)
-    {
-        RLSW.errCode = SW_INVALID_OPERATION;
-        return;
-    }
-
-    RLSW.currentTexture = id;
-}
-
-#endif // RLSW_IMPLEMENTATION
+*   rlsw v1.6 - An OpenGL 1.1-style software renderer implementation
+*
+*   DESCRIPTION:
+*       rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all
+*       functionality available on rlgl.h library used by raylib, becoming a direct software
+*       rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less
+*       devices when required
+*
+*   FEATURES:
+*       - Rendering to custom internal framebuffer with multiple color modes supported:
+*           - Color buffer: RGB - 8-bit (3:3:2) | RGB - 16-bit (5:6:5) | RGB - 24-bit (8:8:8)
+*           - Depth buffer: D - 8-bit (unorm) | D - 16-bit (unorm) | D - 24-bit (unorm)
+*       - Rendering modes supported: POINT, LINES, TRIANGLE, QUADS
+*           - Additional features: Polygon modes, Point width, Line width
+*       - Clipping support for all rendering modes
+*       - Texture features supported:
+*           - All uncompressed texture formats supported by raylib
+*           - Texture Minification/Magnification checks
+*           - Point and Bilinear filtering
+*           - Texture Wrap Modes with separate checks for S/T coordinates
+*       - Vertex Arrays support with direct primitive drawing mode
+*       - Matrix Stack support (Matrix Push/Pop)
+*       - Other GL misc features:
+*           - GL-style getter functions
+*           - Framebuffer resizing
+*           - Perspective correction
+*           - Scissor clipping
+*           - Depth testing
+*           - Blend modes
+*           - Face culling
+*
+*   ADDITIONAL NOTES:
+*       Check PR for more info: https://github.com/raysan5/raylib/pull/4832
+*
+*   CONFIGURATION:
+*       #define RLSW_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 RLSW_USE_SIMD_INTRINSICS
+*           Detect and use SIMD intrinsics on the host compilation platform
+*           SIMD could improve rendering considerable vectorizing some raster operations
+*           but the target platforms running the compiled program with SIMD enabled
+*           must support the SIMD the program has been built for, making them only
+*           recommended under specific situations and only if the developers know
+*           what are they doing; this flag is not defined by default
+*
+*       rlsw capabilities could be customized defining some internal
+*       values before library inclusion (default values listed):
+*
+*           #define RLSW_FRAMEBUFFER_OUTPUT_BGRA      true
+*           #define RLSW_FRAMEBUFFER_COLOR_TYPE       R8G8B8A8
+*           #define RLSW_FRAMEBUFFER_DEPTH_TYPE       D32
+*           #define RLSW_MAX_PROJECTION_STACK_SIZE    2
+*           #define RLSW_MAX_MODELVIEW_STACK_SIZE     8
+*           #define RLSW_MAX_TEXTURE_STACK_SIZE       2
+*           #define RLSW_MAX_TEXTURES                 128
+*           #define RLSW_DOUBLE_BUFFERING             0
+*
+*
+*   LICENSE: MIT
+*
+*   Copyright (c) 2025-2026 Le Juez Victor (@Bigfoot71), reviewed by Ramon Santamaria (@raysan5)
+*
+*   Permission is hereby granted, free of charge, to any person obtaining a copy
+*   of this software and associated documentation files (the "Software"), to deal
+*   in the Software without restriction, including without limitation the rights
+*   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+*   copies of the Software, and to permit persons to whom the Software is
+*   furnished to do so, subject to the following conditions:
+*
+*   The above copyright notice and this permission notice shall be included in all
+*   copies or substantial portions of the Software.
+*
+*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+*   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+*   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+*   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+*   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+*   SOFTWARE.
+*
+**********************************************************************************************/
+
+#ifndef RLSW_H
+#define RLSW_H
+
+#define RLSW_VERSION  "1.6"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+//----------------------------------------------------------------------------------
+// RLSW Configuration
+//----------------------------------------------------------------------------------
+#ifndef RLSW_FRAMEBUFFER_OUTPUT_BGRA
+    #define RLSW_FRAMEBUFFER_OUTPUT_BGRA    true
+#endif
+#ifndef RLSW_FRAMEBUFFER_COLOR_TYPE
+    #define RLSW_FRAMEBUFFER_COLOR_TYPE     R8G8B8A8    // Or R5G6B5, R3G3B2, etc; see `sw_pixelformat_t`
+#endif
+#ifndef RLSW_FRAMEBUFFER_DEPTH_TYPE
+    #define RLSW_FRAMEBUFFER_DEPTH_TYPE     D32         // Or D16, D8
+#endif
+#ifndef RLSW_MAX_PROJECTION_STACK_SIZE
+    #define RLSW_MAX_PROJECTION_STACK_SIZE  2
+#endif
+#ifndef RLSW_MAX_MODELVIEW_STACK_SIZE
+    #define RLSW_MAX_MODELVIEW_STACK_SIZE   8
+#endif
+#ifndef RLSW_MAX_TEXTURE_STACK_SIZE
+    #define RLSW_MAX_TEXTURE_STACK_SIZE     2
+#endif
+#ifndef RLSW_MAX_FRAMEBUFFERS
+    #define RLSW_MAX_FRAMEBUFFERS           8
+#endif
+#ifndef RLSW_MAX_TEXTURES
+    #define RLSW_MAX_TEXTURES               128
+#endif
+#ifndef RLSW_DOUBLE_BUFFERING
+    #define RLSW_DOUBLE_BUFFERING           0
+#endif
+
+// Enable the use of a lookup table for uint8_t to float conversion
+// Requires an additional 1KB of global memory
+// Disabled when SIMD intrinsics are enabled
+#ifndef RLSW_USE_COLOR_LUT
+    #if RLSW_USE_SIMD_INTRINSICS
+        #define RLSW_USE_COLOR_LUT          false
+    #else
+        #define RLSW_USE_COLOR_LUT          true
+    #endif
+#endif
+
+// 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
+#ifndef RLSW_SUPPORT_NPOT_TEXTURE
+#   define RLSW_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
+//----------------------------------------------------------------------------------
+typedef unsigned int        GLenum;
+typedef unsigned char       GLboolean;
+typedef unsigned int        GLbitfield;
+typedef void                GLvoid;
+typedef signed char         GLbyte;
+typedef short               GLshort;
+typedef int                 GLint;
+typedef unsigned char       GLubyte;
+typedef unsigned short      GLushort;
+typedef unsigned int        GLuint;
+typedef int                 GLsizei;
+typedef float               GLfloat;
+typedef float               GLclampf;
+typedef double              GLdouble;
+typedef double              GLclampd;
+
+//----------------------------------------------------------------------------------
+// OpenGL Definitions
+// NOTE: Not used/supported definitions are commented
+//----------------------------------------------------------------------------------
+#define GL_FALSE                            0
+#define GL_TRUE                             1
+
+#define GL_SCISSOR_TEST                     0x0C11
+#define GL_TEXTURE_2D                       0x0DE1
+#define GL_DEPTH_TEST                       0x0B71
+#define GL_CULL_FACE                        0x0B44
+#define GL_BLEND                            0x0BE2
+
+#define GL_VENDOR                           0x1F00
+#define GL_RENDERER                         0x1F01
+#define GL_VERSION                          0x1F02
+#define GL_EXTENSIONS                       0x1F03
+#define GL_SHADING_LANGUAGE_VERSION         0x8B8C
+
+//#define GL_ATTRIB_STACK_DEPTH             0x0BB0
+//#define GL_CLIENT_ATTRIB_STACK_DEPTH      0x0BB1
+#define GL_COLOR_CLEAR_VALUE                0x0C22
+#define GL_DEPTH_CLEAR_VALUE                0x0B73
+//#define GL_COLOR_WRITEMASK                0x0C23
+//#define GL_CURRENT_INDEX                  0x0B01
+#define GL_CURRENT_COLOR                    0x0B00
+//#define GL_CURRENT_NORMAL                 0x0B02
+//#define GL_CURRENT_RASTER_COLOR           0x0B04
+//#define GL_CURRENT_RASTER_DISTANCE        0x0B09
+//#define GL_CURRENT_RASTER_INDEX           0x0B05
+//#define GL_CURRENT_RASTER_POSITION        0x0B07
+//#define GL_CURRENT_RASTER_TEXTURE_COORDS  0x0B06
+//#define GL_CURRENT_RASTER_POSITION_VALID  0x0B08
+#define GL_CURRENT_TEXTURE_COORDS           0x0B03
+#define GL_POINT_SIZE                       0x0B11
+#define GL_LINE_WIDTH                       0x0B21
+//#define GL_INDEX_CLEAR_VALUE              0x0C20
+//#define GL_INDEX_MODE                     0x0C30
+//#define GL_INDEX_WRITEMASK                0x0C21
+#define GL_MODELVIEW_MATRIX                 0x0BA6
+#define GL_MODELVIEW_STACK_DEPTH            0x0BA3
+//#define GL_NAME_STACK_DEPTH               0x0D70
+#define GL_PROJECTION_MATRIX                0x0BA7
+#define GL_PROJECTION_STACK_DEPTH           0x0BA4
+//#define GL_RENDER_MODE                    0x0C40
+//#define GL_RGBA_MODE                      0x0C31
+#define GL_TEXTURE_MATRIX                   0x0BA8
+#define GL_TEXTURE_STACK_DEPTH              0x0BA5
+#define GL_VIEWPORT                         0x0BA2
+
+#define GL_COLOR_BUFFER_BIT                 0x00004000
+#define GL_DEPTH_BUFFER_BIT                 0x00000100
+
+#define GL_MODELVIEW                        0x1700
+#define GL_PROJECTION                       0x1701
+#define GL_TEXTURE                          0x1702
+
+#define GL_VERTEX_ARRAY                     0x8074
+#define GL_NORMAL_ARRAY                     0x8075      // WARNING: Not implemented (defined for RLGL)
+#define GL_COLOR_ARRAY                      0x8076
+//#define GL_INDEX_ARRAY                    0x8077
+#define GL_TEXTURE_COORD_ARRAY              0x8078
+
+#define GL_POINTS                           0x0000
+#define GL_LINES                            0x0001
+//#define GL_LINE_LOOP                      0x0002
+//#define GL_LINE_STRIP                     0x0003
+#define GL_TRIANGLES                        0x0004
+//#define GL_TRIANGLE_STRIP                 0x0005
+//#define GL_TRIANGLE_FAN                   0x0006
+#define GL_QUADS                            0x0007
+//#define GL_QUAD_STRIP                     0x0008
+//#define GL_POLYGON                        0x0009
+
+#define GL_POINT                            0x1B00
+#define GL_LINE                             0x1B01
+#define GL_FILL                             0x1B02
+
+#define GL_FRONT                            0x0404
+#define GL_BACK                             0x0405
+
+#define GL_ZERO                             0
+#define GL_ONE                              1
+#define GL_SRC_COLOR                        0x0300
+#define GL_ONE_MINUS_SRC_COLOR              0x0301
+#define GL_SRC_ALPHA                        0x0302
+#define GL_ONE_MINUS_SRC_ALPHA              0x0303
+#define GL_DST_ALPHA                        0x0304
+#define GL_ONE_MINUS_DST_ALPHA              0x0305
+#define GL_DST_COLOR                        0x0306
+#define GL_ONE_MINUS_DST_COLOR              0x0307
+#define GL_SRC_ALPHA_SATURATE               0x0308
+
+#define GL_NEAREST                          0x2600
+#define GL_LINEAR                           0x2601
+
+#define GL_REPEAT                           0x2901
+#define GL_CLAMP                            0x2900
+
+#define GL_TEXTURE_MAG_FILTER               0x2800
+#define GL_TEXTURE_MIN_FILTER               0x2801
+
+#define GL_TEXTURE_WRAP_S                   0x2802
+#define GL_TEXTURE_WRAP_T                   0x2803
+
+#define GL_NO_ERROR                         0
+#define GL_INVALID_ENUM                     0x0500
+#define GL_INVALID_VALUE                    0x0501
+#define GL_INVALID_OPERATION                0x0502
+#define GL_STACK_OVERFLOW                   0x0503
+#define GL_STACK_UNDERFLOW                  0x0504
+#define GL_OUT_OF_MEMORY                    0x0505
+
+#define GL_ALPHA                            0x1906
+#define GL_LUMINANCE                        0x1909
+#define GL_LUMINANCE_ALPHA                  0x190A
+#define GL_RGB                              0x1907
+#define GL_RGBA                             0x1908
+#define GL_DEPTH_COMPONENT			        0x1902
+
+#define GL_BYTE                             0x1400
+#define GL_UNSIGNED_BYTE                    0x1401
+#define GL_SHORT                            0x1402
+#define GL_UNSIGNED_SHORT                   0x1403
+#define GL_INT                              0x1404
+#define GL_UNSIGNED_INT                     0x1405
+#define GL_FLOAT                            0x1406
+#define GL_UNSIGNED_BYTE_3_3_2              0x8032
+#define GL_UNSIGNED_SHORT_5_6_5             0x8363
+#define GL_UNSIGNED_SHORT_4_4_4_4           0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1           0x8034
+
+// OpenGL internal formats (not all are supported; see SWinternalformat)
+#define GL_ALPHA4                           0x803B
+#define GL_ALPHA8                           0x803C
+#define GL_ALPHA12                          0x803D
+#define GL_ALPHA16                          0x803E
+#define GL_LUMINANCE4                       0x803F
+#define GL_LUMINANCE8                       0x8040
+#define GL_LUMINANCE12                      0x8041
+#define GL_LUMINANCE16                      0x8042
+#define GL_LUMINANCE4_ALPHA4                0x8043
+#define GL_LUMINANCE6_ALPHA2                0x8044
+#define GL_LUMINANCE8_ALPHA8                0x8045
+#define GL_LUMINANCE12_ALPHA4               0x8046
+#define GL_LUMINANCE12_ALPHA12              0x8047
+#define GL_LUMINANCE16_ALPHA16              0x8048
+#define GL_INTENSITY                        0x8049
+#define GL_INTENSITY4                       0x804A
+#define GL_INTENSITY8                       0x804B
+#define GL_INTENSITY12                      0x804C
+#define GL_INTENSITY16                      0x804D
+#define GL_R3_G3_B2                         0x2A10
+#define GL_RGB4                             0x804F
+#define GL_RGB5                             0x8050
+#define GL_RGB8                             0x8051
+#define GL_RGB10                            0x8052
+#define GL_RGB12                            0x8053
+#define GL_RGB16                            0x8054
+#define GL_RGBA2                            0x8055
+#define GL_RGBA4                            0x8056
+#define GL_RGB5_A1                          0x8057
+#define GL_RGBA8                            0x8058
+#define GL_RGB10_A2                         0x8059
+#define GL_RGBA12                           0x805A
+#define GL_RGBA16                           0x805B
+
+// OpenGL internal formats extension
+#define GL_DEPTH_COMPONENT16                0x81A5
+#define GL_DEPTH_COMPONENT24                0x81A6
+#define GL_DEPTH_COMPONENT32                0x81A7
+#define GL_DEPTH_COMPONENT32F               0x8CAC
+#define GL_R16F                             0x822D
+#define GL_RGB16F                           0x881B
+#define GL_RGBA16F                          0x881A
+#define GL_R32F                             0x822E
+#define GL_RGB32F                           0x8815
+#define GL_RGBA32F                          0x8814
+
+// OpenGL GL_EXT_framebuffer_object
+#define GL_DRAW_FRAMEBUFFER_BINDING                     0x8CA6
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           0x8CD1
+#define GL_FRAMEBUFFER_COMPLETE                         0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT            0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT    0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS            0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED                      0x8CDD
+#define GL_COLOR_ATTACHMENT0                            0x8CE0
+#define GL_DEPTH_ATTACHMENT                             0x8D00
+#define GL_STENCIL_ATTACHMENT                           0x8D20  // WARNING: Not implemented (defined for RLGL)
+
+// OpenGL Definitions NOT USED
+#define GL_PERSPECTIVE_CORRECTION_HINT      0x0C50
+#define GL_PACK_ALIGNMENT                   0x0D05
+#define GL_UNPACK_ALIGNMENT                 0x0CF5
+#define GL_LINE_SMOOTH                      0x0B20
+#define GL_SMOOTH                           0x1D01
+#define GL_NICEST                           0x1102
+#define GL_CCW                              0x0901
+#define GL_CW                               0x0900
+#define GL_NEVER                            0x0200
+#define GL_LESS                             0x0201
+#define GL_EQUAL                            0x0202
+#define GL_LEQUAL                           0x0203
+#define GL_GREATER                          0x0204
+#define GL_NOTEQUAL                         0x0205
+#define GL_GEQUAL                           0x0206
+#define GL_ALWAYS                           0x0207
+#define GL_RENDERBUFFER                     0x8D41
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X      0x8516
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y      0x8518
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z      0x851A
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X      0x8515
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y      0x8517
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z      0x8519
+
+//----------------------------------------------------------------------------------
+// OpenGL Bindings to rlsw
+//----------------------------------------------------------------------------------
+#define glReadPixels(x, y, w, h, f, t, p)           swReadPixels((x), (y), (w), (h), (f), (t), (p))
+#define glEnable(state)                             swEnable((state))
+#define glDisable(state)                            swDisable((state))
+#define glGetIntegerv(pname, params)                swGetIntegerv((pname), (params))
+#define glGetFloatv(pname, params)                  swGetFloatv((pname), (params))
+#define glGetString(pname)                          swGetString((pname))
+#define glGetError()                                swGetError()
+#define glViewport(x, y, w, h)                      swViewport((x), (y), (w), (h))
+#define glScissor(x, y, w, h)                       swScissor((x), (y), (w), (h))
+#define glClearColor(r, g, b, a)                    swClearColor((r), (g), (b), (a))
+#define glClearDepth(d)                             swClearDepth((d))
+#define glClear(bitmask)                            swClear((bitmask))
+#define glBlendFunc(sfactor, dfactor)               swBlendFunc((sfactor), (dfactor))
+#define glPolygonMode(face, mode)                   swPolygonMode((mode))
+#define glCullFace(face)                            swCullFace((face))
+#define glPointSize(size)                           swPointSize((size))
+#define glLineWidth(width)                          swLineWidth((width))
+#define glMatrixMode(mode)                          swMatrixMode((mode))
+#define glPushMatrix()                              swPushMatrix()
+#define glPopMatrix()                               swPopMatrix()
+#define glLoadIdentity()                            swLoadIdentity()
+#define glTranslatef(x, y, z)                       swTranslatef((x), (y), (z))
+#define glRotatef(a, x, y, z)                       swRotatef((a), (x), (y), (z))
+#define glScalef(x, y, z)                           swScalef((x), (y), (z))
+#define glMultMatrixf(v)                            swMultMatrixf((v))
+#define glFrustum(l, r, b, t, n, f)                 swFrustum((l), (r), (b), (t), (n), (f))
+#define glOrtho(l, r, b, t, n, f)                   swOrtho((l), (r), (b), (t), (n), (f))
+#define glBegin(mode)                               swBegin((mode))
+#define glEnd()                                     swEnd()
+#define glVertex2i(x, y)                            swVertex2i((x), (y))
+#define glVertex2f(x, y)                            swVertex2f((x), (y))
+#define glVertex2fv(v)                              swVertex2fv((v))
+#define glVertex3i(x, y, z)                         swVertex3i((x), (y), (z))
+#define glVertex3f(x, y, z)                         swVertex3f((x), (y), (z))
+#define glvertex3fv(v)                              swVertex3fv((v))
+#define glVertex4i(x, y, z, w)                      swVertex4i((x), (y), (z), (w))
+#define glVertex4f(x, y, z, w)                      swVertex4f((x), (y), (z), (w))
+#define glVertex4fv(v)                              swVertex4fv((v))
+#define glColor3ub(r, g, b)                         swColor3ub((r), (g), (b))
+#define glColor3ubv(v)                              swColor3ubv((v))
+#define glColor3f(r, g, b)                          swColor3f((r), (g), (b))
+#define glColor3fv(v)                               swColor3fv((v))
+#define glColor4ub(r, g, b, a)                      swColor4ub((r), (g), (b), (a))
+#define glColor4ubv(v)                              swColor4ubv((v))
+#define glColor4f(r, g, b, a)                       swColor4f((r), (g), (b), (a))
+#define glColor4fv(v)                               swColor4fv((v))
+#define glTexCoord2f(u, v)                          swTexCoord2f((u), (v))
+#define glTexCoord2fv(v)                            swTexCoord2fv((v))
+
+#define glEnableClientState(t)                      ((void)(t))
+#define glDisableClientState(t)                     swBindArray((t), 0)
+#define glVertexPointer(sz, t, s, p)                swBindArray(SW_VERTEX_ARRAY, (p))
+#define glTexCoordPointer(sz, t, s, p)              swBindArray(SW_TEXTURE_COORD_ARRAY, (p))
+#define glColorPointer(sz, t, s, p)                 swBindArray(SW_COLOR_ARRAY, (p))
+#define glDrawArrays(m, o, c)                       swDrawArrays((m), (o), (c))
+#define glDrawElements(m,c,t,i)                     swDrawElements((m),(c),(t),(i))
+#define glGenTextures(c, v)                         swGenTextures((c), (v))
+#define glDeleteTextures(c, v)                      swDeleteTextures((c), (v))
+#define glBindTexture(tr, id)                       swBindTexture((id))
+#define glTexImage2D(tr, l, if, w, h, b, f, t, p)   swTexImage2D((w), (h), (f), (t), (p))
+#define glTexSubImage2D(tr, l, x, y, w, h, f, t, p) swTexSubImage2D((x), (y), (w), (h), (f), (t), (p));
+#define glTexParameteri(tr, pname, param)           swTexParameteri((pname), (param))
+
+// OpenGL GL_EXT_framebuffer_object
+#define glGenFramebuffers(c, v)                             swGenFramebuffers((c), (v))
+#define glDeleteFramebuffers(c, v)                          swDeleteFramebuffers((c), (v))
+#define glBindFramebuffer(tr, id)                           swBindFramebuffer((id))
+#define glFramebufferTexture2D(tr, a, t, tex, ml)           swFramebufferTexture2D((a), (tex))
+#define glFramebufferRenderbuffer(tr, a, rbtr, rb)          swFramebufferTexture2D((a), (rb))
+#define glCheckFramebufferStatus(tr)                        swCheckFramebufferStatus()
+#define glGetFramebufferAttachmentParameteriv(tr, a, p, v)  swGetFramebufferAttachmentParameteriv((a), (p), (v))
+#define glGenRenderbuffers(c, v)                            swGenTextures((c), (v))
+#define glDeleteRenderbuffers(c, v)                         swDeleteTextures((c), (v))
+#define glBindRenderbuffer(tr, rb)                          swBindTexture((rb))
+#define glRenderbufferStorage(tr, f, w, h)                  swTexStorage2D((w), (h), (f))
+
+// OpenGL functions NOT IMPLEMENTED by rlsw
+#define glDepthMask(X)                              ((void)(X))
+#define glColorMask(X,Y,Z,W)                        ((void)(X),(void)(Y),(void)(Z),(void)(W))
+#define glPixelStorei(X,Y)                          ((void)(X),(void)(Y))
+#define glHint(X,Y)                                 ((void)(X),(void)(Y))
+#define glShadeModel(X)                             ((void)(X))
+#define glFrontFace(X)                              ((void)(X))
+#define glDepthFunc(X)                              ((void)(X))
+#define glGetTexImage(X,Y,Z,W,A)                    ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A))
+#define glNormal3f(X,Y,Z)                           ((void)(X),(void)(Y),(void)(Z))
+#define glNormal3fv(X)                              ((void)(X))
+#define glNormalPointer(X,Y,Z)                      ((void)(X),(void)(Y),(void)(Z))
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef enum {
+    SW_SCISSOR_TEST = GL_SCISSOR_TEST,
+    SW_TEXTURE_2D = GL_TEXTURE_2D,
+    SW_DEPTH_TEST = GL_DEPTH_TEST,
+    SW_CULL_FACE = GL_CULL_FACE,
+    SW_BLEND = GL_BLEND
+} SWstate;
+
+typedef enum {
+    SW_VENDOR = GL_VENDOR,
+    SW_RENDERER = GL_RENDERER,
+    SW_VERSION = GL_VERSION,
+    SW_EXTENSIONS = GL_EXTENSIONS,
+    SW_SHADING_LANGUAGE_VERSION = GL_SHADING_LANGUAGE_VERSION,
+    SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
+    SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
+    SW_CURRENT_COLOR = GL_CURRENT_COLOR,
+    SW_CURRENT_TEXTURE_COORDS = GL_CURRENT_TEXTURE_COORDS,
+    SW_POINT_SIZE = GL_POINT_SIZE,
+    SW_LINE_WIDTH = GL_LINE_WIDTH,
+    SW_MODELVIEW_MATRIX = GL_MODELVIEW_MATRIX,
+    SW_MODELVIEW_STACK_DEPTH = GL_MODELVIEW_STACK_DEPTH,
+    SW_PROJECTION_MATRIX = GL_PROJECTION_MATRIX,
+    SW_PROJECTION_STACK_DEPTH = GL_PROJECTION_STACK_DEPTH,
+    SW_TEXTURE_MATRIX = GL_TEXTURE_MATRIX,
+    SW_TEXTURE_STACK_DEPTH = GL_TEXTURE_STACK_DEPTH,
+    SW_VIEWPORT = GL_VIEWPORT,
+    SW_DRAW_FRAMEBUFFER_BINDING = GL_DRAW_FRAMEBUFFER_BINDING,
+} SWget;
+
+typedef enum {
+    SW_COLOR_BUFFER_BIT = GL_COLOR_BUFFER_BIT,
+    SW_DEPTH_BUFFER_BIT = GL_DEPTH_BUFFER_BIT
+} SWbuffer;
+
+typedef enum {
+    SW_PROJECTION = GL_PROJECTION,
+    SW_MODELVIEW = GL_MODELVIEW,
+    SW_TEXTURE = GL_TEXTURE
+} SWmatrix;
+
+typedef enum {
+    SW_VERTEX_ARRAY = GL_VERTEX_ARRAY,
+    SW_TEXTURE_COORD_ARRAY = GL_TEXTURE_COORD_ARRAY,
+    SW_COLOR_ARRAY = GL_COLOR_ARRAY
+} SWarray;
+
+typedef enum {
+    SW_DRAW_INVALID = -1,
+    SW_POINTS = GL_POINTS,
+    SW_LINES = GL_LINES,
+    SW_TRIANGLES = GL_TRIANGLES,
+    SW_QUADS = GL_QUADS
+} SWdraw;
+
+typedef enum {
+    SW_POINT = GL_POINT,
+    SW_LINE = GL_LINE,
+    SW_FILL = GL_FILL
+} SWpoly;
+
+typedef enum {
+    SW_FRONT = GL_FRONT,
+    SW_BACK = GL_BACK,
+} SWface;
+
+typedef enum {
+    SW_ZERO = GL_ZERO,
+    SW_ONE = GL_ONE,
+    SW_SRC_COLOR = GL_SRC_COLOR,
+    SW_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,
+    SW_SRC_ALPHA = GL_SRC_ALPHA,
+    SW_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,
+    SW_DST_ALPHA = GL_DST_ALPHA,
+    SW_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,
+    SW_DST_COLOR = GL_DST_COLOR,
+    SW_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,
+    SW_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE
+} SWfactor;
+
+typedef enum {
+    SW_LUMINANCE = GL_LUMINANCE,
+    SW_LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA,
+    SW_RGB = GL_RGB,
+    SW_RGBA = GL_RGBA,
+    SW_DEPTH_COMPONENT = GL_DEPTH_COMPONENT,
+} SWformat;
+
+typedef enum {
+    SW_UNSIGNED_BYTE = GL_UNSIGNED_BYTE,
+    SW_UNSIGNED_BYTE_3_3_2 = GL_UNSIGNED_BYTE_3_3_2,
+    SW_BYTE = GL_BYTE,
+    SW_UNSIGNED_SHORT = GL_UNSIGNED_SHORT,
+    SW_UNSIGNED_SHORT_5_6_5 = GL_UNSIGNED_SHORT_5_6_5,
+    SW_UNSIGNED_SHORT_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4,
+    SW_UNSIGNED_SHORT_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1,
+    SW_SHORT = GL_SHORT,
+    SW_UNSIGNED_INT = GL_UNSIGNED_INT,
+    SW_INT = GL_INT,
+    SW_FLOAT = GL_FLOAT
+} SWtype;
+
+typedef enum {
+    SW_LUMINANCE8 = GL_LUMINANCE8,
+    SW_LUMINANCE8_ALPHA8 = GL_LUMINANCE8_ALPHA8,
+    SW_R3_G3_B2 = GL_R3_G3_B2,
+    SW_RGB8 = GL_RGB8,
+    SW_RGBA4 = GL_RGBA4,
+    SW_RGB5_A1 = GL_RGB5_A1,
+    SW_RGBA8 = GL_RGBA8,
+    SW_R16F = GL_R16F,
+    SW_RGB16F = GL_RGB16F,
+    SW_RGBA16F = GL_RGBA16F,
+    SW_R32F = GL_R32F,
+    SW_RGB32F = GL_RGB32F,
+    SW_RGBA32F = GL_RGBA32F,
+    SW_DEPTH_COMPONENT16 = GL_DEPTH_COMPONENT16,
+    SW_DEPTH_COMPONENT24 = GL_DEPTH_COMPONENT24,
+    SW_DEPTH_COMPONENT32 = GL_DEPTH_COMPONENT32,
+    SW_DEPTH_COMPONENT32F = GL_DEPTH_COMPONENT32F,
+    //SW_R5_G6_B5, // Not defined by OpenGL
+} SWinternalformat;
+
+typedef enum {
+    SW_NEAREST = GL_NEAREST,
+    SW_LINEAR  = GL_LINEAR
+} SWfilter;
+
+typedef enum {
+    SW_REPEAT = GL_REPEAT,
+    SW_CLAMP = GL_CLAMP,
+} SWwrap;
+
+typedef enum {
+    SW_TEXTURE_MIN_FILTER = GL_TEXTURE_MIN_FILTER,
+    SW_TEXTURE_MAG_FILTER = GL_TEXTURE_MAG_FILTER,
+    SW_TEXTURE_WRAP_S = GL_TEXTURE_WRAP_S,
+    SW_TEXTURE_WRAP_T = GL_TEXTURE_WRAP_T
+} SWtexparam;
+
+typedef enum {
+    SW_COLOR_ATTACHMENT = GL_COLOR_ATTACHMENT0,
+    SW_DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT,
+} SWattachment;
+
+typedef enum {
+    SW_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+    SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+} SWattachget;
+
+typedef enum {
+    SW_FRAMEBUFFER_COMPLETE = GL_FRAMEBUFFER_COMPLETE,
+    SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
+    SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
+    SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
+} SWfbstatus;
+
+typedef enum {
+    SW_NO_ERROR = GL_NO_ERROR,
+    SW_INVALID_ENUM = GL_INVALID_ENUM,
+    SW_INVALID_VALUE = GL_INVALID_VALUE,
+    SW_STACK_OVERFLOW = GL_STACK_OVERFLOW,
+    SW_STACK_UNDERFLOW = GL_STACK_UNDERFLOW,
+    SW_INVALID_OPERATION = GL_INVALID_OPERATION,
+    SW_OUT_OF_MEMORY = GL_OUT_OF_MEMORY,
+} SWerrcode;
+
+//------------------------------------------------------------------------------------
+// Functions Declaration - Public API
+//------------------------------------------------------------------------------------
+SWAPI bool swInit(int w, int h);
+SWAPI void swClose(void);
+
+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);
+
+SWAPI void swGetFloatv(SWget name, float *v);
+SWAPI const char *swGetString(SWget name);
+SWAPI SWerrcode swGetError(void);
+
+SWAPI void swViewport(int x, int y, int width, int height);
+SWAPI void swScissor(int x, int y, int width, int height);
+
+SWAPI void swClearColor(float r, float g, float b, float a);
+SWAPI void swClearDepth(float depth);
+SWAPI void swClear(uint32_t bitmask);
+
+SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor);
+SWAPI void swPolygonMode(SWpoly mode);
+SWAPI void swCullFace(SWface face);
+
+SWAPI void swPointSize(float size);
+SWAPI void swLineWidth(float width);
+
+SWAPI void swMatrixMode(SWmatrix mode);
+SWAPI void swPushMatrix(void);
+SWAPI void swPopMatrix(void);
+SWAPI void swLoadIdentity(void);
+SWAPI void swTranslatef(float x, float y, float z);
+SWAPI void swRotatef(float angle, float x, float y, float z);
+SWAPI void swScalef(float x, float y, float z);
+SWAPI void swMultMatrixf(const float *mat);
+SWAPI void swFrustum(double left, double right, double bottom, double top, double znear, double zfar);
+SWAPI void swOrtho(double left, double right, double bottom, double top, double znear, double zfar);
+
+SWAPI void swBegin(SWdraw mode);
+SWAPI void swEnd(void);
+
+SWAPI void swVertex2i(int x, int y);
+SWAPI void swVertex2f(float x, float y);
+SWAPI void swVertex2fv(const float *v);
+SWAPI void swVertex3i(int x, int y, int z);
+SWAPI void swVertex3f(float x, float y, float z);
+SWAPI void swVertex3fv(const float *v);
+SWAPI void swVertex4i(int x, int y, int z, int w);
+SWAPI void swVertex4f(float x, float y, float z, float w);
+SWAPI void swVertex4fv(const float *v);
+
+SWAPI void swColor3ub(uint8_t r, uint8_t g, uint8_t b);
+SWAPI void swColor3ubv(const uint8_t *v);
+SWAPI void swColor3f(float r, float g, float b);
+SWAPI void swColor3fv(const float *v);
+SWAPI void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
+SWAPI void swColor4ubv(const uint8_t *v);
+SWAPI void swColor4f(float r, float g, float b, float a);
+SWAPI void swColor4fv(const float *v);
+
+SWAPI void swTexCoord2f(float u, float v);
+SWAPI void swTexCoord2fv(const float *v);
+
+SWAPI void swBindArray(SWarray type, void *buffer);
+SWAPI void swDrawArrays(SWdraw mode, int offset, int count);
+SWAPI void swDrawElements(SWdraw mode, int count, int type, const void *indices);
+
+SWAPI void swGenTextures(int count, uint32_t *textures);
+SWAPI void swDeleteTextures(int count, uint32_t *textures);
+SWAPI void swBindTexture(uint32_t id);
+SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data);
+SWAPI void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+SWAPI void swTexParameteri(int param, int value);
+
+SWAPI void swGenFramebuffers(int count, uint32_t *framebuffers);
+SWAPI void swDeleteFramebuffers(int count, uint32_t *framebuffers);
+SWAPI void swBindFramebuffer(uint32_t id);
+SWAPI void swFramebufferTexture2D(SWattachment attach, uint32_t texture);
+SWAPI SWfbstatus swCheckFramebufferStatus(void);
+SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget property, int *v);
+
+#endif // RLSW_H
+
+/***********************************************************************************
+*
+*   RLSW IMPLEMENTATION
+*
+************************************************************************************/
+#if defined(RLSW_IMPLEMENTATION)
+
+#undef RLSW_IMPLEMENTATION  // Undef to allow template expanding without implementation redefinition
+
+#include <stdlib.h>         // Required for: malloc(), free()
+#include <stddef.h>         // Required for: NULL, size_t, uint8_t, uint16_t, uint32_t...
+#include <math.h>           // Required for: sinf(), cosf(), floorf(), fabsf(), sqrtf(), roundf()
+
+// Simple log system to avoid printf() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+#define RLSW_SUPPORT_LOG_INFO
+#if defined(RLSW_SUPPORT_LOG_INFO)
+    #include <stdio.h>
+    #define SW_LOG(...) printf(__VA_ARGS__)
+#else
+    #define SW_LOG(...)
+#endif
+
+#if defined(_MSC_VER)
+    #define SW_ALIGN(x) __declspec(align(x))
+#elif defined(__GNUC__) || defined(__clang__)
+    #define SW_ALIGN(x) __attribute__((aligned(x)))
+#else
+    #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__)
+    #define SW_ARCH_X86
+#elif defined(_M_ARM) || defined(__arm__)
+    #define SW_ARCH_ARM32
+#elif defined(_M_ARM64) || defined(__aarch64__)
+    #define SW_ARCH_ARM64
+#elif defined(__riscv)
+    #define SW_ARCH_RISCV
+#endif
+
+#if RLSW_USE_SIMD_INTRINSICS
+    // Check for SIMD vector instructions
+    // NOTE: Compiler is responsible to enable required flags for host device,
+    // supported features are detected at compiler init but varies depending on compiler
+    // TODO: This logic must be reviewed to avoid the inclusion of multiple headers
+    // and enable the higher level of SIMD available
+    #if defined(__FMA__) && defined(__AVX2__)
+        #define SW_HAS_FMA_AVX2
+        #include <immintrin.h>
+    #elif defined(__FMA__) && defined(__AVX__)
+        #define SW_HAS_FMA_AVX
+        #include <immintrin.h>
+    #elif defined(__AVX2__)
+        #define SW_HAS_AVX2
+        #include <immintrin.h>
+    #elif defined(__AVX__)
+        #define SW_HAS_AVX
+        #include <immintrin.h>
+    #endif
+    #if defined(__SSE4_2__)
+        #define SW_HAS_SSE42
+        #include <nmmintrin.h>
+    #elif defined(__SSE4_1__)
+        #define SW_HAS_SSE41
+        #include <smmintrin.h>
+    #elif defined(__SSSE3__)
+        #define SW_HAS_SSSE3
+        #include <tmmintrin.h>
+    #elif defined(__SSE3__)
+        #define SW_HAS_SSE3
+        #include <pmmintrin.h>
+    #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64
+        #define SW_HAS_SSE2
+        #include <emmintrin.h>
+    #elif defined(__SSE__)
+        #define SW_HAS_SSE
+        #include <xmmintrin.h>
+    #endif
+    #if defined(__ARM_NEON) || defined(__aarch64__)
+        #if defined(__ARM_FEATURE_FMA)
+            #define SW_HAS_NEON_FMA
+        #else
+            #define SW_HAS_NEON
+        #endif
+        #include <arm_neon.h>
+    #endif
+    #if defined(__riscv_vector)
+        // NOTE: Requires compilation flags: -march=rv64gcv -mabi=lp64d
+        #define SW_HAS_RVV
+        #include <riscv_vector.h>
+    #endif
+#endif
+
+// ESP-DSP acceleration: ESP-IDF ships an optimized math library that includes
+// `dspm_mult_4x4x4_f32` (4x4 matrix multiply) and `dspm_mult_4x4x1_f32` (matrix * vector)
+// These are S3-tuned hand-vectorized kernels that beat the scalar versions for both throughput and code-size
+// Detection is opt-in to keep the dependency optional: define SW_USE_ESP_DSP from your build system
+#if defined(ESP_PLATFORM) && defined(SW_USE_ESP_DSP)
+    #define SW_HAS_ESP_DSP
+    #include "dspm_mult.h"
+#endif
+
+#ifdef __cplusplus
+    #define SW_CURLY_INIT(name) name
+#else
+    #define SW_CURLY_INIT(name) (name)
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#define SW_PI       3.14159265358979323846f
+#define SW_INV_255  0.00392156862745098f            // 1.0f/255.0f
+#define SW_DEG2RAD  (SW_PI/180.0f)
+#define SW_RAD2DEG  (180.0f/SW_PI)
+
+// When clipping a convex polygon against a plane, at most one vertex is added
+// Starting from a quadrilateral (4 vertices), clipped sequentially against
+// the frustum (6 planes) then the scissor rectangle (4 planes):
+// 4 + 6 + 4 = 14 vertices maximum
+#define SW_MAX_CLIPPED_POLYGON_VERTICES     14
+#define SW_CLIP_EPSILON                     1e-4f
+
+#define SW_HANDLE_NULL                      0u
+#define SW_POOL_SLOT_LIVE                   0x80u   // bit7 of the generation byte
+#define SW_POOL_SLOT_VER_MASK               0x7Fu   // bits6:0 = anti-ABA counter
+
+#define SW_CONCAT(a, b)                     a##b
+#define SW_CONCATX(a, b)                    SW_CONCAT(a, b)
+
+#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o)    SW_CONCATX(sw_pixel_read_color8_, RLSW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
+#define SW_FRAMEBUFFER_COLOR_GET(c,p,o)     SW_CONCATX(sw_pixel_read_color_, RLSW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o))
+#define SW_FRAMEBUFFER_COLOR_SET(p,c,o)     SW_CONCATX(sw_pixel_write_color_, RLSW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o))
+
+#define SW_FRAMEBUFFER_DEPTH_GET(p,o)       SW_CONCATX(sw_pixel_read_depth_, RLSW_FRAMEBUFFER_DEPTH_TYPE)((p),(o))
+#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o)     SW_CONCATX(sw_pixel_write_depth_, RLSW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o))
+
+#define SW_FRAMEBUFFER_COLOR_FORMAT         SW_CONCATX(SW_PIXELFORMAT_COLOR_, RLSW_FRAMEBUFFER_COLOR_TYPE)
+#define SW_FRAMEBUFFER_DEPTH_FORMAT         SW_CONCATX(SW_PIXELFORMAT_DEPTH_, RLSW_FRAMEBUFFER_DEPTH_TYPE)
+
+#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_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)
+
+//----------------------------------------------------------------------------------
+// Module Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Aliases types
+typedef uint32_t sw_handle_t;
+typedef uint16_t sw_half_t;
+
+// Pixel data format type
+typedef enum {
+    SW_PIXELFORMAT_UNKNOWN = 0,
+    SW_PIXELFORMAT_COLOR_GRAYSCALE,         // 8 bit per pixel (no alpha)
+    SW_PIXELFORMAT_COLOR_GRAYALPHA,         // 8*2 bpp (2 channels)
+    SW_PIXELFORMAT_COLOR_R3G3B2,            // 8 bpp
+    SW_PIXELFORMAT_COLOR_R5G6B5,            // 16 bpp
+    SW_PIXELFORMAT_COLOR_R8G8B8,            // 24 bpp
+    SW_PIXELFORMAT_COLOR_R5G5B5A1,          // 16 bpp (1 bit alpha)
+    SW_PIXELFORMAT_COLOR_R4G4B4A4,          // 16 bpp (4 bit alpha)
+    SW_PIXELFORMAT_COLOR_R8G8B8A8,          // 32 bpp
+    SW_PIXELFORMAT_COLOR_R32,               // 32 bpp (1 channel - float)
+    SW_PIXELFORMAT_COLOR_R32G32B32,         // 32*3 bpp (3 channels - float)
+    SW_PIXELFORMAT_COLOR_R32G32B32A32,      // 32*4 bpp (4 channels - float)
+    SW_PIXELFORMAT_COLOR_R16,               // 16 bpp (1 channel - half float)
+    SW_PIXELFORMAT_COLOR_R16G16B16,         // 16*3 bpp (3 channels - half float)
+    SW_PIXELFORMAT_COLOR_R16G16B16A16,      // 16*4 bpp (4 channels - half float)
+    SW_PIXELFORMAT_DEPTH_D8,                // 1 bpp
+    SW_PIXELFORMAT_DEPTH_D16,               // 2 bpp
+    SW_PIXELFORMAT_DEPTH_D32,               // 4 bpp
+    SW_PIXELFORMAT_COUNT
+} sw_pixelformat_t;
+
+typedef enum {
+    SW_PIXEL_ALPHA_NONE = 0,    // No transparency
+    SW_PIXEL_ALPHA_BIN,         // Binary transparency
+    SW_PIXEL_ALPHA_YES,         // Contains transparency
+} sw_pixel_alpha_t;
+
+// Forward declarations
+typedef struct sw_texture sw_texture_t;
+typedef struct sw_vertex sw_vertex_t;
+
+// Pixel getter functions
+typedef void (*sw_pixel_read_color8_f)(uint8_t *SW_RESTRICT, const void *SW_RESTRICT, uint32_t);
+typedef void (*sw_pixel_read_color_f)(float *SW_RESTRICT, const void *SW_RESTRICT, uint32_t);
+
+// Pixel setter functions
+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);
+
+// Rasterizer functions
+typedef void (*sw_raster_triangle_f)(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*);
+typedef void (*sw_raster_quad_f)(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*);
+typedef void (*sw_raster_line_f)(const sw_vertex_t*, const sw_vertex_t*);
+typedef void (*sw_raster_point_f)(const sw_vertex_t*);
+
+typedef float sw_matrix_t[4*4];
+
+typedef struct sw_vertex {
+    float position[4];          // Clip space (x,y,z,w) -> NDC (after /w) -> screen space (x,y,z,1/w)
+    float color[4];             // Color value (RGBA)
+    float texcoord[2];          // Texture coordinates
+} sw_vertex_t;
+
+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
+    sw_pixelformat_t format;            // Texture format
+    sw_pixel_alpha_t alpha;             // Texture alpha mode
+    int width, height;                  // Dimensions of the texture
+    int wMinus1, hMinus1;               // Dimensions minus one
+    int allocSz;                        // Allocated size
+    SWfilter minFilter;                 // Minification filter
+    SWfilter magFilter;                 // Magnification filter
+    SWwrap sWrap;                       // Wrap mode for texcoord.x
+    SWwrap tWrap;                       // Wrap mode for texcoord.y
+    float tx;                           // Texel width
+    float ty;                           // Texel height
+} sw_texture_t;
+
+typedef struct {
+    sw_texture_t color;         // Default framebuffer color texture
+#if RLSW_DOUBLE_BUFFERING
+    sw_texture_t backColor; // Back buffer for multicore.
+#endif
+    sw_texture_t depth;         // Default framebuffer depth texture
+} sw_default_framebuffer_t;
+
+typedef struct {
+    sw_handle_t colorAttachment; // Framebuffer color attachment id
+    sw_handle_t depthAttachment; // Framebuffer depth attachment id
+} sw_framebuffer_t;
+
+typedef struct {
+    void *data;             // Flat storage [capacity*stride] bytes
+    uint8_t *gen;           // Generation per slot [capacity]
+    uint32_t *freeList;     // Free indices stack [capacity]
+    int freeCount;
+    int watermark;          // Next blank index (starts at 1, skips 0)
+    int capacity;
+    size_t stride;
+} sw_pool_t;
+
+// Graphic context data structure
+typedef struct {
+    sw_default_framebuffer_t framebuffer;   // Default framebuffer
+    float clearColor[4];                    // Clear color of the framebuffer
+    float clearDepth;                       // Clear depth of the framebuffer
+
+    float vpCenter[2];                      // Viewport center
+    float vpHalf[2];                        // Viewport half dimensions
+    int vpSize[2];                          // Viewport dimensions
+
+    int scMin[2];                           // Scissor rectangle minimum renderable point (top-left)
+    int scMax[2];                           // Scissor rectangle maximum renderable point (bottom-right)
+    float scClipMin[2];                     // Scissor rectangle minimum renderable point in clip space
+    float scClipMax[2];                     // Scissor rectangle maximum renderable point in clip space
+
+    struct {
+        sw_vertex_t buffer[SW_MAX_CLIPPED_POLYGON_VERTICES];    // Buffer used for storing primitive vertices, used for processing and rendering
+        int vertexCount;                                        // Number of vertices in the primtive buffer
+        float color[4];                                         // Current color for the next pushed vertex
+        float texcoord[2];                                      // Current texture coordinates for the next push vertex
+        bool hasColorAlpha;                                     // Flag indicating whether the current primitive contains transparency
+    } primitive;
+
+    struct {
+        float *positions;
+        float *texcoords;
+        uint8_t *colors;
+    } array;
+
+    SWdraw drawMode;                                            // Current primitive mode (e.g., lines, triangles)
+    SWpoly polyMode;                                            // Current polygon filling mode (e.g., lines, triangles)
+    float pointRadius;                                          // Rasterized point radius
+    float lineWidth;                                            // Rasterized line width
+
+    sw_matrix_t stackProjection[RLSW_MAX_PROJECTION_STACK_SIZE];  // Projection matrix stack for push/pop operations
+    sw_matrix_t stackModelview[RLSW_MAX_MODELVIEW_STACK_SIZE];    // Modelview matrix stack for push/pop operations
+    sw_matrix_t stackTexture[RLSW_MAX_TEXTURE_STACK_SIZE];        // Texture matrix stack for push/pop operations
+    uint32_t stackProjectionCounter;                            // Counter for matrix stack operations
+    uint32_t stackModelviewCounter;                             // Counter for matrix stack operations
+    uint32_t stackTextureCounter;                               // Counter for matrix stack operations
+    SWmatrix currentMatrixMode;                                 // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
+    sw_matrix_t *currentMatrix;                                 // Pointer to the currently used matrix according to the mode
+    sw_matrix_t matMVP;                                         // Model view projection matrix, calculated and used internally
+#ifdef SW_HAS_ESP_DSP
+    float matMVP_rm[16];                                        // Row-major MVP, kept in sync for esp-dsp dspm_mult_4x4x1_f32 vertex transform
+#endif
+    bool isDirtyMVP;                                            // Indicates if the MVP matrix should be rebuilt
+
+    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
+
+    sw_texture_t *boundTexture;                                 // Texture currently bound
+    sw_pool_t texturePool;                                      // Texture object pool
+
+    SWfactor srcFactor;                                         // Source blending factor
+    SWfactor dstFactor;                                         // Destination bleending factor
+    uint32_t blendFlags;                                        // Flags about the current blend mode
+    sw_blend_f blendFunc;                                       // Source blend function
+
+    SWface cullFace;                                            // Faces to cull
+    SWerrcode errCode;                                          // Last error code
+
+    uint32_t userState;                                         // User-defined pipeline state
+    uint32_t rasterState;                                       // Cleaned pipeline state for the rasterizer
+} sw_context_t;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static sw_context_t RLSW = { 0 };
+
+#if RLSW_USE_COLOR_LUT
+static float SW_LUT_UINT8_TO_FLOAT[256] = { 0 };
+#endif
+
+//----------------------------------------------------------------------------------
+// Internal Constants Definition
+//----------------------------------------------------------------------------------
+// Pixel formats that has an alpha channel
+static const sw_pixel_alpha_t SW_PIXELFORMAT_ALPHA[SW_PIXELFORMAT_COUNT] =
+{
+    [SW_PIXELFORMAT_COLOR_GRAYSCALE]    = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_GRAYALPHA]    = SW_PIXEL_ALPHA_YES,
+    [SW_PIXELFORMAT_COLOR_R3G3B2]       = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R5G6B5]       = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R8G8B8]       = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R5G5B5A1]     = SW_PIXEL_ALPHA_BIN,
+    [SW_PIXELFORMAT_COLOR_R4G4B4A4]     = SW_PIXEL_ALPHA_YES,
+    [SW_PIXELFORMAT_COLOR_R8G8B8A8]     = SW_PIXEL_ALPHA_YES,
+    [SW_PIXELFORMAT_COLOR_R32]          = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R32G32B32]    = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R32G32B32A32] = SW_PIXEL_ALPHA_YES,
+    [SW_PIXELFORMAT_COLOR_R16]          = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R16G16B16]    = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_COLOR_R16G16B16A16] = SW_PIXEL_ALPHA_YES,
+    [SW_PIXELFORMAT_DEPTH_D8]           = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_DEPTH_D16]          = SW_PIXEL_ALPHA_NONE,
+    [SW_PIXELFORMAT_DEPTH_D32]          = SW_PIXEL_ALPHA_NONE,
+};
+
+// Pixel formats sizes in bytes
+static const int SW_PIXELFORMAT_SIZE[SW_PIXELFORMAT_COUNT] =
+{
+    [SW_PIXELFORMAT_COLOR_GRAYSCALE]    = 1,
+    [SW_PIXELFORMAT_COLOR_GRAYALPHA]    = 2,
+    [SW_PIXELFORMAT_COLOR_R3G3B2]       = 1,
+    [SW_PIXELFORMAT_COLOR_R5G6B5]       = 2,
+    [SW_PIXELFORMAT_COLOR_R8G8B8]       = 3,
+    [SW_PIXELFORMAT_COLOR_R5G5B5A1]     = 2,
+    [SW_PIXELFORMAT_COLOR_R4G4B4A4]     = 2,
+    [SW_PIXELFORMAT_COLOR_R8G8B8A8]     = 4,
+    [SW_PIXELFORMAT_COLOR_R32]          = 4,
+    [SW_PIXELFORMAT_COLOR_R32G32B32]    = 12,
+    [SW_PIXELFORMAT_COLOR_R32G32B32A32] = 16,
+    [SW_PIXELFORMAT_COLOR_R16]          = 2,
+    [SW_PIXELFORMAT_COLOR_R16G16B16]    = 6,
+    [SW_PIXELFORMAT_COLOR_R16G16B16A16] = 8,
+    [SW_PIXELFORMAT_DEPTH_D8]           = 1,
+    [SW_PIXELFORMAT_DEPTH_D16]          = 2,
+    [SW_PIXELFORMAT_DEPTH_D32]          = 4,
+};
+
+static const int SW_PRIMITIVE_VERTEX_COUNT[] =
+{
+    // Remember that this is acceptable; these are small indices
+    [SW_POINTS]     = 1,
+    [SW_LINES]      = 2,
+    [SW_TRIANGLES]  = 3,
+    [SW_QUADS]      = 4,
+};
+
+//----------------------------------------------------------------------------------
+// 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 SW_INLINE void sw_matrix_id(sw_matrix_t dst)
+{
+    dst[0]  = 1, dst[1]  = 0, dst[2]  = 0, dst[3]  = 0;
+    dst[4]  = 0, dst[5]  = 1, dst[6]  = 0, dst[7]  = 0;
+    dst[8]  = 0, dst[9]  = 0, dst[10] = 1, dst[11] = 0;
+    dst[12] = 0, dst[13] = 0, dst[14] = 0, dst[15] = 1;
+}
+
+static void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RESTRICT left, const float *SW_RESTRICT right)
+{
+#ifdef SW_HAS_ESP_DSP
+    // dspm_mult_4x4x4_f32 treats its operands as row-major. rlsw stores matrices
+    // column-major, so passing them flat is equivalent to passing transposes:
+    // dspm_mult(L^T, R^T) computes (L^T)*(R^T) = (R*L)^T, written back into a
+    // flat array gives the same bit pattern as the column-major product (R*L)
+    // -- exactly the semantic the scalar fallback below has
+    dspm_mult_4x4x4_f32(left, right, dst);
+#else
+    float l00 = left[0],  l01 = left[1],  l02 = left[2],  l03 = left[3];
+    float l10 = left[4],  l11 = left[5],  l12 = left[6],  l13 = left[7];
+    float l20 = left[8],  l21 = left[9],  l22 = left[10], l23 = left[11];
+    float l30 = left[12], l31 = left[13], l32 = left[14], l33 = left[15];
+
+    dst[0]  = l00*right[0] + l01*right[4] + l02*right[8]  + l03*right[12];
+    dst[4]  = l10*right[0] + l11*right[4] + l12*right[8]  + l13*right[12];
+    dst[8]  = l20*right[0] + l21*right[4] + l22*right[8]  + l23*right[12];
+    dst[12] = l30*right[0] + l31*right[4] + l32*right[8]  + l33*right[12];
+
+    dst[1]  = l00*right[1] + l01*right[5] + l02*right[9]  + l03*right[13];
+    dst[5]  = l10*right[1] + l11*right[5] + l12*right[9]  + l13*right[13];
+    dst[9]  = l20*right[1] + l21*right[5] + l22*right[9]  + l23*right[13];
+    dst[13] = l30*right[1] + l31*right[5] + l32*right[9]  + l33*right[13];
+
+    dst[2]  = l00*right[2] + l01*right[6] + l02*right[10] + l03*right[14];
+    dst[6]  = l10*right[2] + l11*right[6] + l12*right[10] + l13*right[14];
+    dst[10] = l20*right[2] + l21*right[6] + l22*right[10] + l23*right[14];
+    dst[14] = l30*right[2] + l31*right[6] + l32*right[10] + l33*right[14];
+
+    dst[3]  = l00*right[3] + l01*right[7] + l02*right[11] + l03*right[15];
+    dst[7]  = l10*right[3] + l11*right[7] + l12*right[11] + l13*right[15];
+    dst[11] = l20*right[3] + l21*right[7] + l22*right[11] + l23*right[15];
+    dst[15] = l30*right[3] + l31*right[7] + l32*right[11] + l33*right[15];
+#endif
+}
+
+static SW_INLINE void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right)
+{
+    float result[16];
+    sw_matrix_mul_rst(result, left, right);
+    for (int i = 0; i < 16; i++) dst[i] = result[i];
+}
+
+static SW_INLINE int sw_clamp_int(int v, int min, int max)
+{
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+static SW_INLINE int sw_clamp(float v, float min, float max)
+{
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+static SW_INLINE float sw_saturate(float x)
+{
+    union { float f; uint32_t u; } fb;
+    fb.f = x;
+
+    // Check if x < 0.0f
+    // If sign bit is set (MSB), x is negative
+    if ((fb.u & 0x80000000) != 0) return 0.0f;
+
+    // Check if x > 1.0f
+    // Works for positive floats: IEEE 754 ordering matches integer ordering
+    if (fb.u > 0x3F800000) return 1.0f;
+
+    // x is in [0.0f, 1.0f]
+    return x;
+}
+
+static SW_INLINE float sw_fract(float x)
+{
+    return (x - floorf(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"
+        "const.s  %1, 1\n"
+        "msub.s   %1, %2, %0\n"
+        "madd.s   %0, %0, %1\n"
+        "const.s  %1, 1\n"
+        "msub.s   %1, %2, %0\n"
+        "maddn.s  %0, %0, %1\n"
+        : "=&f"(result), "=&f"(temp) : "f"(x)
+    );
+    return result;
+#else
+    return 1.0f/x;
+#endif
+}
+
+static SW_INLINE uint8_t sw_luminance8(const uint8_t *color)
+{
+    return (uint8_t)((color[0]*77 + color[1]*150 + color[2]*29) >> 8);
+}
+
+static SW_INLINE float sw_luminance(const float *color)
+{
+    return color[0]*0.299f + color[1]*0.587f + color[2]*0.114f;
+}
+
+static void sw_lerp_vertex_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t)
+{
+    const float tInv = 1.0f - t;
+
+    // Position interpolation (4 components)
+    out->position[0] = a->position[0]*tInv + b->position[0]*t;
+    out->position[1] = a->position[1]*tInv + b->position[1]*t;
+    out->position[2] = a->position[2]*tInv + b->position[2]*t;
+    out->position[3] = a->position[3]*tInv + b->position[3]*t;
+
+    // Color interpolation (4 components)
+    out->color[0] = a->color[0]*tInv + b->color[0]*t;
+    out->color[1] = a->color[1]*tInv + b->color[1]*t;
+    out->color[2] = a->color[2]*tInv + b->color[2]*t;
+    out->color[3] = a->color[3]*tInv + b->color[3]*t;
+
+    // Texture coordinate interpolation (2 components)
+    out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t;
+    out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t;
+}
+
+// Half conversion functions
+static SW_INLINE uint16_t sw_float_to_half_ui(uint32_t ui)
+{
+    int32_t s = (ui >> 16) & 0x8000;
+    int32_t em = ui & 0x7fffffff;
+
+    // Bias exponent and round to nearest; 112 is relative exponent bias (127-15)
+    int32_t h = (em - (112 << 23) + (1 << 12)) >> 13;
+
+    // Underflow: flush to zero; 113 encodes exponent -14
+    h = (em < (113 << 23))? 0 : h;
+
+    // Overflow: infinity; 143 encodes exponent 16
+    h = (em >= (143 << 23))? 0x7c00 : h;
+
+    // NaN; note that all types of NaN are converted to qNaN
+    h = (em > (255 << 23))? 0x7e00 : h;
+
+    return (uint16_t)(s | h);
+}
+
+static SW_INLINE uint32_t sw_half_to_float_ui(uint16_t h)
+{
+    uint32_t s = (unsigned)(h & 0x8000) << 16;
+    int32_t em = h & 0x7fff;
+
+    // Bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15)
+    int32_t r = (em + (112 << 10)) << 13;
+
+    // Denormal: flush to zero
+    r = (em < (1 << 10))? 0 : r;
+
+    // Infinity/NaN; note that NaN payload is preeserved as a byproduct of unifying inf/nan cases
+    // 112 is an exponent bias fixup; since it was already applied once, applying it twice converts 31 to 255
+    r += (em >= (31 << 10))? (112 << 23) : 0;
+
+    return s | r;
+}
+
+static SW_INLINE sw_half_t sw_float_to_half(float i)
+{
+    union { float f; uint32_t i; } v;
+    v.f = i;
+    return sw_float_to_half_ui(v.i);
+}
+
+static SW_INLINE float sw_half_to_float(sw_half_t y)
+{
+    union { float f; uint32_t i; } v;
+    v.i = sw_half_to_float_ui(y);
+    return v.f;
+}
+
+static SW_INLINE uint8_t sw_expand_1to8(uint32_t v) { return v? 255 : 0; }
+static SW_INLINE uint8_t sw_expand_2to8(uint32_t v) { return (uint8_t)(v*85); }
+static SW_INLINE uint8_t sw_expand_3to8(uint32_t v) { return (uint8_t)((v << 5) | (v << 2) | (v >> 1)); }
+static SW_INLINE uint8_t sw_expand_4to8(uint32_t v) { return (uint8_t)((v << 4) | v); }
+static SW_INLINE uint8_t sw_expand_5to8(uint32_t v) { return (uint8_t)((v << 3) | (v >> 2)); }
+static SW_INLINE uint8_t sw_expand_6to8(uint32_t v) { return (uint8_t)((v << 2) | (v >> 4)); }
+
+static SW_INLINE uint32_t sw_compress_8to1(uint8_t v) { return v >> 7; }
+static SW_INLINE uint32_t sw_compress_8to2(uint8_t v) { return v >> 6; }
+static SW_INLINE uint32_t sw_compress_8to3(uint8_t v) { return v >> 5; }
+static SW_INLINE uint32_t sw_compress_8to4(uint8_t v) { return v >> 4; }
+static SW_INLINE uint32_t sw_compress_8to5(uint8_t v) { return v >> 3; }
+static SW_INLINE uint32_t sw_compress_8to6(uint8_t v) { return v >> 2; }
+
+static SW_INLINE void sw_color8_to_color(float *SW_RESTRICT dst, const uint8_t *SW_RESTRICT src)
+{
+#if defined(SW_HAS_NEON)
+    uint8x8_t bytes = vreinterpret_u8_u32(vld1_dup_u32((const uint32_t *)src));
+    uint16x8_t words = vmovl_u8(bytes);
+    uint32x4_t dwords = vmovl_u16(vget_low_u16(words));
+    float32x4_t fvals = vmulq_f32(vcvtq_f32_u32(dwords), vdupq_n_f32(SW_INV_255));
+    vst1q_f32(dst, fvals);
+
+#elif defined(SW_HAS_SSE41)
+    __m128i bytes = _mm_loadu_si32(src);
+    __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(_mm_cvtepu8_epi32(bytes)), _mm_set1_ps(SW_INV_255));
+    _mm_storeu_ps(dst, fvals);
+
+#elif defined(SW_HAS_SSE2)
+    __m128i zero = _mm_setzero_si128();
+    __m128i bytes = _mm_loadu_si32(src);
+    __m128i words = _mm_unpacklo_epi8(bytes, zero);
+    __m128i dwords = _mm_unpacklo_epi16(words, zero);
+    __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(dwords), _mm_set1_ps(SW_INV_255));
+    _mm_storeu_ps(dst, fvals);
+
+#elif defined(SW_HAS_RVV)
+    // TODO: WARNING: Sample code generated by AI, needs testing and review
+    size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements
+    vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers
+    vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers
+    vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32
+    vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize
+    __riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result
+
+#elif RLSW_USE_COLOR_LUT
+    dst[0] = SW_LUT_UINT8_TO_FLOAT[src[0]];
+    dst[1] = SW_LUT_UINT8_TO_FLOAT[src[1]];
+    dst[2] = SW_LUT_UINT8_TO_FLOAT[src[2]];
+    dst[3] = SW_LUT_UINT8_TO_FLOAT[src[3]];
+
+#else
+    dst[0] = (float)src[0]*SW_INV_255;
+    dst[1] = (float)src[1]*SW_INV_255;
+    dst[2] = (float)src[2]*SW_INV_255;
+    dst[3] = (float)src[3]*SW_INV_255;
+#endif
+}
+
+static SW_INLINE void sw_color_to_color8(uint8_t *SW_RESTRICT dst, const float *SW_RESTRICT src)
+{
+#if defined(SW_HAS_NEON)
+    float32x4_t fvals = vmulq_f32(vld1q_f32(src), vdupq_n_f32(255.0f));
+    uint32x4_t i32 = vcvtq_u32_f32(fvals);
+    uint16x4_t i16 = vmovn_u32(i32);
+    uint8x8_t i8 = vmovn_u16(vcombine_u16(i16, i16));
+    vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(i8), 0);
+
+#elif defined(SW_HAS_SSE41)
+    __m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f));
+    __m128i i32 = _mm_cvttps_epi32(fvals);
+    __m128i i16 = _mm_packus_epi32(i32, i32);
+    __m128i i8 = _mm_packus_epi16(i16, i16);
+    _mm_storeu_si32(dst, i8);
+
+#elif defined(SW_HAS_SSE2)
+    __m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f));
+    __m128i i32 = _mm_cvttps_epi32(fvals);
+    __m128i i16 = _mm_packs_epi32(i32, i32);
+    __m128i i8 = _mm_packus_epi16(i16, i16);
+    _mm_storeu_si32(dst, i8);
+
+#elif defined(SW_HAS_RVV)
+    // TODO: WARNING: Sample code generated by AI, needs testing and review
+    // REVIEW: It shouldn't perform so many operations; take inspiration from other versions
+    // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions
+    size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register
+    vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values
+
+    // Multiply by 255.0f and add 0.5f for rounding
+    vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl);
+    vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl);
+
+    // Convert to unsigned integer (truncate toward zero)
+    vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl);
+
+    // Narrow from u32 -> u8
+    vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero
+    __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result
+
+#else
+    dst[0] = (uint8_t)(src[0]*255.0f);
+    dst[1] = (uint8_t)(src[1]*255.0f);
+    dst[2] = (uint8_t)(src[2]*255.0f);
+    dst[3] = (uint8_t)(src[3]*255.0f);
+#endif
+}
+//-------------------------------------------------------------------------------------------
+
+// Object pool functions
+//-------------------------------------------------------------------------------------------
+static bool sw_pool_init(sw_pool_t *pool, int capacity, size_t stride)
+{
+    *pool = (sw_pool_t) { 0 };
+
+    pool->data = SW_CALLOC(capacity, stride);
+    pool->gen = SW_CALLOC(capacity, sizeof(uint8_t));
+    pool->freeList = SW_MALLOC(capacity*sizeof(uint32_t));
+
+    if (!pool->data || !pool->gen || !pool->freeList)
+    {
+        SW_FREE(pool->data);
+        SW_FREE(pool->gen);
+        SW_FREE(pool->freeList);
+        return false;
+    }
+
+    pool->watermark = 1;
+    pool->capacity = capacity;
+    pool->stride = stride;
+
+    return true;
+}
+
+static void sw_pool_destroy(sw_pool_t *pool)
+{
+    SW_FREE(pool->data);
+    SW_FREE(pool->gen);
+    SW_FREE(pool->freeList);
+    *pool = (sw_pool_t) { 0 };
+}
+
+static sw_handle_t sw_pool_alloc(sw_pool_t *pool)
+{
+    uint32_t index;
+
+    if (pool->freeCount > 0)
+    {
+        index = pool->freeList[--pool->freeCount];
+    }
+    else
+    {
+        if (pool->watermark >= pool->capacity) return SW_HANDLE_NULL;
+        index = (uint32_t)pool->watermark++;
+    }
+
+    uint8_t ver = ((pool->gen[index] & SW_POOL_SLOT_VER_MASK) + 1) & SW_POOL_SLOT_VER_MASK;
+    if (ver == 0) ver = 1;
+    pool->gen[index] = SW_POOL_SLOT_LIVE | ver;
+
+    uint8_t *slot = (uint8_t *)pool->data + index*pool->stride;
+    for (size_t i = 0; i < pool->stride; i++) slot[i] = 0;
+
+    return (sw_handle_t)index;
+}
+
+static void *sw_pool_get(const sw_pool_t *pool, sw_handle_t handle)
+{
+    if (handle == SW_HANDLE_NULL) return NULL;
+    if ((int)handle >= pool->capacity) return NULL;
+    if (!(pool->gen[handle] & SW_POOL_SLOT_LIVE)) return NULL;
+
+    return (char *)pool->data + handle*pool->stride;
+}
+
+static bool sw_pool_valid(const sw_pool_t *pool, sw_handle_t handle)
+{
+    return sw_pool_get(pool, handle) != NULL;
+}
+
+static bool sw_pool_free(sw_pool_t *pool, sw_handle_t handle)
+{
+    if (!sw_pool_valid(pool, handle)) return false;
+
+    pool->gen[handle] &= SW_POOL_SLOT_VER_MASK;   // delete live flag
+    pool->freeList[pool->freeCount++] = handle;
+    return true;
+}
+//-------------------------------------------------------------------------------------------
+
+// Validity check helper functions
+//-------------------------------------------------------------------------------------------
+static SW_INLINE bool sw_is_texture_valid(sw_handle_t id)
+{
+    return sw_pool_valid(&RLSW.texturePool, id);
+}
+
+static SW_INLINE bool sw_is_texture_complete(sw_texture_t *tex)
+{
+    return (tex != NULL) && (tex->pixels != NULL);
+}
+
+static SW_INLINE bool sw_is_texture_filter_valid(int filter)
+{
+    return ((filter == SW_NEAREST) || (filter == SW_LINEAR));
+}
+
+static SW_INLINE bool sw_is_texture_wrap_valid(int wrap)
+{
+    return ((wrap == SW_REPEAT) || (wrap == SW_CLAMP));
+}
+
+static bool sw_is_draw_mode_valid(int mode)
+{
+    bool result = false;
+
+    switch (mode)
+    {
+        case SW_POINTS:
+        case SW_LINES:
+        case SW_TRIANGLES:
+        case SW_QUADS: result = true; break;
+        default: break;
+    }
+
+    return result;
+}
+
+static bool sw_is_poly_mode_valid(int mode)
+{
+    bool result = false;
+
+    switch (mode)
+    {
+        case SW_POINT:
+        case SW_LINE:
+        case SW_FILL: result = true; break;
+        default: break;
+    }
+
+    return result;
+}
+
+static SW_INLINE bool sw_is_face_valid(int face)
+{
+    return (face == SW_FRONT || face == SW_BACK);
+}
+
+static SW_INLINE bool sw_is_ready_to_render(void)
+{
+    return (swCheckFramebufferStatus() == SW_FRAMEBUFFER_COMPLETE);
+}
+//-------------------------------------------------------------------------------------------
+
+// Pixel management functions
+//-------------------------------------------------------------------------------------------
+static int sw_pixel_get_format(SWformat format, SWtype type)
+{
+    int channels = 0;
+    int bitsPerChannel = 8; // Default: 8 bits per channel
+
+    // Handle case where format is a depth component
+    if (format == SW_DEPTH_COMPONENT)
+    {
+        switch (type)
+        {
+            case SW_UNSIGNED_BYTE:  return SW_PIXELFORMAT_DEPTH_D8;
+            case SW_BYTE:           return SW_PIXELFORMAT_DEPTH_D8;
+            case SW_UNSIGNED_SHORT: return SW_PIXELFORMAT_DEPTH_D16;
+            case SW_SHORT:          return SW_PIXELFORMAT_DEPTH_D16;
+            case SW_UNSIGNED_INT:   return SW_PIXELFORMAT_DEPTH_D32;
+            case SW_INT:            return SW_PIXELFORMAT_DEPTH_D32;
+            case SW_FLOAT:          return SW_PIXELFORMAT_DEPTH_D32;
+            default: return SW_PIXELFORMAT_UNKNOWN;
+        }
+    }
+
+    // Handle case where the type is a packed color
+    switch (type)
+    {
+        case SW_UNSIGNED_BYTE_3_3_2:    return SW_PIXELFORMAT_COLOR_R3G3B2;
+        case SW_UNSIGNED_SHORT_5_6_5:   return SW_PIXELFORMAT_COLOR_R5G6B5;
+        case SW_UNSIGNED_SHORT_4_4_4_4: return SW_PIXELFORMAT_COLOR_R4G4B4A4;
+        case SW_UNSIGNED_SHORT_5_5_5_1: return SW_PIXELFORMAT_COLOR_R5G5B5A1;
+        default: break;
+    }
+
+    // Determine the number of channels (format)
+    switch (format)
+    {
+        case SW_LUMINANCE:        channels = 1; break;
+        case SW_LUMINANCE_ALPHA:  channels = 2; break;
+        case SW_RGB:              channels = 3; break;
+        case SW_RGBA:             channels = 4; break;
+        default: return SW_PIXELFORMAT_UNKNOWN;
+    }
+
+    // Determine the depth of each channel (type)
+    switch (type)
+    {
+        case SW_UNSIGNED_BYTE:    bitsPerChannel = 8;  break;
+        case SW_BYTE:             bitsPerChannel = 8;  break;
+        case SW_UNSIGNED_SHORT:   bitsPerChannel = 16; break;
+        case SW_SHORT:            bitsPerChannel = 16; break;
+        case SW_UNSIGNED_INT:     bitsPerChannel = 32; break;
+        case SW_INT:              bitsPerChannel = 32; break;
+        case SW_FLOAT:            bitsPerChannel = 32; break;
+        default: return SW_PIXELFORMAT_UNKNOWN;
+    }
+
+    // Map the format and type to the correct internal format
+    if (bitsPerChannel == 8)
+    {
+        if (channels == 1) return SW_PIXELFORMAT_COLOR_GRAYSCALE;
+        if (channels == 2) return SW_PIXELFORMAT_COLOR_GRAYALPHA;
+        if (channels == 3) return SW_PIXELFORMAT_COLOR_R8G8B8;
+        if (channels == 4) return SW_PIXELFORMAT_COLOR_R8G8B8A8;
+    }
+    else if (bitsPerChannel == 16)
+    {
+        if (channels == 1) return SW_PIXELFORMAT_COLOR_R16;
+        if (channels == 3) return SW_PIXELFORMAT_COLOR_R16G16B16;
+        if (channels == 4) return SW_PIXELFORMAT_COLOR_R16G16B16A16;
+    }
+    else if (bitsPerChannel == 32)
+    {
+        if (channels == 1) return SW_PIXELFORMAT_COLOR_R32;
+        if (channels == 3) return SW_PIXELFORMAT_COLOR_R32G32B32;
+        if (channels == 4) return SW_PIXELFORMAT_COLOR_R32G32B32A32;
+    }
+
+    return SW_PIXELFORMAT_UNKNOWN;
+}
+
+static bool sw_pixel_is_depth_format(sw_pixelformat_t format)
+{
+    switch (format)
+    {
+        case SW_PIXELFORMAT_DEPTH_D8:
+        case SW_PIXELFORMAT_DEPTH_D16:
+        case SW_PIXELFORMAT_DEPTH_D32: return true;
+        default: break;
+    }
+
+    return false;
+}
+
+static void sw_pixel_read_color8_GRAYSCALE(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t gray = ((const uint8_t *)pixels)[offset];
+    color[0] = gray;
+    color[1] = gray;
+    color[2] = gray;
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_GRAYALPHA(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint8_t *src = &((const uint8_t *)pixels)[offset*2];
+    color[0] = src[0];
+    color[1] = src[0];
+    color[2] = src[0];
+    color[3] = src[1];
+}
+
+static void sw_pixel_read_color8_R3G3B2(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t pixel = ((const uint8_t *)pixels)[offset];
+    color[0] = sw_expand_3to8((pixel >> 5) & 0x07);
+    color[1] = sw_expand_3to8((pixel >> 2) & 0x07);
+    color[2] = sw_expand_2to8( pixel       & 0x03);
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R5G6B5(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint16_t pixel = ((const uint16_t *)pixels)[offset];
+    color[0] = sw_expand_5to8((pixel >> 11) & 0x1F);
+    color[1] = sw_expand_6to8((pixel >>  5) & 0x3F);
+    color[2] = sw_expand_5to8( pixel        & 0x1F);
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R8G8B8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint8_t *src = &((const uint8_t *)pixels)[offset*3];
+    color[0] = src[0];
+    color[1] = src[1];
+    color[2] = src[2];
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R5G5B5A1(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint16_t pixel = ((const uint16_t *)pixels)[offset];
+    color[0] = sw_expand_5to8((pixel >> 11) & 0x1F);
+    color[1] = sw_expand_5to8((pixel >>  6) & 0x1F);
+    color[2] = sw_expand_5to8((pixel >>  1) & 0x1F);
+    color[3] = sw_expand_1to8( pixel        & 0x01);
+}
+
+static void sw_pixel_read_color8_R4G4B4A4(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint16_t pixel = ((const uint16_t *)pixels)[offset];
+    color[0] = sw_expand_4to8((pixel >> 12) & 0x0F);
+    color[1] = sw_expand_4to8((pixel >>  8) & 0x0F);
+    color[2] = sw_expand_4to8((pixel >>  4) & 0x0F);
+    color[3] = sw_expand_4to8( pixel        & 0x0F);
+}
+
+static void sw_pixel_read_color8_R8G8B8A8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint8_t *src = &((const uint8_t *)pixels)[offset*4];
+    color[0] = src[0];
+    color[1] = src[1];
+    color[2] = src[2];
+    color[3] = src[3];
+}
+
+static void sw_pixel_read_color8_R32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t gray = (uint8_t)(((const float *)pixels)[offset]*255.0f);
+    color[0] = gray;
+    color[1] = gray;
+    color[2] = gray;
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R32G32B32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const float *src = &((const float *)pixels)[offset*3];
+    color[0] = (uint8_t)(src[0]*255.0f);
+    color[1] = (uint8_t)(src[1]*255.0f);
+    color[2] = (uint8_t)(src[2]*255.0f);
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R32G32B32A32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const float *src = &((const float *)pixels)[offset*4];
+    color[0] = (uint8_t)(src[0]*255.0f);
+    color[1] = (uint8_t)(src[1]*255.0f);
+    color[2] = (uint8_t)(src[2]*255.0f);
+    color[3] = (uint8_t)(src[3]*255.0f);
+}
+
+static void sw_pixel_read_color8_R16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t gray = (uint8_t)(sw_half_to_float(((const uint16_t *)pixels)[offset])*255.0f);
+    color[0] = gray;
+    color[1] = gray;
+    color[2] = gray;
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R16G16B16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint16_t *src = &((const uint16_t *)pixels)[offset*3];
+    color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f);
+    color[1] = (uint8_t)(sw_half_to_float(src[1])*255.0f);
+    color[2] = (uint8_t)(sw_half_to_float(src[2])*255.0f);
+    color[3] = 255;
+}
+
+static void sw_pixel_read_color8_R16G16B16A16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint16_t *src = &((const uint16_t *)pixels)[offset*4];
+    color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f);
+    color[1] = (uint8_t)(sw_half_to_float(src[1])*255.0f);
+    color[2] = (uint8_t)(sw_half_to_float(src[2])*255.0f);
+    color[3] = (uint8_t)(sw_half_to_float(src[3])*255.0f);
+}
+
+static sw_pixel_read_color8_f sw_pixel_get_read_color8_func(sw_pixelformat_t format)
+{
+    switch (format)
+    {
+        case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_read_color8_GRAYSCALE;
+        case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_read_color8_GRAYALPHA;
+        case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_read_color8_R3G3B2;
+        case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_read_color8_R5G6B5;
+        case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_read_color8_R8G8B8;
+        case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_read_color8_R5G5B5A1;
+        case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_read_color8_R4G4B4A4;
+        case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_read_color8_R8G8B8A8;
+        case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_read_color8_R32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_read_color8_R32G32B32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_read_color8_R32G32B32A32;
+        case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_read_color8_R16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_read_color8_R16G16B16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_read_color8_R16G16B16A16;
+
+        case SW_PIXELFORMAT_UNKNOWN:
+        case SW_PIXELFORMAT_DEPTH_D8:
+        case SW_PIXELFORMAT_DEPTH_D16:
+        case SW_PIXELFORMAT_DEPTH_D32:
+        case SW_PIXELFORMAT_COUNT:
+        default: break;
+    }
+
+    return NULL;
+}
+
+static void sw_pixel_write_color8_GRAYSCALE(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    ((uint8_t *)pixels)[offset] = sw_luminance8(color);
+}
+
+static void sw_pixel_write_color8_GRAYALPHA(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t *dst = &((uint8_t *)pixels)[offset*2];
+    dst[0] = sw_luminance8(color);
+    dst[1] = color[3];
+}
+
+static void sw_pixel_write_color8_R3G3B2(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t pixel = (sw_compress_8to3(color[0]) << 5)
+                  | (sw_compress_8to3(color[1]) << 2)
+                  |  sw_compress_8to2(color[2]);
+    ((uint8_t *)pixels)[offset] = pixel;
+}
+
+static void sw_pixel_write_color8_R5G6B5(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t pixel = (sw_compress_8to5(color[0]) << 11)
+                   | (sw_compress_8to6(color[1]) <<  5)
+                   |  sw_compress_8to5(color[2]);
+    ((uint16_t *)pixels)[offset] = pixel;
+}
+
+static void sw_pixel_write_color8_R8G8B8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t *dst = &((uint8_t *)pixels)[offset*3];
+    dst[0] = color[0];
+    dst[1] = color[1];
+    dst[2] = color[2];
+}
+
+static void sw_pixel_write_color8_R5G5B5A1(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t pixel = (sw_compress_8to5(color[0]) << 11)
+                   | (sw_compress_8to5(color[1]) <<  6)
+                   | (sw_compress_8to5(color[2]) <<  1)
+                   |  sw_compress_8to1(color[3]);
+    ((uint16_t *)pixels)[offset] = pixel;
+}
+
+static void sw_pixel_write_color8_R4G4B4A4(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t pixel = (sw_compress_8to4(color[0]) << 12)
+                   | (sw_compress_8to4(color[1]) <<  8)
+                   | (sw_compress_8to4(color[2]) <<  4)
+                   |  sw_compress_8to4(color[3]);
+    ((uint16_t *)pixels)[offset] = pixel;
+}
+
+static void sw_pixel_write_color8_R8G8B8A8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t *dst = &((uint8_t *)pixels)[offset*4];
+    dst[0] = color[0];
+    dst[1] = color[1];
+    dst[2] = color[2];
+    dst[3] = color[3];
+}
+
+static void sw_pixel_write_color8_R32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    ((float *)pixels)[offset] = sw_luminance8(color)*SW_INV_255;
+}
+
+static void sw_pixel_write_color8_R32G32B32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    float *dst = &((float *)pixels)[offset*3];
+    dst[0] = color[0]*SW_INV_255;
+    dst[1] = color[1]*SW_INV_255;
+    dst[2] = color[2]*SW_INV_255;
+}
+
+static void sw_pixel_write_color8_R32G32B32A32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    float *dst = &((float *)pixels)[offset*4];
+    dst[0] = color[0]*SW_INV_255;
+    dst[1] = color[1]*SW_INV_255;
+    dst[2] = color[2]*SW_INV_255;
+    dst[3] = color[3]*SW_INV_255;
+}
+
+static void sw_pixel_write_color8_R16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance8(color)*SW_INV_255);
+}
+
+static void sw_pixel_write_color8_R16G16B16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t *dst = &((uint16_t *)pixels)[offset*3];
+    dst[0] = sw_float_to_half(color[0]*SW_INV_255);
+    dst[1] = sw_float_to_half(color[1]*SW_INV_255);
+    dst[2] = sw_float_to_half(color[2]*SW_INV_255);
+}
+
+static void sw_pixel_write_color8_R16G16B16A16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t *dst = &((uint16_t *)pixels)[offset*4];
+    dst[0] = sw_float_to_half(color[0]*SW_INV_255);
+    dst[1] = sw_float_to_half(color[1]*SW_INV_255);
+    dst[2] = sw_float_to_half(color[2]*SW_INV_255);
+    dst[3] = sw_float_to_half(color[3]*SW_INV_255);
+}
+
+static sw_pixel_write_color8_f sw_pixel_get_write_color8_func(sw_pixelformat_t format)
+{
+    switch (format)
+    {
+        case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_write_color8_GRAYSCALE;
+        case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_write_color8_GRAYALPHA;
+        case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color8_R3G3B2;
+        case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_write_color8_R5G6B5;
+        case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_write_color8_R8G8B8;
+        case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_write_color8_R5G5B5A1;
+        case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_write_color8_R4G4B4A4;
+        case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_write_color8_R8G8B8A8;
+        case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_write_color8_R32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_write_color8_R32G32B32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_write_color8_R32G32B32A32;
+        case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_write_color8_R16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_write_color8_R16G16B16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_write_color8_R16G16B16A16;
+
+        case SW_PIXELFORMAT_UNKNOWN:
+        case SW_PIXELFORMAT_DEPTH_D8:
+        case SW_PIXELFORMAT_DEPTH_D16:
+        case SW_PIXELFORMAT_DEPTH_D32:
+        case SW_PIXELFORMAT_COUNT:
+        default: break;
+    }
+
+    return NULL;
+}
+
+static void sw_pixel_read_color_GRAYSCALE(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    float gray = ((const uint8_t *)pixels)[offset]*SW_INV_255;
+    color[0] = gray;
+    color[1] = gray;
+    color[2] = gray;
+    color[3] = 1.0f;
+}
+
+static void sw_pixel_read_color_GRAYALPHA(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint8_t *src = &((const uint8_t *)pixels)[offset*2];
+    float gray = src[0]*SW_INV_255;
+    color[0] = gray;
+    color[1] = gray;
+    color[2] = gray;
+    color[3] = src[1]*SW_INV_255;
+}
+
+static void sw_pixel_read_color_R3G3B2(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t unpack[4];
+    sw_pixel_read_color8_R3G3B2(unpack, pixels, offset);
+    sw_color8_to_color(color, unpack);
+}
+
+static void sw_pixel_read_color_R5G6B5(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t unpack[4];
+    sw_pixel_read_color8_R5G6B5(unpack, pixels, offset);
+    sw_color8_to_color(color, unpack);
+}
+
+static void sw_pixel_read_color_R8G8B8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t unpack[4];
+    sw_pixel_read_color8_R8G8B8(unpack, pixels, offset);
+    sw_color8_to_color(color, unpack);
+}
+
+static void sw_pixel_read_color_R5G5B5A1(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t unpack[4];
+    sw_pixel_read_color8_R5G5B5A1(unpack, pixels, offset);
+    sw_color8_to_color(color, unpack);
+}
+
+static void sw_pixel_read_color_R4G4B4A4(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    uint8_t unpack[4];
+    sw_pixel_read_color8_R4G4B4A4(unpack, pixels, offset);
+    sw_color8_to_color(color, unpack);
+}
+
+static void sw_pixel_read_color_R8G8B8A8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    sw_color8_to_color(color, &((const uint8_t *)pixels)[offset*4]);
+}
+
+static void sw_pixel_read_color_R32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    float val = ((const float *)pixels)[offset];
+    color[0] = val;
+    color[1] = val;
+    color[2] = val;
+    color[3] = 1.0f;
+}
+
+static void sw_pixel_read_color_R32G32B32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const float *src = &((const float *)pixels)[offset*3];
+    color[0] = src[0];
+    color[1] = src[1];
+    color[2] = src[2];
+    color[3] = 1.0f;
+}
+
+static void sw_pixel_read_color_R32G32B32A32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const float *src = &((const float *)pixels)[offset*4];
+    color[0] = src[0];
+    color[1] = src[1];
+    color[2] = src[2];
+    color[3] = src[3];
+}
+
+static void sw_pixel_read_color_R16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    float val = sw_half_to_float(((const uint16_t *)pixels)[offset]);
+    color[0] = val;
+    color[1] = val;
+    color[2] = val;
+    color[3] = 1.0f;
+}
+
+static void sw_pixel_read_color_R16G16B16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint16_t *src = &((const uint16_t *)pixels)[offset*3];
+    color[0] = sw_half_to_float(src[0]);
+    color[1] = sw_half_to_float(src[1]);
+    color[2] = sw_half_to_float(src[2]);
+    color[3] = 1.0f;
+}
+
+static void sw_pixel_read_color_R16G16B16A16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset)
+{
+    const uint16_t *src = &((const uint16_t *)pixels)[offset*4];
+    color[0] = sw_half_to_float(src[0]);
+    color[1] = sw_half_to_float(src[1]);
+    color[2] = sw_half_to_float(src[2]);
+    color[3] = sw_half_to_float(src[3]);
+}
+
+static sw_pixel_read_color_f sw_pixel_get_read_color_func(sw_pixelformat_t format)
+{
+    switch (format)
+    {
+        case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_read_color_GRAYSCALE;
+        case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_read_color_GRAYALPHA;
+        case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_read_color_R3G3B2;
+        case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_read_color_R5G6B5;
+        case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_read_color_R8G8B8;
+        case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_read_color_R5G5B5A1;
+        case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_read_color_R4G4B4A4;
+        case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_read_color_R8G8B8A8;
+        case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_read_color_R32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_read_color_R32G32B32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_read_color_R32G32B32A32;
+        case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_read_color_R16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_read_color_R16G16B16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_read_color_R16G16B16A16;
+
+        case SW_PIXELFORMAT_UNKNOWN:
+        case SW_PIXELFORMAT_DEPTH_D8:
+        case SW_PIXELFORMAT_DEPTH_D16:
+        case SW_PIXELFORMAT_DEPTH_D32:
+        case SW_PIXELFORMAT_COUNT:
+        default: break;
+    }
+
+    return NULL;
+}
+
+static void sw_pixel_write_color_GRAYSCALE(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    ((uint8_t *)pixels)[offset] = (uint8_t)(sw_luminance(color)*255.0f);
+}
+
+static void sw_pixel_write_color_GRAYALPHA(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t *dst = &((uint8_t *)pixels)[offset*2];
+    dst[0] = (uint8_t)(sw_luminance(color)*255.0f);
+    dst[1] = (uint8_t)(color[3]*255.0f);
+}
+
+static void sw_pixel_write_color_R3G3B2(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t color8[4];
+    sw_color_to_color8(color8, color);
+    sw_pixel_write_color8_R3G3B2(pixels, color8, offset);
+}
+
+static void sw_pixel_write_color_R5G6B5(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t color8[4];
+    sw_color_to_color8(color8, color);
+    sw_pixel_write_color8_R5G6B5(pixels, color8, offset);
+}
+
+static void sw_pixel_write_color_R8G8B8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t color8[4];
+    sw_color_to_color8(color8, color);
+    sw_pixel_write_color8_R8G8B8(pixels, color8, offset);
+}
+
+static void sw_pixel_write_color_R5G5B5A1(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t color8[4];
+    sw_color_to_color8(color8, color);
+    sw_pixel_write_color8_R5G5B5A1(pixels, color8, offset);
+}
+
+static void sw_pixel_write_color_R4G4B4A4(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint8_t color8[4];
+    sw_color_to_color8(color8, color);
+    sw_pixel_write_color8_R4G4B4A4(pixels, color8, offset);
+}
+
+static void sw_pixel_write_color_R8G8B8A8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    sw_color_to_color8(&((uint8_t *)pixels)[offset*4], color);
+}
+
+static void sw_pixel_write_color_R32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    ((float *)pixels)[offset] = sw_luminance(color);
+}
+
+static void sw_pixel_write_color_R32G32B32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    float *dst = &((float *)pixels)[offset*3];
+    dst[0] = color[0];
+    dst[1] = color[1];
+    dst[2] = color[2];
+}
+
+static void sw_pixel_write_color_R32G32B32A32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    float *dst = &((float *)pixels)[offset*4];
+    dst[0] = color[0];
+    dst[1] = color[1];
+    dst[2] = color[2];
+    dst[3] = color[3];
+}
+
+static void sw_pixel_write_color_R16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance(color));
+}
+
+static void sw_pixel_write_color_R16G16B16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t *dst = &((uint16_t *)pixels)[offset*3];
+    dst[0] = sw_float_to_half(color[0]);
+    dst[1] = sw_float_to_half(color[1]);
+    dst[2] = sw_float_to_half(color[2]);
+}
+
+static void sw_pixel_write_color_R16G16B16A16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset)
+{
+    uint16_t *dst = &((uint16_t *)pixels)[offset*4];
+    dst[0] = sw_float_to_half(color[0]);
+    dst[1] = sw_float_to_half(color[1]);
+    dst[2] = sw_float_to_half(color[2]);
+    dst[3] = sw_float_to_half(color[3]);
+}
+
+static sw_pixel_write_color_f sw_pixel_get_write_color_func(sw_pixelformat_t format)
+{
+    switch (format)
+    {
+        case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_write_color_GRAYSCALE;
+        case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_write_color_GRAYALPHA;
+        case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color_R3G3B2;
+        case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_write_color_R5G6B5;
+        case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_write_color_R8G8B8;
+        case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_write_color_R5G5B5A1;
+        case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_write_color_R4G4B4A4;
+        case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_write_color_R8G8B8A8;
+        case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_write_color_R32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_write_color_R32G32B32;
+        case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_write_color_R32G32B32A32;
+        case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_write_color_R16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_write_color_R16G16B16;
+        case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_write_color_R16G16B16A16;
+
+        case SW_PIXELFORMAT_UNKNOWN:
+        case SW_PIXELFORMAT_DEPTH_D8:
+        case SW_PIXELFORMAT_DEPTH_D16:
+        case SW_PIXELFORMAT_DEPTH_D32:
+        case SW_PIXELFORMAT_COUNT:
+        default: break;
+    }
+
+    return NULL;
+}
+
+static float sw_pixel_read_depth_D8(const void *pixels, uint32_t offset)
+{
+    return (float)((uint8_t *)pixels)[offset]*SW_INV_255;
+}
+
+static float sw_pixel_read_depth_D16(const void *pixels, uint32_t offset)
+{
+    return (float)((uint16_t *)pixels)[offset]/UINT16_MAX;
+}
+
+static float sw_pixel_read_depth_D32(const void *pixels, uint32_t offset)
+{
+    return ((float *)pixels)[offset];
+}
+
+static void sw_pixel_write_depth_D8(void *pixels, float depth, uint32_t offset)
+{
+    ((uint8_t *)pixels)[offset] = (uint8_t)(depth*UINT8_MAX);
+}
+
+static void sw_pixel_write_depth_D16(void *pixels, float depth, uint32_t offset)
+{
+    ((uint16_t *)pixels)[offset] = (uint16_t)(depth*UINT16_MAX);
+}
+
+static void sw_pixel_write_depth_D32(void *pixels, float depth, uint32_t offset)
+{
+    ((float *)pixels)[offset] = depth;
+}
+//-------------------------------------------------------------------------------------------
+
+// Texture functionality
+//-------------------------------------------------------------------------------------------
+static bool sw_texture_alloc(sw_texture_t *texture, const void *data, int w, int h, sw_pixelformat_t format)
+{
+    bool isDepth = sw_pixel_is_depth_format(format);
+    int bpp = SW_PIXELFORMAT_SIZE[format];
+    int newSize = w*h*bpp;
+
+    if (texture->pixels == NULL)
+    {
+        texture->minFilter = SW_NEAREST;
+        texture->magFilter = SW_NEAREST;
+        texture->sWrap = SW_CLAMP;
+        texture->tWrap = SW_CLAMP;
+    }
+
+    if (newSize > texture->allocSz)
+    {
+        void *ptr = SW_REALLOC(texture->pixels, newSize);
+        if (!ptr) { RLSW.errCode = SW_OUT_OF_MEMORY; return false; }
+        texture->allocSz = newSize;
+        texture->pixels = ptr;
+    }
+
+    uint8_t *dst = texture->pixels;
+    const uint8_t *src = data;
+
+    sw_pixel_read_color8_f readColor8 = NULL;
+    sw_pixel_read_color_f readColor = NULL;
+    if (!isDepth)
+    {
+        readColor8 = sw_pixel_get_read_color8_func(format);
+        readColor = sw_pixel_get_read_color_func(format);
+    }
+
+    sw_pixel_alpha_t pixelAlpha = SW_PIXELFORMAT_ALPHA[format];
+    bool alphaFound = !data; // No data: assume transparency
+
+    if (data && !isDepth)
+    {
+        for (int i = 0; i < newSize; i++) dst[i] = src[i];
+
+        if (pixelAlpha != SW_PIXEL_ALPHA_NONE)
+        {
+            for (int i = 0; i < newSize; i += bpp)
+            {
+                uint8_t color[4] = { 0 };
+                readColor8(color, &src[i], 0);
+                if (color[3] < 255) { alphaFound = true; break; }
+            }
+        }
+    }
+    else
+    {
+        for (int i = 0; i < newSize; i++) dst[i] = 0;
+    }
+
+    texture->readColor8 = readColor8;
+    texture->readColor = readColor;
+    texture->format = format;
+    texture->alpha = alphaFound? pixelAlpha : SW_PIXEL_ALPHA_NONE;
+    texture->width = w;
+    texture->height = h;
+    texture->wMinus1 = w - 1;
+    texture->hMinus1 = h - 1;
+    texture->tx = 1.0f/w;
+    texture->ty = 1.0f/h;
+
+    return true;
+}
+
+static void sw_texture_free(sw_texture_t *texture)
+{
+    SW_FREE(texture->pixels);
+}
+
+static void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
+{
+    int x, y;
+
+#if RLSW_SUPPORT_NPOT_TEXTURE
+    if (tex->sWrap == SW_REPEAT) x = (int)(sw_fract(u)*tex->width);
+    else x = (int)(sw_saturate(u)*tex->width);
+
+    if (tex->tWrap == SW_REPEAT) y = (int)(sw_fract(v)*tex->height);
+    else y = (int)(sw_saturate(v)*tex->height);
+#else
+    if (tex->sWrap == SW_REPEAT) x = (int)(u*tex->width) & tex->wMinus1;
+    else x = (int)(sw_saturate(u)*tex->width);
+
+    if (tex->tWrap == SW_REPEAT) y = (int)(v*tex->height) & tex->hMinus1;
+    else y = (int)(sw_saturate(v)*tex->height);
+#endif
+
+    tex->readColor(color, tex->pixels, y*tex->width + x);
+}
+
+static void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v)
+{
+    float xf = (u*tex->width) - 0.5f;
+    float yf = (v*tex->height) - 0.5f;
+
+    float fx = sw_fract(xf);
+    float fy = sw_fract(yf);
+
+    int x0 = (int)xf;
+    int y0 = (int)yf;
+
+    int x1 = x0 + 1;
+    int y1 = y0 + 1;
+
+    if (tex->sWrap == SW_REPEAT)
+    {
+    #if RLSW_SUPPORT_NPOT_TEXTURE
+        x0 = (x0%tex->width + tex->width)%tex->width;
+        x1 = (x1%tex->width + tex->width)%tex->width;
+    #else
+        x0 = x0 & tex->wMinus1;
+        x1 = x1 & tex->wMinus1;
+    #endif
+    }
+    else
+    {
+        x0 = sw_clamp_int(x0, 0, tex->wMinus1);
+        x1 = sw_clamp_int(x1, 0, tex->wMinus1);
+    }
+
+    if (tex->tWrap == SW_REPEAT)
+    {
+    #if RLSW_SUPPORT_NPOT_TEXTURE
+        y0 = (y0%tex->height + tex->height)%tex->height;
+        y1 = (y1%tex->height + tex->height)%tex->height;
+    #else
+        y0 = y0 & tex->hMinus1;
+        y1 = y1 & tex->hMinus1;
+    #endif
+    }
+    else
+    {
+        y0 = sw_clamp_int(y0, 0, tex->hMinus1);
+        y1 = sw_clamp_int(y1, 0, tex->hMinus1);
+    }
+
+    float c00[4], c10[4], c01[4], c11[4];
+    tex->readColor(c00, tex->pixels, y0*tex->width + x0);
+    tex->readColor(c10, tex->pixels, y0*tex->width + x1);
+    tex->readColor(c01, tex->pixels, y1*tex->width + x0);
+    tex->readColor(c11, tex->pixels, y1*tex->width + x1);
+
+    for (int i = 0; i < 4; i++)
+    {
+        float t = c00[i] + fx*(c10[i] - c00[i]);
+        float b = c01[i] + fx*(c11[i] - c01[i]);
+        color[i] = t + fy*(b - t);
+    }
+}
+
+// Resolves which sample function to use from the texel-to-pixel derivative magnitude
+static 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
+    // using the squared value, the comparison remains (L2 > 1.0f*1.0f)
+    //float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
+    //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy);
+    //float L = (du > dv)? du : dv;
+
+    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;
+    return (filter == SW_LINEAR)? sw_texture_sample_linear : sw_texture_sample_nearest;
+}
+//-------------------------------------------------------------------------------------------
+
+// Framebuffer management functions
+//-------------------------------------------------------------------------------------------
+static bool sw_default_framebuffer_alloc(sw_default_framebuffer_t *fb, int w, int h)
+{
+    if (!sw_texture_alloc(&fb->color, NULL, w, h, SW_FRAMEBUFFER_COLOR_FORMAT))
+    {
+        return false;
+    }
+
+#if RLSW_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;
+    }
+
+    return true;
+}
+
+static void sw_default_framebuffer_free(sw_default_framebuffer_t *fb)
+{
+    sw_texture_free(&fb->color);
+    sw_texture_free(&fb->depth);
+#if RLSW_DOUBLE_BUFFERING
+    sw_texture_free(&fb->backColor);
+#endif
+}
+
+static void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const float color[4])
+{
+    // NOTE: MSVC doesn't support VLA, so the largest possible size is allocated: 16 bytes
+    //uint8_t pixel[SW_FRAMEBUFFER_COLOR_SIZE] = { 0 };
+    uint8_t pixel[16] = { 0 };
+    SW_FRAMEBUFFER_COLOR_SET(pixel, color, 0);
+
+    uint8_t *dst = (uint8_t *)colorBuffer->pixels;
+
+    if (RLSW.userState & SW_STATE_SCISSOR_TEST)
+    {
+        int xMin = sw_clamp_int(RLSW.scMin[0], 0, colorBuffer->width - 1);
+        int xMax = sw_clamp_int(RLSW.scMax[0], 0, colorBuffer->width - 1);
+        int yMin = sw_clamp_int(RLSW.scMin[1], 0, colorBuffer->height - 1);
+        int yMax = sw_clamp_int(RLSW.scMax[1], 0, colorBuffer->height - 1);
+
+        int w = xMax - xMin;
+        for (int y = yMin; y <= yMax; y++)
+        {
+            uint8_t *row = dst + (y*colorBuffer->width + xMin)*SW_FRAMEBUFFER_COLOR_SIZE;
+            for (int x = 0; x <= w; x++, row += SW_FRAMEBUFFER_COLOR_SIZE)
+            {
+                for (int b = 0; b < SW_FRAMEBUFFER_COLOR_SIZE; b++) row[b] = pixel[b];
+            }
+        }
+    }
+    else
+    {
+        int size = colorBuffer->width*colorBuffer->height;
+        for (int i = 0; i < size; i++)
+        {
+            for (int b = 0; b < SW_FRAMEBUFFER_COLOR_SIZE; b++)
+            {
+                dst[i*SW_FRAMEBUFFER_COLOR_SIZE + b] = pixel[b];
+            }
+        }
+    }
+}
+
+static void sw_framebuffer_fill_depth(sw_texture_t *depthBuffer, float depth)
+{
+    // NOTE: MSVC doesn't support VLA, so the largest possible size is allocated: 4 bytes
+    //uint8_t pixel[SW_FRAMEBUFFER_DEPTH_SIZE] = { 0 };
+    uint8_t pixel[4] = { 0 };
+    SW_FRAMEBUFFER_DEPTH_SET(pixel, depth, 0);
+
+    uint8_t *dst = (uint8_t *)depthBuffer->pixels;
+
+    if (RLSW.userState & SW_STATE_SCISSOR_TEST)
+    {
+        int xMin = sw_clamp_int(RLSW.scMin[0], 0, depthBuffer->width - 1);
+        int xMax = sw_clamp_int(RLSW.scMax[0], 0, depthBuffer->width - 1);
+        int yMin = sw_clamp_int(RLSW.scMin[1], 0, depthBuffer->height - 1);
+        int yMax = sw_clamp_int(RLSW.scMax[1], 0, depthBuffer->height - 1);
+
+        int w = xMax - xMin;
+        for (int y = yMin; y <= yMax; y++)
+        {
+            uint8_t *row = dst + (y*depthBuffer->width + xMin)*SW_FRAMEBUFFER_DEPTH_SIZE;
+            for (int x = 0; x <= w; x++, row += SW_FRAMEBUFFER_DEPTH_SIZE)
+            {
+                for (int b = 0; b < SW_FRAMEBUFFER_DEPTH_SIZE; b++) row[b] = pixel[b];
+            }
+        }
+    }
+    else
+    {
+        int size = depthBuffer->width*depthBuffer->height;
+        for (int i = 0; i < size; i++)
+        {
+            for (int b = 0; b < SW_FRAMEBUFFER_DEPTH_SIZE; b++)
+            {
+                dst[i*SW_FRAMEBUFFER_DEPTH_SIZE + b] = pixel[b];
+            }
+        }
+    }
+}
+
+static void sw_framebuffer_output_fast(void *dst, const sw_texture_t *buffer)
+{
+    int width = buffer->width;
+    int height = buffer->height;
+
+    uint8_t *d = (uint8_t *)dst;
+
+#if RLSW_FRAMEBUFFER_OUTPUT_BGRA && (SW_FRAMEBUFFER_COLOR_FORMAT == SW_PIXELFORMAT_COLOR_R8G8B8A8)
+    for (int y = height - 1; y >= 0; y--)
+    {
+        const uint8_t *src = (uint8_t *)(buffer->pixels) + y*width*4;
+        for (int x = 0; x < width; x++, src += 4, d += 4)
+        {
+            d[0] = src[2];
+            d[1] = src[1];
+            d[2] = src[0];
+            d[3] = src[3];
+        }
+    }
+#elif RLSW_FRAMEBUFFER_OUTPUT_BGRA && (SW_FRAMEBUFFER_COLOR_FORMAT == SW_PIXELFORMAT_COLOR_R8G8B8)
+    for (int y = height - 1; y >= 0; y--)
+    {
+        const uint8_t *src = (uint8_t *)(buffer->pixels) + y*width*3;
+        for (int x = 0; x < width; x++, src += 3, d += 3)
+        {
+            d[0] = src[2];
+            d[1] = src[1];
+            d[2] = src[0];
+        }
+    }
+#else
+    int rowBytes = width*SW_FRAMEBUFFER_COLOR_SIZE;
+    for (int y = height - 1; y >= 0; y--)
+    {
+        const uint8_t *src = (uint8_t *)(buffer->pixels) + y*rowBytes;
+        for (int i = 0; i < rowBytes; i++) d[i] = src[i];
+        d += rowBytes;
+    }
+#endif
+}
+
+static void sw_framebuffer_output_copy(void *dst, const sw_texture_t *buffer, int x, int y, int w, int h, sw_pixelformat_t format)
+{
+    int stride = buffer->width;
+    int dstPixelSize = SW_PIXELFORMAT_SIZE[format];
+    sw_pixel_write_color8_f setColor8 = sw_pixel_get_write_color8_func(format);
+
+    const uint8_t *src = (uint8_t *)(buffer->pixels) + ((y + h - 1)*stride + x)*SW_FRAMEBUFFER_COLOR_SIZE;
+    uint8_t *d = dst;
+
+    for (int iy = 0; iy < h; iy++)
+    {
+        const uint8_t *line = src;
+        uint8_t *dline = d;
+
+        for (int ix = 0; ix < w; ix++)
+        {
+            uint8_t color[4];
+            SW_FRAMEBUFFER_COLOR8_GET(color, line, 0);
+
+            #if RLSW_FRAMEBUFFER_OUTPUT_BGRA
+            if (format == SW_PIXELFORMAT_COLOR_R8G8B8A8 || format == SW_PIXELFORMAT_COLOR_R8G8B8)
+            {
+                uint8_t tmp = color[0]; color[0] = color[2]; color[2] = tmp;
+            }
+            #endif
+
+            setColor8(dline, color, 0);
+            line += SW_FRAMEBUFFER_COLOR_SIZE;
+            dline += dstPixelSize;
+        }
+
+        src -= stride*SW_FRAMEBUFFER_COLOR_SIZE;
+        d += w*dstPixelSize;
+    }
+}
+
+static void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buffer,
+    int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, sw_pixelformat_t format)
+{
+    const uint8_t *srcBase = buffer->pixels;
+
+    int fbWidth = buffer->width;
+    int dstPixelSize = SW_PIXELFORMAT_SIZE[format];
+    sw_pixel_write_color8_f setColor8 = sw_pixel_get_write_color8_func(format);
+
+    uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst;
+    uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst;
+
+    int ySrcLast = ySrc + hSrc - 1;
+    uint8_t *d = (uint8_t *)dst;
+
+    for (int dy = 0; dy < hDst; dy++)
+    {
+        int sy = ySrcLast - (int)(dy*yScale >> 16);
+        const uint8_t *srcLine = srcBase + (sy*fbWidth + xSrc)*SW_FRAMEBUFFER_COLOR_SIZE;
+        uint8_t *dline = d;
+
+        for (int dx = 0; dx < wDst; dx++)
+        {
+            int sx = (int)(dx*xScale >> 16);
+            const uint8_t *pixel = srcLine + sx*SW_FRAMEBUFFER_COLOR_SIZE;
+
+            uint8_t color[4];
+            SW_FRAMEBUFFER_COLOR8_GET(color, pixel, 0);
+
+            #if RLSW_FRAMEBUFFER_OUTPUT_BGRA
+            if (format == SW_PIXELFORMAT_COLOR_R8G8B8A8 || format == SW_PIXELFORMAT_COLOR_R8G8B8)
+            {
+                uint8_t tmp = color[0]; color[0] = color[2]; color[2] = tmp;
+            }
+            #endif
+
+            setColor8(dline, color, 0);
+            dline += dstPixelSize;
+        }
+
+        d += wDst*dstPixelSize;
+    }
+}
+//-------------------------------------------------------------------------------------------
+
+// Color blending functionality
+//-------------------------------------------------------------------------------------------
+// Blend factor component macros: SW_BF_XXX(src, dst, component_index)
+// Each expands to the scalar factor value for one RGBA channel
+#define SW_BF_ZERO(s,d,i)                0.0f
+#define SW_BF_ONE(s,d,i)                 1.0f
+#define SW_BF_SRC_COLOR(s,d,i)           (s)[i]
+#define SW_BF_ONE_MINUS_SRC_COLOR(s,d,i) (1.0f-(s)[i])
+#define SW_BF_SRC_ALPHA(s,d,i)           (s)[3]
+#define SW_BF_ONE_MINUS_SRC_ALPHA(s,d,i) (1.0f-(s)[3])
+#define SW_BF_DST_ALPHA(s,d,i)           (d)[3]
+#define SW_BF_ONE_MINUS_DST_ALPHA(s,d,i) (1.0f-(d)[3])
+#define SW_BF_DST_COLOR(s,d,i)           (d)[i]
+#define SW_BF_ONE_MINUS_DST_COLOR(s,d,i) (1.0f-(d)[i])
+#define SW_BF_SRC_ALPHA_SATURATE(s,d,i)  (((i)<3)? 1.0f : (((s)[3]<1.0f)?(s)[3]:1.0f))
+
+// Generates one specialized blend function for a (sfactor, dfactor) pair
+#define DEFINE_BLEND_FUNC(sn, dn, SF, DF)                                               \
+static void sw_blend_##sn##_##dn(float *SW_RESTRICT dst, const float *SW_RESTRICT src)  \
+{                                                                                       \
+    dst[0] = SF(src,dst,0)*src[0] + DF(src,dst,0)*dst[0];                               \
+    dst[1] = SF(src,dst,1)*src[1] + DF(src,dst,1)*dst[1];                               \
+    dst[2] = SF(src,dst,2)*src[2] + DF(src,dst,2)*dst[2];                               \
+    dst[3] = SF(src,dst,3)*src[3] + DF(src,dst,3)*dst[3];                               \
+}
+
+// Master factor list: X(c_name, gl_enum, compact_index, SW_BF_macro)
+// compact_index is used to index SW_BLEND_TABLE (GL enums are non contiguous)
+#define FOREACH_FACTOR(X) \
+    X(ZERO,                SW_ZERO,                0,  SW_BF_ZERO               ) \
+    X(ONE,                 SW_ONE,                 1,  SW_BF_ONE                ) \
+    X(SRC_COLOR,           SW_SRC_COLOR,           2,  SW_BF_SRC_COLOR          ) \
+    X(ONE_MINUS_SRC_COLOR, SW_ONE_MINUS_SRC_COLOR, 3,  SW_BF_ONE_MINUS_SRC_COLOR) \
+    X(SRC_ALPHA,           SW_SRC_ALPHA,           4,  SW_BF_SRC_ALPHA          ) \
+    X(ONE_MINUS_SRC_ALPHA, SW_ONE_MINUS_SRC_ALPHA, 5,  SW_BF_ONE_MINUS_SRC_ALPHA) \
+    X(DST_ALPHA,           SW_DST_ALPHA,           6,  SW_BF_DST_ALPHA          ) \
+    X(ONE_MINUS_DST_ALPHA, SW_ONE_MINUS_DST_ALPHA, 7,  SW_BF_ONE_MINUS_DST_ALPHA) \
+    X(DST_COLOR,           SW_DST_COLOR,           8,  SW_BF_DST_COLOR          ) \
+    X(ONE_MINUS_DST_COLOR, SW_ONE_MINUS_DST_COLOR, 9,  SW_BF_ONE_MINUS_DST_COLOR) \
+    X(SRC_ALPHA_SATURATE,  SW_SRC_ALPHA_SATURATE,  10, SW_BF_SRC_ALPHA_SATURATE )
+
+// Same list but forwards 3 extra args (A, B, C) to X
+#define FOREACH_FACTOR_WITH(X, A, B, C) \
+    X(ZERO,                SW_ZERO,                0,  SW_BF_ZERO,               A,B,C) \
+    X(ONE,                 SW_ONE,                 1,  SW_BF_ONE,                A,B,C) \
+    X(SRC_COLOR,           SW_SRC_COLOR,           2,  SW_BF_SRC_COLOR,          A,B,C) \
+    X(ONE_MINUS_SRC_COLOR, SW_ONE_MINUS_SRC_COLOR, 3,  SW_BF_ONE_MINUS_SRC_COLOR,A,B,C) \
+    X(SRC_ALPHA,           SW_SRC_ALPHA,           4,  SW_BF_SRC_ALPHA,          A,B,C) \
+    X(ONE_MINUS_SRC_ALPHA, SW_ONE_MINUS_SRC_ALPHA, 5,  SW_BF_ONE_MINUS_SRC_ALPHA,A,B,C) \
+    X(DST_ALPHA,           SW_DST_ALPHA,           6,  SW_BF_DST_ALPHA,          A,B,C) \
+    X(ONE_MINUS_DST_ALPHA, SW_ONE_MINUS_DST_ALPHA, 7,  SW_BF_ONE_MINUS_DST_ALPHA,A,B,C) \
+    X(DST_COLOR,           SW_DST_COLOR,           8,  SW_BF_DST_COLOR,          A,B,C) \
+    X(ONE_MINUS_DST_COLOR, SW_ONE_MINUS_DST_COLOR, 9,  SW_BF_ONE_MINUS_DST_COLOR,A,B,C) \
+    X(SRC_ALPHA_SATURATE,  SW_SRC_ALPHA_SATURATE,  10, SW_BF_SRC_ALPHA_SATURATE, A,B,C)
+
+// Inner loop: receives dst factor + forwarded (sn, si, sf) from outer loop
+#define GEN_COMBO(dn, de, di, df, sn, si, sf) DEFINE_BLEND_FUNC(sn, dn, sf, df)
+
+// Outer loop: for each src factor, iterate all dst factors
+#define GEN_ROW(sn, se, si, sf) FOREACH_FACTOR_WITH(GEN_COMBO, sn, si, sf)
+
+// Generates all 121 sw_blend_SFACTOR_DFACTOR functions
+FOREACH_FACTOR(GEN_ROW)
+
+#undef GEN_COMBO
+#undef GEN_ROW
+
+// Inner loop: emits one table entry using compact indices (not GL enum values)
+#define GEN_TABLE_ENTRY(dn, de, di, df, sn, si, sf) [si][di] = sw_blend_##sn##_##dn,
+
+// Outer loop: fills one row of the table for a given src factor
+#define GEN_TABLE_ROW(sn, se, si, sf) FOREACH_FACTOR_WITH(GEN_TABLE_ENTRY, sn, si, sf)
+
+// 2D dispatch table indexed by compact src/dst factor indices
+#define SW_BLEND_FACTOR_COUNT 11
+static const sw_blend_f SW_BLEND_TABLE[SW_BLEND_FACTOR_COUNT][SW_BLEND_FACTOR_COUNT] = {
+    FOREACH_FACTOR(GEN_TABLE_ROW)
+};
+
+#undef GEN_TABLE_ENTRY
+#undef GEN_TABLE_ROW
+
+// Maps a GL blend factor enum to its compact table index
+static int sw_blend_factor_index(SWfactor f)
+{
+    switch (f)
+    {
+        case SW_ZERO:                return 0;
+        case SW_ONE:                 return 1;
+        case SW_SRC_COLOR:           return 2;
+        case SW_ONE_MINUS_SRC_COLOR: return 3;
+        case SW_SRC_ALPHA:           return 4;
+        case SW_ONE_MINUS_SRC_ALPHA: return 5;
+        case SW_DST_ALPHA:           return 6;
+        case SW_ONE_MINUS_DST_ALPHA: return 7;
+        case SW_DST_COLOR:           return 8;
+        case SW_ONE_MINUS_DST_COLOR: return 9;
+        case SW_SRC_ALPHA_SATURATE:  return 10;
+        default:                     return -1;
+    }
+}
+
+static bool sw_blend_factor_needs_alpha(SWfactor f)
+{
+    switch (f)
+    {
+        case SW_SRC_ALPHA:
+        case SW_ONE_MINUS_SRC_ALPHA:
+        case SW_DST_ALPHA:
+        case SW_ONE_MINUS_DST_ALPHA:
+        case SW_SRC_ALPHA_SATURATE: return true;
+        default: break;
+    }
+
+    return false;
+}
+
+static uint32_t sw_blend_compute_flags(SWfactor src, SWfactor dst)
+{
+    uint32_t flags = 0;
+
+    // Blend is a no-op: result = src*1 + dst*0 = src
+    if (src == SW_ONE && dst == SW_ZERO) flags |= SW_BLEND_FLAG_NOOP;
+
+    // Factors that depend on the alpha channel
+    if (sw_blend_factor_needs_alpha(src) || sw_blend_factor_needs_alpha(dst)) flags |= SW_BLEND_FLAG_NEEDS_ALPHA;
+
+    return flags;
+}
+//-------------------------------------------------------------------------------------------
+
+// Projection helper functions
+//-------------------------------------------------------------------------------------------
+static void sw_project_ndc_to_screen(float ndc[4])
+{
+    ndc[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f;
+    ndc[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f;
+}
+//-------------------------------------------------------------------------------------------
+
+// Polygon clipping management
+//-------------------------------------------------------------------------------------------
+#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T)                          \
+static int sw_clip_##name(                                                              \
+    sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES],                                \
+    const sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES],                           \
+    int n)                                                                              \
+{                                                                                       \
+    const sw_vertex_t *prev = &input[n - 1];                                            \
+    int prevInside = FUNC_IS_INSIDE(prev->position);                                    \
+    int outputCount = 0;                                                                \
+                                                                                        \
+    for (int i = 0; i < n; i++) {                                                       \
+        const sw_vertex_t *curr = &input[i];                                            \
+        int currInside = FUNC_IS_INSIDE(curr->position);                                \
+                                                                                        \
+        /* If transition between interior/exterior, calculate intersection point */     \
+        if (prevInside != currInside) {                                                 \
+            float t = FUNC_COMPUTE_T(prev->position, curr->position);                   \
+            sw_lerp_vertex_PCT(&output[outputCount++], prev, curr, t);                  \
+        }                                                                               \
+                                                                                        \
+        /* If current vertex inside, add it */                                          \
+        if (currInside) {                                                               \
+            output[outputCount++] = *curr;                                              \
+        }                                                                               \
+                                                                                        \
+        prev = curr;                                                                    \
+        prevInside = currInside;                                                        \
+    }                                                                                   \
+                                                                                        \
+    return outputCount;                                                                 \
+}
+//-------------------------------------------------------------------------------------------
+
+// Frustum cliping functions
+//-------------------------------------------------------------------------------------------
+#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON)
+#define IS_INSIDE_PLANE_X_POS(h) ( (h)[0] <  (h)[3])        // Exclusive for +X
+#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <  (h)[3])        // Exclusive for -X
+#define IS_INSIDE_PLANE_Y_POS(h) ( (h)[1] <  (h)[3])        // Exclusive for +Y
+#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] <  (h)[3])        // Exclusive for -Y
+#define IS_INSIDE_PLANE_Z_POS(h) ( (h)[2] <= (h)[3])        // Inclusive for +Z
+#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3])        // Inclusive for -Z
+
+#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3]))
+#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0])))
+#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0])/(((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0])))
+#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1])/(((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1])))
+#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1])/(((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1])))
+#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2])/(((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2])))
+#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2])/(((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2])))
+
+DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W)
+DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS)
+DEFINE_CLIP_FUNC(x_neg, IS_INSIDE_PLANE_X_NEG, COMPUTE_T_PLANE_X_NEG)
+DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS)
+DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG)
+DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS)
+DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG)
+//-------------------------------------------------------------------------------------------
+
+// Scissor clip functions
+//-------------------------------------------------------------------------------------------
+#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3])))
+#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3])))
+#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3])))
+#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMax[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1])*(hPrev)[3])))
+
+#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0])*(h)[3])
+#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0])*(h)[3])
+#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1])*(h)[3])
+#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1])*(h)[3])
+
+DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN)
+DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX)
+DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN)
+DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX)
+//-------------------------------------------------------------------------------------------
+
+// Main polygon clip function
+static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter)
+{
+    static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES];
+
+    int n = *vertexCounter;
+
+    #define CLIP_AGAINST_PLANE(FUNC_CLIP)                       \
+    {                                                           \
+        n = FUNC_CLIP(tmp, polygon, n);                         \
+        if (n < 3)                                              \
+        {                                                       \
+            *vertexCounter = 0;                                 \
+            return false;                                       \
+        }                                                       \
+        for (int i = 0; i < n; i++) polygon[i] = tmp[i];        \
+    }
+
+    CLIP_AGAINST_PLANE(sw_clip_w);
+    CLIP_AGAINST_PLANE(sw_clip_x_pos);
+    CLIP_AGAINST_PLANE(sw_clip_x_neg);
+    CLIP_AGAINST_PLANE(sw_clip_y_pos);
+    CLIP_AGAINST_PLANE(sw_clip_y_neg);
+    CLIP_AGAINST_PLANE(sw_clip_z_pos);
+    CLIP_AGAINST_PLANE(sw_clip_z_neg);
+
+    if (RLSW.userState & SW_STATE_SCISSOR_TEST)
+    {
+        CLIP_AGAINST_PLANE(sw_clip_scissor_x_min);
+        CLIP_AGAINST_PLANE(sw_clip_scissor_x_max);
+        CLIP_AGAINST_PLANE(sw_clip_scissor_y_min);
+        CLIP_AGAINST_PLANE(sw_clip_scissor_y_max);
+    }
+
+    *vertexCounter = n;
+
+    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
+//-------------------------------------------------------------------------------------------
+#define SW_RASTER_TRIANGLE_STATE_MASK SW_FLAGS(COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND)
+
+#define SW_RASTER_TRIANGLE_STATES NONE
+#include __FILE__ // IWYU pragma: keep
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D, BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D, BLEND
+#include __FILE__
+#undef SW_RASTER_TRIANGLE_STATES
+
+#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
+//-------------------------------------------------------------------------------------------
+#define SW_RASTER_QUAD_STATE_MASK SW_FLAGS(COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND)
+
+#define SW_RASTER_QUAD_STATES NONE
+#include __FILE__ // IWYU pragma: keep
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES TEXTURE_2D
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES TEXTURE_2D, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES TEXTURE_2D, BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D, BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#define SW_RASTER_QUAD_STATES COLOR_INTERP, DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_QUAD_STATES
+
+#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
+//-------------------------------------------------------------------------------------------
+#define SW_RASTER_LINE_STATE_MASK SW_FLAGS(COLOR_INTERP, DEPTH_TEST, BLEND)
+
+#define SW_RASTER_LINE_STATES NONE
+#include __FILE__ // IWYU pragma: keep
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES COLOR_INTERP
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES BLEND
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES COLOR_INTERP, DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES COLOR_INTERP, BLEND
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+#define SW_RASTER_LINE_STATES COLOR_INTERP, DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_LINE_STATES
+
+// 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
+
+static const sw_raster_line_f SW_RASTER_LINE_TABLE[] = {
+    SW_RASTER_VARIANTS_3(SW_RASTER_ENTRY, sw_raster_line_)
+};
+//-------------------------------------------------------------------------------------------
+
+// Point rasterizer variant dispatch
+//-------------------------------------------------------------------------------------------
+#define SW_RASTER_POINT_STATE_MASK SW_FLAGS(DEPTH_TEST, BLEND)
+
+#define SW_RASTER_POINT_STATES NONE
+#include __FILE__ // IWYU pragma: keep
+#undef SW_RASTER_POINT_STATES
+
+#define SW_RASTER_POINT_STATES DEPTH_TEST
+#include __FILE__
+#undef SW_RASTER_POINT_STATES
+
+#define SW_RASTER_POINT_STATES BLEND
+#include __FILE__
+#undef SW_RASTER_POINT_STATES
+
+#define SW_RASTER_POINT_STATES DEPTH_TEST, BLEND
+#include __FILE__
+#undef SW_RASTER_POINT_STATES
+
+// 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
+
+static const sw_raster_point_f SW_RASTER_POINT_TABLE[] = {
+    SW_RASTER_VARIANTS_2(SW_RASTER_ENTRY, sw_raster_point_)
+};
+//-------------------------------------------------------------------------------------------
+
+// Triangle rendering logic
+//-------------------------------------------------------------------------------------------
+static bool sw_triangle_face_culling(void)
+{
+    // NOTE: Face culling is done before clipping to avoid unnecessary computations
+    // To handle triangles crossing the w=0 plane correctly,
+    // the winding order test is performeed in clip space directly,
+    // before the perspective division (division by w)
+    // This test determines the orientation of the triangle in the (x,y,w) plane,
+    // which corresponds to the projected 2D winding order sign,
+    // even with negative w values
+
+    // Preload clip coordinates into local variables
+    const float *p0 = RLSW.primitive.buffer[0].position;
+    const float *p1 = RLSW.primitive.buffer[1].position;
+    const float *p2 = RLSW.primitive.buffer[2].position;
+
+    // Compute a value proportional to the signed area in the projected 2D plane,
+    // calculated directly using clip coordinates BEFORE division by w
+    // This is the determinant of the matrix formed by the (x, y, w) components
+    // of the vertices, which correctly captures the winding order in clip
+    // space and its relationship to the projected 2D winding order, even with
+    // negative w values
+    // The determinant formula used here is:
+    // p0.x*(p1.y*p2.w - p2.y*p1.w) +
+    // p1.x*(p2.y*p0.w - p0.y*p2.w) +
+    // p2.x*(p0.y*p1.w - p1.y*p0.w)
+
+    const float sgnArea =
+        p0[0]*(p1[1]*p2[3] - p2[1]*p1[3]) +
+        p1[0]*(p2[1]*p0[3] - p0[1]*p2[3]) +
+        p2[0]*(p0[1]*p1[3] - p1[1]*p0[3]);
+
+    // Discard the triangle if its winding order (determined by the sign
+    // of the homogeneous area/determinant) matches the culled direction
+    // A positive sgnArea typically corresponds to a counter-clockwise
+    // winding in the projected space when all w > 0
+    // This test is robust for points with w > 0 or w < 0, correctly
+    // capturing the change in orientation when crossing the w=0 plane
+
+    // The culling logic remains the same based on the signed area/determinant
+    // A value of 0 for sgnArea means the points are collinear in (x, y, w)
+    // space, which corresponds to a degenerate triangle projection
+    // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
+    // and should be handled by the clipper if necessary
+    return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0) : (sgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise"
+}
+
+static void sw_triangle_clip_and_project(void)
+{
+    sw_vertex_t *polygon = RLSW.primitive.buffer;
+    int *vertexCounter = &RLSW.primitive.vertexCount;
+
+    if (sw_polygon_clip(polygon, vertexCounter))
+    {
+        // Transformation to screen space and normalization
+        for (int i = 0; i < *vertexCounter; i++)
+        {
+            sw_vertex_t *v = &polygon[i];
+
+            // Calculation of the reciprocal of W for normalization
+            // as well as perspective-correct attributes
+            const float wRcp = sw_rcp(v->position[3]);
+
+            // Division of XYZ coordinates by weight
+            v->position[0] *= wRcp;
+            v->position[1] *= wRcp;
+            v->position[2] *= wRcp;
+            v->position[3] = wRcp;
+
+            // Division of texture coordinates (perspective-correct)
+            v->texcoord[0] *= wRcp;
+            v->texcoord[1] *= wRcp;
+
+            // Division of colors (perspective-correct)
+            v->color[0] *= wRcp;
+            v->color[1] *= wRcp;
+            v->color[2] *= wRcp;
+            v->color[3] *= wRcp;
+
+            // Transformation to screen space
+            sw_project_ndc_to_screen(v->position);
+        }
+    }
+}
+
+static void sw_triangle_render(uint32_t state)
+{
+    if (RLSW.userState & SW_STATE_CULL_FACE)
+    {
+        if (!sw_triangle_face_culling()) return;
+    }
+
+    sw_triangle_clip_and_project();
+    if (RLSW.primitive.vertexCount < 3) return;
+
+    state &= SW_RASTER_TRIANGLE_STATE_MASK;
+
+    for (int i = 0; i < RLSW.primitive.vertexCount - 2; i++)
+    {
+        SW_RASTER_TRIANGLE_TABLE[state](
+            &RLSW.primitive.buffer[0],
+            &RLSW.primitive.buffer[i + 1],
+            &RLSW.primitive.buffer[i + 2]
+        );
+    }
+}
+//-------------------------------------------------------------------------------------------
+
+// Quad rendering logic
+//-------------------------------------------------------------------------------------------
+static bool sw_quad_face_culling(void)
+{
+    // NOTE: Face culling is done before clipping to avoid unnecessary computations
+    // To handle quads crossing the w=0 plane correctly,
+    // the winding order test is performed in clip space directly,
+    // before the perspective division (division by w)
+    // For a convex quad with vertices P0, P1, P2, P3 in sequential order,
+    // the winding order of the quad is the same as the winding order
+    // of the triangle P0 P1 P2. The triangle in clip space is used on
+    // winding test on this first triangle
+
+    // Preload clip coordinates into local variables
+    const float *p0 = RLSW.primitive.buffer[0].position;
+    const float *p1 = RLSW.primitive.buffer[1].position;
+    const float *p2 = RLSW.primitive.buffer[2].position;
+
+    // NOTE: h3 is not needed for this test
+    // const float *h3 = RLSW.primitive.buffer[3].position;
+
+    // Compute a value proportional to the signed area of the triangle P0 P1 P2
+    // in the projected 2D plane, calculated directly using clip coordinates
+    // BEFORE division by w
+    // This is the determinant of the matrix formed by the (x, y, w) components
+    // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order
+    // in clip space and its relationship to the projected 2D winding order,
+    // even with negative w values
+    // The determinant formula used here is:
+    // p0.x*(p1.y*p2.w - p2.y*p1.w) +
+    // p1.x*(p2.y*p0.w - p0.y*p2.w) +
+    // p2.x*(p0.y*p1.w - p1.y*p0.w)
+
+    const float sgnArea =
+        p0[0]*(p1[1]*p2[3] - p2[1]*p1[3]) +
+        p1[0]*(p2[1]*p0[3] - p0[1]*p2[3]) +
+        p2[0]*(p0[1]*p1[3] - p1[1]*p0[3]);
+
+    // Perform face culling based on the winding order determined by the sign
+    // of the homogeneous area/determinant of triangle P0 P1 P2
+    // This test is robust for points with w > 0 or w < 0 within the triangle,
+    // correctly capturing the change in orientation when crossing the w=0 plane
+
+    // A positive sgnArea typically corresponds to a counter-clockwise
+    // winding in the projected space when all w > 0
+    // A value of 0 for sgnArea means P0, P1, P2 are collinear in (x, y, w)
+    // space, which corresponds to a degenerate triangle projection
+    // Such quads might also be degenerate or non-planar
+    // They are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
+    // and should be handled by the clipper if necessary
+
+    return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0.0f) : (sgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
+}
+
+static void sw_quad_clip_and_project(void)
+{
+    sw_vertex_t *polygon = RLSW.primitive.buffer;
+    int *vertexCounter = &RLSW.primitive.vertexCount;
+
+    if (sw_polygon_clip(polygon, vertexCounter))
+    {
+        // Transformation to screen space and normalization
+        for (int i = 0; i < *vertexCounter; i++)
+        {
+            sw_vertex_t *v = &polygon[i];
+
+            // Calculation of the reciprocal of W for normalization
+            // as well as perspective-correct attributes
+            const float wRcp = sw_rcp(v->position[3]);
+
+            // Division of XYZ coordinates by weight
+            v->position[0] *= wRcp;
+            v->position[1] *= wRcp;
+            v->position[2] *= wRcp;
+            v->position[3] = wRcp;
+
+            // Division of texture coordinates (perspective-correct)
+            v->texcoord[0] *= wRcp;
+            v->texcoord[1] *= wRcp;
+
+            // Division of colors (perspective-correct)
+            v->color[0] *= wRcp;
+            v->color[1] *= wRcp;
+            v->color[2] *= wRcp;
+            v->color[3] *= wRcp;
+
+            // Transformation to screen space
+            sw_project_ndc_to_screen(v->position);
+        }
+    }
+}
+
+static bool sw_quad_is_axis_aligned(void)
+{
+    // Reject quads with perspective projection
+    // The fast path assumes affine (non-perspective) quads,
+    // so it's required for all vertices to have homogeneous w = 1.0
+    for (int i = 0; i < 4; i++)
+    {
+        if (RLSW.primitive.buffer[i].position[3] != 1.0f) return false;
+    }
+
+    // Epsilon tolerance in screen space (pixels)
+    const float epsilon = 0.5f;
+
+    // Fetch screen-space positions for the four quad vertices
+    const float *p0 = RLSW.primitive.buffer[0].position;
+    const float *p1 = RLSW.primitive.buffer[1].position;
+    const float *p2 = RLSW.primitive.buffer[2].position;
+    const float *p3 = RLSW.primitive.buffer[3].position;
+
+    // Compute edge vectors between consecutive vertices
+    // These define the four sides of the quad in screen space
+    float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1];
+    float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1];
+    float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1];
+    float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1];
+
+    // Each edge must be either horizontal or vertical within epsilon tolerance
+    // If any edge deviates significantly from either axis, the quad is not axis-aligned
+    if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false;
+    if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false;
+    if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false;
+    if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false;
+
+    return true;
+}
+
+static void sw_quad_render(uint32_t state)
+{
+    if (RLSW.userState & SW_STATE_CULL_FACE)
+    {
+        if (!sw_quad_face_culling()) return;
+    }
+
+    sw_quad_clip_and_project();
+    if (RLSW.primitive.vertexCount < 3) return;
+
+    state &= SW_RASTER_QUAD_STATE_MASK;
+
+    if ((RLSW.primitive.vertexCount == 4) && sw_quad_is_axis_aligned())
+    {
+        SW_RASTER_QUAD_TABLE[state](
+            &RLSW.primitive.buffer[0],
+            &RLSW.primitive.buffer[1],
+            &RLSW.primitive.buffer[2],
+            &RLSW.primitive.buffer[3]
+        );
+    }
+    else
+    {
+        for (int i = 0; i < RLSW.primitive.vertexCount - 2; i++)
+        {
+            SW_RASTER_TRIANGLE_TABLE[state](
+                &RLSW.primitive.buffer[0],
+                &RLSW.primitive.buffer[i + 1],
+                &RLSW.primitive.buffer[i + 2]
+            );
+        }
+    }
+}
+//-------------------------------------------------------------------------------------------
+
+// Line rendering logic
+//-------------------------------------------------------------------------------------------
+static bool sw_line_clip_coord(float q, float p, float *t0, float *t1)
+{
+    if (fabsf(p) < SW_CLIP_EPSILON)
+    {
+        // Check if the line is entirely outside the window
+        if (q < -SW_CLIP_EPSILON) return 0; // Completely outside
+        return 1; // Completely inside or on the edges
+    }
+
+    const float r = q/p;
+
+    if (p < 0)
+    {
+        if (r > *t1) return 0;
+        if (r > *t0) *t0 = r;
+    }
+    else
+    {
+        if (r < *t0) return 0;
+        if (r < *t1) *t1 = r;
+    }
+
+    return 1;
+}
+
+static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1)
+{
+    float t0 = 0.0f, t1 = 1.0f;
+    float dH[4] = { 0 };
+    float dC[4] = { 0 };
+
+    for (int i = 0; i < 4; i++)
+    {
+        dH[i] = v1->position[i] - v0->position[i];
+        dC[i] = v1->color[i] - v0->color[i];
+    }
+
+    // Clipping Liang-Barsky
+    if (!sw_line_clip_coord(v0->position[3] - v0->position[0], -dH[3] + dH[0], &t0, &t1)) return false;
+    if (!sw_line_clip_coord(v0->position[3] + v0->position[0], -dH[3] - dH[0], &t0, &t1)) return false;
+    if (!sw_line_clip_coord(v0->position[3] - v0->position[1], -dH[3] + dH[1], &t0, &t1)) return false;
+    if (!sw_line_clip_coord(v0->position[3] + v0->position[1], -dH[3] - dH[1], &t0, &t1)) return false;
+    if (!sw_line_clip_coord(v0->position[3] - v0->position[2], -dH[3] + dH[2], &t0, &t1)) return false;
+    if (!sw_line_clip_coord(v0->position[3] + v0->position[2], -dH[3] - dH[2], &t0, &t1)) return false;
+
+    // Clipping Scissor
+    if (RLSW.userState & SW_STATE_SCISSOR_TEST)
+    {
+        if (!sw_line_clip_coord(v0->position[0] - RLSW.scClipMin[0]*v0->position[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false;
+        if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->position[3] - v0->position[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false;
+        if (!sw_line_clip_coord(v0->position[1] - RLSW.scClipMin[1]*v0->position[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false;
+        if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->position[3] - v0->position[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false;
+    }
+
+    // Interpolation of new coordinates
+    if (t1 < 1.0f)
+    {
+        for (int i = 0; i < 4; i++)
+        {
+            v1->position[i] = v0->position[i] + t1*dH[i];
+            v1->color[i] = v0->color[i] + t1*dC[i];
+        }
+    }
+
+    if (t0 > 0.0f)
+    {
+        for (int i = 0; i < 4; i++)
+        {
+            v0->position[i] += t0*dH[i];
+            v0->color[i] += t0*dC[i];
+        }
+    }
+
+    return true;
+}
+
+static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
+{
+    if (!sw_line_clip(v0, v1)) return false;
+
+    // Convert clip coordinates to NDC
+    v0->position[3] = sw_rcp(v0->position[3]);
+    v1->position[3] = sw_rcp(v1->position[3]);
+    for (int i = 0; i < 3; i++)
+    {
+        v0->position[i] *= v0->position[3];
+        v1->position[i] *= v1->position[3];
+    }
+
+    // Convert NDC coordinates to screen space
+    sw_project_ndc_to_screen(v0->position);
+    sw_project_ndc_to_screen(v1->position);
+
+    // NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds
+    // The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible
+    v0->position[0] = sw_clamp(v0->position[0], 0.0f, (float)(RLSW.colorBuffer->width  - 1) + 0.5f);
+    v0->position[1] = sw_clamp(v0->position[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f);
+    v1->position[0] = sw_clamp(v1->position[0], 0.0f, (float)(RLSW.colorBuffer->width  - 1) + 0.5f);
+    v1->position[1] = sw_clamp(v1->position[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f);
+
+    return true;
+}
+
+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;
+    SW_RASTER_LINE_TABLE[state](&vertices[0], &vertices[1]);
+}
+//-------------------------------------------------------------------------------------------
+
+// Point rendering logic
+//-------------------------------------------------------------------------------------------
+static bool sw_point_clip_and_project(sw_vertex_t *v)
+{
+    if (v->position[3] != 1.0f)
+    {
+        for (int_fast8_t i = 0; i < 3; i++)
+        {
+            if ((v->position[i] < -v->position[3]) || (v->position[i] > v->position[3])) return false;
+        }
+
+        v->position[3] = sw_rcp(v->position[3]);
+        v->position[0] *= v->position[3];
+        v->position[1] *= v->position[3];
+        v->position[2] *= v->position[3];
+    }
+
+    sw_project_ndc_to_screen(v->position);
+
+    int min[2] = { 0, 0 };
+    int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height };
+
+    if (RLSW.userState & SW_STATE_SCISSOR_TEST)
+    {
+        min[0] = sw_clamp_int(RLSW.scMin[0], 0, RLSW.colorBuffer->width);
+        min[1] = sw_clamp_int(RLSW.scMin[1], 0, RLSW.colorBuffer->height);
+        max[0] = sw_clamp_int(RLSW.scMax[0], 0, RLSW.colorBuffer->width);
+        max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height);
+    }
+
+    bool insideX = (v->position[0] - RLSW.pointRadius < max[0]) && (v->position[0] + RLSW.pointRadius > min[0]);
+    bool insideY = (v->position[1] - RLSW.pointRadius < max[1]) && (v->position[1] + RLSW.pointRadius > min[1]);
+
+    return (insideX && insideY);
+}
+
+static void sw_point_render(uint32_t state, sw_vertex_t *v)
+{
+    if (!sw_point_clip_and_project(v)) return;
+    state &= SW_RASTER_POINT_STATE_MASK;
+    SW_RASTER_POINT_TABLE[state](v);
+}
+//-------------------------------------------------------------------------------------------
+
+// Polygon modes rendering logic
+//-------------------------------------------------------------------------------------------
+static void sw_poly_point_render(uint32_t state)
+{
+    for (int i = 0; i < RLSW.primitive.vertexCount; i++) sw_point_render(state, &RLSW.primitive.buffer[i]);
+}
+
+static void sw_poly_line_render(uint32_t state)
+{
+    const sw_vertex_t *vertices = RLSW.primitive.buffer;
+    int cm1 = RLSW.primitive.vertexCount - 1;
+
+    for (int i = 0; i < cm1; i++)
+    {
+        sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] };
+        sw_line_render(state, verts);
+    }
+
+    sw_vertex_t verts[2] = { vertices[cm1], vertices[0] };
+    sw_line_render(state, verts);
+}
+
+static void sw_poly_fill_render(uint32_t state)
+{
+    switch (RLSW.drawMode)
+    {
+        case SW_POINTS: sw_point_render(state, &RLSW.primitive.buffer[0]); break;
+        case SW_LINES: sw_line_render(state, RLSW.primitive.buffer); break;
+        case SW_TRIANGLES: sw_triangle_render(state); break;
+        case SW_QUADS: sw_quad_render(state); break;
+        default: break;
+    }
+}
+//-------------------------------------------------------------------------------------------
+
+// Immediate rendering logic
+//-------------------------------------------------------------------------------------------
+static void sw_immediate_begin(SWdraw mode)
+{
+    // NOTE: Any checks to ensure command recording can start must be performed before calling this function
+
+    // Recalculate the MVP if this is needed
+    if (RLSW.isDirtyMVP)
+    {
+        sw_matrix_mul_rst(RLSW.matMVP,
+            RLSW.stackModelview[RLSW.stackModelviewCounter - 1],
+            RLSW.stackProjection[RLSW.stackProjectionCounter - 1]);
+
+#ifdef SW_HAS_ESP_DSP
+        // Pre-transpose to row-major so dspm_mult_4x4x1_f32(matMVP_rm, v, out)
+        // computes M*v directly in the per-vertex hot path; 16 scalar copies
+        // per MVP update vs saving ~20 cycles per vertex transform
+        for (int i = 0; i < 4; i++)
+        {
+            for (int j = 0; j < 4; j++)
+            {
+                RLSW.matMVP_rm[4*i + j] = RLSW.matMVP[4*j + i];
+            }
+        }
+#endif
+
+        RLSW.isDirtyMVP = false;
+    }
+
+    // Disable pipeline states that are incompatible with the global state
+    uint32_t state = RLSW.userState;
+    if (!sw_is_texture_complete(RLSW.depthBuffer)) state &= ~SW_STATE_DEPTH_TEST;
+    if (!sw_is_texture_complete(RLSW.boundTexture)) state &= ~SW_STATE_TEXTURE_2D;
+    else if (sw_pixel_is_depth_format(RLSW.boundTexture->format)) state &= ~SW_STATE_TEXTURE_2D;
+
+    // Initialize required values
+    RLSW.primitive.hasColorAlpha = false;
+    RLSW.primitive.vertexCount = 0;
+    RLSW.rasterState = state;
+    RLSW.drawMode = mode;
+}
+
+static bool sw_immediate_is_active(void)
+{
+    return (RLSW.drawMode != SW_DRAW_INVALID);
+}
+
+static void sw_immediate_set_color(const float color[4])
+{
+    RLSW.primitive.color[0] = color[0];
+    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])
+{
+    const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
+    RLSW.primitive.texcoord[0] = m[0]*texcoord[0] + m[4]*texcoord[1] + m[12];
+    RLSW.primitive.texcoord[1] = m[1]*texcoord[0] + m[5]*texcoord[1] + m[13];
+}
+
+static void sw_immediate_push_vertex(const float position[4])
+{
+    // Check if the draw mode is valid
+    if (!sw_is_draw_mode_valid(RLSW.drawMode))
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    // Gets the current vertex
+    sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++];
+
+    // Calculate clip coordinates
+#ifdef SW_HAS_ESP_DSP
+    // dspm_mult_4x4x1_f32 declares its inputs non-const; rlsw treats them as
+    // read-only and the cast is safe (the kernel only loads from B)
+    dspm_mult_4x4x1_f32(RLSW.matMVP_rm, (float *)position, vertex->position);
+#else
+    const float *m = RLSW.matMVP;
+    vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3];
+    vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3];
+    vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3];
+    vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3];
+#endif
+
+    // Copy the attributes in the current vertex
+    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])
+    {
+        uint32_t state = RLSW.rasterState;
+
+        // Reduces blend mode costs when it's possible
+        if (state & SW_STATE_BLEND)
+        {
+            if (RLSW.blendFlags & SW_BLEND_FLAG_NOOP) state &= ~SW_STATE_BLEND;
+            else if ((RLSW.blendFlags & SW_BLEND_FLAG_NEEDS_ALPHA) && (!RLSW.primitive.hasColorAlpha))
+            {
+                if (!(state & SW_STATE_TEXTURE_2D) || (RLSW.boundTexture->alpha == SW_PIXEL_ALPHA_NONE)) state &= ~SW_STATE_BLEND;
+            }
+        }
+
+        // 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;
+            case SW_LINE: sw_poly_line_render(state); break;
+            case SW_POINT: sw_poly_point_render(state); break;
+            default: break;
+        }
+
+        RLSW.primitive.hasColorAlpha = false;
+        RLSW.primitive.vertexCount = 0;
+    }
+}
+
+static void sw_immediate_end(void)
+{
+    RLSW.drawMode = SW_DRAW_INVALID;
+}
+//-------------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+bool swInit(int w, int h)
+{
+    if (!sw_default_framebuffer_alloc(&RLSW.framebuffer, w, h))
+    {
+        swClose();
+        return false;
+    }
+
+    if (!sw_pool_init(&RLSW.framebufferPool, RLSW_MAX_FRAMEBUFFERS, sizeof(sw_framebuffer_t)))
+    {
+        swClose();
+        return false;
+    }
+
+    if (!sw_pool_init(&RLSW.texturePool, RLSW_MAX_TEXTURES, sizeof(sw_texture_t)))
+    {
+        swClose();
+        return false;
+    }
+
+    RLSW.colorBuffer = &RLSW.framebuffer.color;
+    RLSW.depthBuffer = &RLSW.framebuffer.depth;
+
+    swViewport(0, 0, w, h);
+    swScissor(0, 0, w, h);
+
+    RLSW.clearColor[0] = 0.0f;
+    RLSW.clearColor[1] = 0.0f;
+    RLSW.clearColor[2] = 0.0f;
+    RLSW.clearColor[3] = 1.0f;
+    RLSW.clearDepth = 1.0f;
+
+    RLSW.currentMatrixMode = SW_MODELVIEW;
+    RLSW.currentMatrix = &RLSW.stackModelview[0];
+
+    sw_matrix_id(RLSW.stackProjection[0]);
+    sw_matrix_id(RLSW.stackModelview[0]);
+    sw_matrix_id(RLSW.stackTexture[0]);
+    sw_matrix_id(RLSW.matMVP);
+
+    RLSW.stackProjectionCounter = 1;
+    RLSW.stackModelviewCounter = 1;
+    RLSW.stackTextureCounter = 1;
+    RLSW.isDirtyMVP = false;
+
+    RLSW.primitive.texcoord[0] = 0.0f;
+    RLSW.primitive.texcoord[1] = 0.0f;
+
+    RLSW.primitive.color[0] = 1.0f;
+    RLSW.primitive.color[1] = 1.0f;
+    RLSW.primitive.color[2] = 1.0f;
+    RLSW.primitive.color[3] = 1.0f;
+
+    RLSW.srcFactor = SW_SRC_ALPHA;
+    RLSW.dstFactor = SW_ONE_MINUS_SRC_ALPHA;
+    RLSW.blendFunc = sw_blend_SRC_ALPHA_ONE_MINUS_SRC_ALPHA;
+
+    RLSW.drawMode = SW_DRAW_INVALID;
+    RLSW.polyMode = SW_FILL;
+    RLSW.cullFace = SW_BACK;
+
+#if RLSW_USE_COLOR_LUT
+    for (int i = 0; i < 256; i++) SW_LUT_UINT8_TO_FLOAT[i] = (float)i*SW_INV_255;
+#endif
+
+    SW_LOG("INFO: RLSW: Software renderer initialized successfully\n");
+#if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2)
+    SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n");
+#endif
+#if defined(SW_HAS_AVX) || defined(SW_HAS_AVX2)
+    SW_LOG("INFO: RLSW: Using SIMD instructions: AVX\n");
+#endif
+#if defined(SW_HAS_SSE) || defined(SW_HAS_SSE2) || defined(SW_HAS_SSE3) || defined(SW_HAS_SSSE3) || defined(SW_HAS_SSE41) || defined(SW_HAS_SSE42)
+    SW_LOG("INFO: RLSW: Using SIMD instructions: SSE\n");
+#endif
+#if defined(SW_HAS_NEON_FMA) || defined(SW_HAS_NEON)
+    SW_LOG("INFO: RLSW: Using SIMD instructions: NEON\n");
+#endif
+#if defined(SW_HAS_RVV)
+    SW_LOG("INFO: RLSW: Using SIMD instructions: RVV\n");
+#endif
+
+    return true;
+}
+
+void swClose(void)
+{
+    for (int i = 1; i < RLSW.texturePool.watermark; i++)
+    {
+        if (RLSW.texturePool.gen[i] & SW_POOL_SLOT_LIVE)
+        {
+            sw_texture_free((sw_texture_t *)RLSW.texturePool.data + i);
+        }
+    }
+
+    sw_pool_destroy(&RLSW.texturePool);
+    sw_pool_destroy(&RLSW.framebufferPool);
+    sw_default_framebuffer_free(&RLSW.framebuffer);
+
+    RLSW = SW_CURLY_INIT(sw_context_t) { 0 };
+}
+
+bool swResize(int w, int h)
+{
+    return sw_default_framebuffer_alloc(&RLSW.framebuffer, w, h);
+}
+
+void swReadPixels(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels)
+{
+    // REVIEW: Handle depth buffer copy here or consider it as an error ?
+    if (format == SW_DEPTH_COMPONENT) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_pixel_get_format(format, type);
+    if (pFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    if (w <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+    if (h <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+
+    if (w > RLSW.colorBuffer->width) w = RLSW.colorBuffer->width;
+    if (h > RLSW.colorBuffer->height) h = RLSW.colorBuffer->height;
+
+    x = sw_clamp_int(x, 0, w);
+    y = sw_clamp_int(y, 0, h);
+
+    if ((x >= w) || (y >= h)) return;
+
+    if ((pFormat == SW_FRAMEBUFFER_COLOR_FORMAT) && (x == 0) && (y == 0) && (w == RLSW.colorBuffer->width) && (h == RLSW.colorBuffer->height))
+    {
+        sw_framebuffer_output_fast(pixels, RLSW.colorBuffer);
+    }
+    else
+    {
+        sw_framebuffer_output_copy(pixels, RLSW.colorBuffer, x, y, w, h, pFormat);
+    }
+}
+
+void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels)
+{
+    // REVIEW: Handle depth buffer copy here or consider it as an error ?
+    if (format == SW_DEPTH_COMPONENT) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_pixel_get_format(format, type);
+    if (pFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+    if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+
+    if (wSrc > RLSW.colorBuffer->width) wSrc = RLSW.colorBuffer->width;
+    if (hSrc > RLSW.colorBuffer->height) hSrc = RLSW.colorBuffer->height;
+
+    xSrc = sw_clamp_int(xSrc, 0, wSrc);
+    ySrc = sw_clamp_int(ySrc, 0, hSrc);
+
+    // Check if the sizes are identical after clamping the source to avoid unexpected issues
+    // TODO: REVIEW: This repeats the operations if true, so a copy function can be made without these checks
+    if ((xDst == xSrc) && (yDst == ySrc) && (wDst == wSrc) && (hDst == hSrc))
+    {
+        swReadPixels(xSrc, ySrc, wSrc, hSrc, format, type, pixels);
+    }
+    else
+    {
+        sw_framebuffer_output_blit(pixels, RLSW.colorBuffer, xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pFormat);
+    }
+}
+
+// Get framefuffer pixel data pointer and size
+void *swGetColorBuffer(int *width, int *height)
+{
+    if (width != NULL) *width = RLSW.framebuffer.color.width;
+    if (height != NULL) *height = RLSW.framebuffer.color.height;
+    return RLSW.framebuffer.color.pixels;
+}
+
+
+void swSwapColorBuffers(void)
+{
+#if RLSW_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 RLSW_DOUBLE_BUFFERING=1)\n");
+#endif
+}
+
+
+void swEnable(SWstate state)
+{
+    switch (state)
+    {
+        case SW_SCISSOR_TEST: RLSW.userState |= SW_STATE_SCISSOR_TEST; break;
+        case SW_TEXTURE_2D: RLSW.userState |= SW_STATE_TEXTURE_2D; break;
+        case SW_DEPTH_TEST: RLSW.userState |= SW_STATE_DEPTH_TEST; break;
+        case SW_CULL_FACE: RLSW.userState |= SW_STATE_CULL_FACE; break;
+        case SW_BLEND: RLSW.userState |= SW_STATE_BLEND; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+void swDisable(SWstate state)
+{
+    switch (state)
+    {
+        case SW_SCISSOR_TEST: RLSW.userState &= ~SW_STATE_SCISSOR_TEST; break;
+        case SW_TEXTURE_2D: RLSW.userState &= ~SW_STATE_TEXTURE_2D; break;
+        case SW_DEPTH_TEST: RLSW.userState &= ~SW_STATE_DEPTH_TEST; break;
+        case SW_CULL_FACE: RLSW.userState &= ~SW_STATE_CULL_FACE; break;
+        case SW_BLEND: RLSW.userState &= ~SW_STATE_BLEND; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+void swGetIntegerv(SWget name, int *v)
+{
+    switch (name)
+    {
+        case SW_MODELVIEW_STACK_DEPTH: *v = SW_MODELVIEW_STACK_DEPTH; break;
+        case SW_PROJECTION_STACK_DEPTH: *v = SW_PROJECTION_STACK_DEPTH; break;
+        case SW_TEXTURE_STACK_DEPTH: *v = SW_TEXTURE_STACK_DEPTH; break;
+        case SW_DRAW_FRAMEBUFFER_BINDING: *v = RLSW.boundFramebufferId; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+void swGetFloatv(SWget name, float *v)
+{
+    switch (name)
+    {
+        case SW_COLOR_CLEAR_VALUE:
+        {
+            v[0] = RLSW.clearColor[0];
+            v[1] = RLSW.clearColor[1];
+            v[2] = RLSW.clearColor[2];
+            v[3] = RLSW.clearColor[3];
+        } break;
+        case SW_DEPTH_CLEAR_VALUE:
+        {
+            v[0] = RLSW.clearDepth;
+        } break;
+        case SW_CURRENT_COLOR:
+        {
+            v[0] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[0];
+            v[1] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[1];
+            v[2] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[2];
+            v[3] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[3];
+        } break;
+        case SW_CURRENT_TEXTURE_COORDS:
+        {
+            v[0] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].texcoord[0];
+            v[1] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].texcoord[1];
+        } break;
+        case SW_POINT_SIZE:
+        {
+            v[0] = 2.0f*RLSW.pointRadius;
+        } break;
+        case SW_LINE_WIDTH:
+        {
+            v[0] = RLSW.lineWidth;
+        } break;
+        case SW_MODELVIEW_MATRIX:
+        {
+            for (int i = 0; i < 16; i++) v[i] = RLSW.stackModelview[RLSW.stackModelviewCounter - 1][i];
+
+        } break;
+        case SW_PROJECTION_MATRIX:
+        {
+            for (int i = 0; i < 16; i++) v[i] = RLSW.stackProjection[RLSW.stackProjectionCounter - 1][i];
+
+        } break;
+        case SW_TEXTURE_MATRIX:
+        {
+            for (int i = 0; i < 16; i++) v[i] = RLSW.stackTexture[RLSW.stackTextureCounter - 1][i];
+
+        } break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+const char *swGetString(SWget name)
+{
+    const char *result = NULL;
+
+    switch (name)
+    {
+        case SW_VENDOR: result = "RLSW"; break;
+        case SW_RENDERER: result = "RLSW OpenGL Software Renderer"; break;
+        case SW_VERSION: result = RLSW_VERSION; break;
+        case SW_EXTENSIONS: result = "None"; break;
+        case SW_SHADING_LANGUAGE_VERSION: result = "Not supported"; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+
+    return result;
+}
+
+SWerrcode swGetError(void)
+{
+    SWerrcode ret = RLSW.errCode;
+    RLSW.errCode = SW_NO_ERROR;
+    return ret;
+}
+
+void swViewport(int x, int y, int width, int height)
+{
+    if ((width < 0) || (height < 0))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    RLSW.vpSize[0] = width;
+    RLSW.vpSize[1] = height;
+
+    RLSW.vpHalf[0] = width/2.0f;
+    RLSW.vpHalf[1] = height/2.0f;
+
+    RLSW.vpCenter[0] = (float)x + RLSW.vpHalf[0];
+    RLSW.vpCenter[1] = (float)y + RLSW.vpHalf[1];
+}
+
+void swScissor(int x, int y, int width, int height)
+{
+    if ((width < 0) || (height < 0))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    RLSW.scMin[0] = x;
+    RLSW.scMin[1] = y;
+    RLSW.scMax[0] = x + width;
+    RLSW.scMax[1] = y + 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.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)
+{
+    RLSW.clearColor[0] = r;
+    RLSW.clearColor[1] = g;
+    RLSW.clearColor[2] = b;
+    RLSW.clearColor[3] = a;
+}
+
+void swClearDepth(float depth)
+{
+    RLSW.clearDepth = depth;
+}
+
+void swClear(uint32_t bitmask)
+{
+    if (!sw_is_ready_to_render()) return;
+
+    if ((bitmask & (SW_COLOR_BUFFER_BIT)) && (RLSW.colorBuffer != NULL) && (RLSW.colorBuffer->pixels != NULL))
+    {
+        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);
+    }
+}
+
+void swBlendFunc(SWfactor sfactor, SWfactor dfactor)
+{
+    int sIndex = sw_blend_factor_index(sfactor);
+    if (sIndex < 0) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    int dIndex = sw_blend_factor_index(dfactor);
+    if (dIndex < 0) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    RLSW.srcFactor = sfactor;
+    RLSW.dstFactor = dfactor;
+    RLSW.blendFlags = sw_blend_compute_flags(sfactor, dfactor);
+    RLSW.blendFunc = SW_BLEND_TABLE[sIndex][dIndex];
+}
+
+void swPolygonMode(SWpoly mode)
+{
+    if (!sw_is_poly_mode_valid(mode))
+    {
+        RLSW.errCode = SW_INVALID_ENUM;
+        return;
+    }
+
+    RLSW.polyMode = mode;
+}
+
+void swCullFace(SWface face)
+{
+    if (!sw_is_face_valid(face))
+    {
+        RLSW.errCode = SW_INVALID_ENUM;
+        return;
+    }
+
+    RLSW.cullFace = face;
+}
+
+void swPointSize(float size)
+{
+    RLSW.pointRadius = floorf(size*0.5f);
+}
+
+void swLineWidth(float width)
+{
+    RLSW.lineWidth = roundf(width);
+}
+
+void swMatrixMode(SWmatrix mode)
+{
+    switch (mode)
+    {
+        case SW_PROJECTION: RLSW.currentMatrix = &RLSW.stackProjection[RLSW.stackProjectionCounter - 1]; break;
+        case SW_MODELVIEW: RLSW.currentMatrix = &RLSW.stackModelview[RLSW.stackModelviewCounter - 1]; break;
+        case SW_TEXTURE: RLSW.currentMatrix = &RLSW.stackTexture[RLSW.stackTextureCounter - 1]; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; return;
+    }
+
+    RLSW.currentMatrixMode = mode;
+}
+
+void swPushMatrix(void)
+{
+    switch (RLSW.currentMatrixMode)
+    {
+        case SW_PROJECTION:
+        {
+            if (RLSW.stackProjectionCounter >= RLSW_MAX_PROJECTION_STACK_SIZE)
+            {
+                RLSW.errCode = SW_STACK_OVERFLOW;
+                return;
+            }
+
+            int iOld = RLSW.stackProjectionCounter - 1;
+            int iNew = RLSW.stackProjectionCounter++;
+
+            for (int i = 0; i < 16; i++)
+            {
+                RLSW.stackProjection[iNew][i] = RLSW.stackProjection[iOld][i];
+            }
+
+            RLSW.currentMatrix = &RLSW.stackProjection[iNew];
+        } break;
+        case SW_MODELVIEW:
+        {
+            if (RLSW.stackModelviewCounter >= RLSW_MAX_MODELVIEW_STACK_SIZE)
+            {
+                RLSW.errCode = SW_STACK_OVERFLOW;
+                return;
+            }
+
+            int iOld = RLSW.stackModelviewCounter - 1;
+            int iNew = RLSW.stackModelviewCounter++;
+
+            for (int i = 0; i < 16; i++)
+            {
+                RLSW.stackModelview[iNew][i] = RLSW.stackModelview[iOld][i];
+            }
+
+            RLSW.currentMatrix = &RLSW.stackModelview[iNew];
+        } break;
+        case SW_TEXTURE:
+        {
+            if (RLSW.stackTextureCounter >= RLSW_MAX_TEXTURE_STACK_SIZE)
+            {
+                RLSW.errCode = SW_STACK_OVERFLOW;
+                return;
+            }
+
+            int iOld = RLSW.stackTextureCounter - 1;
+            int iNew = RLSW.stackTextureCounter++;
+
+            for (int i = 0; i < 16; i++)
+            {
+                RLSW.stackTexture[iNew][i] = RLSW.stackTexture[iOld][i];
+            }
+
+            RLSW.currentMatrix = &RLSW.stackTexture[iNew];
+        } break;
+        default: break;
+    }
+}
+
+void swPopMatrix(void)
+{
+    switch (RLSW.currentMatrixMode)
+    {
+        case SW_PROJECTION:
+        {
+            if (RLSW.stackProjectionCounter <= 0)
+            {
+                RLSW.errCode = SW_STACK_UNDERFLOW;
+                return;
+            }
+
+            RLSW.currentMatrix = &RLSW.stackProjection[(--RLSW.stackProjectionCounter) - 1];
+            RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed
+        } break;
+        case SW_MODELVIEW:
+        {
+            if (RLSW.stackModelviewCounter <= 0)
+            {
+                RLSW.errCode = SW_STACK_UNDERFLOW;
+                return;
+            }
+
+            RLSW.currentMatrix = &RLSW.stackModelview[(--RLSW.stackModelviewCounter) - 1];
+            RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed
+        } break;
+        case SW_TEXTURE:
+        {
+            if (RLSW.stackTextureCounter <= 0)
+            {
+                RLSW.errCode = SW_STACK_UNDERFLOW;
+                return;
+            }
+
+            RLSW.currentMatrix = &RLSW.stackTexture[(--RLSW.stackTextureCounter) - 1];
+        } break;
+        default: break;
+    }
+}
+
+void swLoadIdentity(void)
+{
+    sw_matrix_id(*RLSW.currentMatrix);
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swTranslatef(float x, float y, float z)
+{
+    sw_matrix_t mat = { 0 };
+    sw_matrix_id(mat);
+
+    mat[12] = x;
+    mat[13] = y;
+    mat[14] = z;
+
+    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swRotatef(float angle, float x, float y, float z)
+{
+    angle *= SW_DEG2RAD;
+
+    float lengthSq = x*x + y*y + z*z;
+
+    if ((lengthSq != 1.0f) && (lengthSq != 0.0f))
+    {
+        float invLength = 1.0f/sqrtf(lengthSq);
+        x *= invLength;
+        y *= invLength;
+        z *= invLength;
+    }
+
+    float sinres = sinf(angle);
+    float cosres = cosf(angle);
+    float t = 1.0f - cosres;
+
+    sw_matrix_t mat = { 0 };
+
+    mat[0] = x*x*t + cosres;
+    mat[1] = y*x*t + z*sinres;
+    mat[2] = z*x*t - y*sinres;
+    mat[3] = 0.0f;
+
+    mat[4] = x*y*t - z*sinres;
+    mat[5] = y*y*t + cosres;
+    mat[6] = z*y*t + x*sinres;
+    mat[7] = 0.0f;
+
+    mat[8] = x*z*t + y*sinres;
+    mat[9] = y*z*t - x*sinres;
+    mat[10] = z*z*t + cosres;
+    mat[11] = 0.0f;
+
+    mat[12] = 0.0f;
+    mat[13] = 0.0f;
+    mat[14] = 0.0f;
+    mat[15] = 1.0f;
+
+    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swScalef(float x, float y, float z)
+{
+    sw_matrix_t mat = { 0 };
+
+    mat[0]  = x, mat[1]  = 0, mat[2]  = 0, mat[3]  = 0;
+    mat[4]  = 0, mat[5]  = y, mat[6]  = 0, mat[7]  = 0;
+    mat[8]  = 0, mat[9]  = 0, mat[10] = z, mat[11] = 0;
+    mat[12] = 0, mat[13] = 0, mat[14] = 0, mat[15] = 1;
+
+    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swMultMatrixf(const float *mat)
+{
+    sw_matrix_mul(*RLSW.currentMatrix, mat, *RLSW.currentMatrix);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swFrustum(double left, double right, double bottom, double top, double znear, double zfar)
+{
+    sw_matrix_t mat = { 0 };
+
+    double rl = right - left;
+    double tb = top - bottom;
+    double fn = zfar - znear;
+
+    mat[0] = (float)(znear*2.0)/rl;
+    mat[1] = 0.0f;
+    mat[2] = 0.0f;
+    mat[3] = 0.0f;
+
+    mat[4] = 0.0f;
+    mat[5] = (float)(znear*2.0)/tb;
+    mat[6] = 0.0f;
+    mat[7] = 0.0f;
+
+    mat[8] = (float)(right + left)/rl;
+    mat[9] = (float)(top + bottom)/tb;
+    mat[10] = -(float)(zfar + znear)/fn;
+    mat[11] = -1.0f;
+
+    mat[12] = 0.0f;
+    mat[13] = 0.0f;
+    mat[14] = -(zfar*znear*2.0)/fn;
+    mat[15] = 0.0f;
+
+    sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swOrtho(double left, double right, double bottom, double top, double znear, double zfar)
+{
+    sw_matrix_t mat = { 0 };
+
+    double rl = right - left;
+    double tb = top - bottom;
+    double fn = zfar - znear;
+
+    mat[0] = 2.0f/(float)rl;
+    mat[1] = 0.0f;
+    mat[2] = 0.0f;
+    mat[3] = 0.0f;
+
+    mat[4] = 0.0f;
+    mat[5] = 2.0f/(float)tb;
+    mat[6] = 0.0f;
+    mat[7] = 0.0f;
+
+    mat[8] = 0.0f;
+    mat[9] = 0.0f;
+    mat[10] = -2.0f/(float)fn;
+    mat[11] = 0.0f;
+
+    mat[12] = -(float)(left + right)/rl;
+    mat[13] = -(float)(top + bottom)/tb;
+    mat[14] = -(float)(zfar + znear)/fn;
+    mat[15] = 1.0f;
+
+    sw_matrix_mul(*RLSW.currentMatrix, *RLSW.currentMatrix, mat);
+
+    if (RLSW.currentMatrixMode != SW_TEXTURE) RLSW.isDirtyMVP = true;
+}
+
+void swBegin(SWdraw mode)
+{
+    // Check if render is possible
+    if (!sw_is_ready_to_render())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    // Check if the draw mode is valid
+    if (!sw_is_draw_mode_valid(mode))
+    {
+        RLSW.errCode = SW_INVALID_ENUM;
+        return;
+    }
+
+    // Ensures that a recording has not already started (spec)
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    sw_immediate_begin(mode);
+}
+
+void swEnd(void)
+{
+    // Ensures that a recording has already started (spec)
+    if (!sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    sw_immediate_end();
+}
+
+void swVertex2i(int x, int y)
+{
+    const float v[4] = { (float)x, (float)y, 0.0f, 1.0f };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex2f(float x, float y)
+{
+    const float v[4] = { x, y, 0.0f, 1.0f };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex2fv(const float *v)
+{
+    const float v4[4] = { v[0], v[1], 0.0f, 1.0f };
+    sw_immediate_push_vertex(v4);
+}
+
+void swVertex3i(int x, int y, int z)
+{
+    const float v[4] = { (float)x, (float)y, (float)z, 1.0f };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex3f(float x, float y, float z)
+{
+    const float v[4] = { x, y, z, 1.0f };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex3fv(const float *v)
+{
+    const float v4[4] = { v[0], v[1], v[2], 1.0f };
+    sw_immediate_push_vertex(v4);
+}
+
+void swVertex4i(int x, int y, int z, int w)
+{
+    const float v[4] = { (float)x, (float)y, (float)z, (float)w };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex4f(float x, float y, float z, float w)
+{
+    const float v[4] = { x, y, z, w };
+    sw_immediate_push_vertex(v);
+}
+
+void swVertex4fv(const float *v)
+{
+    sw_immediate_push_vertex(v);
+}
+
+void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
+{
+    float cv[4] = { 0 };
+    cv[0] = (float)r*SW_INV_255;
+    cv[1] = (float)g*SW_INV_255;
+    cv[2] = (float)b*SW_INV_255;
+    cv[3] = 1.0f;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor3ubv(const uint8_t *v)
+{
+    float cv[4] = { 0 };
+    cv[0] = (float)v[0]*SW_INV_255;
+    cv[1] = (float)v[1]*SW_INV_255;
+    cv[2] = (float)v[2]*SW_INV_255;
+    cv[3] = 1.0f;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor3f(float r, float g, float b)
+{
+    float cv[4] = { 0 };
+    cv[0] = r;
+    cv[1] = g;
+    cv[2] = b;
+    cv[3] = 1.0f;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor3fv(const float *v)
+{
+    float cv[4] = { 0 };
+    cv[0] = v[0];
+    cv[1] = v[1];
+    cv[2] = v[2];
+    cv[3] = 1.0f;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+{
+    float cv[4] = { 0 };
+    cv[0] = (float)r*SW_INV_255;
+    cv[1] = (float)g*SW_INV_255;
+    cv[2] = (float)b*SW_INV_255;
+    cv[3] = (float)a*SW_INV_255;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor4ubv(const uint8_t *v)
+{
+    float cv[4] = { 0 };
+    cv[0] = (float)v[0]*SW_INV_255;
+    cv[1] = (float)v[1]*SW_INV_255;
+    cv[2] = (float)v[2]*SW_INV_255;
+    cv[3] = (float)v[3]*SW_INV_255;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor4f(float r, float g, float b, float a)
+{
+    float cv[4] = { 0 };
+    cv[0] = r;
+    cv[1] = g;
+    cv[2] = b;
+    cv[3] = a;
+
+    sw_immediate_set_color(cv);
+}
+
+void swColor4fv(const float *v)
+{
+    sw_immediate_set_color(v);
+}
+
+void swTexCoord2f(float u, float v)
+{
+    const float texcoord[2] = { u, v };
+    sw_immediate_set_texcoord(texcoord);
+}
+
+void swTexCoord2fv(const float *v)
+{
+    sw_immediate_set_texcoord(v);
+}
+
+void swBindArray(SWarray type, void *buffer)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    switch (type)
+    {
+        case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break;
+        case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break;
+        case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break;
+        default: break;
+    }
+}
+
+void swDrawArrays(SWdraw mode, int offset, int count)
+{
+    if ((sw_immediate_is_active()) || (!sw_is_ready_to_render()) || (RLSW.array.positions == NULL))
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    sw_immediate_begin(mode);
+    {
+        const float *positions = RLSW.array.positions;
+        const float *texcoords = RLSW.array.texcoords;
+        const uint8_t *colors = RLSW.array.colors;
+
+        int end = offset + count;
+        for (int i = offset; i < end; i++)
+        {
+            if (texcoords) sw_immediate_set_texcoord(&texcoords[2*i]);
+
+            if (colors)
+            {
+                const uint8_t *c = &colors[4*i];
+                float color[4] = {
+                    (float)c[0]*SW_INV_255,
+                    (float)c[1]*SW_INV_255,
+                    (float)c[2]*SW_INV_255,
+                    (float)c[3]*SW_INV_255,
+                };
+                sw_immediate_set_color(color);
+            }
+
+            const float *p = &positions[3*i];
+            float position[4] = { p[0], p[1], p[2], 1.0f };
+            sw_immediate_push_vertex(position);
+        }
+    }
+    sw_immediate_end();
+}
+
+void swDrawElements(SWdraw mode, int count, int type, const void *indices)
+{
+    if ((sw_immediate_is_active()) || (!sw_is_ready_to_render()) || (RLSW.array.positions == NULL))
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if ((count < 0) || (indices == NULL))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    if ((type != SW_UNSIGNED_BYTE) && (type != SW_UNSIGNED_SHORT) && (type != SW_UNSIGNED_INT))
+    {
+        RLSW.errCode = SW_INVALID_ENUM;
+        return;
+    }
+
+    sw_immediate_begin(mode);
+    {
+        const float *positions = RLSW.array.positions;
+        const float *texcoords = RLSW.array.texcoords;
+        const uint8_t *colors = RLSW.array.colors;
+
+        const uint8_t *indicesUb = (type == SW_UNSIGNED_BYTE)? indices : NULL;
+        const uint16_t *indicesUs = (type == SW_UNSIGNED_SHORT)? indices : NULL;
+        const uint32_t *indicesUi = (type == SW_UNSIGNED_INT)? indices : NULL;
+
+        for (int i = 0; i < count; i++)
+        {
+            uint32_t index = indicesUb? (uint32_t)indicesUb[i] : (indicesUs? (uint32_t)indicesUs[i] : (uint32_t)indicesUi[i]);
+
+            if (texcoords) sw_immediate_set_texcoord(&texcoords[2*index]);
+
+            if (colors)
+            {
+                const uint8_t *c = &colors[4*index];
+                float color[4] = {
+                    (float)c[0]*SW_INV_255,
+                    (float)c[1]*SW_INV_255,
+                    (float)c[2]*SW_INV_255,
+                    (float)c[3]*SW_INV_255,
+                };
+                sw_immediate_set_color(color);
+            }
+
+            const float *p = &positions[3*index];
+            float position[4] = { p[0], p[1], p[2], 1.0f };
+            sw_immediate_push_vertex(position);
+        }
+    }
+    sw_immediate_end();
+}
+
+void swGenTextures(int count, sw_handle_t *textures)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (!count || !textures) return;
+
+    for (int i = 0; i < count; i++)
+    {
+        sw_handle_t h = sw_pool_alloc(&RLSW.texturePool);
+        if (h == SW_HANDLE_NULL) { RLSW.errCode = SW_OUT_OF_MEMORY; return; }
+        textures[i] = h;
+    }
+}
+
+void swDeleteTextures(int count, sw_handle_t *textures)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (!count || !textures) return;
+
+    for (int i = 0; i < count; i++)
+    {
+        sw_texture_t *tex = sw_pool_get(&RLSW.texturePool, textures[i]);
+        if (!tex) { RLSW.errCode = SW_INVALID_VALUE; continue; }
+        if (tex == RLSW.boundTexture) RLSW.boundTexture = NULL;
+        if (tex == RLSW.colorBuffer) RLSW.colorBuffer = NULL;
+        if (tex == RLSW.depthBuffer) RLSW.depthBuffer = NULL;
+
+        sw_texture_free(tex);
+        *tex = (sw_texture_t) { 0 };
+
+        sw_pool_free(&RLSW.texturePool, textures[i]);
+    }
+}
+
+void swBindTexture(sw_handle_t id)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (id == SW_HANDLE_NULL)
+    {
+        RLSW.boundTexture = NULL;
+        return;
+    }
+
+    if (!sw_is_texture_valid(id))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    RLSW.boundTexture = sw_pool_get(&RLSW.texturePool, id);
+}
+
+void swTexStorage2D(int width, int height, SWinternalformat format)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (RLSW.boundTexture == NULL) return;
+
+    int pixelFormat = SW_PIXELFORMAT_UNKNOWN;
+    switch (format)
+    {
+        case SW_LUMINANCE8: pixelFormat = SW_PIXELFORMAT_COLOR_GRAYSCALE; break;
+        case SW_LUMINANCE8_ALPHA8: pixelFormat = SW_PIXELFORMAT_COLOR_GRAYALPHA; break;
+        case SW_R3_G3_B2: pixelFormat = SW_PIXELFORMAT_COLOR_R3G3B2; break;
+        case SW_RGB8: pixelFormat = SW_PIXELFORMAT_COLOR_R8G8B8; break;
+        case SW_RGBA4: pixelFormat = SW_PIXELFORMAT_COLOR_R4G4B4A4; break;
+        case SW_RGB5_A1: pixelFormat = SW_PIXELFORMAT_COLOR_R5G5B5A1; break;
+        case SW_RGBA8: pixelFormat = SW_PIXELFORMAT_COLOR_R8G8B8A8; break;
+        case SW_R16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16; break;
+        case SW_RGB16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16G16B16; break;
+        case SW_RGBA16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16G16B16A16; break;
+        case SW_R32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32; break;
+        case SW_RGB32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32; break;
+        case SW_RGBA32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32A32; break;
+        case SW_DEPTH_COMPONENT16: pixelFormat = SW_PIXELFORMAT_DEPTH_D16; break;
+        case SW_DEPTH_COMPONENT24: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break;
+        case SW_DEPTH_COMPONENT32: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break;
+        case SW_DEPTH_COMPONENT32F: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break;
+        default: RLSW.errCode = SW_INVALID_ENUM; return;
+    }
+
+    (void)sw_texture_alloc(RLSW.boundTexture, NULL, width, height, pixelFormat);
+}
+
+void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (RLSW.boundTexture == NULL) return;
+
+    int pixelFormat = sw_pixel_get_format(format, type);
+    if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; }
+
+    (void)sw_texture_alloc(RLSW.boundTexture, data, width, height, pixelFormat);
+}
+
+void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (!sw_is_texture_complete(RLSW.boundTexture) || (!pixels) || (width <= 0) || (height <= 0))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    if ((x < 0) || (y < 0) || (x + width > RLSW.boundTexture->width) || (y + height > RLSW.boundTexture->height))
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    sw_pixel_write_color_f writeColor = sw_pixel_get_write_color_func(RLSW.boundTexture->format);
+    if (writeColor == NULL) // probably a depth format
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    sw_pixelformat_t srcPixelFormat = sw_pixel_get_format(format, type);
+    sw_pixel_read_color_f readColor = sw_pixel_get_read_color_func(srcPixelFormat);
+    if (readColor == NULL)
+    {
+        RLSW.errCode = SW_INVALID_ENUM;
+        return;
+    }
+
+    const int srcPixelSize = SW_PIXELFORMAT_SIZE[srcPixelFormat];
+    const int dstPixelSize = SW_PIXELFORMAT_SIZE[RLSW.boundTexture->format];
+
+    const uint8_t *srcBytes = (const uint8_t *)pixels;
+    uint8_t *dstBytes = (uint8_t *)RLSW.boundTexture->pixels;
+
+    if (srcPixelFormat == RLSW.boundTexture->format)
+    {
+        const int rowSize = width*dstPixelSize;
+        const int dstStride = RLSW.boundTexture->width*dstPixelSize;
+        const int srcStride = width*srcPixelSize;
+
+        uint8_t *dstRow = dstBytes + (y*RLSW.boundTexture->width + x)*dstPixelSize;
+        const uint8_t *srcRow = srcBytes;
+
+        for (int j = 0; j < height; ++j)
+        {
+            for (int i = 0; i < rowSize; ++i) dstRow[i] = srcRow[i];
+            dstRow += dstStride;
+            srcRow += srcStride;
+        }
+        return;
+    }
+
+    bool alphaFound = false;
+
+    for (int j = 0; j < height; ++j)
+    {
+        for (int i = 0; i < width; ++i)
+        {
+            float color[4];
+            const int srcPixelOffset = ((j*width) + i)*srcPixelSize;
+            const int dstPixelOffset = (((y + j)*RLSW.boundTexture->width) + (x + i))*dstPixelSize;
+
+            readColor(color, srcBytes, srcPixelOffset);
+            alphaFound |= (color[3] < 1.0f);
+
+            writeColor(dstBytes, color, dstPixelOffset);
+        }
+    }
+
+    RLSW.boundTexture->alpha = alphaFound? SW_PIXELFORMAT_ALPHA[srcPixelFormat] : SW_PIXEL_ALPHA_NONE;
+}
+
+void swTexParameteri(int param, int value)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (RLSW.boundTexture == NULL) return;
+
+    switch (param)
+    {
+        case SW_TEXTURE_MIN_FILTER:
+        {
+            if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
+            RLSW.boundTexture->minFilter = (SWfilter)value;
+        } break;
+        case SW_TEXTURE_MAG_FILTER:
+        {
+            if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
+            RLSW.boundTexture->magFilter = (SWfilter)value;
+        } break;
+        case SW_TEXTURE_WRAP_S:
+        {
+            if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
+        #if !RLSW_SUPPORT_NPOT_TEXTURE
+            if (value == SW_REPEAT && (RLSW.boundTexture->width & RLSW.boundTexture->wMinus1) != 0)
+            {
+                RLSW.errCode = SW_INVALID_OPERATION;
+                return;
+            }
+        #endif
+            RLSW.boundTexture->sWrap = (SWwrap)value;
+        } break;
+        case SW_TEXTURE_WRAP_T:
+        {
+            if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; }
+        #if !RLSW_SUPPORT_NPOT_TEXTURE
+            if (value == SW_REPEAT && (RLSW.boundTexture->height & RLSW.boundTexture->hMinus1) != 0)
+            {
+                RLSW.errCode = SW_INVALID_OPERATION;
+                return;
+            }
+        #endif
+            RLSW.boundTexture->tWrap = (SWwrap)value;
+        } break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+void swGenFramebuffers(int count, uint32_t *framebuffers)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (!count || !framebuffers) return;
+
+    for (int i = 0; i < count; i++)
+    {
+        sw_handle_t h = sw_pool_alloc(&RLSW.framebufferPool);
+        if (h == SW_HANDLE_NULL) { RLSW.errCode = SW_OUT_OF_MEMORY; return; }
+        framebuffers[i] = h;
+    }
+}
+
+void swDeleteFramebuffers(int count, uint32_t *framebuffers)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (!count || !framebuffers) return;
+
+    for (int i = 0; i < count; i++)
+    {
+        sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, framebuffers[i]);
+        if (!fb) { RLSW.errCode = SW_INVALID_VALUE; continue; }
+
+        if (framebuffers[i] == RLSW.boundFramebufferId)
+        {
+            RLSW.boundFramebufferId = SW_HANDLE_NULL;
+            RLSW.colorBuffer = &RLSW.framebuffer.color;
+            RLSW.depthBuffer = &RLSW.framebuffer.depth;
+        }
+
+        sw_pool_free(&RLSW.framebufferPool, framebuffers[i]);
+    }
+}
+
+void swBindFramebuffer(uint32_t id)
+{
+    if (sw_immediate_is_active())
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (id == SW_HANDLE_NULL)
+    {
+        RLSW.boundFramebufferId = SW_HANDLE_NULL;
+        RLSW.colorBuffer = &RLSW.framebuffer.color;
+        RLSW.depthBuffer = &RLSW.framebuffer.depth;
+        return;
+    }
+
+    sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, id);
+    if (fb == NULL)
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    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);
+}
+
+void swFramebufferTexture2D(SWattachment attach, uint32_t texture)
+{
+    if ((sw_immediate_is_active()) || (RLSW.boundFramebufferId == SW_HANDLE_NULL))
+    {
+        RLSW.errCode = SW_INVALID_OPERATION; // not really standard but hey
+        return;
+    }
+
+    sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId);
+    if (fb == NULL) return; // Should never happen
+
+    switch (attach)
+    {
+        case SW_COLOR_ATTACHMENT:
+        {
+            fb->colorAttachment = texture;
+            RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, texture);
+        } break;
+        case SW_DEPTH_ATTACHMENT:
+        {
+            fb->depthAttachment = texture;
+            RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, texture);
+        } break;
+        default: RLSW.errCode = SW_INVALID_ENUM; break;
+    }
+}
+
+SWfbstatus swCheckFramebufferStatus(void)
+{
+    if (RLSW.boundFramebufferId == SW_HANDLE_NULL) return SW_FRAMEBUFFER_COMPLETE;
+
+    if (RLSW.colorBuffer == NULL) return SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+
+    if (!sw_is_texture_complete(RLSW.colorBuffer)) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+
+    if (RLSW.colorBuffer->format != SW_FRAMEBUFFER_COLOR_FORMAT) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+
+    if (RLSW.depthBuffer)
+    {
+        if (!sw_is_texture_complete(RLSW.depthBuffer)) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+
+        if (RLSW.depthBuffer->format != SW_FRAMEBUFFER_DEPTH_FORMAT) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+
+        if ((RLSW.colorBuffer->width != RLSW.depthBuffer->width) ||
+            (RLSW.colorBuffer->height != RLSW.depthBuffer->height)) return SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+    }
+
+    return SW_FRAMEBUFFER_COMPLETE;
+}
+
+void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget property, int *v)
+{
+    if (RLSW.boundFramebufferId == SW_HANDLE_NULL)
+    {
+        RLSW.errCode = SW_INVALID_OPERATION;
+        return;
+    }
+
+    if (v == NULL)
+    {
+        RLSW.errCode = SW_INVALID_VALUE;
+        return;
+    }
+
+    sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId);
+    if (fb == NULL) return; // Should never happen
+
+    switch (property)
+    {
+        case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+        {
+            if (attachment == SW_COLOR_ATTACHMENT) *v = fb->colorAttachment;
+            else if (attachment == SW_DEPTH_ATTACHMENT) *v = fb->depthAttachment;
+        } break;
+        case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: *v = GL_TEXTURE; break;
+        default: break;
+    }
+}
+
+#endif // RLSW_IMPLEMENTATION
+
+//----------------------------------------------------------------------------------
+// Template Rasterization Functions
+//----------------------------------------------------------------------------------
+
+// Triangle rasterization functions
+//-------------------------------------------------------------------------------------------
+#ifdef SW_RASTER_TRIANGLE_STATES
+
+#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))
+
+// 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))
+
+#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))
+
+// 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 SW_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 SW_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 SW_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];
+    if (xStart == xEnd) return;
+
+    // Intercept the span bounds to ensure to not write before the framebuffer
+    int xLoopStart = (xStart >= 0)? xStart : 0;
+    int xLoopEnd = (xEnd <= RLSW.colorBuffer->width)? xEnd : RLSW.colorBuffer->width;
+    if (xLoopStart >= xLoopEnd) return; // Nothing to draw
+
+    // 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;
+
+    // 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;
+#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;
+        float blockLenF = (float)(blockEnd - x);
+        float blockLenRcp = sw_rcp(blockLenF);
+
+        // Only 2 '1/w' here; none inside the pixel loop
+        float wRcpA = sw_rcp(w);
+        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], 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
+
+    #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D
+        // Perspective-correct UVs at both endpoints, then affine gradient
+        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++)
+        {
+        #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST
+            float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0);
+            if (z <= depth)
+            {
+                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
+
+            #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_BLEND
+            {
+                float dstColor[4];
+                SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0);
+                RLSW.blendFunc(dstColor, SW_FINAL_COLOR);
+                SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0);
+            }
+            #else
+                SW_FRAMEBUFFER_COLOR_SET(cPtr, SW_FINAL_COLOR, 0);
+            #endif
+
+            #undef SW_FINAL_COLOR
+
+        #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST
+            }
+        #endif
+
+            // Advance unconditionally: depth test only guards the write above
+            cPtr += SW_FRAMEBUFFER_COLOR_SIZE;
+        #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;
+    #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
+}
+
+static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2)
+{
+    // Swap vertices by increasing Y
+    if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
+    if (v1->position[1] > v2->position[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; }
+    if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
+
+    // Extracting Y coordinates from the sorted vertices
+    float y0 = v0->position[1];
+    float y1 = v1->position[1];
+    float y2 = v2->position[1];
+
+    // Compute height differences
+    float h02 = y2 - y0;
+    float h01 = y1 - y0;
+    float h12 = y2 - y1;
+
+    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_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);
+    float y1Substep = 1.0f - sw_fract(y1);
+
+    // Get a copy of vertices for interpolation and apply substep correction
+    sw_vertex_t lVert = *v0, rVert = *v0;
+    SW_VMAD(&lVert, &dVXdy02, y0Substep);
+    SW_VMAD(&rVert, &dVXdy01, y0Substep);
+
+    // Y bounds (vertical clipping)
+    int yTop = (int)y0;
+    int yMid = (int)y1;
+    int yBot = (int)y2;
+
+    // Scanline for the upper part of the triangle
+    for (int y = yTop; y < yMid; y++)
+    {
+        lVert.position[1] = rVert.position[1] = y;
+        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, &ctx);
+        SW_VADD(&lVert, &dVXdy02);
+        SW_VADD(&rVert, &dVXdy01);
+    }
+
+    // Get a copy of next right for interpolation and apply substep correction
+    rVert = *v1;
+    SW_VMAD(&rVert, &dVXdy12, y1Substep);
+
+    // Scanline for the lower part of the triangle
+    for (int y = yMid; y < yBot; y++)
+    {
+        lVert.position[1] = rVert.position[1] = y;
+        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, &ctx);
+        SW_VADD(&lVert, &dVXdy02);
+        SW_VADD(&rVert, &dVXdy12);
+    }
+}
+
+#endif // SW_RASTER_TRIANGLE_STATES
+//-------------------------------------------------------------------------------------------
+
+// Quad rasterization functions
+//-------------------------------------------------------------------------------------------
+#ifdef SW_RASTER_QUAD_STATES
+
+#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
+
+static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
+                           const sw_vertex_t *c, const sw_vertex_t *d)
+{
+    // Classify corners
+    // 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  < 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];
+    int yMin = (int)tl->position[1];
+    int xMax = (int)br->position[0];
+    int yMax = (int)br->position[1];
+
+    // Exit early if no pixels to draw.  Use these later for loop boundaries
+    int yLoopMin = (yMin >= 0)? yMin : 0;
+    int xLoopMin = (xMin >= 0)? xMin : 0;
+    int yLoopMax = (yMax <= RLSW.colorBuffer->height)? yMax : RLSW.colorBuffer->height;
+    int xLoopMax = (xMax <= RLSW.colorBuffer->width)?  xMax : RLSW.colorBuffer->width;
+
+    if (yLoopMin >= yLoopMax || xLoopMin >= xLoopMax) return;
+
+    float w = (float)(xMax - xMin);
+    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);
+    float xSubstep = 1.0f - sw_fract(tl->position[0]);
+    float ySubstep = 1.0f - sw_fract(tl->position[1]);
+    // 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;
+#if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST
+    uint8_t *dPixels = RLSW.depthBuffer->pixels;
+#endif
+
+#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
+
+#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;
+    #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST
+        uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
+        float z = zRow;
+    #endif
+    #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
+
+        for (int x = xLoopMin; x < xLoopMax; x++)
+        {
+        #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP
+            #define SW_QUAD_BASE_COLOR color
+        #else
+            #define SW_QUAD_BASE_COLOR flatColor
+        #endif
+
+        #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)
+            {
+                SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0);
+        #endif
+
+            #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D
+                float texColor[4];
+                sample(texColor, RLSW.boundTexture, tc[0], tc[1]);
+                SW_VEC_OP(srcColor[i] *= texColor[i], i, 4);
+            #endif
+
+            #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
+
+        #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST
+            }
+        #endif
+
+            // Move one pixel over without touching the original "start offset"
+        #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP
+            SW_VEC_OP(color[i] += dCdx[i], i, 4);
+        #endif
+
+        #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST
+            z += dZdx;
+            dPtr += SW_FRAMEBUFFER_DEPTH_SIZE;
+        #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;
+        }
+
+        // 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
+    #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 // SW_RASTER_QUAD_STATES
+//-------------------------------------------------------------------------------------------
+
+// Line rasterization functions
+//-------------------------------------------------------------------------------------------
+#ifdef SW_RASTER_LINE_STATES
+
+#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))
+
+// 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;
+    float y0 = v0->position[1] - 0.5f;
+    float x1 = v1->position[0] - 0.5f;
+    float y1 = v1->position[1] - 0.5f;
+
+    float dx = x1 - x0;
+    float dy = y1 - y0;
+
+    // Compute dominant axis and subpixel offset
+    float steps, substep;
+    if (fabsf(dx) > fabsf(dy))
+    {
+        steps = fabsf(dx);
+        if (steps < 1.0f) return;
+        substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0);
+    }
+    else
+    {
+        steps = fabsf(dy);
+        if (steps < 1.0f) return;
+        substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0);
+    }
+
+    // Line setup, independent of pipeline state
+    float stepRcp = sw_rcp(steps);
+    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
+
+    // Initializing the interpolation starting values
+    float x = x0 + xInc*substep;
+    float y = y0 + yInc*substep;
+#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
+#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
+
+    for (int i = 0; i < numPixels; i++)
+    {
+        int px = x;
+        int py = y;
+
+        int baseOffset = py*fbWidth + px;
+        uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
+    #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST
+        uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
+    #endif
+
+    #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 depth mask
+            SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0);
+    #endif
+
+        #if (SW_RASTER_LINE_FLAGS) & SW_STATE_COLOR_INTERP
+            const float *srcColor = color;
+        #endif
+
+        #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
+
+    #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST
+        }
+    #endif
+
+        // Advance unconditionally: depth test only guards the write above
+        x += xInc;
+        y += yInc;
+    #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(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];
+    int y0 = (int)v0->position[1];
+    int x1 = (int)v1->position[0];
+    int y1 = (int)v1->position[1];
+
+    int dx = x1 - x0;
+    int dy = y1 - y0;
+
+    SW_RASTER_LINE_THIN(v0, v1);
+
+    if ((dx != 0) && (abs(dy/dx) < 1))
+    {
+        int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy));
+        wy >>= 1;
+        for (int i = 1; i <= wy; i++)
+        {
+            tv0 = *v0, tv1 = *v1;
+            tv0.position[1] -= i;
+            tv1.position[1] -= i;
+            SW_RASTER_LINE_THIN(&tv0, &tv1);
+            tv0 = *v0, tv1 = *v1;
+            tv0.position[1] += i;
+            tv1.position[1] += i;
+            SW_RASTER_LINE_THIN(&tv0, &tv1);
+        }
+    }
+    else if (dy != 0)
+    {
+        int wx = (int)((RLSW.lineWidth - 1.0f)*abs(dy)/sqrtf(dx*dx + dy*dy));
+        wx >>= 1;
+        for (int i = 1; i <= wx; i++)
+        {
+            tv0 = *v0, tv1 = *v1;
+            tv0.position[0] -= i;
+            tv1.position[0] -= i;
+            SW_RASTER_LINE_THIN(&tv0, &tv1);
+            tv0 = *v0, tv1 = *v1;
+            tv0.position[0] += i;
+            tv1.position[0] += i;
+            SW_RASTER_LINE_THIN(&tv0, &tv1);
+        }
+    }
+}
+
+#endif // SW_RASTER_LINE_STATES
+//-------------------------------------------------------------------------------------------
+
+// Point rasterization functions
+//-------------------------------------------------------------------------------------------
+#ifdef SW_RASTER_POINT_STATES
+
+#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;
+
+    #if (SW_RASTER_POINT_FLAGS) & SW_STATE_DEPTH_TEST
+    {
+        uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + offset*SW_FRAMEBUFFER_DEPTH_SIZE;
+
+        // TODO: Implement different depth funcs?
+        float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0);
+        if (z > depth) return;
+
+        // TODO: Implement depth mask
+        SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0);
+    }
+    #endif
+
+    uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + offset*SW_FRAMEBUFFER_COLOR_SIZE;
+
+    #if (SW_RASTER_POINT_FLAGS) & SW_STATE_BLEND
+    {
+        float dstColor[4];
+        SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0);
+        RLSW.blendFunc(dstColor, color);
+        SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0);
+    }
+    #else
+    {
+        SW_FRAMEBUFFER_COLOR_SET(cPtr, color, 0);
+    }
+    #endif
+}
+
+static void SW_RASTER_POINT(const sw_vertex_t *v)
+{
+    int cx = v->position[0];
+    int cy = v->position[1];
+    float cz = v->position[2];
+    int radius = RLSW.pointRadius;
+    const float *color = v->color;
+
+    for (int dy = -radius; dy <= radius; dy++)
+    {
+        for (int dx = -radius; dx <= radius; dx++)
+        {
+            SW_RASTER_POINT_PIXEL(cx + dx, cy + dy, cz, color);
+        }
+    }
+}
+
+#endif // SW_RASTER_POINT_STATES
+//-------------------------------------------------------------------------------------------
diff --git a/raylib/src/external/rltexgpu.h b/raylib/src/external/rltexgpu.h
new file mode 100644
--- /dev/null
+++ b/raylib/src/external/rltexgpu.h
@@ -0,0 +1,1553 @@
+/**********************************************************************************************
+*
+*   rltexgpu v1.2 - GPU compressed textures loading and saving
+*
+*   DESCRIPTION:
+*
+*     Load GPU compressed image data from image files provided as memory data arrays,
+*     data is loaded compressed, ready to be loaded into GPU
+*
+*     Note that some file formats (DDS, PVR, KTX) also support uncompressed data storage.
+*     In those cases data is loaded uncompressed and format is returned
+*
+*   FIXME: This library still depends on raylib due to the following reasons:
+*     - rl_save_ktx_to_memory() requires rlGetGlTextureFormats() from rlgl.h
+*
+*   TODO:
+*     - Review rl_load_ktx_from_memory() to support KTX v2.2 specs
+*
+*   CONFIGURATION:
+*
+*   #define RLTEXGPU_SUPPORT_DDS
+*   #define RLTEXGPU_SUPPORT_PKM
+*   #define RLTEXGPU_SUPPORT_KTX
+*   #define RLTEXGPU_SUPPORT_PVR
+*   #define RLTEXGPU_SUPPORT_ASTC
+*       Define desired file formats to be supported
+*
+*   #define RLTEXGPU_SHOW_LOG_INFO
+*       Define, if you wish to see warnings generated by the library
+*       This will include <stdio.h> unless you provide your own RLTEXGPU_LOG
+*   #define RLTEXGPU_LOG
+*       Define, if you wish to provide your own warning function
+*       Make sure that this macro puts newline character '\n' at the end
+*
+*   #define RLTEXGPU_MALLOC
+*   #define RLTEXGPU_FREE
+*       Define those macros in order to provide your own libc-compliant allocator;
+*       not doing so will include <stdlib.h>
+*       If you're providing any of those, you must provide ALL of them,
+*       otherwise the code will (most likely) crash...
+*
+*   #define RLTEXGPU_NULL
+*       Define in order to provide your own libc-compliant NULL pointer;
+*       not doing so will include <stdlib.h>
+*
+*   #define RLTEXGPU_MEMCPY
+*       Define in order to provide your own libc-compliant 'memcpy' function;
+*       not doing so will include <string.h>
+*
+*   #define RLGPUTEXAPI
+*       Define to compiler-specific intrinsic, if you wish to export public functions
+*       There is no need to do so when statically linking
+*
+*   VERSIONS HISTORY:
+*       1.2 (18-Mar-2026) Renamed library to `rltexgpu`
+*                         Improved usage as standalone linrary
+*                         Decouple logging and memory allocation from raylib
+*
+*       1.1 (15-Jul-2025) Several minor fixes related to specific image formats; some work has been done
+*           in order to decouple the library from raylib by introducing few new macros; library still
+*           requires raylib in order to function properly
+*
+*       1.0 (17-Sep-2022) First version has been created by migrating part of compressed-texture-loading
+*           functionality from raylib src/rtextures.c into self-contained library
+*
+*   LICENSE: zlib/libpng
+*
+*   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.
+*
+**********************************************************************************************/
+
+#ifndef RLTEXGPU_H
+#define RLTEXGPU_H
+
+#ifndef RLGPUTEXAPI
+    #define RLGPUTEXAPI  // Functions defined as 'extern' by default (implicit specifiers)
+#endif
+
+// Texture pixel formats
+// NOTE: Support depends on OpenGL version
+// WARNING: Enum values aligned with raylib/rlgl equivalent PixelFormat/rlPixelFormat enum,
+// to avoid value mapping between the 3 libraries format values
+typedef enum {
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1,     // 8 bit per pixel (no alpha)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,        // 8*2 bpp (2 channels)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5,            // 16 bpp
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8,            // 24 bpp
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1,          // 16 bpp (1 bit alpha)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4,          // 16 bpp (4 bit alpha)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,          // 32 bpp
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32,               // 32 bpp (1 channel - float)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32,         // 32*3 bpp (3 channels - float)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32,      // 32*4 bpp (4 channels - float)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16,               // 16 bpp (1 channel - half float)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16,         // 16*3 bpp (3 channels - half float)
+    RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16,      // 16*4 bpp (4 channels - half float)
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB,            // 4 bpp (no alpha)
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA,           // 4 bpp (1 bit alpha)
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA,           // 8 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA,           // 8 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB,            // 4 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB,            // 4 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA,       // 8 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB,            // 4 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA,           // 4 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA,       // 8 bpp
+    RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA        // 2 bpp
+} rlGpuTexPixelFormat;
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+#if defined(__cplusplus)
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+// Load image data from memory data files
+RLGPUTEXAPI void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
+RLGPUTEXAPI void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
+RLGPUTEXAPI void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
+RLGPUTEXAPI void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
+RLGPUTEXAPI void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
+
+RLGPUTEXAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int width, int height, int format, int mipmaps);  // Save image data as KTX file
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // RLTEXGPU_H
+
+/***********************************************************************************
+*
+*   RL_GPUTEX IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RLTEXGPU_IMPLEMENTATION)
+
+#if defined(RLTEXGPU_SHOW_LOG_INFO) && !defined(RLTEXGPU_LOG)
+    #include <stdio.h>          // Required for: printf()
+#endif
+#if !defined(RLTEXGPU_MALLOC) || !defined(RLTEXGPU_NULL)
+    #include <stdlib.h>         // Required for: NULL, malloc(), calloc(), free()
+#endif
+#if !defined(RLTEXGPU_MEMCPY)
+    #include <string.h>         // Required for: memcpy()
+#endif
+
+#if defined(RLTEXGPU_MALLOC) || defined(RLTEXGPU_FREE)
+    #if !defined(RLTEXGPU_MALLOC) || !defined(RLTEXGPU_FREE)
+        #warning "RLTEXGPU_MALLOC and RLTEXGPU_FREE allocation functions are required to be provided"
+    #endif
+#endif
+#if !defined(RLTEXGPU_MALLOC)
+    #define RLTEXGPU_MALLOC(sz)        malloc(sz)
+    #define RLTEXGPU_FREE(ptr)         free(ptr)
+#endif
+
+#if !defined(RLTEXGPU_NULL)
+    #define RLTEXGPU_NULL NULL
+#endif
+#if !defined(RLTEXGPU_MEMCPY)
+    #define RLTEXGPU_MEMCPY(dest, src, num)  memcpy(dest, src, num)
+#endif
+
+// Simple warning logging system to avoid LOG() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+// WARNING: This macro expects that newline character is added automatically
+// in order to match the functionality of raylib's TRACELOG()
+#if defined(RLTEXGPU_SHOW_LOG_INFO)
+    #if !defined(RLTEXGPU_LOG)
+        #define RLTEXGPU_LOG(...) (void)(printf("RL_GPUTEX: WARNING: " __VA_ARGS__), printf("\n"))
+    #endif
+#else
+    #if defined(RLTEXGPU_LOG)
+        // Undefine it first in order to supress warnings about macro redefinition
+        #undef RLTEXGPU_LOG
+    #endif
+    #define RLTEXGPU_LOG(...)
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+// Get pixel data size in bytes for certain pixel format
+static int get_pixel_data_size(int width, int height, int format);
+
+// Get OpenGL internal formats and data type from rlGpuTexPixelFormat
+void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsigned int *gl_format, unsigned int *gl_type);
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+#if defined(RLTEXGPU_SUPPORT_DDS)
+// Loading DDS from memory image data (compressed or uncompressed)
+void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
+{
+    void *image_data = RLTEXGPU_NULL;  // Image data pointer
+    int image_pixel_size = 0;           // Image pixel size
+
+    unsigned char *file_data_ptr = (unsigned char *)file_data;
+
+    // Required extension:
+    // GL_EXT_texture_compression_s3tc
+
+    // Supported tokens (defined by extensions)
+    // GL_COMPRESSED_RGB_S3TC_DXT1_EXT      0x83F0
+    // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT     0x83F1
+    // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT     0x83F2
+    // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT     0x83F3
+
+    #define FOURCC_DXT1 0x31545844  // Equivalent to "DXT1" in ASCII
+    #define FOURCC_DXT3 0x33545844  // Equivalent to "DXT3" in ASCII
+    #define FOURCC_DXT5 0x35545844  // Equivalent to "DXT5" in ASCII
+
+    // DDS Pixel Format
+    typedef struct {
+        unsigned int size;
+        unsigned int flags;
+        unsigned int fourcc;
+        unsigned int rgb_bit_count;
+        unsigned int r_bit_mask;
+        unsigned int g_bit_mask;
+        unsigned int b_bit_mask;
+        unsigned int a_bit_mask;
+    } dds_pixel_format;
+
+    // DDS Header (124 bytes)
+    typedef struct {
+        unsigned int size;
+        unsigned int flags;
+        unsigned int height;
+        unsigned int width;
+        unsigned int pitch_or_linear_size;
+        unsigned int depth;
+        unsigned int mipmap_count;
+        unsigned int reserved1[11];
+        dds_pixel_format ddspf;
+        unsigned int caps;
+        unsigned int caps2;
+        unsigned int caps3;
+        unsigned int caps4;
+        unsigned int reserved2;
+    } dds_header;
+
+    if (file_data_ptr != RLTEXGPU_NULL)
+    {
+        // Verify the type of file
+        unsigned char *dds_header_id = file_data_ptr;
+        file_data_ptr += 4;
+
+        if ((dds_header_id[0] != 'D') || (dds_header_id[1] != 'D') || (dds_header_id[2] != 'S') || (dds_header_id[3] != ' '))
+        {
+            RLTEXGPU_LOG("DDS file data not valid");
+        }
+        else
+        {
+            dds_header *header = (dds_header *)file_data_ptr;
+
+            file_data_ptr += sizeof(dds_header);        // Skip header
+
+            *width = header->width;
+            *height = header->height;
+
+            if (*width % 4 != 0) RLTEXGPU_LOG("DDS file width must be multiple of 4. Image will not display correctly");
+            if (*height % 4 != 0) RLTEXGPU_LOG("DDS file height must be multiple of 4. Image will not display correctly");
+
+            image_pixel_size = header->width*header->height;
+
+            if (header->mipmap_count == 0) *mips = 1;   // Parameter not used
+            else *mips = header->mipmap_count;
+
+            if (header->ddspf.rgb_bit_count == 16)      // 16bit mode, no compressed
+            {
+                if (header->ddspf.flags == 0x40)        // No alpha channel
+                {
+                    int data_size = image_pixel_size*sizeof(unsigned short);
+                    if (header->mipmap_count > 1) data_size = data_size + data_size/3;
+                    image_data = RLTEXGPU_MALLOC(data_size);
+
+                    RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                    *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5;
+                }
+                else if (header->ddspf.flags == 0x41)           // With alpha channel
+                {
+                    if (header->ddspf.a_bit_mask == 0x8000)     // 1bit alpha
+                    {
+                        int data_size = image_pixel_size*sizeof(unsigned short);
+                        if (header->mipmap_count > 1) data_size = data_size + data_size/3;
+                        image_data = RLTEXGPU_MALLOC(data_size);
+
+                        RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                        unsigned char alpha = 0;
+
+                        // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1
+                        for (int i = 0; i < data_size/sizeof(unsigned short); i++)
+                        {
+                            alpha = ((unsigned short *)image_data)[i] >> 15;
+                            ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1;
+                            ((unsigned short *)image_data)[i] += alpha;
+                        }
+
+                        *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
+                    }
+                    else if (header->ddspf.a_bit_mask == 0xf000)   // 4bit alpha
+                    {
+                        int data_size = image_pixel_size*sizeof(unsigned short);
+                        if (header->mipmap_count > 1) data_size = data_size + data_size/3;
+                        image_data = RLTEXGPU_MALLOC(data_size);
+
+                        RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                        unsigned char alpha = 0;
+
+                        // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4
+                        for (int i = 0; i < data_size/sizeof(unsigned short); i++)
+                        {
+                            alpha = ((unsigned short *)image_data)[i] >> 12;
+                            ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4;
+                            ((unsigned short *)image_data)[i] += alpha;
+                        }
+
+                        *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
+                    }
+                }
+            }
+            else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
+            {
+                int data_size = image_pixel_size*3*sizeof(unsigned char);
+                if (header->mipmap_count > 1) data_size = data_size + data_size/3;
+                image_data = RLTEXGPU_MALLOC(data_size);
+
+                RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+            }
+            else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed
+            {
+                int data_size = image_pixel_size*4*sizeof(unsigned char);
+                if (header->mipmap_count > 1) data_size = data_size + data_size/3;
+                image_data = RLTEXGPU_MALLOC(data_size);
+
+                RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                unsigned char blue = 0;
+
+                // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment)
+                // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA
+                // So, we must realign B8G8R8A8 to R8G8B8A8
+                for (int i = 0; i < data_size; i += 4)
+                {
+                    blue = ((unsigned char *)image_data)[i];
+                    ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];
+                    ((unsigned char *)image_data)[i + 2] = blue;
+                }
+
+                *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+            }
+            else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed
+            {
+                int data_size = 0;
+
+                // Calculate data size, including all mipmaps
+                if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size/3;
+                else data_size = header->pitch_or_linear_size;
+
+                image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char));
+
+                RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                switch (header->ddspf.fourcc)
+                {
+                    case FOURCC_DXT1:
+                    {
+                        if (header->ddspf.flags == 0x04) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB;
+                        else *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA;
+                    } break;
+                    case FOURCC_DXT3: *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA; break;
+                    case FOURCC_DXT5: *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA; break;
+                    default: break;
+                }
+            }
+        }
+    }
+
+    return image_data;
+}
+#endif
+
+#if defined(RLTEXGPU_SUPPORT_PKM)
+// Loading PKM image data (ETC1/ETC2 compression)
+// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
+// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
+void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
+{
+    void *image_data = RLTEXGPU_NULL;        // Image data pointer
+
+    unsigned char *file_data_ptr = (unsigned char *)file_data;
+
+    // Required extensions:
+    // GL_OES_compressed_ETC1_RGB8_texture  (ETC1) (OpenGL ES 2.0)
+    // GL_ARB_ES3_compatibility  (ETC2/EAC) (OpenGL ES 3.0)
+
+    // Supported tokens (defined by extensions)
+    // GL_ETC1_RGB8_OES                 0x8D64
+    // GL_COMPRESSED_RGB8_ETC2          0x9274
+    // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
+
+    // PKM file (ETC1) Header (16 bytes)
+    typedef struct {
+        char id[4];                 // "PKM "
+        char version[2];            // "10" or "20"
+        unsigned short format;      // Data format (big-endian) (Check list below)
+        unsigned short width;       // Texture width (big-endian) (orig_width rounded to multiple of 4)
+        unsigned short height;      // Texture height (big-endian) (orig_height rounded to multiple of 4)
+        unsigned short orig_width;   // Original width (big-endian)
+        unsigned short orig_height;  // Original height (big-endian)
+    } pkm_header;
+
+    // Formats list
+    // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
+    // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R
+
+    // NOTE: The extended width and height are the widths rounded up to a multiple of 4
+    // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels)
+
+    if (file_data_ptr != RLTEXGPU_NULL)
+    {
+        pkm_header *header = (pkm_header *)file_data_ptr;
+
+        if ((header->id[0] != 'P') || (header->id[1] != 'K') || (header->id[2] != 'M') || (header->id[3] != ' '))
+        {
+            RLTEXGPU_LOG("PKM file data not valid");
+        }
+        else
+        {
+            file_data_ptr += sizeof(pkm_header);   // Skip header
+
+            // NOTE: format, width and height come as big-endian, data must be swapped to little-endian
+            header->format = ((header->format & 0x00FF) << 8) | ((header->format & 0xFF00) >> 8);
+            header->width = ((header->width & 0x00FF) << 8) | ((header->width & 0xFF00) >> 8);
+            header->height = ((header->height & 0x00FF) << 8) | ((header->height & 0xFF00) >> 8);
+
+            *width = header->width;
+            *height = header->height;
+            *mips = 1;
+
+            int bpp = 4;
+            if (header->format == 3) bpp = 8;
+
+            int data_size = (*width)*(*height)*bpp/8;  // Total data size in bytes
+
+            image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char));
+
+            RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+            if (header->format == 0) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB;
+            else if (header->format == 1) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB;
+            else if (header->format == 3) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
+        }
+    }
+
+    return image_data;
+}
+#endif
+
+#if defined(RLTEXGPU_SUPPORT_KTX)
+// Load KTX compressed image data (ETC1/ETC2 compression)
+// TODO: Review KTX loading, many things changed!
+void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
+{
+    void *image_data = RLTEXGPU_NULL;        // Image data pointer
+
+    unsigned char *file_data_ptr = (unsigned char *)file_data;
+
+    // Required extensions:
+    // GL_OES_compressed_ETC1_RGB8_texture  (ETC1)
+    // GL_ARB_ES3_compatibility  (ETC2/EAC)
+
+    // Supported tokens (defined by extensions)
+    // GL_ETC1_RGB8_OES                 0x8D64
+    // GL_COMPRESSED_RGB8_ETC2          0x9274
+    // GL_COMPRESSED_RGBA8_ETC2_EAC     0x9278
+
+    // KTX file Header (64 bytes)
+    // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
+    // v2.0 - http://github.khronos.org/KTX-Specification/
+
+    // KTX 1.1 Header
+    // TODO: Support KTX 2.2 specs!
+    typedef struct {
+        char id[12];                            // Identifier: "«KTX 11»\r\n\x1A\n"
+        unsigned int endianness;                // Little endian: 0x01 0x02 0x03 0x04
+        unsigned int gl_type;                   // For compressed textures, glType must equal 0
+        unsigned int gl_type_size;              // For compressed texture data, usually 1
+        unsigned int gl_format;                 // For compressed textures is 0
+        unsigned int gl_internal_format;        // Compressed internal format
+        unsigned int gl_base_internal_format;   // Same as glFormat (RGB, RGBA, ALPHA...)
+        unsigned int width;                     // Texture image width in pixels
+        unsigned int height;                    // Texture image height in pixels
+        unsigned int depth;                     // For 2D textures is 0
+        unsigned int elements;                  // Number of array elements, usually 0
+        unsigned int faces;                     // Cubemap faces, for no-cubemap = 1
+        unsigned int mipmap_levels;             // Non-mipmapped textures = 1
+        unsigned int key_value_data_size;       // Used to encode any arbitrary data...
+    } ktx_header;
+
+    // NOTE: Before start of every mipmap data block, we have: unsigned int data_size
+
+    if (file_data_ptr != RLTEXGPU_NULL)
+    {
+        ktx_header *header = (ktx_header *)file_data_ptr;
+
+        if ((header->id[1] != 'K') || (header->id[2] != 'T') || (header->id[3] != 'X') ||
+            (header->id[4] != ' ') || (header->id[5] != '1') || (header->id[6] != '1'))
+        {
+            RLTEXGPU_LOG("KTX file data not valid");
+        }
+        else
+        {
+            file_data_ptr += sizeof(ktx_header);           // Move file data pointer
+
+            *width = header->width;
+            *height = header->height;
+            *mips = header->mipmap_levels;
+
+            file_data_ptr += header->key_value_data_size; // Skip value data size
+
+            int data_size = ((int *)file_data_ptr)[0];
+            file_data_ptr += sizeof(int);
+
+            image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char));
+
+            RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+            if (header->gl_internal_format == 0x8D64) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB;
+            else if (header->gl_internal_format == 0x9274) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB;
+            else if (header->gl_internal_format == 0x9278) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
+
+            // TODO: Support uncompressed data formats? Right now it returns format = 0!
+        }
+    }
+
+    return image_data;
+}
+
+// Save image data as KTX file
+// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
+// TODO: Review KTX saving, many things changed!
+int rl_save_ktx(const char *file_name, void *data, int width, int height, int format, int mipmaps)
+{
+    // KTX file Header (64 bytes)
+    // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
+    // v2.0 - https://github.khronos.org/KTX-Specification/ktxspec.v2.html
+    typedef struct {
+        char id[12];                            // Identifier: "«KTX 11»\r\n\x1A\n"         // KTX 2.0: "«KTX 20»\r\n\x1A\n"
+        unsigned int endianness;                // Little endian: 0x01 0x02 0x03 0x04
+        unsigned int gl_type;                   // For compressed textures, glType must equal 0
+        unsigned int gl_type_size;              // For compressed texture data, usually 1
+        unsigned int gl_format;                 // For compressed textures is 0
+        unsigned int gl_internal_format;        // Compressed internal format
+        unsigned int gl_base_internal_format;   // Same as glFormat (RGB, RGBA, ALPHA...)   // KTX 2.0: UInt32 vkFormat
+        unsigned int width;                     // Texture image width in pixels
+        unsigned int height;                    // Texture image height in pixels
+        unsigned int depth;                     // For 2D textures is 0
+        unsigned int elements;                  // Number of array elements, usually 0
+        unsigned int faces;                     // Cubemap faces, for no-cubemap = 1
+        unsigned int mipmap_levels;             // Non-mipmapped textures = 1
+        unsigned int key_value_data_size;       // Used to encode any arbitrary data...     // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0
+                                                                                            // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)...
+        // KTX 2.0 defines additional header elements...
+    } ktx_header;
+
+    /*
+    Byte[12] identifier
+    UInt32 vkFormat
+    UInt32 typeSize
+    UInt32 pixelWidth
+    UInt32 pixelHeight
+    UInt32 pixelDepth
+    UInt32 layerCount
+    UInt32 faceCount
+    UInt32 levelCount
+    UInt32 supercompressionScheme
+    */
+
+    // Calculate file data_size required
+    int data_size = sizeof(ktx_header);
+
+    for (int i = 0, w = width, h = height; i < mipmaps; i++)
+    {
+        data_size += get_pixel_data_size(w, h, format);
+        w /= 2; h /= 2;
+    }
+
+    unsigned char *file_data = RLTEXGPU_MALLOC(data_size);
+    unsigned char *file_data_ptr = file_data;
+
+    ktx_header header = { 0 };
+
+    // KTX identifier (v1.1)
+    //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
+    //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
+
+    const char ktx_identifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
+
+    // Get the image header
+    RLTEXGPU_MEMCPY(header.id, ktx_identifier, 12);  // KTX 1.1 signature
+    header.endianness = 0;
+    header.gl_type = 0;                     // Obtained from format
+    header.gl_type_size = 1;
+    header.gl_format = 0;                   // Obtained from format
+    header.gl_internal_format = 0;          // Obtained from format
+    header.gl_base_internal_format = 0;
+    header.width = width;
+    header.height = height;
+    header.depth = 0;
+    header.elements = 0;
+    header.faces = 1;
+    header.mipmap_levels = mipmaps;         // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
+    header.key_value_data_size = 0;         // No extra data after the header
+
+    // TODO: WARNING: Function dependant on rlgl library!
+    rlGetGlTextureFormats(format, &header.gl_internal_format, &header.gl_format, &header.gl_type); // rlgl module function
+
+    header.gl_base_internal_format = header.gl_format; // TODO: WARNING: KTX 1.1 only
+
+    // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
+
+    if (header.gl_format == -1) RLTEXGPU_LOG("RL_GPUTEX: GL format not supported for KTX export (%i)", header.gl_format);
+    else
+    {
+        RLTEXGPU_MEMCPY(file_data_ptr, &header, sizeof(ktx_header));
+        file_data_ptr += sizeof(ktx_header);
+
+        int temp_width = width;
+        int temp_height = height;
+        int data_offset = 0;
+
+        // Save all mipmaps data
+        for (int i = 0; i < mipmaps; i++)
+        {
+            unsigned int data_size = get_pixel_data_size(temp_width, temp_height, format);
+
+            RLTEXGPU_MEMCPY(file_data_ptr, &data_size, sizeof(unsigned int));
+            RLTEXGPU_MEMCPY(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size);
+
+            temp_width /= 2;
+            temp_height /= 2;
+            data_offset += data_size;
+            file_data_ptr += (4 + data_size);
+        }
+    }
+
+    // Save file data to file
+    int success = false;
+    FILE *file = fopen(file_name, "wb");
+
+    if (file != RLTEXGPU_NULL)
+    {
+        unsigned int count = (unsigned int)fwrite(file_data, sizeof(unsigned char), data_size, file);
+
+        if (count == 0) RLTEXGPU_LOG("FILEIO: [%s] Failed to write file", file_name);
+        else if (count != data_size) RLTEXGPU_LOG("FILEIO: [%s] File partially written", file_name);
+        else (void)0;
+
+        int result = fclose(file);
+        if (result != 0) RLTEXGPU_LOG("FILEIO: [%s] Failed to close file", file_name);
+
+        if (result == 0 && count == data_size) success = true;
+    }
+    else RLTEXGPU_LOG("FILEIO: [%s] Failed to open file", file_name);
+
+    RLTEXGPU_FREE(file_data);    // Free file data buffer
+
+    // If all data has been written correctly to file, success = 1
+    return success;
+}
+#endif
+
+#if defined(RLTEXGPU_SUPPORT_PVR)
+// Loading PVR image data (uncompressed or PVRT compression)
+// NOTE: PVR v2 not supported, use PVR v3 instead
+void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
+{
+    void *image_data = RLTEXGPU_NULL;        // Image data pointer
+
+    unsigned char *file_data_ptr = (unsigned char *)file_data;
+
+    // Required extension:
+    // GL_IMG_texture_compression_pvrtc
+
+    // Supported tokens (defined by extensions)
+    // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG       0x8C00
+    // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG      0x8C02
+
+#if 0   // Not used...
+    // PVR file v2 Header (52 bytes)
+    typedef struct {
+        unsigned int headerLength;
+        unsigned int height;
+        unsigned int width;
+        unsigned int numMipmaps;
+        unsigned int flags;
+        unsigned int dataLength;
+        unsigned int bpp;
+        unsigned int bitmaskRed;
+        unsigned int bitmaskGreen;
+        unsigned int bitmaskBlue;
+        unsigned int bitmaskAlpha;
+        unsigned int pvrTag;
+        unsigned int numSurfs;
+    } PVRHeaderV2;
+#endif
+
+    // PVR file v3 Header (52 bytes)
+    // NOTE: After it could be metadata (15 bytes?)
+    typedef struct {
+        char id[4];
+        unsigned int flags;
+        unsigned char channels[4];      // pixelFormat high part
+        unsigned char channel_depth[4];  // pixelFormat low part
+        unsigned int color_space;
+        unsigned int channel_type;
+        unsigned int height;
+        unsigned int width;
+        unsigned int depth;
+        unsigned int num_surfaces;
+        unsigned int num_faces;
+        unsigned int num_mipmaps;
+        unsigned int metadata_size;
+    } pvr_header;
+
+#if 0   // Not used...
+    // Metadata (usually 15 bytes)
+    typedef struct {
+        unsigned int devFOURCC;
+        unsigned int key;
+        unsigned int data_size;      // Not used?
+        unsigned char *data;        // Not used?
+    } PVRMetadata;
+#endif
+
+    if (file_data_ptr != RLTEXGPU_NULL)
+    {
+        // Check PVR image version
+        unsigned char pvr_version = file_data_ptr[0];
+
+        // Load different PVR data formats
+        if (pvr_version == 0x50)
+        {
+            pvr_header *header = (pvr_header *)file_data_ptr;
+
+            if ((header->id[0] != 'P') || (header->id[1] != 'V') || (header->id[2] != 'R') || (header->id[3] != 3))
+            {
+                RLTEXGPU_LOG("PVR file data not valid");
+            }
+            else
+            {
+                file_data_ptr += sizeof(pvr_header);   // Skip header
+
+                *width = header->width;
+                *height = header->height;
+                *mips = header->num_mipmaps;
+
+                // Check data format
+                if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+                else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
+                else if ((header->channels[0] == 'r') && (header->channels[1] == 'g') && (header->channels[2] == 'b'))
+                {
+                    if (header->channels[3] == 'a')
+                    {
+                        if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
+                        else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
+                        else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+                    }
+                    else if (header->channels[3] == 0)
+                    {
+                        if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5;
+                        else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+                    }
+                }
+                else if (header->channels[0] == 2) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB;
+                else if (header->channels[0] == 3) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA;
+
+                file_data_ptr += header->metadata_size;    // Skip meta data header
+
+                // Calculate data size (depends on format)
+                int bpp = 0;
+                switch (*format)
+                {
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
+                    case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
+                    case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB:
+                    case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
+                    default: break;
+                }
+
+                int data_size = (*width)*(*height)*bpp/8;  // Total data size in bytes
+                image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char));
+
+                RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+            }
+        }
+        else if (pvr_version == 52) RLTEXGPU_LOG("PVRv2 format not supported, update your files to PVRv3");
+    }
+
+    return image_data;
+}
+#endif
+
+#if defined(RLTEXGPU_SUPPORT_ASTC)
+// Load ASTC compressed image data (ASTC compression)
+void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
+{
+    void *image_data = RLTEXGPU_NULL;        // Image data pointer
+
+    unsigned char *file_data_ptr = (unsigned char *)file_data;
+
+    // Required extensions:
+    // GL_KHR_texture_compression_astc_hdr
+    // GL_KHR_texture_compression_astc_ldr
+
+    // Supported tokens (defined by extensions)
+    // GL_COMPRESSED_RGBA_ASTC_4x4_KHR      0x93b0
+    // GL_COMPRESSED_RGBA_ASTC_8x8_KHR      0x93b7
+
+    // ASTC file Header (16 bytes)
+    typedef struct {
+        unsigned char id[4];        // Signature: 0x13 0xAB 0xA1 0x5C
+        unsigned char blockX;       // Block X dimensions
+        unsigned char blockY;       // Block Y dimensions
+        unsigned char blockZ;       // Block Z dimensions (1 for 2D images)
+        unsigned char width[3];     // void *width in pixels (24bit value)
+        unsigned char height[3];    // void *height in pixels (24bit value)
+        unsigned char length[3];    // void *Z-size (1 for 2D images)
+    } astc_header;
+
+    if (file_data_ptr != RLTEXGPU_NULL)
+    {
+        astc_header *header = (astc_header *)file_data_ptr;
+
+        if ((header->id[3] != 0x5c) || (header->id[2] != 0xa1) || (header->id[1] != 0xab) || (header->id[0] != 0x13))
+        {
+            RLTEXGPU_LOG("ASTC file data not valid");
+        }
+        else
+        {
+            file_data_ptr += sizeof(astc_header);   // Skip header
+
+            // NOTE: Assuming Little Endian (could it be wrong?)
+            *width = 0x00000000 | ((int)header->width[2] << 16) | ((int)header->width[1] << 8) | ((int)header->width[0]);
+            *height = 0x00000000 | ((int)header->height[2] << 16) | ((int)header->height[1] << 8) | ((int)header->height[0]);
+            *mips = 1;      // NOTE: ASTC format only contains one mipmap level
+
+            // NOTE: Each block is always stored in 128bit so we can calculate the bpp
+            int bpp = 128/(header->blockX*header->blockY);
+
+            // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
+            if ((bpp == 8) || (bpp == 2))
+            {
+                int data_size = (*width)*(*height)*bpp/8;  // Data size in bytes
+
+                image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char));
+
+                RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size);
+
+                if (bpp == 8) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA;
+                else if (bpp == 2) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA;
+            }
+            else RLTEXGPU_LOG("ASTC block size configuration not supported");
+        }
+    }
+
+    return image_data;
+}
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+// Get pixel data size in bytes for certain pixel format
+static int get_pixel_data_size(int width, int height, int format)
+{
+    int data_size = 0;       // Size in bytes
+    int bpp = 0;            // Bits per pixel
+
+    switch (format)
+    {
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
+        default: break;
+    }
+
+    data_size = width*height*bpp/8;  // 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 ((format >= RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8;
+        else if ((format >= RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16;
+    }
+
+    return data_size;
+}
+
+// Get OpenGL internal formats and data type from rlGpuTexPixelFormat
+void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsigned int *gl_format, unsigned int *gl_type)
+{
+    // KTX 1.1 uses OpenGL formats on header info but KTX 2.0 uses Vulkan texture formats,
+    // if this library is being improved to support KTX 2.0, it requires those formats to be provided -> View list at the end!
+
+    /*
+    *gl_internal_format = 0;
+    *gl_format = 0;
+    *gl_type = 0;
+
+    switch (format)
+    {
+    #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
+        // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_LUMINANCE_ALPHA; *gl_format = GL_LUMINANCE_ALPHA; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break;
+        #if !defined(GRAPHICS_API_OPENGL_11)
+        #if defined(GRAPHICS_API_OPENGL_ES3)
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F_EXT; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F_EXT; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_HALF_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F_EXT; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F_EXT; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break;
+        #else
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_FLOAT; break;            // NOTE: Requires extension OES_texture_float
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;                  // NOTE: Requires extension OES_texture_float
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;             // NOTE: Requires extension OES_texture_float
+        #if defined(GRAPHICS_API_OPENGL_21)
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_ARB; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_ARB; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_ARB; break;
+        #else // defined(GRAPHICS_API_OPENGL_ES2)
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_OES; break;   // NOTE: Requires extension OES_texture_half_float
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_OES; break;         // NOTE: Requires extension OES_texture_half_float
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_OES; break;    // NOTE: Requires extension OES_texture_half_float
+        #endif
+        #endif
+        #endif
+    #elif defined(GRAPHICS_API_OPENGL_33)
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_R8; *gl_format = GL_RED; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_RG8; *gl_format = GL_RG; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB565; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB8; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGB5_A1; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA4; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA8; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F; *gl_format = GL_RED; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F; *gl_format = GL_RED; *gl_type = GL_HALF_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break;
+        case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break;
+    #endif
+    #if !defined(GRAPHICS_API_OPENGL_11)
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB: *gl_internal_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB: *gl_internal_format = GL_ETC1_RGB8_OES; break;                      // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB: *gl_internal_format = GL_COMPRESSED_RGB8_ETC2; break;               // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA8_ETC2_EAC; break;     // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB: *gl_internal_format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break;    // NOTE: Requires PowerVR GPU
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break;  // NOTE: Requires PowerVR GPU
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break;  // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
+        case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break;  // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3
+    #endif
+        default: RLTEXGPU_LOG("GPUTEX: Current format not supported (%i)", format); break;
+    }
+    */
+}
+#endif // RLTEXGPU_IMPLEMENTATION
+
+/*
+// OpenGL texture data formats
+// NOTE: Those values can be useful for KTX 1.1 saving,
+// probably only the latest OpenGL ones, not the extensions ones
+// So, there is no need to include full OpenGL headers
+#define GL_UNSIGNED_BYTE                      0x1401
+#define GL_UNSIGNED_SHORT_5_6_5               0x8363
+#define GL_UNSIGNED_SHORT_4_4_4_4             0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1             0x8034
+#define GL_FLOAT                              0x1406
+#define GL_HALF_FLOAT                         0x140b
+#define GL_HALF_FLOAT_ARB                     0x140b
+#define GL_HALF_FLOAT_OES                     0x8d61
+
+#define GL_RED_EXT                            0x1903
+#define GL_RGB                                0x1907
+#define GL_RGBA                               0x1908
+#define GL_LUMINANCE                          0x1909
+#define GL_R8                                 0x8229
+#define GL_RG8                                0x822b
+#define GL_RGB565                             0x8d62
+#define GL_RGB8                               0x8051
+#define GL_RGB5_A1                            0x8057
+#define GL_RGBA4                              0x8056
+#define GL_RGBA8                              0x8058
+#define GL_R16F                               0x822d
+#define GL_RGB16F                             0x881b
+#define GL_RGBA16F                            0x881a
+#define GL_R32F                               0x822e
+#define GL_RGB32F                             0x8815
+#define GL_RGBA32F                            0x8814
+
+#define GL_R32F_EXT                           0x822e
+#define GL_RGB32F_EXT                         0x8815
+#define GL_RGBA32F_EXT                        0x8814
+#define GL_R16F_EXT                           0x822d
+#define GL_RGB16F_EXT                         0x881b
+#define GL_RGBA16F_EXT                        0x881a
+
+// S3TC (DXT) compression
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT       0x83f0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      0x83f1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      0x83f2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      0x83f3
+
+// ETC formats
+#define GL_ETC1_RGB8_OES                      0x8d64
+#define GL_COMPRESSED_RGB8_ETC2               0x9274
+#define GL_COMPRESSED_RGBA8_ETC2_EAC          0x9278
+
+// PVRTC
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG    0x8c00
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG   0x8c02
+
+// ASTC
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR       0x93b0
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR       0x93b7
+*/
+
+/*
+// Vulkan texture formats
+typedef enum VkFormat {
+    // Provided by VK_VERSION_1_0
+    VK_FORMAT_UNDEFINED = 0,
+    VK_FORMAT_R4G4_UNORM_PACK8 = 1,
+    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
+    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
+    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
+    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
+    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
+    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
+    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
+    VK_FORMAT_R8_UNORM = 9,
+    VK_FORMAT_R8_SNORM = 10,
+    VK_FORMAT_R8_USCALED = 11,
+    VK_FORMAT_R8_SSCALED = 12,
+    VK_FORMAT_R8_UINT = 13,
+    VK_FORMAT_R8_SINT = 14,
+    VK_FORMAT_R8_SRGB = 15,
+    VK_FORMAT_R8G8_UNORM = 16,
+    VK_FORMAT_R8G8_SNORM = 17,
+    VK_FORMAT_R8G8_USCALED = 18,
+    VK_FORMAT_R8G8_SSCALED = 19,
+    VK_FORMAT_R8G8_UINT = 20,
+    VK_FORMAT_R8G8_SINT = 21,
+    VK_FORMAT_R8G8_SRGB = 22,
+    VK_FORMAT_R8G8B8_UNORM = 23,
+    VK_FORMAT_R8G8B8_SNORM = 24,
+    VK_FORMAT_R8G8B8_USCALED = 25,
+    VK_FORMAT_R8G8B8_SSCALED = 26,
+    VK_FORMAT_R8G8B8_UINT = 27,
+    VK_FORMAT_R8G8B8_SINT = 28,
+    VK_FORMAT_R8G8B8_SRGB = 29,
+    VK_FORMAT_B8G8R8_UNORM = 30,
+    VK_FORMAT_B8G8R8_SNORM = 31,
+    VK_FORMAT_B8G8R8_USCALED = 32,
+    VK_FORMAT_B8G8R8_SSCALED = 33,
+    VK_FORMAT_B8G8R8_UINT = 34,
+    VK_FORMAT_B8G8R8_SINT = 35,
+    VK_FORMAT_B8G8R8_SRGB = 36,
+    VK_FORMAT_R8G8B8A8_UNORM = 37,
+    VK_FORMAT_R8G8B8A8_SNORM = 38,
+    VK_FORMAT_R8G8B8A8_USCALED = 39,
+    VK_FORMAT_R8G8B8A8_SSCALED = 40,
+    VK_FORMAT_R8G8B8A8_UINT = 41,
+    VK_FORMAT_R8G8B8A8_SINT = 42,
+    VK_FORMAT_R8G8B8A8_SRGB = 43,
+    VK_FORMAT_B8G8R8A8_UNORM = 44,
+    VK_FORMAT_B8G8R8A8_SNORM = 45,
+    VK_FORMAT_B8G8R8A8_USCALED = 46,
+    VK_FORMAT_B8G8R8A8_SSCALED = 47,
+    VK_FORMAT_B8G8R8A8_UINT = 48,
+    VK_FORMAT_B8G8R8A8_SINT = 49,
+    VK_FORMAT_B8G8R8A8_SRGB = 50,
+    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
+    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
+    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
+    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
+    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
+    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
+    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
+    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
+    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
+    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
+    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
+    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
+    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
+    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
+    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
+    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
+    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
+    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
+    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
+    VK_FORMAT_R16_UNORM = 70,
+    VK_FORMAT_R16_SNORM = 71,
+    VK_FORMAT_R16_USCALED = 72,
+    VK_FORMAT_R16_SSCALED = 73,
+    VK_FORMAT_R16_UINT = 74,
+    VK_FORMAT_R16_SINT = 75,
+    VK_FORMAT_R16_SFLOAT = 76,
+    VK_FORMAT_R16G16_UNORM = 77,
+    VK_FORMAT_R16G16_SNORM = 78,
+    VK_FORMAT_R16G16_USCALED = 79,
+    VK_FORMAT_R16G16_SSCALED = 80,
+    VK_FORMAT_R16G16_UINT = 81,
+    VK_FORMAT_R16G16_SINT = 82,
+    VK_FORMAT_R16G16_SFLOAT = 83,
+    VK_FORMAT_R16G16B16_UNORM = 84,
+    VK_FORMAT_R16G16B16_SNORM = 85,
+    VK_FORMAT_R16G16B16_USCALED = 86,
+    VK_FORMAT_R16G16B16_SSCALED = 87,
+    VK_FORMAT_R16G16B16_UINT = 88,
+    VK_FORMAT_R16G16B16_SINT = 89,
+    VK_FORMAT_R16G16B16_SFLOAT = 90,
+    VK_FORMAT_R16G16B16A16_UNORM = 91,
+    VK_FORMAT_R16G16B16A16_SNORM = 92,
+    VK_FORMAT_R16G16B16A16_USCALED = 93,
+    VK_FORMAT_R16G16B16A16_SSCALED = 94,
+    VK_FORMAT_R16G16B16A16_UINT = 95,
+    VK_FORMAT_R16G16B16A16_SINT = 96,
+    VK_FORMAT_R16G16B16A16_SFLOAT = 97,
+    VK_FORMAT_R32_UINT = 98,
+    VK_FORMAT_R32_SINT = 99,
+    VK_FORMAT_R32_SFLOAT = 100,
+    VK_FORMAT_R32G32_UINT = 101,
+    VK_FORMAT_R32G32_SINT = 102,
+    VK_FORMAT_R32G32_SFLOAT = 103,
+    VK_FORMAT_R32G32B32_UINT = 104,
+    VK_FORMAT_R32G32B32_SINT = 105,
+    VK_FORMAT_R32G32B32_SFLOAT = 106,
+    VK_FORMAT_R32G32B32A32_UINT = 107,
+    VK_FORMAT_R32G32B32A32_SINT = 108,
+    VK_FORMAT_R32G32B32A32_SFLOAT = 109,
+    VK_FORMAT_R64_UINT = 110,
+    VK_FORMAT_R64_SINT = 111,
+    VK_FORMAT_R64_SFLOAT = 112,
+    VK_FORMAT_R64G64_UINT = 113,
+    VK_FORMAT_R64G64_SINT = 114,
+    VK_FORMAT_R64G64_SFLOAT = 115,
+    VK_FORMAT_R64G64B64_UINT = 116,
+    VK_FORMAT_R64G64B64_SINT = 117,
+    VK_FORMAT_R64G64B64_SFLOAT = 118,
+    VK_FORMAT_R64G64B64A64_UINT = 119,
+    VK_FORMAT_R64G64B64A64_SINT = 120,
+    VK_FORMAT_R64G64B64A64_SFLOAT = 121,
+    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
+    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
+    VK_FORMAT_D16_UNORM = 124,
+    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
+    VK_FORMAT_D32_SFLOAT = 126,
+    VK_FORMAT_S8_UINT = 127,
+    VK_FORMAT_D16_UNORM_S8_UINT = 128,
+    VK_FORMAT_D24_UNORM_S8_UINT = 129,
+    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
+    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
+    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
+    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
+    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
+    VK_FORMAT_BC2_UNORM_BLOCK = 135,
+    VK_FORMAT_BC2_SRGB_BLOCK = 136,
+    VK_FORMAT_BC3_UNORM_BLOCK = 137,
+    VK_FORMAT_BC3_SRGB_BLOCK = 138,
+    VK_FORMAT_BC4_UNORM_BLOCK = 139,
+    VK_FORMAT_BC4_SNORM_BLOCK = 140,
+    VK_FORMAT_BC5_UNORM_BLOCK = 141,
+    VK_FORMAT_BC5_SNORM_BLOCK = 142,
+    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
+    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
+    VK_FORMAT_BC7_UNORM_BLOCK = 145,
+    VK_FORMAT_BC7_SRGB_BLOCK = 146,
+    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
+    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
+    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
+    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
+    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
+    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
+    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
+    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
+    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
+    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
+    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
+    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
+    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
+    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
+    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
+    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
+    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
+    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
+    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
+    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
+    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
+    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
+    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
+    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
+    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
+    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
+    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
+    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
+    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
+    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
+    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
+    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
+    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
+    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
+    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
+    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
+    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
+    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
+    // Provided by VK_VERSION_1_1
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012,
+    // Provided by VK_VERSION_1_3
+    VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013,
+    // Provided by VK_VERSION_1_4
+    VK_FORMAT_A1B5G5R5_UNORM_PACK16 = 1000470000,
+    // Provided by VK_VERSION_1_4
+    VK_FORMAT_A8_UNORM = 1000470001,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
+    // Provided by VK_IMG_format_pvrtc
+    VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
+    // Provided by VK_ARM_tensors
+    VK_FORMAT_R8_BOOL_ARM = 1000460000,
+    // Provided by VK_NV_optical_flow
+    VK_FORMAT_R16G16_SFIXED5_NV = 1000464000,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R10X6_UINT_PACK16_ARM = 1000609000,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R10X6G10X6_UINT_2PACK16_ARM = 1000609001,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UINT_4PACK16_ARM = 1000609002,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R12X4_UINT_PACK16_ARM = 1000609003,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R12X4G12X4_UINT_2PACK16_ARM = 1000609004,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UINT_4PACK16_ARM = 1000609005,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2_UINT_PACK16_ARM = 1000609006,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2G14X2_UINT_2PACK16_ARM = 1000609007,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2G14X2B14X2A14X2_UINT_4PACK16_ARM = 1000609008,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2_UNORM_PACK16_ARM = 1000609009,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2G14X2_UNORM_2PACK16_ARM = 1000609010,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_R14X2G14X2B14X2A14X2_UNORM_4PACK16_ARM = 1000609011,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_G14X2_B14X2R14X2_2PLANE_420_UNORM_3PACK16_ARM = 1000609012,
+    // Provided by VK_ARM_format_pack
+    VK_FORMAT_G14X2_B14X2R14X2_2PLANE_422_UNORM_3PACK16_ARM = 1000609013,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK,
+    // Provided by VK_EXT_texture_compression_astc_hdr
+    VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
+    // Provided by VK_KHR_sampler_ycbcr_conversion
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
+    // Provided by VK_EXT_ycbcr_2plane_444_formats
+    VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
+    // Provided by VK_EXT_ycbcr_2plane_444_formats
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16,
+    // Provided by VK_EXT_ycbcr_2plane_444_formats
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16,
+    // Provided by VK_EXT_ycbcr_2plane_444_formats
+    VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM,
+    // Provided by VK_EXT_4444_formats
+    VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16,
+    // Provided by VK_EXT_4444_formats
+    VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16,
+    // Provided by VK_NV_optical_flow
+    // VK_FORMAT_R16G16_S10_5_NV is a deprecated alias
+    VK_FORMAT_R16G16_S10_5_NV = VK_FORMAT_R16G16_SFIXED5_NV,
+    // Provided by VK_KHR_maintenance5
+    VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = VK_FORMAT_A1B5G5R5_UNORM_PACK16,
+    // Provided by VK_KHR_maintenance5
+    VK_FORMAT_A8_UNORM_KHR = VK_FORMAT_A8_UNORM,
+} VkFormat;
+*/
diff --git a/raylib/src/external/rprand.h b/raylib/src/external/rprand.h
--- a/raylib/src/external/rprand.h
+++ b/raylib/src/external/rprand.h
@@ -1,6 +1,6 @@
 /**********************************************************************************************
 *
-*   rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
+*   rprand v1.1 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
 *
 *   FEATURES:
 *       - Pseudo-random values generation, 32 bits: [0..4294967295]
@@ -118,6 +118,7 @@
 //----------------------------------------------------------------------------------
 RPRANDAPI void rprand_set_seed(unsigned long long seed);        // Set rprand_state for Xoshiro128**, seed is 64bit
 RPRANDAPI int rprand_get_value(int min, int max);               // Get random value within a range, min and max included
+RPRANDAPI int rprand_get_value_raw(void);                       // Get random value, Xoshiro128** generator (uses global rprand_state)
 
 RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates
 RPRANDAPI void rprand_unload_sequence(int *sequence);           // Unload pseudo-random numbers sequence
@@ -182,6 +183,13 @@
 int rprand_get_value(int min, int max)
 {
     int value = rprand_xoshiro()%(abs(max - min) + 1) + min;
+
+    return value;
+}
+
+int rprand_get_value_raw(void)
+{
+    int value = rprand_xoshiro();
 
     return value;
 }
diff --git a/raylib/src/external/stb_image_resize2.h b/raylib/src/external/stb_image_resize2.h
--- a/raylib/src/external/stb_image_resize2.h
+++ b/raylib/src/external/stb_image_resize2.h
@@ -1,4 +1,4 @@
-/* stb_image_resize2 - v2.12 - public domain image resizing
+/* stb_image_resize2 - v2.18 - public domain image resizing
 
    by Jeff Roberts (v2) and Jorge L Rodriguez
    http://github.com/nothings/stb
@@ -141,13 +141,13 @@
          COLOR+ALPHA buffer types tell the resizer to do.
 
          When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB,
-         STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are
+         STBIR_ABGR, STBIR_RA, or STBIR_AR you are telling us that the pixels are
          non-premultiplied. In these cases, the resizer will alpha weight the colors
          (effectively creating the premultiplied image), do the filtering, and then
          convert back to non-premult on exit.
 
-         When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM,
-         STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels
+         When you use the pixel layouts STBIR_RGBA_PM, STBIR_BGRA_PM, STBIR_ARGB_PM,
+         STBIR_ABGR_PM, STBIR_RA_PM or STBIR_AR_PM, you are telling that the pixels
          ARE premultiplied. In this case, the resizer doesn't have to do the
          premultipling - it can filter directly on the input. This about twice as
          fast as the non-premultiplied case, so it's the right option if your data is
@@ -254,7 +254,7 @@
          using the stbir_set_filter_callbacks function.
 
       PROGRESS
-         For interactive use with slow resize operations, you can use the the
+         For interactive use with slow resize operations, you can use the 
          scanline callbacks in the extended API. It would have to be a *very* large
          image resample to need progress though - we're very fast.
 
@@ -307,6 +307,8 @@
            some pixel reconversion, but probably dwarfed by things falling out
            of cache. Probably also something possible with alternating between
            scattering and gathering at high resize scales?
+         * Should we have a multiple MIPs at the same time function (could keep
+           more memory in cache during multiple resizes)?
          * Rewrite the coefficient generator to do many at once.
          * AVX-512 vertical kernels - worried about downclocking here.
          * Convert the reincludes to macros when we know they aren't changing.
@@ -327,6 +329,24 @@
       Nathan Reed: warning fixes for 1.0
 
    REVISIONS
+      2.18 (2026-03-25) fixed coefficient calculation when skipping a coefficient off 
+                          the left side of the window, added non-aligned access safe 
+                          memcpy mode for scalar path, fixed various typos, and fixed 
+                          define error in the float clamp output mode. 
+      2.17 (2025-10-25) silly format bug in easy-to-use APIs.
+      2.16 (2025-10-21) fixed the easy-to-use APIs to allow inverted bitmaps (negative
+                          strides), fix vertical filter kernel callback, fix threaded
+                          gather buffer priming (and assert).
+                          (thanks adipose, TainZerL, and Harrison Green)
+      2.15 (2025-07-17) fixed an assert in debug mode when using floats with input
+                          callbacks, work around GCC warning when adding to null ptr
+                          (thanks Johannes Spohr and Pyry Kovanen).
+      2.14 (2025-05-09) fixed a bug using downsampling gather horizontal first, and 
+                          scatter with vertical first.
+      2.13 (2025-02-27) fixed a bug when using input callbacks, turned off simd for 
+                          tiny-c, fixed some variables that should have been static,
+                          fixes a bug when calculating temp memory with resizes that
+                          exceed 2GB of temp memory (very large resizes).
       2.12 (2024-10-18) fix incorrect use of user_data with STBIR_FREE
       2.11 (2024-09-08) fix harmless asan warnings in 2-channel and 3-channel mode
                           with AVX-2, fix some weird scaling edge conditions with
@@ -382,62 +402,6 @@
 typedef uint64_t stbir_uint64;
 #endif
 
-#ifdef _M_IX86_FP
-#if ( _M_IX86_FP >= 1 )
-#ifndef STBIR_SSE
-#define STBIR_SSE
-#endif
-#endif
-#endif
-
-#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2)
-  #ifndef STBIR_SSE2
-    #define STBIR_SSE2
-  #endif
-  #if defined(__AVX__) || defined(STBIR_AVX2)
-    #ifndef STBIR_AVX
-      #ifndef STBIR_NO_AVX
-        #define STBIR_AVX
-      #endif
-    #endif
-  #endif
-  #if defined(__AVX2__) || defined(STBIR_AVX2)
-    #ifndef STBIR_NO_AVX2
-      #ifndef STBIR_AVX2
-        #define STBIR_AVX2
-      #endif
-      #if defined( _MSC_VER ) && !defined(__clang__)
-        #ifndef STBIR_FP16C  // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c
-          #define STBIR_FP16C
-        #endif
-      #endif
-    #endif
-  #endif
-  #ifdef __F16C__
-    #ifndef STBIR_FP16C  // turn on FP16C instructions if the define is set (for clang and gcc)
-      #define STBIR_FP16C
-    #endif
-  #endif
-#endif
-
-#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__)
-#ifndef STBIR_NEON
-#define STBIR_NEON
-#endif
-#endif
-
-#if defined(_M_ARM) || defined(__arm__)
-#ifdef STBIR_USE_FMA
-#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
-#endif
-#endif
-
-#if defined(__wasm__) && defined(__wasm_simd128__)
-#ifndef STBIR_WASM
-#define STBIR_WASM
-#endif
-#endif
-
 #ifndef STBIRDEF
 #ifdef STB_IMAGE_RESIZE_STATIC
 #define STBIRDEF static
@@ -1036,7 +1000,7 @@
   char no_cache_straddle[64];
 } stbir__per_split_info;
 
-typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input );
+typedef float * stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input );
 typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels );
 typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer,
   stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width );
@@ -1099,8 +1063,8 @@
 
 #define stbir__max_uint8_as_float             255.0f
 #define stbir__max_uint16_as_float            65535.0f
-#define stbir__max_uint8_as_float_inverted    (1.0f/255.0f)
-#define stbir__max_uint16_as_float_inverted   (1.0f/65535.0f)
+#define stbir__max_uint8_as_float_inverted    3.9215689e-03f     // (1.0f/255.0f)
+#define stbir__max_uint16_as_float_inverted   1.5259022e-05f     // (1.0f/65535.0f)
 #define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
 
 // min/max friendly
@@ -1205,6 +1169,69 @@
 #define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split?
 #endif
 
+#define STBIR_INPUT_CALLBACK_PADDING 3
+
+#ifdef _M_IX86_FP
+#if ( _M_IX86_FP >= 1 )
+#ifndef STBIR_SSE
+#define STBIR_SSE
+#endif
+#endif
+#endif
+
+#ifdef __TINYC__
+  // tiny c has no intrinsics yet - this can become a version check if they add them
+  #define STBIR_NO_SIMD
+#endif
+
+#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2)
+  #ifndef STBIR_SSE2
+    #define STBIR_SSE2
+  #endif
+  #if defined(__AVX__) || defined(STBIR_AVX2)
+    #ifndef STBIR_AVX
+      #ifndef STBIR_NO_AVX
+        #define STBIR_AVX
+      #endif
+    #endif
+  #endif
+  #if defined(__AVX2__) || defined(STBIR_AVX2)
+    #ifndef STBIR_NO_AVX2
+      #ifndef STBIR_AVX2
+        #define STBIR_AVX2
+      #endif
+      #if defined( _MSC_VER ) && !defined(__clang__)
+        #ifndef STBIR_FP16C  // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -mf16c
+          #define STBIR_FP16C
+        #endif
+      #endif
+    #endif
+  #endif
+  #ifdef __F16C__
+    #ifndef STBIR_FP16C  // turn on FP16C instructions if the define is set (for clang and gcc)
+      #define STBIR_FP16C
+    #endif
+  #endif
+#endif
+
+#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__)
+#ifndef STBIR_NEON
+#define STBIR_NEON
+#endif
+#endif
+
+#if defined(_M_ARM) || defined(__arm__)
+#ifdef STBIR_USE_FMA
+#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
+#endif
+#endif
+
+#if defined(__wasm__) && defined(__wasm_simd128__)
+#ifndef STBIR_WASM
+#define STBIR_WASM
+#endif
+#endif
+
 // restrict pointers for the output pointers, other loop and unroll control
 #if defined( _MSC_VER ) && !defined(__clang__)
   #define STBIR_STREAMOUT_PTR( star ) star __restrict
@@ -1451,8 +1478,8 @@
     #include <smmintrin.h>
     #define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))
   #else
-    STBIR__SIMDI_CONST(stbir__s32_32768, 32768);
-    STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768));
+    static STBIR__SIMDI_CONST(stbir__s32_32768, 32768);
+    static STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768));
 
     #define stbir__simdf_pack_to_8words(out,reg0,reg1) \
       { \
@@ -2545,7 +2572,7 @@
 static const STBIR__SIMDF_CONST(STBIR_ones,          1.0f);
 static const STBIR__SIMDI_CONST(STBIR_almost_zero,   (127 - 13) << 23);
 static const STBIR__SIMDI_CONST(STBIR_almost_one,    0x3f7fffff);
-static const STBIR__SIMDI_CONST(STBIR_mastissa_mask, 0xff);
+static const STBIR__SIMDI_CONST(STBIR_mantissa_mask, 0xff);
 static const STBIR__SIMDI_CONST(STBIR_topscale,      0x02000000);
 
 //   Basically, in simd mode, we unroll the proper amount, and we don't want
@@ -2816,16 +2843,34 @@
   char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;
   ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;
 
-  if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away?
+  if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away
   {
     char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7);
-    STBIR_NO_UNROLL_LOOP_START
-    do
+
+    if ( ( ( ((ptrdiff_t)dest)|((ptrdiff_t)src) ) & 7 ) == 0 ) // is it 8byte aligned?
     {
-      STBIR_NO_UNROLL(sd);
-      *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd;
-      sd += 8;
-    } while ( sd < s_end8 );
+      STBIR_NO_UNROLL_LOOP_START
+      do
+      {
+        STBIR_NO_UNROLL(sd);
+        *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd;
+        sd += 8;
+      } while ( sd < s_end8 );
+    }
+    else
+    {
+      STBIR_NO_UNROLL_LOOP_START
+      do
+      {
+        int a,b;
+        STBIR_NO_UNROLL(sd);
+        a = ((int*)sd)[0];
+        b = ((int*)sd)[1];
+        ((int*)( sd + ofs_to_dest ))[0] = a;
+        ((int*)( sd + ofs_to_dest ))[1] = b;
+        sd += 8;
+      } while ( sd < s_end8 );
+    }
 
     if ( sd == s_end )
       return;
@@ -3217,10 +3262,9 @@
     newspan->n0 = -left_margin;
     newspan->n1 = ( max_left - min_left ) - left_margin;
     scanline_extents->edge_sizes[0] = 0;  // don't need to copy the left margin, since we are directly decoding into the margin
-    return;
   }
-
-  // if we can't merge the min_left range, add it as a second range
+  // if we can't merge the min_right range, add it as a second range
+  else  
   if ( ( right_margin ) && ( min_right != 0x7fffffff ) )
   {
     stbir__span * newspan = scanline_extents->spans + 1;
@@ -3235,8 +3279,15 @@
     newspan->n0 = scanline_extents->spans[1].n1 + 1;
     newspan->n1 = scanline_extents->spans[1].n1 + 1 + ( max_right - min_right );
     scanline_extents->edge_sizes[1] = 0;  // don't need to copy the right margin, since we are directly decoding into the margin
-    return;
   }
+
+  // sort the spans into write output order
+  if ( ( scanline_extents->spans[1].n1 > scanline_extents->spans[1].n0 ) && ( scanline_extents->spans[0].n0 > scanline_extents->spans[1].n0 ) )
+  {
+    stbir__span tspan = scanline_extents->spans[0];
+    scanline_extents->spans[0] = scanline_extents->spans[1];
+    scanline_extents->spans[1] = tspan;
+  }
 }
 
 static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel, float out_pixel_center, float out_filter_radius, float inv_scale, float out_shift, int input_size, stbir_edge edge )
@@ -3328,23 +3379,29 @@
 
 static void stbir__insert_coeff( stbir__contributors * contribs, float * coeffs, int new_pixel, float new_coeff, int max_width )
 {
-  if ( new_pixel <= contribs->n1 )  // before the end
+  if ( contribs->n1 < contribs->n0 ) // this first clause should never happen, but handle in case
   {
+    contribs->n0 = contribs->n1 = new_pixel;
+    coeffs[0] = new_coeff;
+  }
+  else if ( new_pixel <= contribs->n1 )  // before the end
+  {
     if ( new_pixel < contribs->n0 ) // before the front?
     {
       if ( ( contribs->n1 - new_pixel + 1 ) <= max_width )
       { 
         int j, o = contribs->n0 - new_pixel;
-        for ( j = contribs->n1 - contribs->n0 ; j <= 0 ; j-- )
+        for ( j = contribs->n1 - contribs->n0 ; j >= 0 ; j-- )
           coeffs[ j + o ] = coeffs[ j ];
-        for ( j = 1 ; j < o ; j-- )
-          coeffs[ j ] = coeffs[ 0 ];
+        for ( j = 1 ; j < o ; j++ )
+          coeffs[ j ] = 0;
         coeffs[ 0 ] = new_coeff;
         contribs->n0 = new_pixel;
       }
     }
     else
     {
+      // add new weight to existing coeff if already there
       coeffs[ new_pixel - contribs->n0 ] += new_coeff;
     }
   }
@@ -3791,7 +3848,7 @@
     }
   }
 
-  // some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal
+  // some horizontal routines read one float off the end (which is then masked off), so put in a sentinel so we don't read an snan or denormal
   coefficents[ widest * num_contributors ] = 8888.0f;
 
   // the minimum we might read for unrolled filters widths is 12. So, we need to
@@ -4560,7 +4617,8 @@
   int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size);
   const void* input_plane_data = ( (char *) stbir_info->input_data ) + (size_t)row * (size_t) stbir_info->input_stride_bytes;
   stbir__span const * spans = stbir_info->scanline_extents.spans;
-  float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels;
+  float * full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels;
+  float * last_decoded = 0;
 
   // if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed
   STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) );
@@ -4588,12 +4646,12 @@
     if ( stbir_info->in_pixels_cb )
     {
       // call the callback with a temp buffer (that they can choose to use or not).  the temp is just right aligned memory in the decode_buffer itself
-      input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data );
+      input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ) + ( ( stbir_info->input_type != STBIR_TYPE_FLOAT ) ? ( sizeof(float)*STBIR_INPUT_CALLBACK_PADDING ) : 0 ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data );
     }
 
     STBIR_PROFILE_START( decode );
     // convert the pixels info the float decode_buffer, (we index from end_decode, so that when channels<effective_channels, we are right justified in the buffer)
-    stbir_info->decode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );
+    last_decoded = stbir_info->decode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );
     STBIR_PROFILE_END( decode );
 
     if (stbir_info->alpha_weight)
@@ -4628,9 +4686,19 @@
         float * marg = full_decode_buffer + x * effective_channels;
         float const * src = full_decode_buffer + stbir__edge_wrap(edge_horizontal, x, input_full_size) * effective_channels;
         STBIR_MEMCPY( marg, src, margin * effective_channels * sizeof(float) );
+        if ( e == 1 ) last_decoded = marg + margin * effective_channels;
       }
     }
   }
+  
+  // some of the horizontal gathers read one float off the edge (which is masked out), but we force a zero here to make sure no NaNs leak in
+  //   (we can't pre-zero it, because the input callback can use that area as padding)
+  last_decoded[0] = 0.0f; 
+
+  // we clear this extra float, because the final output pixel filter kernel might have used one less coeff than the max filter width
+  //   when this happens, we do read that pixel from the input, so it too could be Nan, so just zero an extra one.
+  //   this fits because each scanline is padded by three floats (STBIR_INPUT_CALLBACK_PADDING)
+  last_decoded[1] = 0.0f;
 }
 
 
@@ -6209,6 +6277,8 @@
   if ( vertical_first )
   {
     // Now resample the gathered vertical data in the horizontal axis into the encode buffer
+    decode_buffer[ width_times_channels ] = 0.0f; // clear two over for horizontals with a remnant of 3
+    decode_buffer[ width_times_channels+1 ] = 0.0f; 
     stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
   }
 
@@ -6380,6 +6450,8 @@
   void * scanline_scatter_buffer;
   void * scanline_scatter_buffer_end;
   int on_first_input_y, last_input_y;
+  int width = (stbir_info->vertical_first) ? ( stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1 ) : stbir_info->horizontal.scale_info.output_sub_size;
+  int width_times_channels = stbir_info->effective_channels * width;
 
   STBIR_ASSERT( !stbir_info->vertical.is_gather );
 
@@ -6414,7 +6486,12 @@
 
   // mark all the buffers as empty to start
   for( y = 0 ; y < stbir_info->ring_buffer_num_entries ; y++ )
-    stbir__get_ring_buffer_entry( stbir_info, split_info, y )[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter
+  {
+    float * decode_buffer = stbir__get_ring_buffer_entry( stbir_info, split_info, y );
+    decode_buffer[ width_times_channels ] = 0.0f; // clear two over for horizontals with a remnant of 3
+    decode_buffer[ width_times_channels+1 ] = 0.0f; 
+    decode_buffer[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter
+  }
 
   // do the loop in input space
   on_first_input_y = 1; last_input_y = start_input_y;
@@ -6562,7 +6639,7 @@
   samp->num_contributors = stbir__get_contributors(samp, samp->is_gather);
 
   samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors);
-  samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding
+  samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float)*STBIR_INPUT_CALLBACK_PADDING; // extra sizeof(float) is padding
 
   samp->gather_prescatter_contributors = 0;
   samp->gather_prescatter_coefficients = 0;
@@ -6667,7 +6744,7 @@
   }
 }
 
-static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height )
+static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height, int is_gather, stbir__contributors * contribs )
 {
   int i, cur;
   int left = output_height;
@@ -6676,9 +6753,58 @@
   for( i = 0 ; i < splits ; i++ )
   {
     int each;
+
     split_info[i].start_output_y = cur;
     each = left / ( splits - i );
     split_info[i].end_output_y = cur + each;
+
+    // ok, when we are gathering, we need to make sure we are starting on a y offset that doesn't have
+    //   a "special" set of coefficients. Basically, with exactly the right filter at exactly the right
+    //   resize at exactly the right phase, some of the coefficents can be zero. When they are zero, we
+    //   don't process them at all.  But this leads to a tricky thing with the thread splits, where we
+    //   might have a set of two coeffs like this for example: (4,4) and (3,6).  The 4,4 means there was
+    //   just one single coeff because things worked out perfectly (normally, they all have 4 coeffs
+    //   like the range 3,6.  The problem is that if we start right on the (4,4) on a brand new thread,
+    //   then when we get to (3,6), we don't have the "3" sample in memory (because we didn't load
+    //   it on the initial (4,4) range because it didn't have a 3 (we only add new samples that are 
+    //   larger than our existing samples - it's just how the eviction works). So, our solution here
+    //   is pretty simple, if we start right on a range that has samples that start earlier, then we 
+    //   simply bump up our previous thread split range to include it, and then start this threads
+    //   range with the smaller sample. It just moves one scanline from one thread split to another,
+    //   so that we end with the unusual one, instead of start with it. To do this, we check 2-4 
+    //   sample at each thread split start and then occassionally move them.
+    
+    if ( ( is_gather ) && ( i ) )
+    {
+      stbir__contributors * small_contribs;
+      int j, smallest, stop, start_n0;
+      stbir__contributors * split_contribs = contribs + cur;
+
+      // scan for a max of 3x the filter width or until the next thread split
+      stop = vertical_pixel_margin * 3;
+      if ( each < stop )
+        stop = each;
+
+      // loops a few times before early out
+      smallest = 0;
+      small_contribs = split_contribs;
+      start_n0 = small_contribs->n0;
+      for( j = 1 ; j <= stop ; j++ )
+      {
+        ++split_contribs;
+        if ( split_contribs->n0 > start_n0 )
+          break;
+        if ( split_contribs->n0 < small_contribs->n0 )
+        {
+          small_contribs = split_contribs;
+          smallest = j;
+        }
+      }
+
+      split_info[i-1].end_output_y += smallest;
+      split_info[i].start_output_y += smallest;
+    }
+
     cur += each;
     left -= each;
 
@@ -6774,45 +6900,45 @@
     { 0.56250f, 0.59375f, 0.00000f, 0.96875f },
     { 1.00000f, 0.06250f, 0.00000f, 1.00000f },
     { 0.00000f, 0.09375f, 1.00000f, 1.00000f },
-    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.31250f, 1.00000f },
     { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
-    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.06250f, 1.00000f },
     { 0.00000f, 1.00000f, 0.00000f, 0.03125f },
   }, {
     { 0.00000f, 0.84375f, 0.00000f, 0.03125f },
     { 0.09375f, 0.93750f, 0.00000f, 0.78125f },
     { 0.87500f, 0.21875f, 0.00000f, 0.96875f },
     { 0.09375f, 0.09375f, 1.00000f, 1.00000f },
-    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.00000f, 0.84375f, 0.00000f, 0.03125f },
     { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
-    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.06250f, 1.00000f },
     { 0.00000f, 1.00000f, 0.00000f, 0.53125f },
   }, {
     { 0.00000f, 0.53125f, 0.00000f, 0.03125f },
     { 0.06250f, 0.96875f, 0.00000f, 0.53125f },
     { 0.87500f, 0.18750f, 0.00000f, 0.93750f },
     { 0.00000f, 0.09375f, 1.00000f, 1.00000f },
-    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.00000f, 0.53125f, 0.00000f, 0.03125f },
     { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
-    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.06250f, 1.00000f },
     { 0.00000f, 1.00000f, 0.00000f, 0.56250f },
   }, {
     { 0.00000f, 0.50000f, 0.00000f, 0.71875f },
     { 0.06250f, 0.84375f, 0.00000f, 0.87500f },
     { 1.00000f, 0.50000f, 0.50000f, 0.96875f },
     { 1.00000f, 0.09375f, 0.31250f, 0.50000f },
-    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.00000f, 0.50000f, 0.00000f, 0.71875f },
     { 1.00000f, 0.03125f, 0.03125f, 0.53125f },
-    { 0.18750f, 0.12500f, 0.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.06250f, 1.00000f },
     { 0.00000f, 1.00000f, 0.03125f, 0.18750f },
   }, {
     { 0.00000f, 0.59375f, 0.00000f, 0.96875f },
     { 0.06250f, 0.81250f, 0.06250f, 0.59375f },
     { 0.75000f, 0.43750f, 0.12500f, 0.96875f },
     { 0.87500f, 0.06250f, 0.18750f, 0.43750f },
-    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.00000f, 0.59375f, 0.00000f, 0.96875f },
     { 0.15625f, 0.12500f, 1.00000f, 1.00000f },
-    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 0.06250f, 1.00000f },
     { 0.00000f, 1.00000f, 0.03125f, 0.34375f },
   }
 };
@@ -6866,16 +6992,16 @@
   // categorize the resize into buckets
   if ( ( vertical_output_size <= 4 ) || ( horizontal_output_size <= 4 ) )
     v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7;
+  else if ( ( !is_gather ) && ( ( vertical_output_size <= 16 ) || ( horizontal_output_size <= 16 ) ) )
+    v_classification = 4;
   else if ( vertical_scale <= 1.0f )
     v_classification = ( is_gather ) ? 1 : 0;
   else if ( vertical_scale <= 2.0f)
     v_classification = 2;
   else if ( vertical_scale <= 3.0f)
     v_classification = 3;
-  else if ( vertical_scale <= 4.0f)
-    v_classification = 5;
-  else
-    v_classification = 6;
+  else 
+    v_classification = 5; // everything bigger than 3x
 
   // use the right weights
   weights = weights_table[ v_classification ];
@@ -6927,7 +7053,8 @@
   void * alloced = 0;
   size_t alloced_total = 0;
   int vertical_first;
-  int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries;
+  size_t decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size;
+  int alloc_ring_buffer_num_entries;
 
   int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy
   int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size );
@@ -6972,14 +7099,16 @@
   vertical_first = stbir__should_do_vertical_first( stbir__compute_weights[ (int)stbir_channel_count_index[ effective_channels ] ], horizontal->filter_pixel_width, horizontal->scale_info.scale, horizontal->scale_info.output_sub_size, vertical->filter_pixel_width, vertical->scale_info.scale, vertical->scale_info.output_sub_size, vertical->is_gather, STBIR__V_FIRST_INFO_POINTER );
 
   // sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect)
-  decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
+  //   we use a few extra floats instead of just 1, so that input callback buffer can overlap with the decode buffer without
+  //   the conversion routines overwriting the callback input data.
+  decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float)*STBIR_INPUT_CALLBACK_PADDING; // extra floats for input callback stagger
 
 #if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8)
   if ( effective_channels == 3 )
     decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations)
 #endif
 
-  ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
+  ring_buffer_length_bytes = (size_t)horizontal->scale_info.output_sub_size * (size_t)effective_channels * sizeof(float) + sizeof(float)*STBIR_INPUT_CALLBACK_PADDING; // extra floats for padding
 
   // if we do vertical first, the ring buffer holds a whole decoded line
   if ( vertical_first )
@@ -6994,13 +7123,13 @@
   if ( ( !vertical->is_gather ) && ( alloc_ring_buffer_num_entries > conservative_split_output_size ) )
     alloc_ring_buffer_num_entries = conservative_split_output_size;
 
-  ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes;
+  ring_buffer_size = (size_t)alloc_ring_buffer_num_entries * (size_t)ring_buffer_length_bytes;
 
   // The vertical buffer is used differently, depending on whether we are scattering
   //   the vertical scanlines, or gathering them.
   //   If scattering, it's used at the temp buffer to accumulate each output.
   //   If gathering, it's just the output buffer.
-  vertical_buffer_size = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float);  // extra float for padding
+  vertical_buffer_size = (size_t)horizontal->scale_info.output_sub_size * (size_t)effective_channels * sizeof(float) + sizeof(float);  // extra float for padding
 
   // we make two passes through this loop, 1st to add everything up, 2nd to allocate and init
   for(;;)
@@ -7013,7 +7142,7 @@
 #ifdef STBIR__SEPARATE_ALLOCATIONS
     #define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; }
 #else
-    #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size);
+    #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = (char*)(((size_t)advance_mem) + (size));
 #endif
 
     STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info );
@@ -7036,9 +7165,9 @@
 
       info->offset_x = new_x;
       info->offset_y = new_y;
-      info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries;
+      info->alloc_ring_buffer_num_entries = (int)alloc_ring_buffer_num_entries;
       info->ring_buffer_num_entries = 0;
-      info->ring_buffer_length_bytes = ring_buffer_length_bytes;
+      info->ring_buffer_length_bytes = (int)ring_buffer_length_bytes;
       info->splits = splits;
       info->vertical_first = vertical_first;
 
@@ -7119,14 +7248,14 @@
     // alloc memory for to-be-pivoted coeffs (if necessary)
     if ( vertical->is_gather == 0 )
     {
-      int both;
-      int temp_mem_amt;
+      size_t both;
+      size_t temp_mem_amt;
 
       // when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after,
       //   that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that
       //   is too small, we just allocate extra memory to use as this temp.
 
-      both = vertical->gather_prescatter_contributors_size + vertical->gather_prescatter_coefficients_size;
+      both = (size_t)vertical->gather_prescatter_contributors_size + (size_t)vertical->gather_prescatter_coefficients_size;
 
 #ifdef STBIR__SEPARATE_ALLOCATIONS
       temp_mem_amt = decode_buffer_size;
@@ -7136,7 +7265,7 @@
         --temp_mem_amt; // avx in 3 channel mode needs one float at the start of the buffer
       #endif
 #else
-      temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits;
+      temp_mem_amt = (size_t)( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * (size_t)splits;
 #endif
       if ( temp_mem_amt >= both )
       {
@@ -7222,7 +7351,7 @@
       }
 
       // setup the vertical split ranges
-      stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size );
+      stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size, info->vertical.is_gather, info->vertical.contributors );
 
       // now we know precisely how many entries we need
       info->ring_buffer_num_entries = info->vertical.extent_info.widest;
@@ -7231,39 +7360,7 @@
       if ( ( !info->vertical.is_gather ) && ( info->ring_buffer_num_entries > conservative_split_output_size ) )
         info->ring_buffer_num_entries = conservative_split_output_size;
       STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries );
-
-      // a few of the horizontal gather functions read past the end of the decode (but mask it out), 
-      //   so put in normal values so no snans or denormals accidentally sneak in (also, in the ring 
-      //   buffer for vertical first)
-      for( i = 0 ; i < splits ; i++ )
-      {
-        int t, ofs, start;
-
-        ofs = decode_buffer_size / 4;
-
-        #if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8)
-        if ( effective_channels == 3 ) 
-          --ofs; // avx in 3 channel mode needs one float at the start of the buffer, so we snap back for clearing
-        #endif
-
-        start = ofs - 4;
-        if ( start < 0 ) start = 0;
-
-        for( t = start ; t < ofs; t++ )
-          info->split_info[i].decode_buffer[ t ] = 9999.0f;
-
-        if ( vertical_first )
-        {
-          int j;
-          for( j = 0; j < info->ring_buffer_num_entries ; j++ )
-          {
-            for( t = start ; t < ofs; t++ )
-              stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f;
-          }
-        }
-      }
     }
-
     #undef STBIR__NEXT_PTR
 
 
@@ -7528,7 +7625,7 @@
     numer_estimate = temp;
   }
 
-  // we didn't fine anything good enough for float, use a full range estimate
+  // we didn't find anything good enough for float, use a full range estimate
   if ( limit_denom )
   {
     numer_estimate= (stbir_uint64)( f * (double)limit + 0.5 );
@@ -7818,7 +7915,7 @@
 
   stbir__set_sampler(&horizontal, resize->horizontal_filter, resize->horizontal_filter_kernel, resize->horizontal_filter_support, resize->horizontal_edge, &horizontal.scale_info, 1, resize->user_data );
   stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data );
-  stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data );
+  stbir__set_sampler(&vertical, resize->vertical_filter, resize->vertical_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data );
 
   if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice)
   {
@@ -7849,7 +7946,7 @@
   return 0;
 }
 
-void stbir_free_samplers( STBIR_RESIZE * resize )
+STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize )
 {
   if ( resize->samplers )
   {
@@ -7943,93 +8040,99 @@
   return stbir__perform_resize( resize->samplers, split_start, split_count );
 }
 
-static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * output_pixels, int type_size, int output_w, int output_h, int output_stride_in_bytes, stbir_internal_pixel_layout pixel_layout )
+
+static void * stbir_quick_resize_helper( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                               void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                               stbir_pixel_layout pixel_layout, stbir_datatype data_type, stbir_edge edge, stbir_filter filter )
 {
-  size_t size;
-  int pitch;
-  void * ptr;
+  STBIR_RESIZE resize;
+  int scanline_output_in_bytes;
+  int positive_output_stride_in_bytes;
+  void * start_ptr;
+  void * free_ptr;
 
-  pitch = output_w * type_size * stbir__pixel_channels[ pixel_layout ];
-  if ( pitch == 0 )
+  scanline_output_in_bytes = output_w * stbir__type_size[ data_type ] * stbir__pixel_channels[ stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ];
+  if ( scanline_output_in_bytes == 0 )
     return 0;
 
+  // if zero stride, use scanline output
   if ( output_stride_in_bytes == 0 )
-    output_stride_in_bytes = pitch;
+    output_stride_in_bytes = scanline_output_in_bytes;
 
-  if ( output_stride_in_bytes < pitch )
-    return 0;
+  // abs value for inverted images (negative pitches)
+  positive_output_stride_in_bytes = output_stride_in_bytes;
+  if ( positive_output_stride_in_bytes < 0 )
+    positive_output_stride_in_bytes = -positive_output_stride_in_bytes;
 
-  size = (size_t)output_stride_in_bytes * (size_t)output_h;
-  if ( size == 0 )
+  // is the requested stride smaller than the scanline output? if so, just fail
+  if ( positive_output_stride_in_bytes < scanline_output_in_bytes )
     return 0;
 
-  *ret_ptr = 0;
-  *ret_pitch = output_stride_in_bytes;
+  start_ptr = output_pixels;
+  free_ptr = 0;  // no free pointer, since they passed buffer to use
 
+  // did they pass a zero for the dest? if so, allocate the buffer
   if ( output_pixels == 0 )
   {
-    ptr = STBIR_MALLOC( size, 0 );
-    if ( ptr == 0 )
+    size_t size;
+    char * ptr;
+  
+    size = (size_t)positive_output_stride_in_bytes * (size_t)output_h;
+    if ( size == 0 )
       return 0;
 
-    *ret_ptr = ptr;
-    *ret_pitch = pitch;
-  }
-
-  return 1;
-}
-
+    ptr = (char*) STBIR_MALLOC( size, 0 );
+    if ( ptr == 0 )
+      return 0;
 
-STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
-                                                          unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                                          stbir_pixel_layout pixel_layout )
-{
-  STBIR_RESIZE resize;
-  unsigned char * optr;
-  int opitch;
+    free_ptr = ptr;
 
-  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
-    return 0;
+    // point at the last scanline, if they requested a flipped image
+    if ( output_stride_in_bytes < 0 )
+      start_ptr = ptr + ( (size_t)positive_output_stride_in_bytes * (size_t)( output_h - 1 ) );
+    else
+      start_ptr = ptr;
+  }
 
+  // ok, now do the resize
   stbir_resize_init( &resize,
                      input_pixels,  input_w,  input_h,  input_stride_in_bytes,
-                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
-                     pixel_layout, STBIR_TYPE_UINT8 );
+                     start_ptr, output_w, output_h, output_stride_in_bytes,
+                     pixel_layout, data_type );
 
+  resize.horizontal_edge = edge;
+  resize.vertical_edge = edge;
+  resize.horizontal_filter = filter;
+  resize.vertical_filter = filter;
+
   if ( !stbir_resize_extended( &resize ) )
   {
-    if ( optr )
-      STBIR_FREE( optr, 0 );
+    if ( free_ptr )
+      STBIR_FREE( free_ptr, 0 );
     return 0;
   }
 
-  return (optr) ? optr : output_pixels;
+  return (free_ptr) ? free_ptr : start_ptr;
 }
 
+
+
+STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                          unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                          stbir_pixel_layout pixel_layout )
+{
+  return (unsigned char *) stbir_quick_resize_helper( input_pixels , input_w , input_h, input_stride_in_bytes, 
+                                                      output_pixels, output_w, output_h, output_stride_in_bytes, 
+                                                      pixel_layout, STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT );
+}
+
 STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
                                                         unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
                                                         stbir_pixel_layout pixel_layout )
 {
-  STBIR_RESIZE resize;
-  unsigned char * optr;
-  int opitch;
-
-  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
-    return 0;
-
-  stbir_resize_init( &resize,
-                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
-                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
-                     pixel_layout, STBIR_TYPE_UINT8_SRGB );
-
-  if ( !stbir_resize_extended( &resize ) )
-  {
-    if ( optr )
-      STBIR_FREE( optr, 0 );
-    return 0;
-  }
-
-  return (optr) ? optr : output_pixels;
+  return (unsigned char *) stbir_quick_resize_helper( input_pixels , input_w , input_h, input_stride_in_bytes, 
+                                                      output_pixels, output_w, output_h, output_stride_in_bytes, 
+                                                      pixel_layout, STBIR_TYPE_UINT8_SRGB, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT );
 }
 
 
@@ -8037,66 +8140,27 @@
                                                   float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
                                                   stbir_pixel_layout pixel_layout )
 {
-  STBIR_RESIZE resize;
-  float * optr;
-  int opitch;
-
-  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
-    return 0;
-
-  stbir_resize_init( &resize,
-                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
-                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
-                     pixel_layout, STBIR_TYPE_FLOAT );
-
-  if ( !stbir_resize_extended( &resize ) )
-  {
-    if ( optr )
-      STBIR_FREE( optr, 0 );
-    return 0;
-  }
-
-  return (optr) ? optr : output_pixels;
+  return (float *) stbir_quick_resize_helper( input_pixels , input_w , input_h, input_stride_in_bytes, 
+                                              output_pixels, output_w, output_h, output_stride_in_bytes, 
+                                              pixel_layout, STBIR_TYPE_FLOAT, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT  );
 }
 
 
 STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
                                     void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                              stbir_pixel_layout pixel_layout, stbir_datatype data_type,
-                              stbir_edge edge, stbir_filter filter )
+                                    stbir_pixel_layout pixel_layout, stbir_datatype data_type,
+                                    stbir_edge edge, stbir_filter filter )
 {
-  STBIR_RESIZE resize;
-  float * optr;
-  int opitch;
-
-  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
-    return 0;
-
-  stbir_resize_init( &resize,
-                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
-                     (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes,
-                     pixel_layout, data_type );
-
-  resize.horizontal_edge = edge;
-  resize.vertical_edge = edge;
-  resize.horizontal_filter = filter;
-  resize.vertical_filter = filter;
-
-  if ( !stbir_resize_extended( &resize ) )
-  {
-    if ( optr )
-      STBIR_FREE( optr, 0 );
-    return 0;
-  }
-
-  return (optr) ? optr : output_pixels;
+  return (void *) stbir_quick_resize_helper( input_pixels , input_w , input_h, input_stride_in_bytes, 
+                                             output_pixels, output_w, output_h, output_stride_in_bytes, 
+                                             pixel_layout, data_type, edge, filter  );
 }
 
 #ifdef STBIR_PROFILE
 
 STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )
 {
-  static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient piovot" } ;
+  static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient pivot" } ;
   stbir__info* samp = resize->samplers;
   int i;
 
@@ -8147,7 +8211,7 @@
     info->clocks[i] = sum;
   }
 
-  info->total_clocks = split_info->profile.named.total;
+  info->total_clocks = split_info->profile.named.total; 
   info->descriptions = descriptions;
   info->count = STBIR__ARRAY_SIZE( descriptions );
 }
@@ -8226,7 +8290,7 @@
 #define stbir__encode_simdfX_unflip  stbir__encode_simdf4_unflip
 #endif
 
-static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
   float * decode_end = (float*) decode + width_times_channels;
@@ -8286,7 +8350,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m16;
     }
-    return;
+    return decode_end + 16;
   }
   #endif
 
@@ -8324,6 +8388,8 @@
     input += stbir__coder_min_num;
   }
   #endif
+
+  return decode_end;
 }
 
 static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outputp, int width_times_channels, float const * encode )
@@ -8443,7 +8509,7 @@
   #endif
 }
 
-static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
   float * decode_end = (float*) decode + width_times_channels;
@@ -8497,7 +8563,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m16;
     }
-    return;
+    return decode_end + 16;
   }
   #endif
 
@@ -8535,6 +8601,7 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 }
 
 static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int width_times_channels, float const * encode )
@@ -8636,10 +8703,10 @@
   #endif
 }
 
-static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
-  float const * decode_end = (float*) decode + width_times_channels;
+  float * decode_end = (float*) decode + width_times_channels;
   unsigned char const * input = (unsigned char const *)inputp;
 
   // try to do blocks of 4 when you can
@@ -8674,6 +8741,7 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 }
 
 #define stbir__min_max_shift20( i, f ) \
@@ -8691,7 +8759,7 @@
 { \
     stbir__simdi temp;  \
     stbir__simdi_32shr( temp, stbir_simdi_castf( f ), 12 ) ; \
-    stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mastissa_mask) ); \
+    stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mantissa_mask) ); \
     stbir__simdi_or( temp, temp, STBIR__CONSTI(STBIR_topscale) ); \
     stbir__simdi_16madd( i, i, temp ); \
     stbir__simdi_32shr( i, i, 16 ); \
@@ -8826,11 +8894,12 @@
 
 #if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
 
-static void STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
-  float const * decode_end = (float*) decode + width_times_channels;
+  float * decode_end = (float*) decode + width_times_channels;
   unsigned char const * input = (unsigned char const *)inputp;
+
   do {
     decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];
     decode[1] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order1] ];
@@ -8839,6 +8908,7 @@
     input += 4;
     decode += 4;
   } while( decode < decode_end );
+  return decode_end;
 }
 
 
@@ -8911,11 +8981,12 @@
 
 #if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
 
-static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
-  float const * decode_end = (float*) decode + width_times_channels;
+  float * decode_end = (float*) decode + width_times_channels;
   unsigned char const * input = (unsigned char const *)inputp;
+
   decode += 4;
   while( decode <= decode_end )
   {
@@ -8929,9 +9000,10 @@
   decode -= 4;
   if( decode < decode_end )
   {
-    decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ];
+    decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];
     decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;
   }
+  return decode_end;
 }
 
 static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * outputp, int width_times_channels, float const * encode )
@@ -8997,7 +9069,7 @@
 
 #endif
 
-static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
   float * decode_end = (float*) decode + width_times_channels;
@@ -9045,7 +9117,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m8;
     }
-    return;
+    return decode_end + 8;
   }
   #endif
 
@@ -9083,6 +9155,7 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 }
 
 
@@ -9202,7 +9275,7 @@
   #endif
 }
 
-static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
   float * decode_end = (float*) decode + width_times_channels;
@@ -9247,7 +9320,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m8;
     }
-    return;
+    return decode_end + 8;
   }
   #endif
 
@@ -9285,6 +9358,7 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 }
 
 static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int width_times_channels, float const * encode )
@@ -9385,7 +9459,7 @@
   #endif
 }
 
-static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp )
 {
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
   float * decode_end = (float*) decode + width_times_channels;
@@ -9431,7 +9505,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m8;
     }
-    return;
+    return decode_end + 8;
   }
   #endif
 
@@ -9469,6 +9543,7 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 }
 
 static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp, int width_times_channels, float const * encode )
@@ -9555,7 +9630,7 @@
   #endif
 }
 
-static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp )
+static float * STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp )
 {
   #ifdef stbir__decode_swizzle
   float STBIR_STREAMOUT_PTR( * ) decode = decodep;
@@ -9609,7 +9684,7 @@
       decode = decode_end; // backup and do last couple
       input = end_input_m16;
     }
-    return;
+    return decode_end + 16;
   }
   #endif
 
@@ -9647,18 +9722,21 @@
     input += stbir__coder_min_num;
   }
   #endif
+  return decode_end;
 
   #else
 
   if ( (void*)decodep != inputp )
     STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) );
 
+  return decodep + width_times_channels;
+
   #endif
 }
 
 static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int width_times_channels, float const * encode )
 {
-  #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle)
+  #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LOW_CLAMP) && !defined(stbir__decode_swizzle)
 
   if ( (void*)outputp != (void*) encode )
     STBIR_MEMCPY( outputp, encode, width_times_channels * sizeof( float ) );
@@ -9713,7 +9791,7 @@
       stbir__simdfX_store( output+stbir__simdfX_float_count, e1 );
       encode += stbir__simdfX_float_count * 2;
       output += stbir__simdfX_float_count * 2;
-      if ( output < end_output )
+      if ( output <= end_output )
         continue;
       if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) )
         break;
diff --git a/raylib/src/external/tinyobj_loader_c.h b/raylib/src/external/tinyobj_loader_c.h
--- a/raylib/src/external/tinyobj_loader_c.h
+++ b/raylib/src/external/tinyobj_loader_c.h
@@ -1020,7 +1020,12 @@
                      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 @@
       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 @@
 
     } 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];
       }
diff --git a/raylib/src/external/win32_clipboard.h b/raylib/src/external/win32_clipboard.h
--- a/raylib/src/external/win32_clipboard.h
+++ b/raylib/src/external/win32_clipboard.h
@@ -4,50 +4,50 @@
 
 #ifndef WIN32_CLIPBOARD_
 #define WIN32_CLIPBOARD_
-unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize);
+unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize);
 #endif // WIN32_CLIPBOARD_
 
 #ifdef WIN32_CLIPBOARD_IMPLEMENTATION
 #include <stdio.h>
 #include <stdbool.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <limits.h>
 
-// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h
-// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined.
+// NOTE: These search for architecture is taken from "windows.h", and it's necessary to avoid including windows.h
+// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined
 #if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86)
-#define _X86_
-#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID)
-#define _CHPE_X86_ARM64_
-#endif
+    #define _X86_
+    #if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID)
+        #define _CHPE_X86_ARM64_
+    #endif
 #endif
 
 #if !defined(_AMD64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && (defined(_M_AMD64) || defined(_M_ARM64EC))
-#define _AMD64_
+    #define _AMD64_
 #endif
 
 #if !defined(_ARM_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM)
-#define _ARM_
+    #define _ARM_
 #endif
 
 #if !defined(_ARM64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64EC_) && defined(_M_ARM64)
-#define _ARM64_
+    #define _ARM64_
 #endif
 
 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM64EC)
-#define _ARM64EC_
+    #define _ARM64EC_
 #endif
 
 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_M68K)
-#define _68K_
+    #define _68K_
 #endif
 
 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_MPPC)
-#define _MPPC_
+    #define _MPPC_
 #endif
 
 #if !defined(_IA64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IA64)
-#define _IA64_
+    #define _IA64_
 #endif
 
 
@@ -59,40 +59,39 @@
 // #include <minwinbase.h>
 
 #ifndef WINAPI
-#if defined(_ARM_)
-#define WINAPI
-#else
-#define WINAPI __stdcall
-#endif
+    #if defined(_ARM_)
+        #define WINAPI
+    #else
+        #define WINAPI __stdcall
+    #endif
 #endif
 
 #ifndef WINAPI
-#if defined(_ARM_)
-#define WINAPI
-#else
-#define WINAPI __stdcall
-#endif
+    #if defined(_ARM_)
+        #define WINAPI
+    #else
+        #define WINAPI __stdcall
+    #endif
 #endif
 
 #ifndef WINBASEAPI
-#ifndef _KERNEL32_
-#define WINBASEAPI DECLSPEC_IMPORT
-#else
-#define WINBASEAPI
-#endif
+    #ifndef _KERNEL32_
+        #define WINBASEAPI DECLSPEC_IMPORT
+    #else
+        #define WINBASEAPI
+    #endif
 #endif
 
 #ifndef WINUSERAPI
-#ifndef _USER32_
-#define WINUSERAPI __declspec (dllimport)
-#else
-#define WINUSERAPI
-#endif
+    #ifndef _USER32_
+        #define WINUSERAPI __declspec (dllimport)
+    #else
+        #define WINUSERAPI
+    #endif
 #endif
 
 typedef int WINBOOL;
 
-
 #if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED)
 WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner);
 WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID);
@@ -116,7 +115,7 @@
 #endif
 
 #ifndef HGLOBAL
-#define HGLOBAL void*
+    #define HGLOBAL void*
 #endif
 
 #if !defined(_WINBASE_) || !defined(WINBASE_ALREADY_INCLUDED)
@@ -125,7 +124,6 @@
 WINBASEAPI WINBOOL WINAPI GlobalUnlock (HGLOBAL hMem);
 #endif
 
-
 #if !defined(_WINGDI_) || !defined(WINGDI_ALREADY_INCLUDED)
 #ifndef BITMAPINFOHEADER_ALREADY_DEFINED
 #define BITMAPINFOHEADER_ALREADY_DEFINED
@@ -170,8 +168,7 @@
 } RGBQUAD, *LPRGBQUAD;
 #endif
 
-
-// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
+// REF: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57
 #define BI_RGB       0x0000
 #define BI_RLE8      0x0001
 #define BI_RLE4      0x0002
@@ -181,13 +178,18 @@
 #define BI_CMYK      0x000B
 #define BI_CMYKRLE8  0x000C
 #define BI_CMYKRLE4  0x000D
+#endif
 
+#ifndef BI_ALPHABITFIELDS
+// Bitmap not compressed and that the color table consists of four DWORD color masks,
+// that specify the red, green, blue, and alpha components of each pixel
+#define BI_ALPHABITFIELDS 0x0006
 #endif
 
-// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
+// REF: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
 #define CF_DIB 8
 
-// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor
+// REF: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor
 // #define OCR_NORMAL      32512 // Normal     select
 // #define OCR_IBEAM       32513 // Text       select
 // #define OCR_WAIT        32514 // Busy
@@ -202,164 +204,136 @@
 // #define OCR_HAND        32649 // Link       select
 // #define OCR_APPSTARTING 32650 //
 
-
 //----------------------------------------------------------------------------------
 // Module Internal Functions Declaration
 //----------------------------------------------------------------------------------
-
-
-static BOOL           OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
-static int            GetPixelDataOffset(BITMAPINFOHEADER bih);
+static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries
+static int GetPixelDataOffset(BITMAPINFOHEADER bih); // Get pixel data offset from DIB image
 
-unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize)
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned int *dataSize)
 {
-    HWND win = NULL; // Get from somewhere but is doesnt seem to matter
-    const char* msgString = "";
-    int severity = LOG_INFO;
-    BYTE* bmpData = NULL;
-    if (!OpenClipboardRetrying(win)) {
-        severity = LOG_ERROR;
-        msgString = "Couldn't open clipboard";
-        goto end;
-    }
-
-    HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB);
-    if (!clipHandle) {
-        severity = LOG_ERROR;
-        msgString = "Clipboard data is not an Image";
-        goto close;
-    }
-
-    BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle);
-    if (!bmpInfoHeader) {
-        // Mapping from HGLOBAL to our local *address space* failed
-        severity = LOG_ERROR;
-        msgString = "Clipboard data failed to be locked";
-        goto unlock;
-    }
-
-    *width = bmpInfoHeader->biWidth;
-    *height = bmpInfoHeader->biHeight;
-
-    SIZE_T clipDataSize = GlobalSize(clipHandle);
-    if (clipDataSize < sizeof(BITMAPINFOHEADER)) {
-        // Format CF_DIB needs space for BITMAPINFOHEADER struct.
-        msgString = "Clipboard has Malformed data";
-        severity = LOG_ERROR;
-        goto unlock;
-    }
-
-    // Denotes where the pixel data starts from the bmpInfoHeader pointer
-    int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
-
-    //--------------------------------------------------------------------------------//
-    //
-    // The rest of the section is about create the bytes for a correct BMP file
-    // Then we copy the data and to a pointer
-    //
-    //--------------------------------------------------------------------------------//
+    unsigned char *bmpData = NULL;
 
-    BITMAPFILEHEADER bmpFileHeader = {0};
-    SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
-    *dataSize = bmpFileSize;
+    if (OpenClipboardRetrying(NULL))
+    {
+        HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB);
+        if (clipHandle != NULL)
+        {
+            BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle);
+            if (bmpInfoHeader)
+            {
+                *width = bmpInfoHeader->biWidth;
+                *height = bmpInfoHeader->biHeight;
+                SIZE_T clipDataSize = GlobalSize(clipHandle);
+                if ((clipDataSize >= sizeof(BITMAPINFOHEADER)) && (clipDataSize < INT_MAX))
+                {
+                    int pixelOffset = GetPixelDataOffset(*bmpInfoHeader);
 
-    bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536
+                    // Create the bytes for a correct BMP file and copy the data to a pointer
+                    //------------------------------------------------------------------------
+                    BITMAPFILEHEADER bmpFileHeader = { 0 };
+                    SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize;
+                    *dataSize = (unsigned int)bmpFileSize;
 
-    bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
-    bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset;
+                    bmpFileHeader.bfType = 0x4D42; // BMP fil type constant
+                    bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine
+                    bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset;
 
-    //
-    // Each process has a default heap provided by the system
-    // Memory objects allocated by GlobalAlloc and LocalAlloc are in private,
-    // committed pages with read/write access that cannot be accessed by other processes.
-    //
-    // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application
-    // that may cause heap corruption. We could create a FreeImage function
-    //
-    bmpData = (BYTE *)malloc(sizeof(bmpFileHeader) + clipDataSize);
-    // First we add the header for a bmp file
-    memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader));
-    // Then we add the header for the bmp itself + the pixel data
-    memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize);
-    msgString = "Clipboad image acquired successfully";
+                    bmpData = (unsigned char *)RL_MALLOC(sizeof(bmpFileHeader) + clipDataSize);
+                    memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); // Add BMP file header data
+                    memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize); // Add BMP info header data
 
+                    GlobalUnlock(clipHandle);
+                    CloseClipboard();
 
-unlock:
-    GlobalUnlock(clipHandle);
-close:
-    CloseClipboard();
-end:
+                    TRACELOG(LOG_INFO, "Clipboad image acquired successfully");
+                    //------------------------------------------------------------------------
+                }
+                else
+                {
+                    TRACELOG(LOG_WARNING, "Clipboard data is not supported (>2GB?)");
+                    GlobalUnlock(clipHandle);
+                    CloseClipboard();
+                }
+            }
+            else
+            {
+                TRACELOG(LOG_WARNING, "Clipboard data failed to be locked");
+                GlobalUnlock(clipHandle);
+                CloseClipboard();
+            }
+        }
+        else
+        {
+            TRACELOG(LOG_WARNING, "Clipboard data is not an image");
+            CloseClipboard();
+        }
+    }
+    else TRACELOG(LOG_WARNING, "Clipboard can not be opened");
 
-    TRACELOG(severity, msgString);
     return bmpData;
 }
 
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+// Open clipboard with several tries
+// NOTE: If parameter is NULL, the open clipboard is associated with the current task
 static BOOL OpenClipboardRetrying(HWND hWnd)
 {
     static const int maxTries = 20;
     static const int sleepTimeMS = 60;
-    for (int _ = 0; _ < maxTries; ++_)
+
+    for (int i = 0; i < maxTries; i++)
     {
         // Might be being hold by another process
         // Or yourself forgot to CloseClipboard
-        if (OpenClipboard(hWnd)) {
-            return true;
-        }
+        if (OpenClipboard(hWnd)) return true;
+
         Sleep(sleepTimeMS);
     }
+
     return false;
 }
 
-// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
-// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
 // Get the byte offset where does the pixels data start (from a packed DIB)
+// REF: https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856
+// REF: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
 static int GetPixelDataOffset(BITMAPINFOHEADER bih)
 {
     int offset = 0;
     const unsigned int rgbaSize = sizeof(RGBQUAD);
 
-    // biSize Specifies the number of bytes required by the structure
-    // We expect to always be 40 because it should be packed
-    if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER))
+    // NOTE: biSize specifies the number of bytes required by the structure
+    // It's expected to be always 40 because it should be packed
+    if ((bih.biSize == 40) && (sizeof(BITMAPINFOHEADER) == 40))
     {
-        //
-        // biBitCount Specifies the number of bits per pixel.
+        // NOTE: biBitCount specifies the number of bits per pixel
         // Might exist some bit masks *after* the header and *before* the pixel offset
-        // we're looking, but only if we have more than
-        // 8 bits per pixel, so we need to ajust for that
-        //
+        // we're looking, but only if more than 8 bits per pixel, so it needs to be ajusted for that
         if (bih.biBitCount > 8)
         {
-            // if bih.biCompression is RBG we should NOT offset more
+            // If (bih.biCompression == BI_RGB) no need to be offset more
 
-            if (bih.biCompression == BI_BITFIELDS)
-            {
-                offset += 3 * rgbaSize;
-            } else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */)
-            {
-                // Not widely supported, but valid.
-                offset += 4 * rgbaSize;
-            }
+            if (bih.biCompression == BI_BITFIELDS) offset += 3*rgbaSize;
+            else if (bih.biCompression == BI_ALPHABITFIELDS) offset += 4 * rgbaSize; // Not widely supported, but valid
         }
     }
 
-    //
-    // biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap.
+    // NOTE: biClrUsed specifies the number of color indices in the color table that are actually used by the bitmap
     // If this value is zero, the bitmap uses the maximum number of colors
-    // corresponding to the value of the biBitCount member for the compression mode specified by biCompression.
+    // corresponding to the value of the biBitCount member for the compression mode specified by biCompression
     // If biClrUsed is nonzero and the biBitCount member is less than 16
     // the biClrUsed member specifies the actual number of colors
-    //
-    if (bih.biClrUsed > 0) {
-        offset += bih.biClrUsed * rgbaSize;
-    } else {
-        if (bih.biBitCount < 16)
-        {
-            offset = offset + (rgbaSize << bih.biBitCount);
-        }
+    if (bih.biClrUsed > 0) offset += bih.biClrUsed*rgbaSize;
+    else
+    {
+        if (bih.biBitCount < 16) offset = offset + (rgbaSize << bih.biBitCount);
     }
 
     return bih.biSize + offset;
 }
 #endif // WIN32_CLIPBOARD_IMPLEMENTATION
-// EOF
diff --git a/raylib/src/platforms/rcore_android.c b/raylib/src/platforms/rcore_android.c
--- a/raylib/src/platforms/rcore_android.c
+++ b/raylib/src/platforms/rcore_android.c
@@ -275,12 +275,36 @@
 static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
 static int android_close(void *cookie);
 
-FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
+// WARNING: fopen() calls are intercepted via linker flag -Wl,--wrap=fopen: the linker renames
+// the original fopen -> __real_fopen and redirects all call sites to __wrap_fopen
+// The flag MUST be applied at every final link step that needs wrapping;
+// it has no effect when only building a static archive (.a)
+//
+// STATIC library (.a) — wrapping deferred to consumer's final link step:
+//   both raylib and consumer fopen calls are wrapped together in one link
+//       CMake: handled automatically — the PUBLIC flag propagates as INTERFACE_LINK_OPTIONS
+//              to the consumer's final link via target_link_libraries
+//        Make: pass -Wl,--wrap=fopen to the linker command producing the final artifact
+//   build.zig: pass -Wl,--wrap=fopen to the linker command producing the final artifact
+//      custom: pass -Wl,--wrap=fopen to the linker command producing the final artifact
+//
+// SHARED library (.so) — wrapping is self-contained:
+//   only fopen calls linked into the .so are wrapped; the consumer's own fopen calls
+//   are NOT wrapped unless the consumer also links with -Wl,--wrap=fopen independently
+//       CMake: handled automatically — CMakeLists.txt sets target_link_options(raylib PUBLIC
+//              -Wl,--wrap=fopen) which applies the flag to the .so link;
+//              only raylib internals are wrapped, app code requires a separate flag
+//        Make: handled automatically — src/Makefile sets LDFLAGS += -Wl,--wrap=fopen;
+//              only raylib internals are wrapped, app code requires a separate flag
+//   build.zig: NOT supported — std.Build has no dedicated linker wrap helper, the flag
+//              is not correctly applied at the .so link step
+//      custom: apply -Wl,--wrap=fopen to the linker command producing the .so
+FILE *__real_fopen(const char *fileName, const char *mode); // Real fopen, provided by the linker (--wrap=fopen)
+FILE *__wrap_fopen(const char *fileName, const char *mode); // Replacement for fopen()
+
 FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),
               fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
 
-#define fopen(name, mode) android_fopen(name, mode)
-
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
 //----------------------------------------------------------------------------------
@@ -290,8 +314,8 @@
 // Module Functions Definition: Application
 //----------------------------------------------------------------------------------
 
-// To allow easier porting to android, we allow the user to define a
-// main function which we call from android_main, defined by ourselves
+// To allow easier porting to android, allow the user to define a
+// custom main function which is called from android_main
 extern int main(int argc, char *argv[]);
 
 // Android main function
@@ -313,7 +337,7 @@
     // Waiting for application events before complete finishing
     while (!app->destroyRequested)
     {
-        // Poll all events until we reach return value TIMEOUT, meaning no events left to process
+        // Poll all events until return value TIMEOUT is reached, meaning no events left to process
         while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, (void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)
         {
             if (platform.source != NULL) platform.source->process(app, platform.source);
@@ -449,8 +473,7 @@
 // Get native window handle
 void *GetWindowHandle(void)
 {
-    TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform");
-    return NULL;
+    return (void *)platform.app->window; // Type: ANativeWindow*
 }
 
 // Get number of monitors
@@ -592,13 +615,13 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     // Set cursor position in the middle
@@ -632,21 +655,30 @@
     double time = 0.0;
     struct timespec ts = { 0 };
     clock_gettime(CLOCK_MONOTONIC, &ts);
-    unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
+    unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
 
-    time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
+    time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
 
     return time;
 }
 
 // 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
+// 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(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");
+    }
     else
     {
         JNIEnv *env = NULL;
@@ -694,7 +726,6 @@
 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
@@ -713,9 +744,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -726,12 +757,12 @@
     for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
 
     // Reset last gamepad button/axis registered state
-    CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
+    CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
     //CORE.Input.Gamepad.axisCount = 0;
 
     for (int i = 0; i < MAX_GAMEPADS; i++)
     {
-        if (CORE.Input.Gamepad.ready[i])     // Check if gamepad is available
+        if (CORE.Input.Gamepad.ready[i]) // Check if gamepad is available
         {
             // Register previous gamepad states
             for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
@@ -757,7 +788,7 @@
     int pollResult = 0;
     int pollEvents = 0;
 
-    // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
+    // Poll Events (registered events) until TIMEOUT is reached which indicates there are no events left to poll
     // NOTE: Activity is paused if not enabled (platform.appEnabled) and always run flag is not set (FLAG_WINDOW_ALWAYS_RUN)
     while ((pollResult = ALooper_pollOnce((platform.appEnabled || FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
     {
@@ -770,6 +801,7 @@
         if (platform.app->destroyRequested != 0)
         {
             CORE.Window.shouldClose = true;
+            break;
         }
     }
 }
@@ -843,7 +875,7 @@
     // Wait for window to be initialized (display and context)
     while (!CORE.Window.ready)
     {
-        // Process events until we reach TIMEOUT, which indicates no more events queued
+        // Process events until TIMEOUT is reached, which indicates no more events queued
         while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
         {
             // Process this event
@@ -886,8 +918,8 @@
     // NOTE: Reset global state in case the activity is being relaunched
     if (platform.app->destroyRequested != 0)
     {
-        CORE = (CoreData){0};
-        platform = (PlatformData){0};
+        CORE = (CoreData){ 0 };
+        platform = (PlatformData){ 0 };
     }
 }
 
@@ -964,10 +996,10 @@
     EGLint displayFormat = 0;
 
     // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
-    // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
+    // As soon as an EGLConfig is picked, it's safe to reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
     eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat);
 
-    // At this point we need to manage render size vs screen size
+    // At this point render size vs screen size needs to be managed
     // NOTE: This function use and modify global module variables:
     //  -> CORE.Window.screen.width/CORE.Window.screen.height
     //  -> CORE.Window.render.width/CORE.Window.render.height
@@ -1055,7 +1087,7 @@
                     InitGraphicsDevice();
 
                     // Initialize OpenGL context (states and resources)
-                    // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
+                    // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, stored as globals in rlgl
                     rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
 
                     // Setup default viewport
@@ -1065,27 +1097,27 @@
                     // Initialize hi-res timer
                     InitTimer();
 
-                #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
+                #if SUPPORT_MODULE_RTEXT
                     // Load default font
                     // WARNING: External function: Module required: rtext
                     LoadFontDefault();
-                    #if defined(SUPPORT_MODULE_RSHAPES)
+                    #if SUPPORT_MODULE_RSHAPES
                     // Set font white rectangle for shapes drawing, so shapes and text can be batched together
                     // WARNING: rshapes module is required, if not available, default internal white rectangle is used
                     Rectangle rec = GetFontDefault().recs[95];
                     if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
                     {
-                        // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
+                        // NOTE: Trying to maxime rec padding to avoid pixel bleeding on MSAA filtering
                         SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
                     }
                     else
                     {
-                        // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
+                        // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding
                         SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
                     }
                     #endif
                 #else
-                    #if defined(SUPPORT_MODULE_RSHAPES)
+                    #if SUPPORT_MODULE_RSHAPES
                     // Set default texture and rectangle to be used for shapes drawing
                     // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
                     Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
@@ -1189,7 +1221,7 @@
         if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
             FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
         {
-            // For now we'll assume a single gamepad which we "detect" on its input event
+            // Assuming a single gamepad, "detected" on its input event
             CORE.Input.Gamepad.ready[0] = true;
 
             CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_X] = AMotionEvent_getAxisValue(
@@ -1249,27 +1281,28 @@
         int32_t keycode = AKeyEvent_getKeyCode(event);
         //int32_t AKeyEvent_getMetaState(event);
 
-        // Handle gamepad button presses and releases
-        // NOTE: Skip gamepad handling if this is a keyboard event, as some devices
-        // report both AINPUT_SOURCE_KEYBOARD and AINPUT_SOURCE_GAMEPAD flags
-        if ((FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
-             FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) &&
-            !FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD))
+        // Handle gamepad button presses and releases. AOSP stamps the
+        // KEYBOARD source bit on every key event from a gamepad, so
+        // discriminate on the keycode rather than gating on source bits.
+        if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
+            FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
         {
-            // For now we'll assume a single gamepad which we "detect" on its input event
-            CORE.Input.Gamepad.ready[0] = true;
-
             GamepadButton button = AndroidTranslateGamepadButton(keycode);
 
-            if (button == GAMEPAD_BUTTON_UNKNOWN) return 1;
-
-            if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
+            if (button != GAMEPAD_BUTTON_UNKNOWN)
             {
-                CORE.Input.Gamepad.currentButtonState[0][button] = 1;
-            }
-            else CORE.Input.Gamepad.currentButtonState[0][button] = 0;  // Key up
+                // Assuming a single gamepad, "detected" on its input event
+                CORE.Input.Gamepad.ready[0] = true;
 
-            return 1; // Handled gamepad button
+                if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
+                {
+                    CORE.Input.Gamepad.currentButtonState[0][button] = 1;
+                }
+                else CORE.Input.Gamepad.currentButtonState[0][button] = 0;  // Key up
+
+                return 1; // Handled gamepad button
+            }
+            // Unknown keycode: fall through to the keyboard handler below.
         }
 
         KeyboardKey key = ((keycode > 0) && (keycode < KEYCODE_MAP_SIZE))? mapKeycode[keycode] : KEY_NULL;
@@ -1299,7 +1332,7 @@
         }
         else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU))
         {
-            // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!
+            // Eat BACK_BUTTON and AKEYCODE_MENU, do nothing... and don't let to be handled by OS!
             return 1;
         }
         else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))
@@ -1347,7 +1380,7 @@
         }
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     GestureEvent gestureEvent = { 0 };
 
     gestureEvent.pointCount = 0;
@@ -1450,7 +1483,7 @@
 // NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
 static void SetupFramebuffer(int width, int height)
 {
-    // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
+    // Calculate CORE.Window.render.width and CORE.Window.render.height, having the display size (input params) and the desired screen size (global var)
     if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
     {
         TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
@@ -1478,8 +1511,8 @@
         float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
         CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
 
-        // NOTE: We render to full display resolution!
-        // We just need to calculate above parameters for downscale matrix and offsets
+        // NOTE: Rendering to full display resolution
+        // Above parameters need to be calculate for downscale matrix and offsets
         CORE.Window.render.width = CORE.Window.display.width;
         CORE.Window.render.height = CORE.Window.display.height;
 
@@ -1524,25 +1557,20 @@
     }
 }
 
-// Replacement for fopen()
+// Replacement for fopen(), used as linker wrap entry point (-Wl,--wrap=fopen)
 // REF: https://developer.android.com/ndk/reference/group/asset
-FILE *android_fopen(const char *fileName, const char *mode)
+__attribute__((visibility("default"))) FILE *__wrap_fopen(const char *fileName, const char *mode)
 {
     FILE *file = NULL;
-    
+
+    // NOTE: AAsset provides access to read-only asset, write operations use regular fopen
     if (mode[0] == 'w')
     {
-        // NOTE: fopen() is mapped to android_fopen() that only grants read access to
-        // assets directory through AAssetManager but we want to also be able to
-        // write data when required using the standard stdio FILE access functions
-        // REF: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
-        #undef fopen
-        file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
-        #define fopen(name, mode) android_fopen(name, mode)
+        file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
+        if (file == NULL) file = __real_fopen(fileName, mode);
     }
     else
     {
-        // NOTE: AAsset provides access to read-only asset
         AAsset *asset = AAssetManager_open(platform.app->activity->assetManager, fileName, AASSET_MODE_UNKNOWN);
 
         if (asset != NULL)
@@ -1552,14 +1580,12 @@
         }
         else
         {
-            #undef fopen
-            // Just do a regular open if file is not found in the assets
-            file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
-            if (file == NULL) file = fopen(fileName, mode);
-            #define fopen(name, mode) android_fopen(name, mode)
+            // Do a regular open if file is not found in the assets
+            file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
+            if (file == NULL) file = __real_fopen(fileName, mode);
         }
     }
-    
+
     return file;
 }
 
diff --git a/raylib/src/platforms/rcore_desktop_glfw.c b/raylib/src/platforms/rcore_desktop_glfw.c
--- a/raylib/src/platforms/rcore_desktop_glfw.c
+++ b/raylib/src/platforms/rcore_desktop_glfw.c
@@ -65,7 +65,7 @@
     #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
     #include "GLFW/glfw3native.h"
 
-    #if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
+    #if SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
         // NOTE: Those functions require linking with winmm library
         //#pragma warning(disable: 4273)
         __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
@@ -100,7 +100,7 @@
     #include <unistd.h>                 // Required for: usleep()
 
     //#define GLFW_EXPOSE_NATIVE_COCOA    // WARNING: Fails due to type redefinition
-    void *glfwGetCocoaWindow(GLFWwindow* handle);
+    void *glfwGetCocoaWindow(GLFWwindow *handle);
     #include "GLFW/glfw3native.h"       // Required for: glfwGetCocoaWindow()
 #endif
 
@@ -111,6 +111,12 @@
 //----------------------------------------------------------------------------------
 typedef struct {
     GLFWwindow *handle;                 // GLFW window handle (graphic device)
+#if defined(__linux__) && defined(_GLFW_X11)
+    // Local storage for the window handle returned by glfwGetX11Window
+    // This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
+    // Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
+    Window windowHandleX11;             // Underlying type: unsigned long (XID, Window)
+#endif
 } PlatformData;
 
 //----------------------------------------------------------------------------------
@@ -145,7 +151,7 @@
 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()]
@@ -219,13 +225,14 @@
         // and considered by GetWindowScaleDPI()
         FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
 
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
         // Make sure to restore render size considering HighDPI scaling
+        // NOTE: On Wayland, GLFW_SCALE_FRAMEBUFFER handles scaling, skip manual resize
         if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
         {
             Vector2 scaleDpi = GetWindowScaleDPI();
-            CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x);
-            CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y);
+            CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width*scaleDpi.x);
+            CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height*scaleDpi.y);
         }
 #endif
 
@@ -280,8 +287,14 @@
                 CORE.Window.screen.height = mode->height;
 
                 // Set screen position and size
+            #if defined(_WIN32)
+                // NOTE: To prevent the fullscreen window from always staying on top, don't pass a monitor at this point.
+                glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y,
+                    CORE.Window.screen.width, CORE.Window.screen.height, mode->refreshRate);
+            #else
                 glfwSetWindowMonitor(platform.handle, monitors[monitor], CORE.Window.position.x, CORE.Window.position.y,
                     CORE.Window.screen.width, CORE.Window.screen.height, mode->refreshRate);
+            #endif
 
                 // Refocus window
                 glfwFocusWindow(platform.handle);
@@ -298,13 +311,14 @@
                 glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
                 FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
 
-            #if !defined(__APPLE__)
+            #if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
                 // Make sure to restore size considering HighDPI scaling
+                // NOTE: On Wayland, GLFW_SCALE_FRAMEBUFFER handles scaling, skip manual resize
                 if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
                 {
                     Vector2 scaleDpi = GetWindowScaleDPI();
-                    CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x);
-                    CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y);
+                    CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width*scaleDpi.x);
+                    CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height*scaleDpi.y);
                 }
             #endif
 
@@ -602,7 +616,7 @@
             icon[0].height = image.height;
             icon[0].pixels = (unsigned char *)image.data;
 
-            // NOTE 1: We only support one image icon
+            // NOTE 1: Only one image icon supported
             // NOTE 2: The specified image data is copied before this function returns
             glfwSetWindowIcon(platform.handle, 1, icon);
         }
@@ -753,18 +767,13 @@
     glfwFocusWindow(platform.handle);
 }
 
-#if defined(__linux__) && defined(_GLFW_X11)
-// Local storage for the window handle returned by glfwGetX11Window
-// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
-// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
-static XID X11WindowHandle;
-#endif
 // Get native window handle
 void *GetWindowHandle(void)
 {
+    void *handle = NULL;
+
 #if defined(_WIN32)
-    // NOTE: Returned handle is: void *HWND (windows.h)
-    return glfwGetWin32Window(platform.handle);
+    handle = glfwGetWin32Window(platform.handle); // Type: HWND
 #endif
 #if defined(__linux__)
     #if defined(_GLFW_WAYLAND)
@@ -772,29 +781,27 @@
             int platformID = glfwGetPlatform();
             if (platformID == GLFW_PLATFORM_WAYLAND)
             {
-                return glfwGetWaylandWindow(platform.handle);
+                handle = (void *)glfwGetWaylandWindow(platform.handle); // Type: struct wl_surface*
             }
             else
             {
-                X11WindowHandle = glfwGetX11Window(platform.handle);
-                return &X11WindowHandle;
+                platform.windowHandleX11 = glfwGetX11Window(platform.handle); // Type: Window (unsigned long)
+                handle = &platform.windowHandleX11;
             }
         #else
-            return glfwGetWaylandWindow(platform.handle);
+            handle = (void *)glfwGetWaylandWindow(platform.handle);
         #endif
     #elif defined(_GLFW_X11)
-        // Store the window handle localy and return a pointer to the variable instead
-        // Reasoning detailed in the declaration of X11WindowHandle
-        X11WindowHandle = glfwGetX11Window(platform.handle);
-        return &X11WindowHandle;
+        // Store the window handle locally and return a pointer to the variable instead
+        platform.windowHandleX11 = glfwGetX11Window(platform.handle);
+        handle = &platform.windowHandleX11;
     #endif
 #endif
 #if defined(__APPLE__)
-    // NOTE: Returned handle is: (objc_object *)
-    return (void *)glfwGetCocoaWindow(platform.handle);
+    handle = (void *)glfwGetCocoaWindow(platform.handle); // Type: NSWindow*
 #endif
 
-    return NULL;
+    return handle;
 }
 
 // Get number of monitors
@@ -833,12 +840,12 @@
         }
         else
         {
-            // In case the window is between two monitors, we use below logic
+            // In case the window is between two monitors, below logic is used
             // to try to detect the "current monitor" for that window, note that
-            // this is probably an overengineered solution for a very side case
+            // this is probably an overengineered solution for a side case
             // trying to match SDL behaviour
 
-            int closestDist = 0x7FFFFFFF;
+            unsigned int closestDist = 0xFFFFFFFFu;
 
             // Window center position
             int wcx = 0;
@@ -882,7 +889,14 @@
 
                     int dx = wcx - xclosest;
                     int dy = wcy - yclosest;
-                    int dist = (dx*dx) + (dy*dy);
+
+                    // Unsigned to dodge signed overflow UB; (-x)^2 == x^2 mod 2^32 so sign drops out.
+                    // If |dx| or |dy| >= 65536, dist wraps and the wrong monitor may win.
+                    // Not a concern for realistic monitor layouts.
+                    unsigned int ux = (unsigned int)dx;
+                    unsigned int uy = (unsigned int)dy;
+                    unsigned int dist = ux*ux + uy*uy;
+
                     if (dist < closestDist)
                     {
                         index = i;
@@ -1016,6 +1030,8 @@
 // Get window position XY on monitor
 Vector2 GetWindowPosition(void)
 {
+    glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y);
+
     return (Vector2){ (float)CORE.Window.position.x, (float)CORE.Window.position.y };
 }
 
@@ -1046,20 +1062,70 @@
 {
     Image image = { 0 };
 
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
+#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
 #if defined(_WIN32)
-    unsigned long long int dataSize = 0;
-    void *fileData = NULL;
+
+    unsigned int dataSize = 0;
+    void *bmpData = NULL;
     int width = 0;
     int height = 0;
 
-    fileData  = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
+    bmpData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
 
-    if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
-    else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize);
+    if (bmpData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
+    else
+    {
+        image = LoadImageFromMemory(".bmp", (const unsigned char *)bmpData, (int)dataSize);
+
+        RL_FREE(bmpData);
+    }
+
+#elif defined(__linux__) && defined(_GLFW_X11)
+    // REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
+
+    static Atom clipboard = 0;
+    static Atom targetType = 0;
+    static Atom property = 0;
+
+    Display *display = glfwGetX11Display();
+    XID window = glfwGetX11Window(platform.handle);
+
+    // Lazy-load X11 atoms
+    if (clipboard == 0)
+    {
+        clipboard = XInternAtom(display, "CLIPBOARD", False);
+        targetType = XInternAtom(display, "image/png", False);
+        property = XInternAtom(display, "RAYLIB_CLIPBOARD_MANAGER", False);
+    }
+
+    XConvertSelection(display, clipboard, targetType, property, window, CurrentTime);
+    XSync(display, 0);
+
+    XEvent ev = { 0 };
+
+    // Keep calling until we get SelectionNotify
+    while (XCheckTypedEvent(display, SelectionNotify, &ev) == False);
+
+    Atom actualType = { 0 };
+    int actualFormat = 0;
+    unsigned long nitems = 0;
+    unsigned long bytesAfter = 0;
+    unsigned char *data = NULL;
+
+    XGetWindowProperty(display, window, property, 0, ~0L, False, AnyPropertyType,
+                       &actualType, &actualFormat, &nitems, &bytesAfter, &data);
+
+    if (data != NULL)
+    {
+        image = LoadImageFromMemory(".png", data, (int)nitems);
+        XFree(data);
+    }
+
 #else
     TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
-#endif
+#endif // _WIN32
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
 #endif // SUPPORT_CLIPBOARD_IMAGE
 
     return image;
@@ -1073,7 +1139,7 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
@@ -1081,7 +1147,7 @@
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
@@ -1095,7 +1161,7 @@
     CORE.Input.Mouse.cursorLocked = false;
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     // Reset mouse position within the window area before disabling cursor
@@ -1123,21 +1189,30 @@
 double GetTime(void)
 {
     double time = glfwGetTime();   // Elapsed time since glfwInit()
+
     return time;
 }
 
 // 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");
+    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(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");
+    }
     else
     {
-        char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
+        char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
 #if defined(_WIN32)
         sprintf(cmd, "explorer \"%s\"", url);
 #endif
@@ -1147,7 +1222,9 @@
 #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);
     }
@@ -1173,7 +1250,6 @@
 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);
@@ -1186,7 +1262,7 @@
     if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL);
     else
     {
-        // NOTE: We are relating internal GLFW enum values to our MouseCursor enum values
+        // NOTE: Mapping internal GLFW enum values to MouseCursor enum values
         glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor));
     }
 }
@@ -1200,9 +1276,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -1211,7 +1287,7 @@
     CORE.Input.Keyboard.charPressedQueueCount = 0;
 
     // Reset last gamepad button/axis registered state
-    CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
+    CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
     //CORE.Input.Gamepad.axisCount = 0;
 
     // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
@@ -1247,7 +1323,7 @@
     CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
 
     // Check if gamepads are ready
-    // NOTE: We do it here in case of disconnection
+    // NOTE: Doing it here in case of disconnection
     for (int i = 0; i < MAX_GAMEPADS; i++)
     {
         if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true;
@@ -1262,8 +1338,8 @@
             // 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
-            // NOTE: There is no callback available, so we get it manually
+            // 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
             if (result == GLFW_FALSE) // No joystick is connected, no gamepad mapping or an error occurred
@@ -1277,7 +1353,7 @@
 
             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)
                 {
@@ -1303,7 +1379,7 @@
                     default: break;
                 }
 
-                if (button != -1)   // Check for valid button
+                if (button != -1) // Check for valid button
                 {
                     if (buttons[k] == GLFW_PRESS)
                     {
@@ -1345,10 +1421,10 @@
     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);
 
@@ -1359,8 +1435,8 @@
 //----------------------------------------------------------------------------------
 // Module Internal Functions Definition
 //----------------------------------------------------------------------------------
-// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
-// We need to provide these because GLFWallocator expects function pointers with specific signatures
+// Function wrappers around RL_*ALLOC macros, used by glfwInitAllocator() inside of InitPlatform()
+// GLFWallocator expects function pointers with specific signatures to be provided
 // REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
 static void *AllocateWrapper(size_t size, void *user)
 {
@@ -1465,6 +1541,11 @@
 #if defined(__APPLE__)
         glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
 #endif
+#if defined(_GLFW_WAYLAND) && !defined(_GLFW_X11)
+        // GLFW 3.4+ defaults GLFW_SCALE_FRAMEBUFFER to TRUE,
+        // causing framebuffer/window size mismatch on Wayland with display scaling
+        glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
+#endif
     }
 
     // Mouse passthrough
@@ -1507,7 +1588,7 @@
         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);          // Choose OpenGL minor version (just hint)
         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
         glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE);
-#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
+#if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
         glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);   // Enable OpenGL Debug Context
 #endif
     }
@@ -1527,7 +1608,7 @@
     }
 
     // NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions
-    // Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn
+    // Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been drawn
     // The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience
     // REF: https://github.com/raysan5/raylib/issues/1554
     glfwSetJoystickCallback(NULL);
@@ -1624,6 +1705,14 @@
             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;
@@ -1649,35 +1738,54 @@
             TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC");
         }
 
-        int fbWidth = CORE.Window.screen.width;
-        int fbHeight = CORE.Window.screen.height;
-
         if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
         {
-            // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
-            // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
-
-            // Get current framebuffer size, on high-dpi it could be bigger than screen size
-            glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
+            // Set screen size to logical pixel size, considering content scaling
+            Vector2 scaleDpi = GetWindowScaleDPI();
+            CORE.Window.render.width = (int)(CORE.Window.screen.width*scaleDpi.x);
+            CORE.Window.render.height = (int)(CORE.Window.screen.height*scaleDpi.y);
+            //TRACELOG(LOG_INFO, "DPI SCALING: %.2f, %.2f", scaleDpi.x, scaleDpi.y);
 
             // Screen scaling matrix is required in case desired screen area is different from display area
-            CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
+            CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
+
+            // NOTE: On APPLE platforms system manage window and input scaling
+            // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
+
 #if !defined(__APPLE__)
-            // Mouse input scaling for the new screen size
-            SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
+            if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND)
+            {
+                // On Wayland, GLFW_SCALE_FRAMEBUFFER handles scaling; read actual framebuffer size
+                // instead of resizing the window (which would double-scale)
+                int fbWidth = 0;
+                int fbHeight = 0;
+                glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
+
+                CORE.Window.render.width = fbWidth;
+                CORE.Window.render.height = fbHeight;
+            }
+            else
+            {
+                // Mouse input scaling for the new screen size
+                SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
+
+                // Force window size (and framebuffer) refresh
+                glfwSetWindowSize(platform.handle, CORE.Window.render.width, CORE.Window.render.height);
+            }
 #endif
         }
+        else CORE.Window.render = CORE.Window.screen;
 
-        CORE.Window.render.width = fbWidth;
-        CORE.Window.render.height = fbHeight;
-        CORE.Window.currentFbo.width = fbWidth;
-        CORE.Window.currentFbo.height = fbHeight;
+        // Current active framebuffer size is main framebuffer size
+        CORE.Window.currentFbo = CORE.Window.render;
 
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+            FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
         TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
+        //TRACELOG(LOG_INFO, "    > Content Scaling: %.2f, %.2f", scaleDpi.x, scaleDpi.y);
 
         // Try to center window on screen but avoiding window-bar outside of screen
         int monitorCount = 0;
@@ -1691,13 +1799,17 @@
         int monitorHeight = 0;
         glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
 
-        // TODO: Here CORE.Window.render.width/height should be used instead of
-        // CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled
-        CORE.Window.position.x = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2;
-        CORE.Window.position.y = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2;
-        //if (CORE.Window.position.x < monitorX) CORE.Window.position.x = monitorX;
-        //if (CORE.Window.position.y < monitorY) CORE.Window.position.y = monitorY;
+        // NOTE: It seems on macOS monitor size is not correct
+        //TRACELOG(LOG_WARNING, "Monitor info: [%i, %i, %i, %i]", monitorX, monitorY, monitorWidth, monitorHeight);
 
+        // Center window into current monitor
+    #if defined(__APPLE__)
+        CORE.Window.position.x = monitorX + (monitorWidth - CORE.Window.screen.width)/2;
+        CORE.Window.position.y = monitorY + (monitorHeight - CORE.Window.screen.height)/2;
+    #else
+        CORE.Window.position.x = monitorX + (monitorWidth - CORE.Window.render.width)/2;
+        CORE.Window.position.y = monitorY + (monitorHeight - CORE.Window.render.height)/2;
+    #endif
         SetWindowPosition(CORE.Window.position.x, CORE.Window.position.y);
 
         if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
@@ -1742,17 +1854,17 @@
     for (int i = 0; i < MAX_GAMEPADS; i++)
     {
         // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
-        // we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
+        // only copying up to (MAX_GAMEPAD_NAME_LENGTH - 1)
         if (glfwJoystickPresent(i))
         {
           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));
         }
     }
     //----------------------------------------------------------------------------
 
-    // Initialize timming system
+    // Initialize timing system
     //----------------------------------------------------------------------------
     InitTimer();
     //----------------------------------------------------------------------------
@@ -1789,7 +1901,7 @@
     glfwDestroyWindow(platform.handle);
     glfwTerminate();
 
-#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
+#if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
     timeEndPeriod(1);           // Restore time period
 #endif
 }
@@ -1819,8 +1931,8 @@
 {
     //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height);
 
-    // WARNING: On window minimization, callback is called,
-    // but we don't want to change internal screen values, it breaks things
+    // WARNING: On window minimization, callback is called with 0 values,
+    // but internal screen values should not be changed, it breaks things
     if ((width == 0) || (height == 0)) return;
 
     // Reset viewport and projection matrix for new size
@@ -1828,8 +1940,9 @@
     SetupViewport(width, height);
 
     // Set render size
-    CORE.Window.currentFbo.width = width;
-    CORE.Window.currentFbo.height = height;
+    CORE.Window.render.width = width;
+    CORE.Window.render.height = height;
+    CORE.Window.currentFbo = CORE.Window.render;
     CORE.Window.resizedLastFrame = true;
 
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
@@ -1842,6 +1955,26 @@
         CORE.Window.screen.height = height;
         CORE.Window.screenScale = MatrixScale(1.0f, 1.0f, 1.0f);
         SetMouseScale(1.0f, 1.0f);
+
+        // On Wayland with GLFW_SCALE_FRAMEBUFFER, the framebuffer is still scaled in fullscreen, use logical window size as screen and apply screenScale
+#if defined(_GLFW_WAYLAND) && !defined(_GLFW_X11)
+        if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+        {
+            int winWidth = 0;
+            int winHeight = 0;
+            glfwGetWindowSize(platform.handle, &winWidth, &winHeight);
+
+            if ((winWidth != width) || (winHeight != height))
+            {
+                CORE.Window.screen.width = winWidth;
+                CORE.Window.screen.height = winHeight;
+                float scaleX = (float)width/winWidth;
+                float scaleY = (float)height/winHeight;
+
+                CORE.Window.screenScale = MatrixScale(scaleX, scaleY, 1.0f);
+            }
+        }
+#endif
     }
     else // Window mode (including borderless window)
     {
@@ -1853,8 +1986,8 @@
             CORE.Window.screen.width = (int)((float)width/scaleDpi.x);
             CORE.Window.screen.height = (int)((float)height/scaleDpi.y);
             CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
-#if !defined(__APPLE__)
-            // Mouse input scaling for the new screen size
+#if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
+            // On macOS and Linux-Wayland, mouse coords are already in logical space
             SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
 #endif
         }
@@ -1875,21 +2008,18 @@
 {
     //TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley);
 
-    float fbWidth = (float)CORE.Window.screen.width*scalex;
-    float fbHeight = (float)CORE.Window.screen.height*scaley;
+    CORE.Window.render.width = (int)((float)CORE.Window.screen.width*scalex);
+    CORE.Window.render.height = (int)((float)CORE.Window.screen.height*scaley);
+    CORE.Window.currentFbo = CORE.Window.render;
 
     // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
     // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
     CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
 
-#if !defined(__APPLE__)
-    // Mouse input scaling for the new screen size
+#if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
+    // On macOS and Linux-Wayland, mouse coords are already in logical space
     SetMouseScale(1.0f/scalex, 1.0f/scaley);
 #endif
-
-    CORE.Window.render.width = (int)fbWidth;
-    CORE.Window.render.height = (int)fbHeight;
-    CORE.Window.currentFbo = CORE.Window.render;
 }
 
 // GLFW3: Window position callback, runs when window position changes
@@ -1926,7 +2056,7 @@
 {
     if (count > 0)
     {
-        // In case previous dropped filepaths have not been freed, we free them
+        // In case previous dropped filepaths have not been freed, free them
         if (CORE.Window.dropFileCount > 0)
         {
             for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
@@ -1937,14 +2067,14 @@
             CORE.Window.dropFilepaths = NULL;
         }
 
-        // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
+        // WARNING: Paths are freed by GLFW when the callback returns, keeping an internal copy
         CORE.Window.dropFileCount = count;
         CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
 
         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]);
         }
     }
 }
@@ -1954,7 +2084,7 @@
 {
     if (key < 0) return;    // Security check, macOS fn key generates -1
 
-    // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
+    // WARNING: GLFW could return GLFW_REPEAT, it needs to be considered as 1
     // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
     if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
     else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
@@ -2001,7 +2131,7 @@
     CORE.Input.Mouse.currentButtonState[button] = action;
     CORE.Input.Touch.currentTouchState[button] = action;
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -2036,7 +2166,7 @@
     CORE.Input.Mouse.currentPosition.y = (float)y;
     CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -2067,25 +2197,36 @@
 }
 
 // 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
 static void JoystickCallback(int jid, int event)
 {
-    if (event == GLFW_CONNECTED)
-    {
-        // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
-        // we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
-        memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
-        strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
-    }
-    else if (event == GLFW_DISCONNECTED)
+    if (jid < MAX_GAMEPADS)
     {
-        memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
+        if (event == GLFW_CONNECTED)
+        {
+            // 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);
+            snprintf(CORE.Input.Gamepad.name[jid], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(jid));
+        }
+        else if (event == GLFW_DISCONNECTED)
+        {
+            memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
+        }
     }
 }
 
diff --git a/raylib/src/platforms/rcore_desktop_rgfw.c b/raylib/src/platforms/rcore_desktop_rgfw.c
--- a/raylib/src/platforms/rcore_desktop_rgfw.c
+++ b/raylib/src/platforms/rcore_desktop_rgfw.c
@@ -45,1350 +45,2074 @@
 *
 **********************************************************************************************/
 
-#if defined(PLATFORM_WEB_RGFW)
-#define RGFW_NO_GL_HEADER
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(PLATFORM_WEB_RGFW)
-    #define RGFW_OPENGL_ES2
-#endif
-
-void ShowCursor(void);
-void CloseWindow(void);
-
-#if defined(__linux__)
-    #define _INPUT_EVENT_CODES_H
-#endif
-
-#if defined(__unix__) || defined(__linux__)
-    #define _XTYPEDEF_FONT
-#endif
-
-#define RGFW_IMPLEMENTATION
-
-#if defined(_WIN32) || defined(_WIN64)
-    #define WIN32_LEAN_AND_MEAN
-    #define Rectangle rectangle_win32
-    #define CloseWindow CloseWindow_win32
-    #define ShowCursor __imp_ShowCursor
-    #define _APISETSTRING_
-
-    #undef MAX_PATH
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-    __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
-
-#if defined(__APPLE__)
-    #define Point NSPOINT
-    #define Size NSSIZE
-#endif
-
-#define RGFW_ALLOC RL_MALLOC
-#define RGFW_FREE RL_FREE
-#define RGFW_CALLOC RL_CALLOC
-
-#include "../external/RGFW.h"
-
-#if defined(_WIN32) || defined(_WIN64)
-    #undef DrawText
-    #undef ShowCursor
-    #undef CloseWindow
-    #undef Rectangle
-
-    #undef MAX_PATH
-    #define MAX_PATH 1025
-#endif
-
-#if defined(__APPLE__)
-    #undef Point
-    #undef Size
-#endif
-
-#include <stdbool.h>
-#include <string.h>     // Required for: strcmp()
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-typedef struct {
-    RGFW_window *window;                // Native display device (physical screen connection)
-    RGFW_monitor mon;
-} PlatformData;
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-extern CoreData CORE;                   // Global CORE state context
-
-static PlatformData platform = { 0 };   // Platform specific
-
-static bool RGFW_disableCursor = false;
-
-static const unsigned short keyMappingRGFW[] = {
-    [RGFW_keyNULL] = KEY_NULL,
-    [RGFW_return] = KEY_ENTER,
-    [RGFW_apostrophe] = KEY_APOSTROPHE,
-    [RGFW_comma] = KEY_COMMA,
-    [RGFW_minus] = KEY_MINUS,
-    [RGFW_period] = KEY_PERIOD,
-    [RGFW_slash] = KEY_SLASH,
-    [RGFW_escape] = KEY_ESCAPE,
-    [RGFW_F1] = KEY_F1,
-    [RGFW_F2] = KEY_F2,
-    [RGFW_F3] = KEY_F3,
-    [RGFW_F4] = KEY_F4,
-    [RGFW_F5] = KEY_F5,
-    [RGFW_F6] = KEY_F6,
-    [RGFW_F7] = KEY_F7,
-    [RGFW_F8] = KEY_F8,
-    [RGFW_F9] = KEY_F9,
-    [RGFW_F10] = KEY_F10,
-    [RGFW_F11] = KEY_F11,
-    [RGFW_F12] = KEY_F12,
-    [RGFW_backtick] = KEY_GRAVE,
-    [RGFW_0] = KEY_ZERO,
-    [RGFW_1] = KEY_ONE,
-    [RGFW_2] = KEY_TWO,
-    [RGFW_3] = KEY_THREE,
-    [RGFW_4] = KEY_FOUR,
-    [RGFW_5] = KEY_FIVE,
-    [RGFW_6] = KEY_SIX,
-    [RGFW_7] = KEY_SEVEN,
-    [RGFW_8] = KEY_EIGHT,
-    [RGFW_9] = KEY_NINE,
-    [RGFW_equals] = KEY_EQUAL,
-    [RGFW_backSpace] = KEY_BACKSPACE,
-    [RGFW_tab] = KEY_TAB,
-    [RGFW_capsLock] = KEY_CAPS_LOCK,
-    [RGFW_shiftL] = KEY_LEFT_SHIFT,
-    [RGFW_controlL] = KEY_LEFT_CONTROL,
-    [RGFW_altL] = KEY_LEFT_ALT,
-    [RGFW_superL] = KEY_LEFT_SUPER,
-    #ifndef RGFW_MACOS
-    [RGFW_shiftR] = KEY_RIGHT_SHIFT,
-    [RGFW_controlR] = KEY_RIGHT_CONTROL,
-    [RGFW_altR] = KEY_RIGHT_ALT,
-    [RGFW_superR] = KEY_RIGHT_SUPER,
-    #endif
-    [RGFW_space] = KEY_SPACE,
-
-    [RGFW_a] = KEY_A,
-    [RGFW_b] = KEY_B,
-    [RGFW_c] = KEY_C,
-    [RGFW_d] = KEY_D,
-    [RGFW_e] = KEY_E,
-    [RGFW_f] = KEY_F,
-    [RGFW_g] = KEY_G,
-    [RGFW_h] = KEY_H,
-    [RGFW_i] = KEY_I,
-    [RGFW_j] = KEY_J,
-    [RGFW_k] = KEY_K,
-    [RGFW_l] = KEY_L,
-    [RGFW_m] = KEY_M,
-    [RGFW_n] = KEY_N,
-    [RGFW_o] = KEY_O,
-    [RGFW_p] = KEY_P,
-    [RGFW_q] = KEY_Q,
-    [RGFW_r] = KEY_R,
-    [RGFW_s] = KEY_S,
-    [RGFW_t] = KEY_T,
-    [RGFW_u] = KEY_U,
-    [RGFW_v] = KEY_V,
-    [RGFW_w] = KEY_W,
-    [RGFW_x] = KEY_X,
-    [RGFW_y] = KEY_Y,
-    [RGFW_z] = KEY_Z,
-    [RGFW_bracket] = KEY_LEFT_BRACKET,
-    [RGFW_backSlash] = KEY_BACKSLASH,
-    [RGFW_closeBracket] = KEY_RIGHT_BRACKET,
-    [RGFW_semicolon] = KEY_SEMICOLON,
-    [RGFW_insert] = KEY_INSERT,
-    [RGFW_home] = KEY_HOME,
-    [RGFW_pageUp] = KEY_PAGE_UP,
-    [RGFW_delete] = KEY_DELETE,
-    [RGFW_end] = KEY_END,
-    [RGFW_pageDown] = KEY_PAGE_DOWN,
-    [RGFW_right] = KEY_RIGHT,
-    [RGFW_left] = KEY_LEFT,
-    [RGFW_down] = KEY_DOWN,
-    [RGFW_up] = KEY_UP,
-    [RGFW_numLock] = KEY_NUM_LOCK,
-    [RGFW_KP_Slash] = KEY_KP_DIVIDE,
-    [RGFW_multiply] = KEY_KP_MULTIPLY,
-    [RGFW_KP_Minus] = KEY_KP_SUBTRACT,
-    [RGFW_KP_Return] = KEY_KP_ENTER,
-    [RGFW_KP_1] = KEY_KP_1,
-    [RGFW_KP_2] = KEY_KP_2,
-    [RGFW_KP_3] = KEY_KP_3,
-    [RGFW_KP_4] = KEY_KP_4,
-    [RGFW_KP_5] = KEY_KP_5,
-    [RGFW_KP_6] = KEY_KP_6,
-    [RGFW_KP_7] = KEY_KP_7,
-    [RGFW_KP_8] = KEY_KP_8,
-    [RGFW_KP_9] = KEY_KP_9,
-    [RGFW_KP_0] = KEY_KP_0,
-    [RGFW_KP_Period] = KEY_KP_DECIMAL,
-    [RGFW_scrollLock] = KEY_SCROLL_LOCK,
-};
-
-static int RGFW_gpConvTable[18] = {
-    [RGFW_gamepadY] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
-    [RGFW_gamepadB] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
-    [RGFW_gamepadA] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
-    [RGFW_gamepadX] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
-    [RGFW_gamepadL1] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
-    [RGFW_gamepadR1] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
-    [RGFW_gamepadL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
-    [RGFW_gamepadR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
-    [RGFW_gamepadSelect] = GAMEPAD_BUTTON_MIDDLE_LEFT,
-    [RGFW_gamepadHome] = GAMEPAD_BUTTON_MIDDLE,
-    [RGFW_gamepadStart] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
-    [RGFW_gamepadUp] = GAMEPAD_BUTTON_LEFT_FACE_UP,
-    [RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
-    [RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
-    [RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
-    [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
-    [RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
-};
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
-bool InitGraphicsDevice(void);   // Initialize graphics device
-
-static KeyboardKey ConvertScancodeToKey(u32 keycode);
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-// NOTE: Functions declaration is provided by raylib.h
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Window and Graphics Device
-//----------------------------------------------------------------------------------
-
-// Check if application should close
-bool WindowShouldClose(void)
-{
-    if (CORE.Window.shouldClose == false)
-        CORE.Window.shouldClose = RGFW_window_shouldClose(platform.window);
-    if (CORE.Window.ready) return CORE.Window.shouldClose;
-    else return true;
-}
-
-// Toggle fullscreen mode
-void ToggleFullscreen(void)
-{
-    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
-    {
-        // Store previous window position (in case we exit fullscreen)
-        CORE.Window.previousPosition = CORE.Window.position;
-        CORE.Window.previousScreen = CORE.Window.screen;
-
-        platform.mon = RGFW_window_getMonitor(platform.window);
-        FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
-
-        RGFW_monitor_scaleToWindow(platform.mon, platform.window);
-        RGFW_window_setFullscreen(platform.window, 1);
-    }
-    else
-    {
-        FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
-
-        if (platform.mon.mode.area.w)
-        {
-            RGFW_monitor monitor = RGFW_window_getMonitor(platform.window);
-            RGFW_monitor_requestMode(monitor, platform.mon.mode, RGFW_monitorScale);
-
-            platform.mon.mode.area.w = 0;
-        }
-
-        // we update the window position right away
-        CORE.Window.position = CORE.Window.previousPosition;
-        RGFW_window_setFullscreen(platform.window, 0);
-        RGFW_window_move(platform.window, RGFW_POINT(CORE.Window.position.x, CORE.Window.position.y));
-        RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
-    }
-
-    // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
-    // NOTE: V-Sync can be enabled by graphic driver configuration
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
-}
-
-// Toggle borderless windowed mode
-void ToggleBorderlessWindowed(void)
-{
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) ToggleFullscreen();
-
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
-    {
-        CORE.Window.previousPosition = CORE.Window.position;
-        CORE.Window.previousScreen = CORE.Window.screen;
-
-        RGFW_window_setBorder(platform.window, 0);
-
-        RGFW_monitor mon = RGFW_window_getMonitor(platform.window);
-        RGFW_window_resize(platform.window, mon.mode.area);
-    }
-    else
-    {
-        RGFW_window_setBorder(platform.window, 1);
-
-        CORE.Window.position = CORE.Window.previousPosition;
-        RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
-    }
-}
-
-// Set window state: maximized, if resizable
-void MaximizeWindow(void)
-{
-    RGFW_window_maximize(platform.window);
-}
-
-// Set window state: minimized
-void MinimizeWindow(void)
-{
-    RGFW_window_minimize(platform.window);
-}
-
-// Restore window from being minimized/maximized
-void RestoreWindow(void)
-{
-    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
-
-    RGFW_window_restore(platform.window);
-}
-
-// Set window configuration state using flags
-void SetWindowState(unsigned int flags)
-{
-    if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
-
-    FLAG_SET(CORE.Window.flags, flags);
-
-    if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
-    {
-        RGFW_window_swapInterval(platform.window, 1);
-    }
-    if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
-    {
-        ToggleFullscreen();
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
-    {
-        RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0));
-        RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0));
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
-    {
-        RGFW_window_setBorder(platform.window, 0);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
-    {
-        RGFW_window_hide(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
-    {
-        RGFW_window_minimize(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
-    {
-        RGFW_window_maximize(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
-    {
-        FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
-        FLAG_CLEAR(platform.window->_flags, RGFW_windowFocusOnShow);
-        RGFW_window_setFlags(platform.window, platform.window->_flags);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
-    {
-        RGFW_window_setFloating(platform.window, RGFW_TRUE);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
-    {
-        FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
-    {
-        TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
-    {
-        TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
-    {
-        RGFW_window_setMousePassthrough(platform.window, 1);
-    }
-    if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
-    {
-        ToggleBorderlessWindowed();
-    }
-    if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
-    {
-        RGFW_setGLHint(RGFW_glSamples, 4);
-    }
-    if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
-    {
-        TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
-    }
-}
-
-// Clear window configuration state flags
-void ClearWindowState(unsigned int flags)
-{
-    FLAG_CLEAR(CORE.Window.flags, flags);
-
-    if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
-    {
-        RGFW_window_swapInterval(platform.window, 0);
-    }
-    if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
-    {
-        ToggleFullscreen();
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
-    {
-        RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
-        RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
-    {
-        RGFW_window_setBorder(platform.window, 1);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
-    {
-        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
-
-        RGFW_window_show(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
-    {
-        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
-
-        RGFW_window_restore(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
-    {
-        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
-
-        RGFW_window_restore(platform.window);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
-    {
-        RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
-    {
-        RGFW_window_setFloating(platform.window, RGFW_FALSE);
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
-    {
-        TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
-    {
-        TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
-    }
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
-    {
-        RGFW_window_setMousePassthrough(platform.window, 0);
-    }
-    if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
-    {
-        ToggleBorderlessWindowed();
-    }
-    if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
-    {
-        RGFW_setGLHint(RGFW_glSamples, 0);
-    }
-    if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
-    {
-        TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
-    }
-}
-
-// Set icon for window
-void SetWindowIcon(Image image)
-{
-    if (image.format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
-    {
-        TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
-        return;
-    }
-    RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), 4);
-}
-
-// Set icon for window
-void SetWindowIcons(Image *images, int count)
-{
-    if ((images == NULL) || (count <= 0))
-    {
-        RGFW_window_setIcon(platform.window, NULL, RGFW_AREA(0, 0), 0);
-    }
-    else
-    {
-        Image *bigIcon = NULL;
-        Image *smallIcon = NULL;
-
-        for (int i = 0; i < count; i++)
-        {
-            if (images[i].format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
-            {
-                TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
-                continue;
-            }
-            if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
-            if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
-        }
-
-        if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), 4, RGFW_iconWindow);
-        if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), 4, RGFW_iconTaskbar);
-    }
-}
-
-// Set title for window
-void SetWindowTitle(const char *title)
-{
-    RGFW_window_setName(platform.window, (char *)title);
-    CORE.Window.title = title;
-}
-
-// Set window position on screen (windowed mode)
-void SetWindowPosition(int x, int y)
-{
-    RGFW_window_move(platform.window, RGFW_POINT(x, y));
-}
-
-// Set monitor for the current window
-void SetWindowMonitor(int monitor)
-{
-    RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
-}
-
-// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
-void SetWindowMinSize(int width, int height)
-{
-    RGFW_window_setMinSize(platform.window, RGFW_AREA(width, height));
-    CORE.Window.screenMin.width = width;
-    CORE.Window.screenMin.height = height;
-}
-
-// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
-void SetWindowMaxSize(int width, int height)
-{
-    RGFW_window_setMaxSize(platform.window, RGFW_AREA(width, height));
-    CORE.Window.screenMax.width = width;
-    CORE.Window.screenMax.height = height;
-}
-
-// Set window dimensions
-void SetWindowSize(int width, int height)
-{
-    CORE.Window.screen.width = width;
-    CORE.Window.screen.height = height;
-
-    RGFW_window_resize(platform.window, RGFW_AREA(width, height));
-}
-
-// Set window opacity, value opacity is between 0.0 and 1.0
-void SetWindowOpacity(float opacity)
-{
-    RGFW_window_setOpacity(platform.window, opacity);
-}
-
-// Set window focused
-void SetWindowFocused(void)
-{
-    RGFW_window_focus(platform.window);
-}
-
-// Get native window handle
-void *GetWindowHandle(void)
-{
-    if (platform.window == NULL) return NULL;
-#ifdef RGFW_WASM
-    return (void *)platform.window->src.ctx;
-#else
-    return (void *)platform.window->src.window;
-#endif
-}
-
-// Get number of monitors
-int GetMonitorCount(void)
-{
-    #define MAX_MONITORS_SUPPORTED 6
-
-    int count = MAX_MONITORS_SUPPORTED;
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    for (int i = 0; i < 6; i++)
-    {
-        if (!mons[i].x && !mons[i].y && !mons[i].mode.area.w && mons[i].mode.area.h)
-        {
-            count = i;
-            break;
-        }
-    }
-
-    return count;
-}
-
-// Get current monitor where window is placed
-int GetCurrentMonitor(void)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-    RGFW_monitor mon = { 0 };
-
-    if (platform.window) mon = RGFW_window_getMonitor(platform.window);
-    else mon = RGFW_getPrimaryMonitor();
-
-    for (int i = 0; i < 6; i++)
-    {
-        if ((mons[i].x ==  mon.x) && (mons[i].y ==  mon.y)) return i;
-    }
-
-    return 0;
-}
-
-// Get selected monitor position
-Vector2 GetMonitorPosition(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
-}
-
-// Get selected monitor width (currently used by monitor)
-int GetMonitorWidth(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return mons[monitor].mode.area.w;
-}
-
-// Get selected monitor height (currently used by monitor)
-int GetMonitorHeight(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return mons[monitor].mode.area.h;
-}
-
-// Get selected monitor physical width in millimetres
-int GetMonitorPhysicalWidth(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return mons[monitor].physW;
-}
-
-// Get selected monitor physical height in millimetres
-int GetMonitorPhysicalHeight(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return (int)mons[monitor].physH;
-}
-
-// Get selected monitor refresh rate
-int GetMonitorRefreshRate(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return (int)mons[monitor].mode.refreshRate;
-}
-
-// Get the human-readable, UTF-8 encoded name of the selected monitor
-const char *GetMonitorName(int monitor)
-{
-    RGFW_monitor *mons = RGFW_getMonitors(NULL);
-
-    return mons[monitor].name;
-}
-
-// Get window position XY on monitor
-Vector2 GetWindowPosition(void)
-{
-    if (platform.window == NULL) return (Vector2){ 0.0f, 0.0f };
-    return (Vector2){ (float)platform.window->r.x, (float)platform.window->r.y };
-}
-
-// Get window scale DPI factor for current monitor
-Vector2 GetWindowScaleDPI(void)
-{
-    RGFW_monitor monitor = { 0 };
-
-    if (platform.window) monitor = RGFW_window_getMonitor(platform.window);
-    else monitor = RGFW_getPrimaryMonitor();
-
-    return (Vector2){ monitor.scaleX, monitor.scaleX };
-}
-
-// Set clipboard text content
-void SetClipboardText(const char *text)
-{
-    RGFW_writeClipboard(text, strlen(text));
-}
-
-// Get clipboard text content
-// NOTE: returned string is allocated and freed by RGFW
-const char *GetClipboardText(void)
-{
-    return RGFW_readClipboard(NULL);
-}
-
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
-#if defined(_WIN32)
-    #define WIN32_CLIPBOARD_IMPLEMENTATION
-    #define WINUSER_ALREADY_INCLUDED
-    #define WINBASE_ALREADY_INCLUDED
-    #define WINGDI_ALREADY_INCLUDED
-    #include "../external/win32_clipboard.h"
-#endif
-#endif
-
-// Get clipboard image
-Image GetClipboardImage(void)
-{
-    Image image = { 0 };
-    unsigned long long int dataSize = 0;
-    void *fileData = NULL;
-
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
-#if defined(_WIN32)
-    int width = 0;
-    int height = 0;
-    fileData  = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
-
-    if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
-    else image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, dataSize);
-#else
-    TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS");
-#endif
-#endif // SUPPORT_CLIPBOARD_IMAGE
-
-    return image;
-}
-
-// Show mouse cursor
-void ShowCursor(void)
-{
-    RGFW_window_showMouse(platform.window, true);
-    CORE.Input.Mouse.cursorHidden = false;
-}
-
-// Hides mouse cursor
-void HideCursor(void)
-{
-    RGFW_window_showMouse(platform.window, false);
-    CORE.Input.Mouse.cursorHidden = true;
-}
-
-// Enables cursor (unlock cursor)
-void EnableCursor(void)
-{
-    RGFW_disableCursor = false;
-    RGFW_window_mouseUnhold(platform.window);
-
-    // Set cursor position in the middle
-    SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
-    ShowCursor();
-
-    CORE.Input.Mouse.cursorLocked = true;
-}
-
-// Disables cursor (lock cursor)
-void DisableCursor(void)
-{
-    RGFW_disableCursor = true;
-    RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0));
-    HideCursor();
-
-    CORE.Input.Mouse.cursorLocked = true;
-}
-
-// Swap back buffer with front buffer (screen drawing)
-void SwapScreenBuffer(void)
-{
-    RGFW_window_swapBuffers(platform.window);
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Misc
-//----------------------------------------------------------------------------------
-
-// Get elapsed time measure in seconds since InitTimer()
-double GetTime(void)
-{
-    return RGFW_getTime();
-}
-
-// 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
-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
-    {
-        char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
-#if defined(_WIN32)
-        sprintf(cmd, "explorer \"%s\"", url);
-#endif
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-        sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
-#endif
-#if defined(__APPLE__)
-        sprintf(cmd, "open '%s'", url);
-#endif
-        int result = system(cmd);
-        if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
-        RL_FREE(cmd);
-    }
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Inputs
-//----------------------------------------------------------------------------------
-
-// Set internal gamepad mappings
-int SetGamepadMappings(const char *mappings)
-{
-    TRACELOG(LOG_WARNING, "SetGamepadMappings() unsupported on target platform");
-    return 0;
-}
-
-// Set gamepad vibration
-void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
-{
-    TRACELOG(LOG_WARNING, "SetGamepadVibration() unsupported on target platform");
-}
-
-// Set mouse position XY
-void SetMousePosition(int x, int y)
-{
-    RGFW_window_moveMouse(platform.window, RGFW_POINT(x, y));
-    CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
-    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
-}
-
-// Set mouse cursor
-void SetMouseCursor(int cursor)
-{
-    RGFW_window_setMouseStandard(platform.window, cursor);
-}
-
-// Get physical key name
-const char *GetKeyName(int key)
-{
-    TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
-
-    return "";
-}
-
-// Register all input events
-void PollInputEvents(void)
-{
-#if defined(SUPPORT_GESTURES_SYSTEM)
-    // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
-    UpdateGestures();
-#endif
-
-    // Reset keys/chars pressed registered
-    CORE.Input.Keyboard.keyPressedQueueCount = 0;
-    CORE.Input.Keyboard.charPressedQueueCount = 0;
-
-    // Reset mouse wheel
-    CORE.Input.Mouse.currentWheelMove.x = 0;
-    CORE.Input.Mouse.currentWheelMove.y = 0;
-
-    // Register previous mouse position
-
-    // Reset last gamepad button/axis registered state
-    for (int i = 0; (i < 4) && (i < MAX_GAMEPADS); i++)
-    {
-        // Check if gamepad is available
-        if (CORE.Input.Gamepad.ready[i])
-        {
-            // Register previous gamepad button states
-            for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
-            {
-                CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
-            }
-        }
-    }
-
-    // Register previous touch states
-    for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
-
-    // Map touch position to mouse position for convenience
-    CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
-
-    int touchAction = -1;       // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
-    bool realTouch = false;     // Flag to differentiate real touch gestures from mouse ones
-
-    // Register previous keys states
-    // NOTE: Android supports up to 260 keys
-    for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
-    {
-        CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
-        CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
-    }
-
-    // Register previous mouse states
-    for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
-
-    // Poll input events for current platform
-    //-----------------------------------------------------------------------------
-    CORE.Window.resizedLastFrame = false;
-
-    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
-    if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
-    {
-        CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
-        CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
-    }
-    else
-    {
-        CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
-    }
-
-    if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
-    {
-        RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
-        CORE.Time.previous = GetTime();
-    }
-
-    while (RGFW_window_checkEvent(platform.window))
-    {
-        RGFW_event *event = &platform.window->event;
-        // All input events can be processed after polling
-
-        switch (event->type)
-        {
-            case RGFW_mouseEnter: CORE.Input.Mouse.cursorOnScreen = true; break;
-            case RGFW_mouseLeave: CORE.Input.Mouse.cursorOnScreen = false; break;
-            case RGFW_quit:
-                event->type = 0;
-                CORE.Window.shouldClose = true;
-                return;
-            case RGFW_DND:      // Dropped file
-            {
-                for (int i = 0; i < event->droppedFilesCount; i++)
-                {
-                    if (CORE.Window.dropFileCount == 0)
-                    {
-                        // When a new file is dropped, we reserve a fixed number of slots for all possible dropped files
-                        // at the moment we limit the number of drops at once to 1024 files but this behaviour should probably be reviewed
-                        // TODO: Pointers should probably be reallocated for any new file added...
-                        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], event->droppedFiles[i]);
-
-                        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], event->droppedFiles[i]);
-
-                        CORE.Window.dropFileCount++;
-                    }
-                    else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!");
-                }
-            } break;
-
-            // Window events are also polled (Minimized, maximized, close...)
-            case RGFW_windowResized:
-            {
-                SetupViewport(platform.window->r.w, platform.window->r.h);
-
-                // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
-                if (IsWindowState(FLAG_WINDOW_HIGHDPI))
-                {
-                    CORE.Window.screen.width = (int)(platform.window->r.w/GetWindowScaleDPI().x);
-                    CORE.Window.screen.height = (int)(platform.window->r.h/GetWindowScaleDPI().y);
-                }
-                else
-                {
-                    CORE.Window.screen.width = platform.window->r.w;
-                    CORE.Window.screen.height = platform.window->r.h;
-                }
-
-                CORE.Window.currentFbo.width = platform.window->r.w;
-                CORE.Window.currentFbo.height = platform.window->r.h;
-                CORE.Window.resizedLastFrame = true;
-            } break;
-            case RGFW_windowMaximized:
-            {
-                FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);  // The window was maximized
-            } break;
-            case RGFW_windowMinimized:
-            {
-                FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);  // The window was iconified
-            } break;
-            case RGFW_windowRestored:
-            {
-                if (RGFW_window_isMaximized(platform.window))
-                    FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);           // The window was restored
-                if (RGFW_window_isMinimized(platform.window))
-                    FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);           // The window was restored
-            } break;
-            case RGFW_windowMoved:
-            {
-                CORE.Window.position.x = platform.window->r.x;
-                CORE.Window.position.y = platform.window->r.x;
-            } break;
-
-            // Keyboard events
-            case RGFW_keyPressed:
-            {
-                KeyboardKey key = ConvertScancodeToKey(event->key);
-                if (key != KEY_NULL)
-                {
-                    // If key was up, add it to the key pressed queue
-                    if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
-                    {
-                        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
-                        CORE.Input.Keyboard.keyPressedQueueCount++;
-                    }
-
-                    CORE.Input.Keyboard.currentKeyState[key] = 1;
-                }
-
-                if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
-
-                // NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
-                // Check if there is space available in the queue
-                if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
-                {
-                    // Add character (codepoint) to the queue
-                    CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = event->keyChar;
-                    CORE.Input.Keyboard.charPressedQueueCount++;
-                }
-            } break;
-            case RGFW_keyReleased:
-            {
-                KeyboardKey key = ConvertScancodeToKey(event->key);
-                if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
-            } break;
-
-            // Check mouse events
-            case RGFW_mouseButtonPressed:
-            {
-                if ((event->button == RGFW_mouseScrollUp) || (event->button == RGFW_mouseScrollDown))
-                {
-                    CORE.Input.Mouse.currentWheelMove.y = event->scroll;
-                    break;
-                }
-                else CORE.Input.Mouse.currentWheelMove.y = 0;
-
-                int btn = event->button;
-                if (btn == RGFW_mouseLeft) btn = 1;
-                else if (btn == RGFW_mouseRight) btn = 2;
-                else if (btn == RGFW_mouseMiddle) btn = 3;
-
-                CORE.Input.Mouse.currentButtonState[btn - 1] = 1;
-                CORE.Input.Touch.currentTouchState[btn - 1] = 1;
-
-                touchAction = 1;
-            } break;
-            case RGFW_mouseButtonReleased:
-            {
-                if ((event->button == RGFW_mouseScrollUp) || (event->button == RGFW_mouseScrollDown))
-                {
-                    CORE.Input.Mouse.currentWheelMove.y = event->scroll;
-                    break;
-                }
-                else CORE.Input.Mouse.currentWheelMove.y = 0;
-
-                int btn = event->button;
-                if (btn == RGFW_mouseLeft) btn = 1;
-                else if (btn == RGFW_mouseRight) btn = 2;
-                else if (btn == RGFW_mouseMiddle) btn = 3;
-
-                CORE.Input.Mouse.currentButtonState[btn - 1] = 0;
-                CORE.Input.Touch.currentTouchState[btn - 1] = 0;
-
-                touchAction = 0;
-            } break;
-            case RGFW_mousePosChanged:
-            {
-                if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
-                {
-                    CORE.Input.Mouse.currentPosition.x += (float)event->vector.x;
-                    CORE.Input.Mouse.currentPosition.y += (float)event->vector.y;
-                }
-                else
-                {
-                    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
-                    CORE.Input.Mouse.currentPosition.x = (float)event->point.x;
-                    CORE.Input.Mouse.currentPosition.y = (float)event->point.y;
-                }
-
-                CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
-                touchAction = 2;
-            } break;
-            case RGFW_gamepadConnected:
-            {
-                CORE.Input.Gamepad.ready[platform.window->event.gamepad] = true;
-                CORE.Input.Gamepad.axisCount[platform.window->event.gamepad] = platform.window->event.axisesCount;
-                CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
-                CORE.Input.Gamepad.axisState[platform.window->event.gamepad][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
-
-                strcpy(CORE.Input.Gamepad.name[platform.window->event.gamepad], RGFW_getGamepadName(platform.window, platform.window->event.gamepad));
-            } break;
-            case RGFW_gamepadDisconnected:
-            {
-                CORE.Input.Gamepad.ready[platform.window->event.gamepad] = false;
-            } break;
-            case RGFW_gamepadButtonPressed:
-            {
-                int button = RGFW_gpConvTable[event->button];
-
-                if (button >= 0)
-                {
-                    CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 1;
-                    CORE.Input.Gamepad.lastButtonPressed = button;
-                }
-            } break;
-            case RGFW_gamepadButtonReleased:
-            {
-                int button = RGFW_gpConvTable[event->button];
-
-                CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = 0;
-                if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
-            } break;
-            case RGFW_gamepadAxisMove:
-            {
-                int axis = -1;
-                float value = 0;
-
-                switch(event->whichAxis)
-                {
-                    case 0:
-                    {
-                        CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_X] = event->axis[0].x/100.0f;
-                        CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_LEFT_Y] = event->axis[0].y/100.0f;
-                    } break;
-                    case 1:
-                    {
-                        CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_X] = event->axis[1].x/100.0f;
-                        CORE.Input.Gamepad.axisState[event->gamepad][GAMEPAD_AXIS_RIGHT_Y] = event->axis[1].y/100.0f;
-                    } break;
-                    case 2: axis = GAMEPAD_AXIS_LEFT_TRIGGER;
-                    case 3:
-                    {
-                        if (axis == -1) axis = GAMEPAD_AXIS_RIGHT_TRIGGER;
-
-                        int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
-                        int pressed = (value > 0.1f);
-                        CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
-
-                        if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
-                        else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
-                    }
-                    default: break;
-                }
-            } break;
-            default: break;
-        }
-
-#if defined(SUPPORT_GESTURES_SYSTEM)
-        if (touchAction > -1)
-        {
-            // Process mouse events as touches to be able to use mouse-gestures
-            GestureEvent gestureEvent = { 0 };
-
-            // Register touch actions
-            gestureEvent.touchAction = touchAction;
-
-            // Assign a pointer ID
-            gestureEvent.pointId[0] = 0;
-
-            // Register touch points count
-            gestureEvent.pointCount = 1;
-
-            // Register touch points position, only one point registered
-            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
-            gestureEvent.position[0].x /= (float)GetScreenWidth();
-            gestureEvent.position[0].y /= (float)GetScreenHeight();
-
-            // Gesture data is sent to gestures-system for processing
-            ProcessGestureEvent(gestureEvent);
-
-            touchAction = -1;
-        }
-#endif
-    }
-    //-----------------------------------------------------------------------------
-}
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-
-// Initialize platform: graphics, inputs and more
-int InitPlatform(void)
-{
-    // Initialize RGFW internal global state, only required systems
-    unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
-
-    // Check window creation flags
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
-    {
-        FLAG_SET(flags, RGFW_windowFullscreen);
-    }
-
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
-    {
-        FLAG_SET(flags, RGFW_windowedFullscreen);
-    }
-
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
-    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, RGFW_windowFullscreen);
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
-
-    // NOTE: Some OpenGL context attributes must be set before window creation
-    // Check selection OpenGL version
-    if (rlGetVersion() == RL_OPENGL_21)
-    {
-        RGFW_setGLHint(RGFW_glMajor, 2);
-        RGFW_setGLHint(RGFW_glMinor, 1);
-    }
-    else if (rlGetVersion() == RL_OPENGL_33)
-    {
-        RGFW_setGLHint(RGFW_glMajor, 3);
-        RGFW_setGLHint(RGFW_glMinor, 3);
-    }
-    else if (rlGetVersion() == RL_OPENGL_43)
-    {
-        RGFW_setGLHint(RGFW_glMajor, 4);
-        RGFW_setGLHint(RGFW_glMinor, 3);
-    }
-
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) RGFW_setGLHint(RGFW_glSamples, 4);
-
-    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
-
-    platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
-    platform.mon.mode.area.w = 0;
-
-    if (platform.window != NULL)
-    {
-        // NOTE: RGFW's exit key is distinct from raylib's exit key (which can
-        // be set with SetExitKey()) and defaults to Escape
-        platform.window->exitKey = RGFW_keyNULL;
-    }
-
-#ifndef PLATFORM_WEB_RGFW
-    RGFW_area screenSize = RGFW_getScreenSize();
-    CORE.Window.display.width = screenSize.w;
-    CORE.Window.display.height = screenSize.h;
-#else
-    CORE.Window.display.width = CORE.Window.screen.width;
-    CORE.Window.display.height = CORE.Window.screen.height;
-#endif
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
-    RGFW_window_makeCurrent(platform.window);
-
-    // Check surface and context activation
-    if (platform.window != NULL)
-    {
-        CORE.Window.ready = true;
-
-        CORE.Window.render.width = CORE.Window.screen.width;
-        CORE.Window.render.height = CORE.Window.screen.height;
-        CORE.Window.currentFbo.width = CORE.Window.render.width;
-        CORE.Window.currentFbo.height = CORE.Window.render.height;
-    }
-    else
-    {
-        TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
-        return -1;
-    }
-    //----------------------------------------------------------------------------
-
-    // If everything work as expected, we can continue
-    CORE.Window.position.x = platform.window->r.x;
-    CORE.Window.position.y = platform.window->r.y;
-    CORE.Window.render.width = CORE.Window.screen.width;
-    CORE.Window.render.height = CORE.Window.screen.height;
-    CORE.Window.currentFbo.width = CORE.Window.render.width;
-    CORE.Window.currentFbo.height = CORE.Window.render.height;
-
-    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
-    TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
-    TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
-    TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
-    TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
-
-    // Load OpenGL extensions
-    // NOTE: GL procedures address loader is required to load extensions
-    //----------------------------------------------------------------------------
-    rlLoadExtensions((void *)RGFW_getProcAddress);
-    //----------------------------------------------------------------------------
-
-    // Initialize timing system
-    //----------------------------------------------------------------------------
-    InitTimer();
-    //----------------------------------------------------------------------------
-
-    // Initialize storage system
-    //----------------------------------------------------------------------------
-    CORE.Storage.basePath = GetWorkingDirectory();
-    //----------------------------------------------------------------------------
-
-#if defined(RGFW_WAYLAND)
-    if (RGFW_useWaylandBool) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
-    else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
-#elif defined(RGFW_X11)
-    #if defined(__APPLE__)
-        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (MacOS)): Initialized successfully");
-    #else
-        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
-    #endif
-#elif defined (RGFW_WINDOWS)
-    TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
-#elif defined(RGFW_WASM)
-    TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
-#elif defined(RGFW_MACOS)
-    TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
-#endif
-
-    return 0;
-}
-
-// Close platform
-void ClosePlatform(void)
-{
-    RGFW_window_close(platform.window);
-}
-
-// Keycode mapping
-static KeyboardKey ConvertScancodeToKey(u32 keycode)
-{
-    if (keycode > sizeof(keyMappingRGFW)/sizeof(unsigned short)) return KEY_NULL;
-
-    return (KeyboardKey)keyMappingRGFW[keycode];
-}
-
+#if defined(_WIN32) || defined(_WIN64)
+    #define BI_ALPHABITFIELDS 4
+    #define LoadImage LoadImageA
+
+    // Temporarily rename conflicting symbols
+    #define CloseWindow CloseWindowWin32
+    #define Rectangle RectangleWin32
+    #define ShowCursor ShowCursorWin32
+
+    #define WIN32_LEAN_AND_MEAN
+    #include <windows.h>
+
+    // Restore for raylib/RGFW
+    #undef CloseWindow
+    #undef Rectangle
+    #undef ShowCursor
+    #undef LoadImage
+
+    #include "../external/fix_win32_compatibility.h"
+#endif
+
+#if defined(PLATFORM_WEB_RGFW)
+    #define RGFW_NO_GL_HEADER
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(PLATFORM_WEB_RGFW)
+    #define RGFW_OPENGL_ES2
+#endif
+
+void ShowCursor(void);
+void CloseWindow(void);
+double GetTimeSeconds(void);
+
+#if defined(__unix__) || defined(__linux__)
+    #define _XTYPEDEF_FONT
+#endif
+
+#define RGFW_OPENGL
+#define RGFW_IMPLEMENTATION
+
+#if defined(_WIN32) || defined(_WIN64)
+    #define WIN32_LEAN_AND_MEAN
+    #define Rectangle rectangle_win32
+    #define CloseWindow CloseWindow_win32
+    #define ShowCursor __imp_ShowCursor
+    #define _APISETSTRING_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+    __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+    #define Point NSPOINT
+    #define Size NSSIZE
+
+    #ifdef GetColor
+        #undef GetColor
+    #endif
+    #define GetColor GetColor_osx
+    #ifdef EventType
+        #undef EventType
+    #endif
+    #define EventType EventType_osx
+#endif
+
+#if defined(__APPLE__)
+    // older macs (unsupported?) are missing these
+    #include <IOKit/hid/IOHIDUsageTables.h>
+    #ifndef kHIDUsage_Button_5
+        #define kHIDUsage_Button_5 0x05
+    #endif
+    #ifndef kHIDUsage_Button_6
+        #define kHIDUsage_Button_6 0x06
+    #endif
+    #ifndef kHIDUsage_Button_7
+        #define kHIDUsage_Button_7 0x07
+    #endif
+    #ifndef kHIDUsage_Button_8
+        #define kHIDUsage_Button_8 0x08
+    #endif
+    #ifndef kHIDUsage_Button_9
+        #define kHIDUsage_Button_9 0x09
+    #endif
+    #ifndef kHIDUsage_Button_10
+        #define kHIDUsage_Button_10 0x0A
+    #endif
+#endif
+
+// minigamepad used for gamepad support
+#define MG_MAX_GAMEPADS MAX_GAMEPADS // copy raylibs define into minigamepad
+#define MG_IMPLEMENTATION
+#include "../external/RGFW/deps/minigamepad.h"
+
+#define RGFW_ALLOC RL_MALLOC
+#define RGFW_FREE RL_FREE
+#define RGFW_CALLOC RL_CALLOC
+#define RGFW_INT_DEFINED 1 // to avoid issues with minigamepad+RGFW definitions
+
+#include "../external/RGFW/RGFW.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+    #undef DrawText
+    #undef ShowCursor
+    #undef CloseWindow
+    #undef Rectangle
+
+    #ifdef MAX_PATH
+        #undef MAX_PATH
+    #endif
+    #define MAX_PATH 1025
+#endif
+
+#if defined(__APPLE__)
+    #undef Point
+    #undef Size
+#endif
+
+#include <stdbool.h>
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct {
+    RGFW_window *window;                // Native display device (physical screen connection)
+    RGFW_monitor *monitor;
+    mg_gamepads minigamepad;
+
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    RGFW_surface *surface;
+    u8 *surfacePixels;
+    i32 surfaceWidth;
+    i32 surfaceHeight;
+#endif
+#if defined(__linux__) && defined(RGFW_X11)
+    Window windowHandleX11;             // Underlying type: unsigned long
+#endif
+} PlatformData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+extern CoreData CORE;                   // Global CORE state context
+
+static PlatformData platform = { 0 };   // Platform specific
+
+#if defined(__linux__) // prevent collision of raylibs KEY_<X> and linux/input.h KEY_<X>
+    #undef KEY_NULL
+    // Alphanumeric keys
+    #undef KEY_APOSTROPHE
+    #undef KEY_COMMA
+    #undef KEY_MINUS
+    #undef KEY_PERIOD
+    #undef KEY_SLASH
+    #undef KEY_ZERO
+    #undef KEY_ONE
+    #undef KEY_TWO
+    #undef KEY_THREE
+    #undef KEY_FOUR
+    #undef KEY_FIVE
+    #undef KEY_SIX
+    #undef KEY_SEVEN
+    #undef KEY_EIGHT
+    #undef KEY_NINE
+    #undef KEY_SEMICOLON
+    #undef KEY_EQUAL
+    #undef KEY_A
+    #undef KEY_B
+    #undef KEY_C
+    #undef KEY_D
+    #undef KEY_E
+    #undef KEY_F
+    #undef KEY_G
+    #undef KEY_H
+    #undef KEY_I
+    #undef KEY_J
+    #undef KEY_K
+    #undef KEY_L
+    #undef KEY_M
+    #undef KEY_N
+    #undef KEY_O
+    #undef KEY_P
+    #undef KEY_Q
+    #undef KEY_R
+    #undef KEY_S
+    #undef KEY_T
+    #undef KEY_U
+    #undef KEY_V
+    #undef KEY_W
+    #undef KEY_X
+    #undef KEY_Y
+    #undef KEY_Z
+    #undef KEY_LEFT_BRACKET
+    #undef KEY_BACKSLASH
+    #undef KEY_RIGHT_BRACKET
+    #undef KEY_GRAVE
+    // Function keys
+    #undef KEY_SPACE
+    #undef KEY_ESCAPE
+    #undef KEY_ENTER
+    #undef KEY_TAB
+    #undef KEY_BACKSPACE
+    #undef KEY_INSERT
+    #undef KEY_DELETE
+    #undef KEY_RIGHT
+    #undef KEY_LEFT
+    #undef KEY_DOWN
+    #undef KEY_UP
+    #undef KEY_PAGE_UP
+    #undef KEY_PAGE_DOWN
+    #undef KEY_HOME
+    #undef KEY_END
+    #undef KEY_CAPS_LOCK
+    #undef KEY_SCROLL_LOCK
+    #undef KEY_NUM_LOCK
+    #undef KEY_PRINT_SCREEN
+    #undef KEY_PAUSE
+    #undef KEY_F1
+    #undef KEY_F2
+    #undef KEY_F3
+    #undef KEY_F4
+    #undef KEY_F5
+    #undef KEY_F6
+    #undef KEY_F7
+    #undef KEY_F8
+    #undef KEY_F9
+    #undef KEY_F10
+    #undef KEY_F11
+    #undef KEY_F12
+    #undef KEY_LEFT_SHIFT
+    #undef KEY_LEFT_CONTROL
+    #undef KEY_LEFT_ALT
+    #undef KEY_LEFT_SUPER
+    #undef KEY_RIGHT_SHIFT
+    #undef KEY_RIGHT_CONTROL
+    #undef KEY_RIGHT_ALT
+    #undef KEY_RIGHT_SUPER
+    #undef KEY_KB_MENU
+    // Keypad keys
+    #undef KEY_KP_0
+    #undef KEY_KP_1
+    #undef KEY_KP_2
+    #undef KEY_KP_3
+    #undef KEY_KP_4
+    #undef KEY_KP_5
+    #undef KEY_KP_6
+    #undef KEY_KP_7
+    #undef KEY_KP_8
+    #undef KEY_KP_9
+    #undef KEY_KP_DECIMAL
+    #undef KEY_KP_DIVIDE
+    #undef KEY_KP_MULTIPLY
+    #undef KEY_KP_SUBTRACT
+    #undef KEY_KP_ADD
+    #undef KEY_KP_ENTER
+    #undef KEY_KP_EQUAL
+#endif
+
+static const unsigned short RGFW_keyConvertTable[] = {
+    [RGFW_keyNULL] = KEY_NULL,
+    [RGFW_keyApostrophe] = KEY_APOSTROPHE,
+    [RGFW_keyComma] = KEY_COMMA,
+    [RGFW_keyMinus] = KEY_MINUS,
+    [RGFW_keyPeriod] = KEY_PERIOD,
+    [RGFW_keySlash] = KEY_SLASH,
+    [RGFW_key0] = KEY_ZERO,
+    [RGFW_key1] = KEY_ONE,
+    [RGFW_key2] = KEY_TWO,
+    [RGFW_key3] = KEY_THREE,
+    [RGFW_key4] = KEY_FOUR,
+    [RGFW_key5] = KEY_FIVE,
+    [RGFW_key6] = KEY_SIX,
+    [RGFW_key7] = KEY_SEVEN,
+    [RGFW_key8] = KEY_EIGHT,
+    [RGFW_key9] = KEY_NINE,
+    [RGFW_keySemicolon] = KEY_SEMICOLON,
+    [RGFW_keyEquals] = KEY_EQUAL,
+    [RGFW_keyA] = KEY_A,
+    [RGFW_keyB] = KEY_B,
+    [RGFW_keyC] = KEY_C,
+    [RGFW_keyD] = KEY_D,
+    [RGFW_keyE] = KEY_E,
+    [RGFW_keyF] = KEY_F,
+    [RGFW_keyG] = KEY_G,
+    [RGFW_keyH] = KEY_H,
+    [RGFW_keyI] = KEY_I,
+    [RGFW_keyJ] = KEY_J,
+    [RGFW_keyK] = KEY_K,
+    [RGFW_keyL] = KEY_L,
+    [RGFW_keyM] = KEY_M,
+    [RGFW_keyN] = KEY_N,
+    [RGFW_keyO] = KEY_O,
+    [RGFW_keyP] = KEY_P,
+    [RGFW_keyQ] = KEY_Q,
+    [RGFW_keyR] = KEY_R,
+    [RGFW_keyS] = KEY_S,
+    [RGFW_keyT] = KEY_T,
+    [RGFW_keyU] = KEY_U,
+    [RGFW_keyV] = KEY_V,
+    [RGFW_keyW] = KEY_W,
+    [RGFW_keyX] = KEY_X,
+    [RGFW_keyY] = KEY_Y,
+    [RGFW_keyZ] = KEY_Z,
+    [RGFW_keyBracket] = KEY_LEFT_BRACKET,
+    [RGFW_keyBackSlash] = KEY_BACKSLASH,
+    [RGFW_keyCloseBracket] = KEY_RIGHT_BRACKET,
+    [RGFW_keyBacktick] = KEY_GRAVE,
+    [RGFW_keySpace] = KEY_SPACE,
+    [RGFW_keyEscape] = KEY_ESCAPE,
+    [RGFW_keyReturn] = KEY_ENTER,
+    [RGFW_keyTab] = KEY_TAB,
+    [RGFW_keyBackSpace] = KEY_BACKSPACE,
+    [RGFW_keyInsert] = KEY_INSERT,
+    [RGFW_keyDelete] = KEY_DELETE,
+    [RGFW_keyRight] = KEY_RIGHT,
+    [RGFW_keyLeft] = KEY_LEFT,
+    [RGFW_keyDown] = KEY_DOWN,
+    [RGFW_keyUp] = KEY_UP,
+    [RGFW_keyPageUp] = KEY_PAGE_UP,
+    [RGFW_keyPageDown] = KEY_PAGE_DOWN,
+    [RGFW_keyHome] = KEY_HOME,
+    [RGFW_keyEnd] = KEY_END,
+    [RGFW_keyCapsLock] = KEY_CAPS_LOCK,
+    [RGFW_keyScrollLock] = KEY_SCROLL_LOCK,
+    [RGFW_keyNumLock] = KEY_NUM_LOCK,
+    [RGFW_keyPrintScreen] = KEY_PRINT_SCREEN,
+    [RGFW_keyPause] = KEY_PAUSE,
+    [RGFW_keyF1] = KEY_F1,
+    [RGFW_keyF2] = KEY_F2,
+    [RGFW_keyF3] = KEY_F3,
+    [RGFW_keyF4] = KEY_F4,
+    [RGFW_keyF5] = KEY_F5,
+    [RGFW_keyF6] = KEY_F6,
+    [RGFW_keyF7] = KEY_F7,
+    [RGFW_keyF8] = KEY_F8,
+    [RGFW_keyF9] = KEY_F9,
+    [RGFW_keyF10] = KEY_F10,
+    [RGFW_keyF11] = KEY_F11,
+    [RGFW_keyF12] = KEY_F12,
+    [RGFW_keyShiftL] = KEY_LEFT_SHIFT,
+    [RGFW_keyControlL] = KEY_LEFT_CONTROL,
+    [RGFW_keyAltL] = KEY_LEFT_ALT,
+    [RGFW_keySuperL] = KEY_LEFT_SUPER,
+    // #ifndef RGFW_MACOS
+    [RGFW_keyShiftR] = KEY_RIGHT_SHIFT,
+    [RGFW_keyControlR] = KEY_RIGHT_CONTROL,
+    [RGFW_keyAltR] = KEY_RIGHT_ALT,
+    [RGFW_keySuperR] = KEY_RIGHT_SUPER,
+    // #endif
+    [RGFW_keyMenu] = KEY_KB_MENU,
+    [RGFW_keyPad0] = KEY_KP_0,
+    [RGFW_keyPad1] = KEY_KP_1,
+    [RGFW_keyPad2] = KEY_KP_2,
+    [RGFW_keyPad3] = KEY_KP_3,
+    [RGFW_keyPad4] = KEY_KP_4,
+    [RGFW_keyPad5] = KEY_KP_5,
+    [RGFW_keyPad6] = KEY_KP_6,
+    [RGFW_keyPad7] = KEY_KP_7,
+    [RGFW_keyPad8] = KEY_KP_8,
+    [RGFW_keyPad9] = KEY_KP_9,
+    [RGFW_keyPadPeriod] = KEY_KP_DECIMAL,
+    [RGFW_keyPadSlash] = KEY_KP_DIVIDE,
+    [RGFW_keyPadMultiply] = KEY_KP_MULTIPLY,
+    [RGFW_keyPadMinus] = KEY_KP_SUBTRACT,
+    [RGFW_keyPadPlus] = KEY_KP_ADD,
+    [RGFW_keyPadReturn] = KEY_KP_ENTER,
+    [RGFW_keyPadEqual] = KEY_KP_EQUAL,
+};
+
+static int mg_buttonConvertTable[] = {
+    [MG_BUTTON_NORTH] = GAMEPAD_BUTTON_RIGHT_FACE_UP,
+    [MG_BUTTON_EAST] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
+    [MG_BUTTON_SOUTH] = GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
+    [MG_BUTTON_WEST] = GAMEPAD_BUTTON_RIGHT_FACE_LEFT,
+    [MG_BUTTON_LEFT_SHOULDER] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
+    [MG_BUTTON_RIGHT_SHOULDER] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
+    [MG_BUTTON_LEFT_TRIGGER] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
+    [MG_BUTTON_RIGHT_TRIGGER] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
+    [MG_BUTTON_BACK] = GAMEPAD_BUTTON_MIDDLE_LEFT,
+    [MG_BUTTON_GUIDE] = GAMEPAD_BUTTON_MIDDLE,
+    [MG_BUTTON_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
+    [MG_BUTTON_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
+    [MG_BUTTON_DPAD_RIGHT] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
+    [MG_BUTTON_DPAD_DOWN] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
+    [MG_BUTTON_DPAD_LEFT] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
+    [MG_BUTTON_LEFT_STICK] = GAMEPAD_BUTTON_LEFT_THUMB,
+    [MG_BUTTON_RIGHT_STICK] = GAMEPAD_BUTTON_RIGHT_THUMB,
+};
+
+static int mg_axisConvertTable[] = {
+    [MG_AXIS_LEFT_X] = GAMEPAD_AXIS_LEFT_X,
+    [MG_AXIS_LEFT_Y] = GAMEPAD_AXIS_LEFT_Y,
+    [MG_AXIS_RIGHT_X] = GAMEPAD_AXIS_RIGHT_X,
+    [MG_AXIS_RIGHT_Y] = GAMEPAD_AXIS_RIGHT_Y,
+    [MG_AXIS_LEFT_TRIGGER] = GAMEPAD_AXIS_LEFT_TRIGGER,
+    [MG_AXIS_RIGHT_TRIGGER] = GAMEPAD_AXIS_RIGHT_TRIGGER,
+
+    /* unsupported in raylib */
+    [MG_AXIS_HAT_DPAD_LEFT_RIGHT] = -1,
+    [MG_AXIS_HAT_DPAD_LEFT] = -1,
+    [MG_AXIS_HAT_DPAD_RIGHT] = -1,
+    [MG_AXIS_HAT_DPAD_UP_DOWN] = -1,
+    [MG_AXIS_HAT_DPAD_UP] = -1,
+    [MG_AXIS_HAT_DPAD_DOWN] = -1,
+};
+
+static KeyboardKey ConvertScancodeToKey(u32 keycode);
+void RemapMouseToTouch(int touchAction);
+
+// ---------------------------------------------------------------------------------
+// RGFW Callbacks (instead of the older polling)
+// ---------------------------------------------------------------------------------
+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;
+
+    // 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;
+
+    if (CORE.Window.dropFileCount == 0)
+    {
+        CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
+
+        CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+        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));
+        snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data);
+
+        CORE.Window.dropFileCount++;
+    }
+    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)
+{
+    if (e->common.win != platform.window) return;
+
+    CORE.Window.resizedLastFrame = true;
+
+    #if defined(__APPLE__)
+        if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+        {
+            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);
+
+            CORE.Window.screen.width = platform.window->w;
+            CORE.Window.screen.height = platform.window->h;
+            CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
+            CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
+        }
+        else
+        {
+            SetupViewport(platform.window->w, platform.window->h);
+            CORE.Window.screen.width = platform.window->w;
+            CORE.Window.screen.height = platform.window->h;
+            CORE.Window.render.width = CORE.Window.screen.width;
+            CORE.Window.render.height = CORE.Window.screen.height;
+        }
+
+        CORE.Window.currentFbo.width = CORE.Window.render.width;
+        CORE.Window.currentFbo.height = CORE.Window.render.height;
+    #elif defined(PLATFORM_WEB_RGFW)
+        // do nothing but prevent other behavior
+    #else
+        SetupViewport(platform.window->w, platform.window->h);
+
+        // Consider content scaling if required
+        if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+        {
+            Vector2 scaleDpi = GetWindowScaleDPI();
+            CORE.Window.screen.width = (int)(platform.window->w/scaleDpi.x);
+            CORE.Window.screen.height = (int)(platform.window->h/scaleDpi.y);
+            CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
+        }
+        else
+        {
+            CORE.Window.screen.width = platform.window->w;
+            CORE.Window.screen.height = platform.window->h;
+        }
+
+        CORE.Window.currentFbo.width = CORE.Window.screen.width;
+        CORE.Window.currentFbo.height = CORE.Window.screen.height;
+    #endif
+
+    #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+        #if defined(__APPLE__)
+            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);
+
+            CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio;
+            CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
+            CORE.Window.currentFbo.width = CORE.Window.render.width;
+            CORE.Window.currentFbo.height = CORE.Window.render.height;
+        #endif
+        platform.surfaceWidth = CORE.Window.currentFbo.width;
+        platform.surfaceHeight = CORE.Window.currentFbo.height;
+
+        // in software mode we dont have the viewport so we need to reverse the highdpi changes
+        if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+        {
+            Vector2 scaleDpi = GetWindowScaleDPI();
+            platform.surfaceWidth *= scaleDpi.x;
+            platform.surfaceHeight *= scaleDpi.y;
+        }
+
+        if (platform.surfacePixels != NULL)
+        {
+            RL_FREE(platform.surfacePixels);
+            platform.surfacePixels = RL_MALLOC(platform.surfaceWidth*platform.surfaceHeight*4);
+        }
+
+        if (platform.surface != NULL)
+        {
+            RGFW_surface_free(platform.surface);
+            platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
+            swResize(platform.surfaceWidth, platform.surfaceHeight);
+        }
+    #endif
+}
+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)
+{
+    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)
+{
+    if (e->common.win != platform.window) return;
+
+    if (RGFW_window_isMaximized(platform.window))
+        FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored
+    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)
+{
+    if (e->common.win != platform.window) return;
+
+    CORE.Window.position.x = platform.window->x;
+    CORE.Window.position.y = platform.window->y;
+}
+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)
+    {
+        // Add character (codepoint) to the queue
+        CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = e->keyChar.value;
+        CORE.Input.Keyboard.charPressedQueueCount++;
+    }
+}
+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)
+{
+    if (e->common.win != platform.window) return;
+
+    int btn = e->button.value;
+    if (btn == RGFW_mouseLeft) btn = 1;
+    else if (btn == RGFW_mouseRight) btn = 2;
+    else if (btn == RGFW_mouseMiddle) btn = 3;
+
+    // pressed or released
+    if (e->button.state){
+        CORE.Input.Mouse.currentButtonState[btn - 1] = 1;
+        CORE.Input.Touch.currentTouchState[btn - 1] = 1;
+
+        // simulate touch with the mouse
+        RemapMouseToTouch(1);
+    } else
+    {
+        CORE.Input.Mouse.currentButtonState[btn - 1] = 0;
+        CORE.Input.Touch.currentTouchState[btn - 1] = 0;
+
+        // simulate touch with the mouse
+        RemapMouseToTouch(0);
+    }
+}
+static void RGFW_cb_mouserawmotionfunc(const RGFW_event *e)
+{
+    if (!RGFW_window_isRawMouseMode(platform.window))
+    {
+        // if not raw, use non-raw motion. this prevents the doubled events
+        return;
+    }
+
+    float mouseX = 0.0f;
+    float mouseY = 0.0f;
+    mouseX = e->delta.x;
+    mouseY = e->delta.y;
+
+    #if defined(__EMSCRIPTEN__)
+        double canvasWidth = 0.0;
+        double canvasHeight = 0.0;
+        emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
+        mouseX *= ((float)GetScreenWidth()/(float)canvasWidth);
+        mouseY *= ((float)GetScreenHeight()/(float)canvasHeight);
+    #endif
+
+    CORE.Input.Mouse.currentPosition.x += mouseX;
+    CORE.Input.Mouse.currentPosition.y += mouseY;
+
+    // simulate touch with the mouse
+    CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
+    RemapMouseToTouch(2);
+}
+static void RGFW_cb_mousemotionfunc(const RGFW_event *e)
+{
+    if (RGFW_window_isRawMouseMode(platform.window))
+    {
+        // if raw, use raw motion. this prevents the doubled events
+        return;
+    }
+
+    float mouseX = 0.0f;
+    float mouseY = 0.0f;
+    mouseX = e->mouse.x;
+    mouseY = e->mouse.y;
+
+    #if defined(__EMSCRIPTEN__)
+        double canvasWidth = 0.0;
+        double canvasHeight = 0.0;
+        emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
+        mouseX *= ((float)GetScreenWidth()/(float)canvasWidth);
+        mouseY *= ((float)GetScreenHeight()/(float)canvasHeight);
+    #endif
+
+    CORE.Input.Mouse.currentPosition.x = mouseX;
+    CORE.Input.Mouse.currentPosition.y = mouseY;
+
+    // simulate touch with the mouse
+    CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
+    RemapMouseToTouch(2);
+}
+static void RGFW_cb_keyfunc(const RGFW_keyEvent* e)
+{
+    if (e->win != platform.window) return;
+
+    KeyboardKey key = ConvertScancodeToKey(e->value);
+    if (key == KEY_NULL) return;
+
+    // pressed or released
+    if (e->state)
+    {
+        // If key was up, add it to the key pressed queue
+        if ((CORE.Input.Keyboard.currentKeyState[key] == 0) && (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
+        {
+            CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
+            CORE.Input.Keyboard.keyPressedQueueCount++;
+        }
+
+        CORE.Input.Keyboard.currentKeyState[key] = 1;
+
+        if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) RGFW_window_setShouldClose(platform.window, true);
+    }
+    else
+    {
+        CORE.Input.Keyboard.currentKeyState[key] = 0;
+    }
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
+bool InitGraphicsDevice(void);   // Initialize graphics device
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+// NOTE: Functions declaration is provided by raylib.h
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Window and Graphics Device
+//----------------------------------------------------------------------------------
+
+// Check if application should close
+bool WindowShouldClose(void)
+{
+    if (CORE.Window.shouldClose == false) CORE.Window.shouldClose = RGFW_window_shouldClose(platform.window);
+    if (CORE.Window.ready) return CORE.Window.shouldClose;
+    return true;
+}
+
+// Toggle fullscreen mode
+void ToggleFullscreen(void)
+{
+    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+    {
+        FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+        // Store previous window position (in case of exiting fullscreen)
+        Vector2 currentPosition = GetWindowPosition();
+        CORE.Window.previousPosition.x = currentPosition.x;
+        CORE.Window.previousPosition.y = currentPosition.y;
+        CORE.Window.previousScreen = CORE.Window.screen;
+
+        RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window);
+        RGFW_monitor_scaleToWindow(currentMonitor, platform.window);
+        RGFW_window_setFullscreen(platform.window, 1);
+    }
+    else
+    {
+        FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+
+        // Update the window position right away
+        CORE.Window.position = CORE.Window.previousPosition;
+        RGFW_window_setFullscreen(platform.window, 0);
+        RGFW_window_move(platform.window, CORE.Window.position.x, CORE.Window.position.y);
+        RGFW_window_resize(platform.window, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
+    }
+
+    // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
+    // NOTE: V-Sync can be enabled by graphic driver configuration
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval_OpenGL(platform.window, 1);
+}
+
+// Toggle borderless windowed mode
+void ToggleBorderlessWindowed(void)
+{
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+    {
+        ToggleFullscreen();
+
+        // it seems like returning here is a more desireable outcome
+        return;
+    }
+
+    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
+    {
+        FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+
+        Vector2 currentPosition = GetWindowPosition();
+        CORE.Window.previousPosition.x = (int)currentPosition.x;
+        CORE.Window.previousPosition.y = (int)currentPosition.y;
+        CORE.Window.previousScreen = CORE.Window.screen;
+
+        RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window);
+        RGFW_window_setBorder(platform.window, 0);
+        RGFW_window_move(platform.window, 0, 0);
+        RGFW_window_resize(platform.window, currentMonitor->mode.w, currentMonitor->mode.h);
+    }
+    else
+    {
+        FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+        RGFW_window_setBorder(platform.window, 1);
+
+        CORE.Window.position = CORE.Window.previousPosition;
+
+        RGFW_window_resize(platform.window, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
+        RGFW_window_move(platform.window, CORE.Window.position.x, CORE.Window.position.y);
+    }
+}
+
+// Set window state: maximized, if resizable
+void MaximizeWindow(void)
+{
+    RGFW_window_maximize(platform.window);
+}
+
+// Set window state: minimized
+void MinimizeWindow(void)
+{
+    RGFW_window_minimize(platform.window);
+}
+
+// Restore window from being minimized/maximized
+void RestoreWindow(void)
+{
+    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+
+    RGFW_window_restore(platform.window);
+}
+
+// Set window configuration state using flags
+void SetWindowState(unsigned int flags)
+{
+    if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
+
+    FLAG_SET(CORE.Window.flags, flags);
+
+    if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
+    {
+        RGFW_window_swapInterval_OpenGL(platform.window, 1);
+    }
+    if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
+    {
+        ToggleFullscreen();
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
+    {
+        RGFW_window_setMaxSize(platform.window, 0, 0);
+        RGFW_window_setMinSize(platform.window, 0, 0);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
+    {
+        RGFW_window_setBorder(platform.window, 0);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
+    {
+        RGFW_window_hide(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
+    {
+        RGFW_window_minimize(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
+    {
+        RGFW_window_maximize(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
+    {
+        FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
+        FLAG_CLEAR(platform.window->internal.flags, RGFW_windowFocusOnShow);
+        RGFW_window_setFlags(platform.window, platform.window->internal.flags);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
+    {
+        RGFW_window_setFloating(platform.window, RGFW_TRUE);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
+    {
+        FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
+    {
+        TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
+    {
+        TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
+    {
+        RGFW_window_setMousePassthrough(platform.window, 1);
+    }
+    if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
+    {
+        ToggleBorderlessWindowed();
+    }
+    if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
+    {
+        RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL();
+        hints->samples = 4;
+        RGFW_setGlobalHints_OpenGL(hints);
+    }
+    if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
+    {
+        TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
+    }
+}
+
+// Clear window configuration state flags
+void ClearWindowState(unsigned int flags)
+{
+    FLAG_CLEAR(CORE.Window.flags, flags);
+
+    if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
+    {
+        RGFW_window_swapInterval_OpenGL(platform.window, 0);
+    }
+    if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
+    {
+        ToggleFullscreen();
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
+    {
+        RGFW_window_setMaxSize(platform.window, platform.window->w, platform.window->h);
+        RGFW_window_setMinSize(platform.window, platform.window->w, platform.window->h);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
+    {
+        RGFW_window_setBorder(platform.window, 1);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
+    {
+        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+
+        RGFW_window_show(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
+    {
+        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+
+        RGFW_window_restore(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
+    {
+        if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+
+        RGFW_window_restore(platform.window);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
+    {
+        RGFW_window_setFlags(platform.window, platform.window->internal.flags | RGFW_windowFocusOnShow);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
+    {
+        RGFW_window_setFloating(platform.window, RGFW_FALSE);
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
+    {
+        TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
+    {
+        TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
+    }
+    if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
+    {
+        RGFW_window_setMousePassthrough(platform.window, 0);
+    }
+    if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
+    {
+        ToggleBorderlessWindowed();
+    }
+    if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
+    {
+        RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL();
+        hints->samples = 0;
+        RGFW_setGlobalHints_OpenGL(hints);
+    }
+    if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
+    {
+        TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
+    }
+}
+
+// Set icon for window
+void SetWindowIcon(Image image)
+{
+    if (image.format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+    {
+        TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
+        return;
+    }
+    RGFW_window_setIcon(platform.window, (u8 *)image.data, image.width, image.height, RGFW_formatRGBA8);
+}
+
+// Set icon for window
+void SetWindowIcons(Image *images, int count)
+{
+    if ((images == NULL) || (count <= 0))
+    {
+        RGFW_window_setIcon(platform.window, NULL, 0, 0, 0);
+    }
+    else
+    {
+        Image *bigIcon = NULL;
+        Image *smallIcon = NULL;
+
+        for (int i = 0; i < count; i++)
+        {
+            if (images[i].format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+            {
+                TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
+                continue;
+            }
+            if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
+            if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
+        }
+
+        if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, smallIcon->width, smallIcon->height, RGFW_formatRGBA8, RGFW_iconWindow);
+        if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, bigIcon->width, bigIcon->height, RGFW_formatRGBA8, RGFW_iconTaskbar);
+    }
+}
+
+// Set title for window
+void SetWindowTitle(const char *title)
+{
+    RGFW_window_setName(platform.window, (char *)title);
+    CORE.Window.title = title;
+}
+
+// Set window position on screen (windowed mode)
+void SetWindowPosition(int x, int y)
+{
+    RGFW_window_move(platform.window, x, y);
+}
+
+// Set monitor for the current window
+void SetWindowMonitor(int monitor)
+{
+    RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
+}
+
+// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMinSize(int width, int height)
+{
+    RGFW_window_setMinSize(platform.window, width, height);
+    CORE.Window.screenMin.width = width;
+    CORE.Window.screenMin.height = height;
+}
+
+// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMaxSize(int width, int height)
+{
+    RGFW_window_setMaxSize(platform.window, width, height);
+    CORE.Window.screenMax.width = width;
+    CORE.Window.screenMax.height = height;
+}
+
+// Set window dimensions
+void SetWindowSize(int width, int height)
+{
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+    {
+        CORE.Window.screen.width = width;
+        CORE.Window.screen.height = height;
+
+        Vector2 scaleDpi = GetWindowScaleDPI();
+
+        #if defined(__APPLE__)
+            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;
+            CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
+            CORE.Window.currentFbo.width = CORE.Window.render.width;
+            CORE.Window.currentFbo.height = CORE.Window.render.height;
+        #else
+            SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
+            CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
+        #endif
+
+        CORE.Window.currentFbo.width = CORE.Window.render.width;
+        CORE.Window.currentFbo.height = CORE.Window.render.height;
+    }
+    else
+    {
+        CORE.Window.screen.width = width;
+        CORE.Window.screen.height = height;
+    }
+
+    if (!CORE.Window.usingFbo)
+    {
+        SetupViewport(CORE.Window.screen.width, CORE.Window.screen.height);
+    }
+
+    RGFW_window_resize(platform.window, CORE.Window.screen.width, CORE.Window.screen.height);
+}
+
+// Set window opacity, value opacity is between 0.0 and 1.0
+void SetWindowOpacity(float opacity)
+{
+    RGFW_window_setOpacity(platform.window, opacity);
+}
+
+// Set window focused
+void SetWindowFocused(void)
+{
+    RGFW_window_focus(platform.window);
+}
+
+// Get native window handle
+void *GetWindowHandle(void)
+{
+    void *handle = NULL;
+
+    if (platform.window != NULL)
+    {
+#if defined(_WIN32)
+        handle = (void *)platform.window->src.window; // Type: HWND
+#elif defined(__linux__)
+    #if defined(RGFW_X11)
+        platform.windowHandleX11 = platform.window->src.window; // Type: Window (unsigned long)
+        handle = &platform.window->src.window;
+    #elif defined(RGFW_WAYLAND)
+        handle = (void *)platform.window->src.surface; // Type: struct wl_surface*
+    #endif
+#elif defined(__APPLE__)
+        handle = (void *)platform.window->src.window; // Type: id, NSWindow*
+#endif
+    }
+
+    return handle;
+}
+
+// Get number of monitors
+int GetMonitorCount(void)
+{
+    size_t count = 0;
+    RGFW_getMonitors(&count);
+
+    return count;
+}
+
+// Get current monitor where window is placed
+int GetCurrentMonitor(void)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+    RGFW_monitor *mon = NULL;
+
+    if (platform.window) mon = RGFW_window_getMonitor(platform.window);
+    else mon = RGFW_getPrimaryMonitor();
+
+    for (int i = 0; i < 6; i++)
+    {
+        if ((mons[i]->x ==  mon->x) && (mons[i]->y ==  mon->y)) return i;
+    }
+
+    return 0;
+}
+
+// Get selected monitor position
+Vector2 GetMonitorPosition(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return (Vector2){ (float)mons[monitor]->x, (float)mons[monitor]->y };
+}
+
+// Get selected monitor width (currently used by monitor)
+int GetMonitorWidth(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return mons[monitor]->mode.w;
+}
+
+// Get selected monitor height (currently used by monitor)
+int GetMonitorHeight(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return mons[monitor]->mode.h;
+}
+
+// Get selected monitor physical width in millimetres
+int GetMonitorPhysicalWidth(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return mons[monitor]->physW;
+}
+
+// Get selected monitor physical height in millimetres
+int GetMonitorPhysicalHeight(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return (int)mons[monitor]->physH;
+}
+
+// Get selected monitor refresh rate
+int GetMonitorRefreshRate(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return (int)mons[monitor]->mode.refreshRate;
+}
+
+// Get the human-readable, UTF-8 encoded name of the selected monitor
+const char *GetMonitorName(int monitor)
+{
+    RGFW_monitor **mons = RGFW_getMonitors(NULL);
+
+    return mons[monitor]->name;
+}
+
+// Get window position XY on monitor
+Vector2 GetWindowPosition(void)
+{
+    if (platform.window == NULL)
+    {
+        return (Vector2){ 0.0f, 0.0f };
+    }
+
+    if (RGFW_window_getPosition(platform.window, &platform.window->x, &platform.window->y)) {
+        return (Vector2){ (float)platform.window->x, (float)platform.window->y };
+    }
+
+    return (Vector2){ 0.0f, 0.0f };
+}
+
+// Get window scale DPI factor for current monitor
+Vector2 GetWindowScaleDPI(void)
+{
+    RGFW_monitor *monitor = NULL;
+
+    if (platform.window) monitor = RGFW_window_getMonitor(platform.window);
+    else monitor = RGFW_getPrimaryMonitor();
+
+    #if defined(__APPLE__)
+        // Apple does < 1.0f scaling, example: 0.66f, 0.5f
+        // it needs to be convert to be consistent
+        return (Vector2){ 1.0f/monitor->scaleX, 1.0f/monitor->scaleX };
+    #else
+        // Linux and Windows do >= 1.0f scaling, example: 1.0f, 1.25f, 2.0f
+        return (Vector2){ monitor->scaleX, monitor->scaleX };
+    #endif
+}
+
+// Get monitor pixel ratio
+// WARNING: Function not used, neither exposed by raylib
+float GetMonitorPixelRatio(void)
+{
+    RGFW_monitor *monitor = NULL;
+
+    if (platform.window) monitor = RGFW_window_getMonitor(platform.window);
+    else monitor = RGFW_getPrimaryMonitor();
+
+    return monitor->pixelRatio;
+}
+
+// Set clipboard text content
+void SetClipboardText(const char *text)
+{
+    // add 1 for null terminator
+    RGFW_writeClipboard(text, strlen(text)+1);
+}
+
+// Get clipboard text content
+// NOTE: returned string is allocated and freed by RGFW
+const char *GetClipboardText(void)
+{
+    return RGFW_readClipboard(NULL);
+}
+
+#if SUPPORT_CLIPBOARD_IMAGE
+#if defined(_WIN32)
+    #define WIN32_CLIPBOARD_IMPLEMENTATION
+    #define WINUSER_ALREADY_INCLUDED
+    #define WINBASE_ALREADY_INCLUDED
+    #define WINGDI_ALREADY_INCLUDED
+    #include "../external/win32_clipboard.h"
+#elif defined(__linux__) && defined(DRGFW_X11)
+    #include <X11/Xlib.h>
+    #include <X11/Xatom.h>
+#endif
+#endif
+
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+    Image image = { 0 };
+
+#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
+#if defined(_WIN32)
+
+    unsigned int dataSize = 0;
+    void *fileData = NULL;
+
+    int width = 0;
+    int height = 0;
+    fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
+
+    if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data");
+    else
+    {
+        image = LoadImageFromMemory(".bmp", (const unsigned char *)fileData, (int)dataSize);
+
+        RL_FREE(fileData);
+    }
+
+#elif defined(__linux__) && defined(DRGFW_X11)
+
+    // REF: https://github.com/ColleagueRiley/Clipboard-Copy-Paste/blob/main/x11.c
+    Display *dpy = XOpenDisplay(NULL);
+    if (!dpy) return image;
+
+    Window root = DefaultRootWindow(dpy);
+    Window win = XCreateSimpleWindow(
+        dpy,      // The connection to the X Server
+        root,     // The 'Parent' window (usually the desktop/root)
+        0, 0,     // X and Y position on the screen
+        1, 1,     // Width and Height (1x1 pixel)
+        0,        // Border width
+        0,        // Border color
+        0         // Background color
+    );
+
+    Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
+    Atom targetType = XInternAtom(dpy, "image/png", False); // Ask for PNG
+    Atom property = XInternAtom(dpy, "RAYLIB_CLIPBOARD_MANAGER", False);
+
+    // Request the data: "Convert whatever is in CLIPBOARD to image/png and put it in RAYLIB_CLIPBOARD_MANAGER"
+    XConvertSelection(dpy, clipboard, targetType, property, win, CurrentTime);
+
+    // Wait for the SelectionNotify event
+    XEvent ev = { 0 };
+    XNextEvent(dpy, &ev);
+
+    Atom actualType = { 0 };
+    int actualFormat = 0;
+    unsigned long nitems = 0;
+    unsigned long bytesAfter = 0;
+    unsigned char *data = NULL;
+
+    // Read the data from our ghost window's property
+    XGetWindowProperty(dpy, win, property, 0, ~0L, False, AnyPropertyType,
+        &actualType, &actualFormat, &nitems, &bytesAfter, &data);
+
+    if (data != NULL)
+    {
+        image = LoadImageFromMemory(".png", data, (int)nitems);
+        XFree(data);
+    }
+
+    XDestroyWindow(dpy, win);
+    XCloseDisplay(dpy);
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: PLATFORM_DESKTOP_RGFW doesn't implement GetClipboardImage() for this OS");
+#endif // _WIN32
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
+#endif // SUPPORT_CLIPBOARD_IMAGE
+
+    return image;
+}
+
+// Show mouse cursor
+void ShowCursor(void)
+{
+    RGFW_window_showMouse(platform.window, true);
+    CORE.Input.Mouse.cursorHidden = false;
+}
+
+// Hide mouse cursor
+void HideCursor(void)
+{
+    RGFW_window_showMouse(platform.window, false);
+    CORE.Input.Mouse.cursorHidden = true;
+}
+
+// Enable cursor (unlock cursor)
+void EnableCursor(void)
+{
+    RGFW_window_captureRawMouse(platform.window, false);
+
+    // Set cursor position in the middle
+    SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
+    ShowCursor();
+
+    CORE.Input.Mouse.cursorLocked = true;
+}
+
+// Disable cursor (lock cursor)
+void DisableCursor(void)
+{
+    RGFW_window_captureRawMouse(platform.window, true);
+    HideCursor();
+
+    CORE.Input.Mouse.cursorLocked = true;
+}
+
+// Swap back buffer with front buffer (screen drawing)
+void SwapScreenBuffer(void)
+{
+    #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    {
+        if (platform.surface)
+        {
+            // Copy rlsw pixel data to the surface framebuffer
+            rlCopyFramebuffer(0, 0, platform.surfaceWidth, platform.surfaceHeight, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.surfacePixels);
+
+            // Mac wants a different pixel order. I cant seem to get this to work any other way
+            #if defined(__APPLE__)
+                unsigned char temp = 0;
+                unsigned char *p = NULL;
+                for (int i = 0; i < (platform.surfaceWidth*platform.surfaceHeight); i += 1)
+                {
+                    p = platform.surfacePixels + (i*4);
+                    temp = p[0];
+                    p[0] = p[2];
+                    p[2] = temp;
+                }
+            #endif
+
+            // blit surface to the window
+            RGFW_window_blitSurface(platform.window, platform.surface);
+        }
+    }
+    #else
+    {
+        RGFW_window_swapBuffers_OpenGL(platform.window);
+    }
+    #endif
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Misc
+//----------------------------------------------------------------------------------
+
+// Get elapsed time measure in seconds since InitTimer()
+double GetTime(void)
+{
+    // CORE.Time.base is nanoseconds as integer
+    double baseTime = (double)CORE.Time.base*1e-9;
+    double time = GetTimeSeconds() - baseTime;
+
+    return time;
+}
+
+// Open URL with default system browser (if available)
+// 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) || (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(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");
+    }
+    else
+    {
+        char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
+#if defined(_WIN32)
+        sprintf(cmd, "explorer \"%s\"", url);
+#endif
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+        sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
+#endif
+#if defined(__APPLE__)
+        sprintf(cmd, "open '%s'", url);
+#endif
+        int result = system(cmd);
+        if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
+        RL_FREE(cmd);
+    }
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Inputs
+//----------------------------------------------------------------------------------
+
+// Set internal gamepad mappings
+int SetGamepadMappings(const char *mappings)
+{
+    return mg_update_gamepad_mappings(&platform.minigamepad, mappings);
+}
+
+// Set gamepad vibration
+void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
+{
+    TRACELOG(LOG_WARNING, "SetGamepadVibration() unsupported on target platform");
+}
+
+// Set mouse position XY
+void SetMousePosition(int x, int y)
+{
+    RGFW_window_moveMouse(platform.window, x, y);
+    CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
+}
+
+// Set mouse cursor
+void SetMouseCursor(int cursor)
+{
+    RGFW_window_setMouseStandard(platform.window, cursor);
+}
+
+// Get physical key name
+const char *GetKeyName(int key)
+{
+    TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
+
+    return "";
+}
+
+// Register all input events
+void PollInputEvents(void)
+{
+#if SUPPORT_GESTURES_SYSTEM
+    // NOTE: Gestures update must be called every frame to reset gestures correctly
+    // because ProcessGestureEvent() is called on an event, not every frame
+    UpdateGestures();
+#endif
+
+    // Reset keys/chars pressed registered
+    CORE.Input.Keyboard.keyPressedQueueCount = 0;
+    CORE.Input.Keyboard.charPressedQueueCount = 0;
+
+    // Reset mouse wheel
+    CORE.Input.Mouse.currentWheelMove.x = 0;
+    CORE.Input.Mouse.currentWheelMove.y = 0;
+
+    // Register previous mouse position
+
+    // Reset last gamepad button/axis registered state
+    for (int i = 0; i < MAX_GAMEPADS; i++)
+    {
+        // Check if gamepad is available
+        if (CORE.Input.Gamepad.ready[i])
+        {
+            // Register previous gamepad button states
+            for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++)
+            {
+                CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
+            }
+        }
+    }
+
+    // Register previous touch states
+    for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
+
+    // Map touch position to mouse position for convenience
+    CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
+
+    // Register previous keys states
+    // NOTE: Android supports up to 260 keys
+    for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
+    {
+        CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
+        CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
+    }
+
+    // Register previous mouse states
+    for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
+
+    // Poll input events for current platform
+    //-----------------------------------------------------------------------------
+    CORE.Window.resizedLastFrame = false;
+
+    CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+    if (RGFW_window_isCaptured(platform.window))
+    {
+        CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
+        CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
+    }
+    else
+    {
+        CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+    }
+
+    if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
+    {
+        CORE.Time.previous = GetTime();
+    }
+
+    //-----------------------------------------------------------------------------
+    // Using RGFW callbacks instead of polling
+    RGFW_pollEvents();
+    //-----------------------------------------------------------------------------
+
+    mg_event gamepad_event = { 0 };
+    while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event))
+    {
+        int gamepadIndex = gamepad_event.gamepad->index;
+
+        switch (gamepad_event.type)
+        {
+            case MG_EVENT_BUTTON_PRESS:
+            {
+                int button = mg_buttonConvertTable[gamepad_event.button];
+                if (button >= 0)
+                {
+                    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)
+                {
+                    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];
+
+                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);
+
+                        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;
+                }
+
+                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;
+        }
+    }
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// Initialize platform: graphics, inputs and more
+int InitPlatform(void)
+{
+    // Initialize RGFW internal global state, only required systems
+    unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
+
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
+    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
+    if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
+
+    if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
+    {
+        FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+    }
+
+    // Check window creation flags
+
+    // Init window in fullscreen mode if requested
+    // NOTE: Keeping original screen size for toggle
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+    {
+        FLAG_SET(flags, RGFW_windowFullscreen);
+        int result = RGFW_init();
+        if (result != 0)
+        {
+            TRACELOG(LOG_WARNING, "RGFW: Failed to initialize RGFW");
+            return -1;
+        }
+
+        // NOTE: Fullscreen applications default to the primary monitor
+        RGFW_monitor *monitor = RGFW_getPrimaryMonitor();
+        if (!monitor)
+        {
+            TRACELOG(LOG_WARNING, "RGFW: Failed to get primary monitor");
+            return -1;
+        }
+
+        // Default display resolution to that of the current mode
+        CORE.Window.display.width = monitor->mode.w;
+        CORE.Window.display.height = monitor->mode.h;
+
+        // Check if user requested some screen size
+        if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
+        {
+            // Set some default screen size in case user decides to exit fullscreen mode
+            CORE.Window.previousScreen.width = 800;
+            CORE.Window.previousScreen.height = 450;
+            CORE.Window.previousPosition.x = (CORE.Window.display.width - CORE.Window.previousScreen.width)/2;
+            CORE.Window.previousPosition.y = (CORE.Window.display.height - CORE.Window.previousScreen.height)/2;
+
+            // Set screen width/height to the display width/height
+            if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
+            if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
+        }
+        else
+        {
+            CORE.Window.previousScreen = CORE.Window.screen;
+            CORE.Window.screen = CORE.Window.display;
+        }
+    }
+
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
+    {
+        FLAG_SET(flags, RGFW_windowedFullscreen);
+    }
+
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+    {
+        #if !defined(__APPLE__)
+            CORE.Window.screen.width = CORE.Window.screen.width*GetWindowScaleDPI().x;
+            CORE.Window.screen.height = CORE.Window.screen.height*GetWindowScaleDPI().y;
+        #endif
+    }
+
+    // NOTE: Some OpenGL context attributes must be set before window creation
+    // Check selection OpenGL version
+    RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL();
+    if (rlGetVersion() == RL_OPENGL_21)
+    {
+        hints->major = 2;
+        hints->minor = 1;
+    }
+    else if (rlGetVersion() == RL_OPENGL_33)
+    {
+        hints->major = 3;
+        hints->minor = 3;
+    }
+    else if (rlGetVersion() == RL_OPENGL_43)
+    {
+        hints->major = 4;
+        hints->minor = 3;
+    }
+    else if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+    {
+        hints->major = 1;
+        hints->minor = 1;
+        hints->renderer = RGFW_glSoftware;
+    }
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) hints->samples = 4;
+    RGFW_setGlobalHints_OpenGL(hints);
+
+    platform.window = RGFW_createWindow((CORE.Window.title != 0)? CORE.Window.title : " ", 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, flags | RGFW_windowOpenGL);
+
+#ifndef PLATFORM_WEB_RGFW
+    i32 screenSizeWidth;
+    i32 screenSizeHeight;
+    RGFW_window_getSize(platform.window, &screenSizeWidth, &screenSizeHeight);
+    CORE.Window.display.width = screenSizeWidth;
+    CORE.Window.display.height = screenSizeHeight;
+#else
+    CORE.Window.display.width = CORE.Window.screen.width;
+    CORE.Window.display.height = CORE.Window.screen.height;
+#endif
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval_OpenGL(platform.window, 1);
+
+    // Check surface and context activation
+    if (platform.window != NULL)
+    {
+        CORE.Window.ready = true;
+
+        CORE.Window.render.width = CORE.Window.screen.width;
+        CORE.Window.render.height = CORE.Window.screen.height;
+        CORE.Window.currentFbo.width = CORE.Window.render.width;
+        CORE.Window.currentFbo.height = CORE.Window.render.height;
+    }
+    else
+    {
+        TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
+        return -1;
+    }
+
+    // NOTE: RGFW's exit key is distinct from raylib's exit key and
+    // must be set to NULL to not interfere
+    RGFW_window_setExitKey(platform.window, RGFW_keyNULL);
+    RGFW_window_makeCurrentWindow_OpenGL(platform.window);
+
+    //----------------------------------------------------------------------------
+
+    // If everything work as expected, continue
+    CORE.Window.position.x = platform.window->x;
+    CORE.Window.position.y = platform.window->y;
+    CORE.Window.render.width = CORE.Window.screen.width;
+    CORE.Window.render.height = CORE.Window.screen.height;
+    CORE.Window.currentFbo.width = CORE.Window.render.width;
+    CORE.Window.currentFbo.height = CORE.Window.render.height;
+
+    // adjust scale if using highdpi
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) {
+        Vector2 scaleDpi = GetWindowScaleDPI();
+
+        #if defined(__APPLE__)
+            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;
+            CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
+            CORE.Window.currentFbo.width = CORE.Window.render.width;
+            CORE.Window.currentFbo.height = CORE.Window.render.height;
+        #else
+            SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
+            CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
+            CORE.Window.screen.width /= scaleDpi.x;
+            CORE.Window.screen.height /= scaleDpi.y;
+        #endif
+    }
+
+    #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+        // apple always scales for retina
+        #if defined(__APPLE__)
+            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;
+            CORE.Window.render.height = CORE.Window.screen.height*currentMonitor->pixelRatio;
+            CORE.Window.currentFbo.width = CORE.Window.render.width;
+            CORE.Window.currentFbo.height = CORE.Window.render.height;
+        #endif
+
+        platform.surfaceWidth = CORE.Window.currentFbo.width;
+        platform.surfaceHeight = CORE.Window.currentFbo.height;
+
+        platform.surfacePixels = RL_MALLOC(platform.surfaceWidth*platform.surfaceHeight*4);
+        if (platform.surfacePixels == NULL)
+        {
+            TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software pixel buffer");
+            return -1;
+        }
+
+        platform.surface = RGFW_window_createSurface(platform.window, platform.surfacePixels, platform.surfaceWidth, platform.surfaceHeight, RGFW_formatBGRA8);
+
+        if (platform.surface == NULL)
+        {
+            RL_FREE(platform.surfacePixels);
+
+            TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize software surface");
+            return -1;
+        }
+    #endif
+
+    // Set callbacks
+    RGFW_setEventCallback(RGFW_mouseEnter, RGFW_cb_mousenotifyfunc);
+    RGFW_setEventCallback(RGFW_mouseLeave, RGFW_cb_mousenotifyfunc);
+    // RGFW_setEventCallback(RGFW_windowClose, RGFW_cb_windowclosefunc); // do not close here. let raylib handle it
+    RGFW_setEventCallback(RGFW_dataDrop, RGFW_cb_dropfunc);
+    RGFW_setEventCallback(RGFW_windowResized, RGFW_cb_windowresizefunc);
+    RGFW_setEventCallback(RGFW_windowMaximized, RGFW_cb_windowmaximizefunc);
+    RGFW_setEventCallback(RGFW_windowMinimized, RGFW_cb_windowminimizefunc);
+    RGFW_setEventCallback(RGFW_windowRestored, RGFW_cb_windowrestorefunc);
+    RGFW_setEventCallback(RGFW_windowMoved, RGFW_cb_windowmovefunc);
+    RGFW_setEventCallback(RGFW_keyChar, RGFW_cb_keycharfunc);
+    RGFW_setEventCallback(RGFW_mouseScroll, RGFW_cb_scrollfunc);
+    RGFW_setEventCallback(RGFW_mouseButtonPressed, RGFW_cb_mousebuttonfunc);
+    RGFW_setEventCallback(RGFW_mouseButtonReleased, RGFW_cb_mousebuttonfunc);
+    RGFW_setEventCallback(RGFW_mouseRawMotion, RGFW_cb_mouserawmotionfunc);
+    RGFW_setEventCallback(RGFW_mouseMotion, RGFW_cb_mousemotionfunc);
+    RGFW_setEventCallback(RGFW_keyPressed, (RGFW_genericFunc)RGFW_cb_keyfunc);
+    RGFW_setEventCallback(RGFW_keyReleased, (RGFW_genericFunc)RGFW_cb_keyfunc);
+
+    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+        FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
+    TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
+    TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
+    TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
+    TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
+
+    // Load OpenGL extensions
+    // NOTE: GL procedures address loader is required to load extensions
+    //----------------------------------------------------------------------------
+    rlLoadExtensions((void *)RGFW_getProcAddress_OpenGL);
+    //----------------------------------------------------------------------------
+
+    // Initialize timing system
+    //----------------------------------------------------------------------------
+    InitTimer();
+    //----------------------------------------------------------------------------
+
+    // Initialize storage system
+    //----------------------------------------------------------------------------
+    #if defined(__APPLE__)
+        // mac defaults to the users home folder for some reason
+        // this is done to help them read relative paths to the binary
+        ChangeDirectory(GetApplicationDirectory());
+    #endif
+
+    CORE.Storage.basePath = GetWorkingDirectory();
+    //----------------------------------------------------------------------------
+
+#if defined(RGFW_WAYLAND)
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+    {
+        if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland, Software): Initialized successfully");
+        else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software (fallback)): Initialized successfully");
+    }
+    else
+    {
+        if (RGFW_usingWayland()) TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Wayland): Initialized successfully");
+        else TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11 (fallback)): Initialized successfully");
+    }
+#elif defined(RGFW_X11)
+    #if defined(__APPLE__)
+        if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+        {
+            TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software, (MacOS)): Initialized successfully");
+        }
+        else
+        {
+            TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, (MacOS)): Initialized successfully");
+        }
+    #else
+        if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+        {
+            TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11, Software): Initialized successfully");
+        }
+        else
+        {
+            TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - X11): Initialized successfully");
+        }
+    #endif
+#elif defined (RGFW_WINDOWS)
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32, Software): Initialized successfully");
+    }
+    else
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - Win32): Initialized successfully");
+    }
+#elif defined(RGFW_WASM)
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs, Software): Initialized successfully");
+    }
+    else
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - WASMs): Initialized successfully");
+    }
+#elif defined(RGFW_MACOS)
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE)
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS, Software): Initialized successfully");
+    }
+    else
+    {
+        TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (RGFW - MacOS): Initialized successfully");
+    }
+#endif
+
+    mg_gamepads_init(&platform.minigamepad);
+
+    return 0;
+}
+
+// Close platform
+void ClosePlatform(void)
+{
+    mg_gamepads_free(&platform.minigamepad);
+    RGFW_window_close(platform.window);
+
+    #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+        if (platform.surfacePixels != NULL)
+        {
+            RL_FREE(platform.surfacePixels);
+        }
+
+        if (platform.surface != NULL)
+        {
+            RGFW_surface_free(platform.surface);
+        }
+    #endif
+}
+
+// Keycode mapping
+static KeyboardKey ConvertScancodeToKey(u32 keycode)
+{
+    if (keycode > sizeof(RGFW_keyConvertTable)/sizeof(unsigned short)) return KEY_NULL;
+
+    return (KeyboardKey)RGFW_keyConvertTable[keycode];
+}
+
+// assign mouse to touches
+// 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
+void RemapMouseToTouch(int touchAction)
+{
+    #if SUPPORT_GESTURES_SYSTEM
+        if (touchAction < 0) return;
+
+        GestureEvent gestureEvent = { 0 };
+
+        // Register touch actions
+        gestureEvent.touchAction = touchAction;
+
+        // Assign a pointer ID
+        gestureEvent.pointId[0] = 0;
+
+        // Register touch points count
+        gestureEvent.pointCount = 1;
+
+        // Register touch points position, only one point registered
+        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
+        gestureEvent.position[0].x /= (float)GetScreenWidth();
+        gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+        // Gesture data is sent to gestures-system for processing
+        ProcessGestureEvent(gestureEvent);
+    #endif
+}
+
+// Helper functions for Time
+double GetTimeSeconds(void)
+{
+    double currentTime = 0.0;
+
+    #if defined(_WIN32)
+        static LARGE_INTEGER freq = { 0 };
+        static bool freqInitialized = false;
+        LARGE_INTEGER counter = { 0 };
+        if (!freqInitialized)
+        {
+            // Lazy initialization
+            QueryPerformanceFrequency(&freq);
+            freqInitialized = true;
+        }
+        QueryPerformanceCounter(&counter);
+        currentTime = (double)counter.QuadPart/(double)freq.QuadPart;
+    #elif defined(__EMSCRIPTEN__)
+        currentTime = emscripten_get_now()/1000.0;
+    #elif defined(__APPLE__)
+        static mach_timebase_info_data_t tb = { 0 };
+        static bool tbInitialized = false;
+        if (!tbInitialized)
+        {
+            mach_timebase_info(&tb);
+            tbInitialized = true;
+        }
+        uint64_t ticks = mach_absolute_time();
+
+        currentTime = (double)ticks*(double)tb.numer/(double)tb.denom/1e9;
+    #elif defined(__linux__)
+        struct timespec ts = { 0 };
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        currentTime = (double)ts.tv_sec + (double)ts.tv_nsec/1e9;
+    #else
+        // Fallback to cstd
+        currentTime = (double)clock()/(double)CLOCKS_PER_SEC;
+    #endif
+
+    return currentTime;
+}
diff --git a/raylib/src/platforms/rcore_desktop_sdl.c b/raylib/src/platforms/rcore_desktop_sdl.c
--- a/raylib/src/platforms/rcore_desktop_sdl.c
+++ b/raylib/src/platforms/rcore_desktop_sdl.c
@@ -49,18 +49,25 @@
     #define USING_SDL3_PROJECT
 #endif
 #ifndef SDL_ENABLE_OLD_NAMES
-    #define SDL_ENABLE_OLD_NAMES    // Just in case we're on SDL3, we need some in-between compatibily
+    #define SDL_ENABLE_OLD_NAMES    // In case on SDL3, some in-between compatibily is needed
 #endif
 // SDL base library (window/rendered, input, timing... functionality)
 #ifdef USING_SDL3_PROJECT
     #include "SDL3/SDL.h"
 #elif defined(USING_SDL2_PROJECT)
     #include "SDL2/SDL.h"
+
+    // WARNING: On Linux, this header includes Xlib.h, which defines Font
+    // To prevent a conflict with raylib's own Font type, we temporarily
+    // rename it to FontX11
+    #define Font FontX11
+    #include "SDL2/SDL_syswm.h"     // Required to get window handlers
+    #undef Font
 #else
     #include "SDL.h"
 #endif
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
   #if defined(GRAPHICS_API_OPENGL_ES2)
       // It seems it does not need to be included to work
       //#include "SDL_opengles2.h"
@@ -101,6 +108,13 @@
     SDL_GameController *gamepad[MAX_GAMEPADS];
     SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0
     SDL_Cursor *cursor;
+
+#if defined(__linux__)
+    // Local storage for the window handle (X11)
+    // NOTE: On SDL is not possible to know windowing backend at compile time, so,
+    // just in case, avoiding X11 specific types here
+    unsigned long windowHandleX11;          // Underlying type for: XID, Window
+#endif
 } PlatformData;
 
 //----------------------------------------------------------------------------------
@@ -250,14 +264,14 @@
     //SDL_SYSTEM_CURSOR_WAITARROW, // No equivalent implemented on MouseCursor enum on raylib.h
 };
 
-// SDL3 Migration Layer made to avoid 'ifdefs' inside functions when we can
+// SDL3 migration layer made to avoid 'ifdefs' inside functions
 #if defined(USING_VERSION_SDL3)
 
-// SDL3 Migration:
-//     SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
-//     and you can call SDL_GetWindowFullscreenMode()
-//     to see whether an exclusive fullscreen mode will be used
-//     or the borderless fullscreen desktop mode will be used
+// SDL3 migration:
+// SDL_WINDOW_FULLSCREEN_DESKTOP has been removed,
+// SDL_GetWindowFullscreenMode() can be called
+// to see whether an exclusive fullscreen mode will be used
+// or the borderless fullscreen desktop mode
 #define SDL_WINDOW_FULLSCREEN_DESKTOP SDL_WINDOW_FULLSCREEN
 
 #define SDL_IGNORE  false
@@ -265,10 +279,10 @@
 #define SDL_ENABLE  true
 
 // SDL3 Migration: SDL_INIT_TIMER - no longer needed before calling SDL_AddTimer()
-#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
+#define SDL_INIT_TIMER 0x0 // It's a flag, so no problem in setting it to zero to be used in a bitor (|)
 
 // SDL3 Migration: The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag
-#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero if we use in a bitor (|)
+#define SDL_WINDOW_SHOWN 0x0 // It's a flag, so no problem in setting it to zero to be used in a bitor (|)
 
 // SDL3 Migration: Renamed
 // IMPORTANT: Might need to call SDL_CleanupEvent somewhere see :https://github.com/libsdl-org/SDL/issues/3540#issuecomment-1793449852
@@ -323,7 +337,7 @@
     return stateBefore;
 }
 
-void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode)
+void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode *mode)
 {
     const SDL_DisplayMode *currentMode = SDL_GetCurrentDisplayMode(displayID);
 
@@ -340,9 +354,8 @@
 }
 
 // SDL3 Migration:
-//     SDL_GetDisplayDPI() -
-//     not reliable across platforms, approximately replaced by multiplying
-//     SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms
+// SDL_GetDisplayDPI() not reliable across platforms, approximately replaced by multiplying
+// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms
 // returns 0 on success or a negative error code on failure
 int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi)
 {
@@ -413,18 +426,18 @@
     return count;
 }
 
-#else // We're on SDL2
+#else // SDL2 fallback
 
-// Since SDL2 doesn't have this function we leave a stub
+// Since SDL2 doesn't have this function, leaving a stub
 // SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
 void *SDL_GetClipboardData(const char *mime_type, size_t *size)
 {
     TRACELOG(LOG_WARNING, "SDL: Getting clipboard data that is not text not available in SDL2");
 
-    // We could possibly implement it ourselves in this case for some easier platforms
+    // TODO: Implement getting clipboard data
+
     return NULL;
 }
-
 #endif // USING_VERSION_SDL3
 
 //----------------------------------------------------------------------------------
@@ -457,12 +470,11 @@
 void ToggleFullscreen(void)
 {
     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
-    const int monitorCount = SDL_GetNumVideoDisplays();
 
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
@@ -483,12 +495,11 @@
 void ToggleBorderlessWindowed(void)
 {
     const int monitor = SDL_GetWindowDisplayIndex(platform.window);
-    const int monitorCount = SDL_GetNumVideoDisplays();
 
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
@@ -540,12 +551,11 @@
     if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
     {
         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
-        const int monitorCount = SDL_GetNumVideoDisplays();
 
     #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
         if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
     #else
-        if ((monitor >= 0) && (monitor < monitorCount))
+        if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
     #endif
         {
             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
@@ -575,8 +585,6 @@
     }
     if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
     {
-        // NOTE: To be able to implement this part it seems that we should
-        // do it ourselves, via 'windows.h', 'X11/Xlib.h' or even 'Cocoa.h'
         TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
     }
     if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
@@ -604,12 +612,11 @@
     if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
     {
         const int monitor = SDL_GetWindowDisplayIndex(platform.window);
-        const int monitorCount = SDL_GetNumVideoDisplays();
 
     #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
         if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
     #else
-        if ((monitor >= 0) && (monitor < monitorCount))
+        if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
     #endif
         {
             SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
@@ -826,17 +833,15 @@
 // Set monitor for the current window
 void SetWindowMonitor(int monitor)
 {
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
-        // NOTE:
-        // 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
-        //    see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
-        // 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
+        // NOTE 1: SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
+        // see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
+        // NOTE 2: A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
         const bool wasFullscreen = (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))? true : false;
 
         const int screenWidth = CORE.Window.screen.width;
@@ -854,14 +859,13 @@
             // If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it
             if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
             {
-                // NOTE:
-                // 1. There's a known issue where if the window larger than the target display bounds,
-                //    when moving the windows to that display, the window could be clipped back
-                //    ending up positioned partly outside the target display
-                // 2. The workaround for that is, previously to moving the window,
-                //    setting the window size to the target display size, so they match
-                // 3. It wasn't done here because we can't assume changing the window size automatically
-                //    is acceptable behavior by the user
+                // NOTE 1: There's a known issue where if the window larger than the target display bounds,
+                // when moving the windows to that display, the window could be clipped back
+                // 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 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;
                 CORE.Window.position.y = usableBounds.y;
@@ -925,40 +929,82 @@
 }
 
 // Get native window handle
+// NOTE: Handle type depends on OS and windowing system
 void *GetWindowHandle(void)
 {
-    return (void *)platform.window;
+    void *handle = NULL;
+
+#if defined(USING_SDL3_PROJECT)
+    // REF: https://github.com/libsdl-org/SDL/blob/main/include/SDL3/SDL_video.h#L1590
+    SDL_PropertiesID props = SDL_GetWindowProperties(platform.window);
+    #if defined(_WIN32)
+    handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); // Type: HWND
+    #elif defined(__linux__)
+    unsigned long windowId = (unsigned long)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); // Type: unsigned long (XID, Window)
+    if (windowId != 0)
+    {
+        // X11 window ID
+        platform.windowHandleX11 = windowId;
+        handle = &platform.windowHandleX11;
+    }
+    else
+    {
+        // Wayland, get display surface pointer
+        // NOTE: Alternative SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER
+        handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL); // Type: struct wl_surface*
+    }
+    #elif defined(__APPLE__)
+    handle = (void *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); // Type: NSWindow*
+    #endif
+#elif defined(USING_SDL2_PROJECT)
+    SDL_SysWMinfo wmInfo = { 0 };
+    SDL_VERSION(&wmInfo.version);
+    if (SDL_GetWindowWMInfo(platform.window, &wmInfo))
+    {
+    #if defined(_WIN32)
+        handle = (void *)wmInfo.info.win.window; // Type: HWND
+    #elif defined(__linux__)
+        if (wmInfo.subsystem == SDL_SYSWM_X11)
+        {
+            // X11, get window ID (unsigned long)
+            platform.windowHandleX11 = (unsigned long)wmInfo.info.x11.window;
+            handle = &platform.windowHandleX11;
+        }
+        else if (wmInfo.subsystem == SDL_SYSWM_WAYLAND)
+        {
+            // Wayland, get display surface pointer
+            // NOTE: Alternative: wmInfo.info.wl.display
+            handle = (void *)wmInfo.info.wl.surface; // Type: struct wl_surface*
+        }
+    #elif defined(__APPLE__)
+        handle = (void *)wmInfo.info.cocoa.window; // Type: NSWindow*
+    #endif
+    }
+#endif
+
+    return handle;
 }
 
 // Get number of monitors
 int GetMonitorCount(void)
 {
-    int monitorCount = 0;
-
-    monitorCount = SDL_GetNumVideoDisplays();
-
-    return monitorCount;
+    return SDL_GetNumVideoDisplays();
 }
 
 // Get current monitor where window is placed
 int GetCurrentMonitor(void)
 {
-    int currentMonitor = 0;
-
     // Be aware that this returns an ID in SDL3 and a Index in SDL2
-    currentMonitor = SDL_GetWindowDisplayIndex(platform.window);
-
-    return currentMonitor;
+    return SDL_GetWindowDisplayIndex(platform.window);
 }
 
 // Get selected monitor position
 Vector2 GetMonitorPosition(int monitor)
 {
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         SDL_Rect displayBounds;
@@ -982,11 +1028,10 @@
 {
     int width = 0;
 
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         SDL_DisplayMode mode;
@@ -1003,11 +1048,10 @@
 {
     int height = 0;
 
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         SDL_DisplayMode mode;
@@ -1024,11 +1068,10 @@
 {
     int width = 0;
 
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         float ddpi = 0.0f;
@@ -1048,11 +1091,10 @@
 {
     int height = 0;
 
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         float ddpi = 0.0f;
@@ -1072,11 +1114,10 @@
 {
     int refresh = 0;
 
-    const int monitorCount = SDL_GetNumVideoDisplays();
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         SDL_DisplayMode mode;
@@ -1091,12 +1132,10 @@
 // Get the human-readable, UTF-8 encoded name of the selected monitor
 const char *GetMonitorName(int monitor)
 {
-    const int monitorCount = SDL_GetNumVideoDisplays();
-
 #if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
     if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
 #else
-    if ((monitor >= 0) && (monitor < monitorCount))
+    if ((monitor >= 0) && (monitor < SDL_GetNumVideoDisplays()))
 #endif
     {
         return SDL_GetDisplayName(monitor);
@@ -1149,7 +1188,7 @@
 
     char *clipboard = SDL_GetClipboardText();
 
-    int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
+    int clipboardSize = snprintf(buffer, MAX_CLIPBOARD_BUFFER_LENGTH, "%s", clipboard);
     if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
     {
         char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
@@ -1166,7 +1205,22 @@
 {
     Image image = { 0 };
 
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
+#if SUPPORT_CLIPBOARD_IMAGE
+#if !SUPPORT_MODULE_RTEXTURES
+    TRACELOG(LOG_WARNING, "Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
+    return image;
+#endif
+
+// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
+#if !SUPPORT_FILEFORMAT_BMP && defined(_WIN32)
+    TRACELOG(LOG_WARNING, "WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows");
+    return image;
+#endif
+
+// From what I've tested applications on Wayland saves images on clipboard as PNG
+#if (!SUPPORT_FILEFORMAT_PNG || !SUPPORT_FILEFORMAT_JPG) && !defined(_WIN32)
+    TRACELOG(LOG_WARNING, "WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG");
+#endif
     // Let's hope compiler put these arrays in static memory
     const char *imageFormats[] = {
         "image/bmp",
@@ -1186,12 +1240,14 @@
 
     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]);
@@ -1201,7 +1257,7 @@
     }
 
     if (!IsImageValid(image)) TRACELOG(LOG_WARNING, "Clipboard: Couldn't get clipboard data. ERROR: %s", SDL_GetError());
-#endif
+#endif // SUPPORT_CLIPBOARD_IMAGE
 
     return image;
 }
@@ -1217,7 +1273,7 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
 #if defined(USING_VERSION_SDL3)
@@ -1228,7 +1284,7 @@
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     SDL_SetRelativeMouseMode(SDL_FALSE);
@@ -1237,7 +1293,7 @@
     CORE.Input.Mouse.cursorLocked = false;
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     SDL_SetRelativeMouseMode(SDL_TRUE);
@@ -1249,8 +1305,8 @@
 // Swap back buffer with front buffer (screen drawing)
 void SwapScreenBuffer(void)
 {
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
-    // NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    // NOTE: Using a preprocessor condition here because rlCopyFramebuffer() is only declared for software rendering
     SDL_Surface *surface = SDL_GetWindowSurface(platform.window);
     rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels);
     SDL_UpdateWindowSurface(platform.window);
@@ -1266,20 +1322,28 @@
 // Get elapsed time measure in seconds
 double GetTime(void)
 {
-    unsigned int ms = SDL_GetTicks();    // Elapsed time in milliseconds since SDL_Init()
-    double time = (double)ms/1000;
+    double time = ((double)SDL_GetPerformanceCounter()/(double)SDL_GetPerformanceFrequency()) - CORE.Time.base;
+
     return time;
 }
 
 // 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");
+    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(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");
+    }
     else SDL_OpenURL(url);
 }
 
@@ -1290,7 +1354,25 @@
 // Set internal gamepad mappings
 int SetGamepadMappings(const char *mappings)
 {
-    return SDL_GameControllerAddMapping(mappings);
+    const int mappingsLength = strlen(mappings);
+    char *buffer = (char *)RL_CALLOC(mappingsLength + 1, sizeof(char));
+    memcpy(buffer, mappings, mappingsLength);
+    char *p = strtok(buffer, "\n");
+    bool succeed = true;
+
+    while (p != NULL)
+    {
+        if (SDL_GameControllerAddMapping(p) == -1)
+        {
+            succeed = false;
+        }
+        p = strtok(NULL, "\n");
+    }
+
+    RL_FREE(buffer);
+
+    // To make return value is consistent with the GLFW version.
+    return (succeed)? 1 : 0;
 }
 
 // Set gamepad vibration
@@ -1314,7 +1396,6 @@
     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
@@ -1335,9 +1416,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -1413,8 +1494,8 @@
             {
                 if (CORE.Window.dropFileCount == 0)
                 {
-                    // When a new file is dropped, we reserve a fixed number of slots for all possible dropped files
-                    // at the moment we limit the number of drops at once to 1024 files but this behaviour should probably be reviewed
+                    // When a new file is dropped, reserve a fixed number of slots for all possible dropped files
+                    // at the moment limit the number of drops at once to 1024 files but this behaviour should probably be reviewed
                     // TODO: Pointers should probably be reallocated for any new file added...
                     CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
 
@@ -1422,12 +1503,12 @@
 
                 #if defined(USING_VERSION_SDL3)
                     // const char *data;   // The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events
-                    // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE,
-                    // and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
-                    // you should make a copy of it. 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);
+                    // 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
+                    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
 
@@ -1438,9 +1519,9 @@
                     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
 
@@ -1453,10 +1534,10 @@
             // Window events are also polled (minimized, maximized, close...)
 
             #ifndef USING_VERSION_SDL3
-            // SDL3 states:
             // The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
-            // In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
-            // and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event
+            // In general, handling this change means checking for the individual events instead of first checking for SDL_WINDOWEVENT
+            // and then checking for window events; Events >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST can be compared
+            // to see whether it's a window event
             case SDL_WINDOWEVENT:
             {
                 switch (event.window.event)
@@ -1468,7 +1549,8 @@
                         const int width = event.window.data1;
                         const int height = event.window.data2;
                         SetupViewport(width, height);
-                        // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
+
+                        // Consider content scaling if required
                         if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
                         {
                             CORE.Window.screen.width = (int)(width/GetWindowScaleDPI().x);
@@ -1499,6 +1581,10 @@
                             if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
                         }
                         #endif
+
+                        #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+                        swResize(width, height);
+                        #endif
                     } break;
 
                     case SDL_WINDOWEVENT_ENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
@@ -1551,7 +1637,7 @@
             } break;
             #endif
 
-            // Keyboard events
+            // Check keyboard events
             case SDL_KEYDOWN:
             {
             #if defined(USING_VERSION_SDL3)
@@ -1579,10 +1665,8 @@
                 if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
 
             } break;
-
             case SDL_KEYUP:
             {
-
             #if defined(USING_VERSION_SDL3)
                 KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
             #else
@@ -1590,16 +1674,14 @@
             #endif
                 if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
             } break;
-
             case SDL_TEXTINPUT:
             {
-                // NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
+                // NOTE: event.text.text data comes an UTF-8 text sequence but register codepoints (int)
 
                 // Check if there is space available in the queue
                 if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
                 {
                     // Add character (codepoint) to the queue
-
                 #if defined(USING_VERSION_SDL3)
                     size_t textLen = strlen(event.text.text);
                     unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen);
@@ -1617,7 +1699,7 @@
             case SDL_MOUSEBUTTONDOWN:
             {
                 // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW
-                //       The following conditions align SDL with raylib.h MouseButton enum order
+                // The following conditions align SDL with raylib.h MouseButton enum order
                 int btn = event.button.button - 1;
                 if (btn == 2) btn = 1;
                 else if (btn == 1) btn = 2;
@@ -1630,7 +1712,7 @@
             case SDL_MOUSEBUTTONUP:
             {
                 // NOTE: SDL2 mouse button order is LEFT, MIDDLE, RIGHT, but raylib uses LEFT, RIGHT, MIDDLE like GLFW
-                //       The following conditions align SDL with raylib.h MouseButton enum order
+                // The following conditions align SDL with raylib.h MouseButton enum order
                 int btn = event.button.button - 1;
                 if (btn == 2) btn = 1;
                 else if (btn == 1) btn = 2;
@@ -1642,8 +1724,13 @@
             } break;
             case SDL_MOUSEWHEEL:
             {
-                CORE.Input.Mouse.currentWheelMove.x = (float)event.wheel.x;
-                CORE.Input.Mouse.currentWheelMove.y = (float)event.wheel.y;
+#if defined(USING_VERSION_SDL3)
+                CORE.Input.Mouse.currentWheelMove.x = event.wheel.x;
+                CORE.Input.Mouse.currentWheelMove.y = event.wheel.y;
+#else
+                CORE.Input.Mouse.currentWheelMove.x = event.wheel.preciseX;
+                CORE.Input.Mouse.currentWheelMove.y = event.wheel.preciseY;
+#endif
             } break;
             case SDL_MOUSEMOTION:
             {
@@ -1663,6 +1750,7 @@
                 touchAction = 2;
             } break;
 
+            // Check Touch events
             case SDL_FINGERDOWN:
             {
                 UpdateTouchPointsSDL(event.tfinger);
@@ -1682,24 +1770,21 @@
                 realTouch = true;
             } break;
 
-            // Check gamepad events
+            // Check Gamepad events
             case SDL_JOYDEVICEADDED:
             {
                 int jid = event.jdevice.which; // Joystick device index
 
-                // check if already added at InitPlatform
+                // Check if already added at InitPlatform
                 for (int i = 0; i < MAX_GAMEPADS; i++)
                 {
-                    if (jid == platform.gamepadId[i])
-                    {
-                        return;
-                    }
+                    if (jid == platform.gamepadId[i]) return;
                 }
 
                 int nextAvailableSlot = 0;
                 while (nextAvailableSlot < MAX_GAMEPADS && CORE.Input.Gamepad.ready[nextAvailableSlot])
                 {
-                    ++nextAvailableSlot;
+                    nextAvailableSlot++;
                 }
 
                 if ((nextAvailableSlot < MAX_GAMEPADS) && !CORE.Input.Gamepad.ready[nextAvailableSlot])
@@ -1715,8 +1800,8 @@
                         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());
                 }
@@ -1856,7 +1941,7 @@
                     {
                         if (platform.gamepadId[i] == event.jaxis.which)
                         {
-                            // SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range
+                            // SDL axis value range is -32768 to 32767, normalizing it to raylib's -1.0 to 1.0f range
                             float value = event.jaxis.value/(float)32767;
                             CORE.Input.Gamepad.axisState[i][axis] = value;
 
@@ -1877,7 +1962,7 @@
             default: break;
         }
 
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
         if (touchAction > -1)
         {
             // Process mouse events as touches to be able to use mouse-gestures
@@ -1952,7 +2037,7 @@
 
     // NOTE: Some OpenGL context attributes must be set before window creation
 
-    if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
+    if (rlGetVersion() != RL_OPENGL_SOFTWARE)
     {
         // Add the flag telling the window to use an OpenGL context
         flags |= SDL_WINDOW_OPENGL;
@@ -1974,7 +2059,7 @@
             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-    #if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
+    #if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
             SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);   // Enable OpenGL Debug Context
     #endif
         }
@@ -2001,17 +2086,26 @@
     // Init window
 #if defined(USING_VERSION_SDL3)
     platform.window = SDL_CreateWindow(CORE.Window.title, CORE.Window.screen.width, CORE.Window.screen.height, flags);
+
+
+    // NOTE: SDL3 no longer enables text input by default,
+    // it is needed to be enabled manually to keep GetCharPressed() working
+    // REF: https://github.com/libsdl-org/SDL/commit/72fc6f86e5d605a3787222bc7dc18c5379047f4a
+    const char *enableOSK = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD);
+    if (enableOSK == NULL) SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "0");
+    if (!SDL_StartTextInput(platform.window)) TRACELOG(LOG_WARNING, "SDL: Failed to start text input: %s", SDL_GetError());
+    if (enableOSK == NULL) SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, NULL);
 #else
     platform.window = SDL_CreateWindow(CORE.Window.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, CORE.Window.screen.width, CORE.Window.screen.height, flags);
 #endif
 
     // Init OpenGL context
-    if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
+    if (rlGetVersion() != RL_OPENGL_SOFTWARE)
     {
         platform.glContext = SDL_GL_CreateContext(platform.window);
     }
 
-    if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_11_SOFTWARE) || (platform.glContext != NULL)))
+    if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_SOFTWARE) || (platform.glContext != NULL)))
     {
         CORE.Window.ready = true;
 
@@ -2026,7 +2120,8 @@
         CORE.Window.currentFbo.width = CORE.Window.render.width;
         CORE.Window.currentFbo.height = CORE.Window.render.height;
 
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+            FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
@@ -2057,11 +2152,20 @@
         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])
@@ -2070,7 +2174,12 @@
             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
+            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());
@@ -2086,12 +2195,14 @@
 
     // Initialize timing system
     //----------------------------------------------------------------------------
-    // NOTE: No need to call InitTimer(), let SDL manage it internally
-    CORE.Time.previous = GetTime();     // Get time as double
+    // Get base time from window initialization
+    CORE.Time.base = (double)SDL_GetPerformanceCounter()/(double)SDL_GetPerformanceFrequency();
 
-    #if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
+    #if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP
     SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod()
     #endif
+
+    // NOTE: No need to call InitTimer(), let SDL manage it internally
     //----------------------------------------------------------------------------
 
     // Initialize storage system
@@ -2126,7 +2237,7 @@
         return mapScancodeToKey[sdlScancode];
     }
 
-    return KEY_NULL; // No equivalent key in Raylib
+    return KEY_NULL; // No equivalent key in raylib
 }
 
 // Get next codepoint in a byte sequence and bytes processed
diff --git a/raylib/src/platforms/rcore_desktop_win32.c b/raylib/src/platforms/rcore_desktop_win32.c
--- a/raylib/src/platforms/rcore_desktop_win32.c
+++ b/raylib/src/platforms/rcore_desktop_win32.c
@@ -71,7 +71,7 @@
 
 #include <malloc.h>          // Required for alloca()
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     #include <GL/gl.h>
 #endif
 
@@ -141,7 +141,7 @@
 #define STYLE_MASK_READONLY     (WS_MINIMIZE | WS_MAXIMIZE)
 #define STYLE_MASK_WRITABLE     (~STYLE_MASK_READONLY)
 
-#define STYLE_FLAGS_RESIZABLE   WS_THICKFRAME
+#define STYLE_FLAGS_RESIZABLE   (WS_THICKFRAME | WS_MAXIMIZEBOX)
 
 #define STYLE_FLAGS_UNDECORATED_OFF     (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
 #define STYLE_FLAGS_UNDECORATED_ON      WS_POPUP
@@ -156,8 +156,6 @@
 // Flags that have no operations to perform during an update
 #define FLAG_MASK_NO_UPDATE     (FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT)
 
-#define WM_APP_UPDATE_WINDOW_SIZE (WM_APP + 1)
-
 #define WGL_DRAW_TO_WINDOW_ARB              0x2001
 #define WGL_ACCELERATION_ARB                0x2003
 #define WGL_SUPPORT_OPENGL_ARB              0x2010
@@ -270,8 +268,8 @@
 
     // Minimized takes precedence over maximized
     int mized = MIZED_NONE;
-    if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
-    if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
+    if (flags & FLAG_WINDOW_MINIMIZED) mized = MIZED_MIN;
+    else if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
 
     switch (mized)
     {
@@ -426,14 +424,12 @@
     else swpFlags |= SWP_NOMOVE;
 
     // WARNING: This code must be called after swInit() has been called, after InitPlatform() in [rcore]
-    //RECT rc = {0, 0, desired.cx, desired.cy};
-    //AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0);
-    //SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
+    SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, SWP_NOMOVE | SWP_NOZORDER);
 
     return true;
 }
 
-// Verify if we are running in Windows 10 version 1703 (Creators Update)
+// Check if running in Windows 10 version 1703 (Creators Update)
 static BOOL IsWindows10Version1703OrGreaterWin32(void)
 {
     HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
@@ -570,100 +566,100 @@
         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;
     }
 }
@@ -976,25 +972,40 @@
 // Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
 void SetWindowMinSize(int width, int height)
 {
-    TRACELOG(LOG_WARNING, "SetWindowMinSize not implemented");
+    if ((width > CORE.Window.screenMax.width) || (height > CORE.Window.screenMax.height))
+    {
+        TRACELOG(LOG_WARNING, "WIN32: WINDOW: Cannot set minimum screen size higher than the maximum");
+        return;
+    }
 
     CORE.Window.screenMin.width = width;
     CORE.Window.screenMin.height = height;
+
+    SetWindowSize(platform.appScreenWidth, platform.appScreenHeight);
 }
 
 // Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
 void SetWindowMaxSize(int width, int height)
 {
-    TRACELOG(LOG_WARNING, "SetWindowMaxSize not implemented");
+    if ((width < CORE.Window.screenMin.width) || (height < CORE.Window.screenMin.height))
+    {
+        TRACELOG(LOG_WARNING, "WIN32: WINDOW: Cannot set maximum screen size lower than the minimum");
+        return;
+    }
 
     CORE.Window.screenMax.width = width;
     CORE.Window.screenMax.height = height;
+
+    SetWindowSize(platform.appScreenWidth, platform.appScreenHeight);
 }
 
 // Set window dimensions
 void SetWindowSize(int width, int height)
 {
-    TRACELOG(LOG_WARNING, "SetWindowSize not implemented");
+    int screenWidth = fmaxf(CORE.Window.screenMin.width, fminf(CORE.Window.screenMax.width, width));
+    int screenHeight = fmaxf(CORE.Window.screenMin.height, fminf(CORE.Window.screenMax.height, height));
+
+    UpdateWindowSize(1, platform.hwnd, screenWidth, screenHeight, platform.desiredFlags);
 }
 
 // Set window opacity, value opacity is between 0.0 and 1.0
@@ -1012,7 +1023,7 @@
 // Get native window handle
 void *GetWindowHandle(void)
 {
-    return platform.hwnd;
+    return (void *)platform.hwnd;
 }
 
 int GetMonitorCount(void)
@@ -1052,14 +1063,14 @@
 // Get selected monitor width (currently used by monitor)
 int GetMonitorWidth(int monitor)
 {
-    TRACELOG(LOG_WARNING, "GetMonitorWidth not implemented");
+    //TRACELOG(LOG_WARNING, "GetMonitorWidth not implemented");
     return 0;
 }
 
 // Get selected monitor height (currently used by monitor)
 int GetMonitorHeight(int monitor)
 {
-    TRACELOG(LOG_WARNING, "GetMonitorHeight not implemented");
+    //TRACELOG(LOG_WARNING, "GetMonitorHeight not implemented");
     return 0;
 }
 
@@ -1094,7 +1105,7 @@
 // Get window position XY on monitor
 Vector2 GetWindowPosition(void)
 {
-    TRACELOG(LOG_WARNING, "GetWindowPosition not implemented");
+    //TRACELOG(LOG_WARNING, "GetWindowPosition not implemented");
     return (Vector2){ 0, 0 };
 }
 
@@ -1118,13 +1129,38 @@
     return NULL;
 }
 
+#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
+    #define WIN32_CLIPBOARD_IMPLEMENTATION
+    #define WINUSER_ALREADY_INCLUDED
+    #define WINBASE_ALREADY_INCLUDED
+    #define WINGDI_ALREADY_INCLUDED
+    #include "../external/win32_clipboard.h"
+#endif
+
 // Get clipboard image
 Image GetClipboardImage(void)
 {
     Image image = { 0 };
 
-    TRACELOG(LOG_WARNING, "GetClipboardText not implemented");
+#if SUPPORT_CLIPBOARD_IMAGE && SUPPORT_MODULE_RTEXTURES
+    unsigned int dataSize = 0;
+    void *fileData = NULL;
+    int width = 0;
+    int height = 0;
 
+    fileData = (void *)Win32GetClipboardImageData(&width, &height, &dataSize);
+
+    if (fileData == NULL) TRACELOG(LOG_WARNING, "Clipboard image: Couldn't get clipboard data.");
+    else
+    {
+        image = LoadImageFromMemory(".bmp", (const unsigned char*)fileData, (int)dataSize);
+
+        RL_FREE(fileData);
+    }
+#else
+    TRACELOG(LOG_WARNING, "Clipboard image: SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly");
+#endif // SUPPORT_CLIPBOARD_IMAGE
+
     return image;
 }
 
@@ -1135,16 +1171,16 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
-    // NOTE: We use SetCursor() instead of ShowCursor() because
+    // NOTE: Using SetCursor() instead of ShowCursor() because
     // it makes it easy to only hide the cursor while it's inside the client area
     SetCursor(NULL);
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     if (CORE.Input.Mouse.cursorLocked)
@@ -1207,7 +1243,7 @@
 {
     if (!platform.hdc) abort();
 
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Update framebuffer
     rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
 
@@ -1227,24 +1263,37 @@
 // Get elapsed time measure in seconds
 double GetTime(void)
 {
-    LARGE_INTEGER now = 0;
+    double time = 0.0;
+    LARGE_INTEGER now = { 0 };
     QueryPerformanceCounter(&now);
-    return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
+    time = (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
+
+    return time;
 }
 
 // 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(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");
+    }
     else
     {
-        char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
-        sprintf(cmd, "explorer \"%s\"", url);
+        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);
@@ -1275,8 +1324,8 @@
     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");
 }
@@ -1345,7 +1394,7 @@
 //----------------------------------------------------------------------------------
 
 // Initialize modern OpenGL context
-// NOTE: We need to create a dummy context first to query required extensions
+// NOTE: Creating a dummy context first to query required extensions
 HGLRC InitOpenGL(HWND hwnd, HDC hdc)
 {
     // First, create a dummy context to get WGL extensions
@@ -1460,7 +1509,7 @@
             0 // Terminator
         };
 
-        // NOTE: We are not sharing context resources so, second parameters is NULL
+        // NOTE: Not sharing context resources so, second parameters is NULL
         realContext = wglCreateContextAttribsARB(hdc, NULL, contextAttribs);
 
         // Check for error context creation errors
@@ -1476,8 +1525,8 @@
     // Activate real context
     if (realContext) wglMakeCurrent(hdc, realContext);
 
-    // Once we got a real modern OpenGL context,
-    // we can load required extensions (function pointers)
+    // Once a real modern OpenGL context is created,
+    // required extensions can be loaded (function pointers)
     rlLoadExtensions(WglGetProcAddress);
 
     return realContext;
@@ -1494,7 +1543,8 @@
 
     // NOTE: From this point CORE.Window.flags should always reflect the actual state of the window
     CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE);
-
+    CORE.Window.screenMax.width = 9999;
+    CORE.Window.screenMax.height = 9999;
 /*
     // TODO: Review SetProcessDpiAwarenessContext()
     // NOTE: SetProcessDpiAwarenessContext() requires Windows 10, version 1703 and shcore.lib linkage
@@ -1511,7 +1561,6 @@
         if (hr < 0) TRACELOG(LOG_ERROR, "%s failed, hresult=0x%lx", "SetProcessDpiAwareness", (DWORD)hr);
     }
 */
-
     HINSTANCE hInstance = GetModuleHandleW(0);
 
     // Define window class
@@ -1521,7 +1570,7 @@
         .lpfnWndProc = WndProc,                         // Custom procedure assigned
         .cbWndExtra = sizeof(LONG_PTR),                 // extra space for the Tuple object ptr
         .hInstance = hInstance,
-        .hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Audit if we want to set this since we're implementing WM_SETCURSOR
+        .hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Check if this is really required, since WM_SETCURSOR event is processed
         .lpszClassName = CLASS_NAME                     // Class name: L"raylibWindow"
     };
 
@@ -1588,10 +1637,8 @@
     // NOTE: Windows GDI object that represents a drawing surface
     platform.hdc = GetDC(platform.hwnd);
 
-    if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer
     {
-        //ShowWindow(platform.hwnd, SW_SHOWDEFAULT); //SW_SHOWNORMAL
-
         // Initialize software framebuffer
         BITMAPINFO bmi = { 0 };
         ZeroMemory(&bmi, sizeof(bmi));
@@ -1620,6 +1667,9 @@
 
     CORE.Window.ready = true;
 
+    // Activate window to set focus and show taskbar icon
+    ShowWindow(platform.hwnd, SW_SHOWDEFAULT);
+
     // Update flags (in case of deferred state change required)
     UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
 
@@ -1627,22 +1677,23 @@
     CORE.Window.render.height = CORE.Window.screen.height;
     CORE.Window.currentFbo.width = CORE.Window.render.width;
     CORE.Window.currentFbo.height = CORE.Window.render.height;
-    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+        FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
     TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
     TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
     TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
     TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
 
-    if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer
     {
         TRACELOG(LOG_INFO, "GL: OpenGL device information:");
-        TRACELOG(LOG_INFO, "    > Vendor:   %s", "raylib");
-        TRACELOG(LOG_INFO, "    > Renderer: %s", "rlsw - OpenGL 1.1 Software Renderer");
-        TRACELOG(LOG_INFO, "    > Version:  %s", "1.0");
+        TRACELOG(LOG_INFO, "    > Vendor:   %s", glGetString(GL_VENDOR));
+        TRACELOG(LOG_INFO, "    > Renderer: %s", glGetString(GL_RENDERER));
+        TRACELOG(LOG_INFO, "    > Version:  %s", glGetString(GL_VERSION));
         TRACELOG(LOG_INFO, "    > GLSL:     %s", "NOT SUPPORTED");
     }
 
-    // Initialize timming system
+    // Initialize timing system
     //----------------------------------------------------------------------------
     LARGE_INTEGER time = { 0 };
     QueryPerformanceCounter(&time);
@@ -1703,7 +1754,7 @@
         case WM_DESTROY:
         {
             // Clean up for window destruction
-            if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+            if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer
             {
                 if (platform.hdcmem)
                 {
@@ -1744,16 +1795,47 @@
             memset(CORE.Input.Keyboard.previousKeyState, 0, sizeof(CORE.Input.Keyboard.previousKeyState));
             memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState));
         } break;
-        case WM_SIZING:
+        case WM_SIZING: // Sent to a window that the user is resizing
         {
             if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
             {
-                // TODO: Enforce min/max size
+                //HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
             }
-            else TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window");
 
             result = TRUE;
         } break;
+        case WM_SIZE:
+        {
+            // WARNING: Don't trust the docs, they say this message can not be obtained if not calling DefWindowProc()
+            // in response to WM_WINDOWPOSCHANGED but looks like when a window is created,
+            // this message can be obtained without getting WM_WINDOWPOSCHANGED
+
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+            // WARNING: Waiting two frames before resizing because software-renderer backend is initilized with swInit() later
+            // than InitPlatform(), that triggers WM_SIZE, so avoid crashing
+            if (CORE.Time.frameCounter > 2) HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
+#else
+            // NOTE: This message is only triggered on window creation
+            HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
+#endif
+            result = 0; // If an application processes WM_SIZE message, it should return zero
+        } break;
+        case WM_GETMINMAXINFO:
+        {
+            DWORD style = MakeWindowStyle(platform.desiredFlags);
+            SIZE maxClientSize = { CORE.Window.screenMax.width, CORE.Window.screenMax.height };
+            SIZE maxWindowSize = CalcWindowSize(96, maxClientSize, style);
+            SIZE minClientSize = { CORE.Window.screenMin.width, CORE.Window.screenMin.height };
+            SIZE minWindowSize = CalcWindowSize(96, minClientSize, style);
+
+            LPMINMAXINFO lpmmi = (LPMINMAXINFO) lparam;
+            lpmmi->ptMaxSize.x = maxWindowSize.cx;
+            lpmmi->ptMaxSize.y = maxWindowSize.cy;
+            lpmmi->ptMaxTrackSize.x = maxWindowSize.cx;
+            lpmmi->ptMaxTrackSize.y = maxWindowSize.cy;
+            lpmmi->ptMinTrackSize.x = minWindowSize.cx;
+            lpmmi->ptMinTrackSize.y = minWindowSize.cy;
+        } break;
         case WM_STYLECHANGING:
         {
             if (wparam == GWL_STYLE)
@@ -1777,7 +1859,7 @@
                     {
                         // looks like windows will automatically "unminimize" a window
                         // if a style changes modifies it's size
-                        TRACELOG(LOG_INFO, "WIN32: WINDOW: Style change modifed window size, removing maximized flag");
+                        TRACELOG(LOG_INFO, "WIN32: WINDOW: Style change modified window size, removing maximized flag");
                         deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED;
                     }
                 }
@@ -1836,26 +1918,21 @@
                 default: break;
             }
         } break;
-        case WM_SIZE:
-        {
-            // WARNING: Don't trust the docs, they say you won't get this message if you don't call DefWindowProc
-            // in response to WM_WINDOWPOSCHANGED but looks like when a window is created you'll get this
-            // message without getting WM_WINDOWPOSCHANGED
-            HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
-        } break;
-        //case WM_MOVE
+        //case WM_MOVE: break;
         case WM_WINDOWPOSCHANGED:
         {
             WINDOWPOS *pos = (WINDOWPOS*)lparam;
             if (!(pos->flags & SWP_NOSIZE)) HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight);
+
+            DefWindowProc(hwnd, msg, wparam, lparam);
         } break;
         case WM_GETDPISCALEDSIZE:
         {
             SIZE *inoutSize = (SIZE *)lparam;
             UINT newDpi = (UINT)wparam; // TODO: WARNING: Converting from WPARAM = UINT_PTR
 
-            // for any of these other cases, we might want to post a window
-            // resize event after the dpi changes?
+            // For the following flag changes, a window resize event should be posted,
+            // TODO: Should it be done after dpi changes?
             if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return TRUE;
             if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) return TRUE;
             if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) return TRUE;
@@ -1875,8 +1952,8 @@
         case WM_DPICHANGED:
         {
             // Get current dpi scale factor
-            float scalex = HIWORD(wParam)/96.0f;
-            float scaley = LOWORD(wParam)/96.0f;
+            float scalex = HIWORD(wparam)/96.0f;
+            float scaley = LOWORD(wparam)/96.0f;
 
             RECT *suggestedRect = (RECT *)lparam;
 
@@ -1906,7 +1983,7 @@
         } break;
         case WM_PAINT:
         {
-            if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+            if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer
             {
                 PAINTSTRUCT ps = { 0 };
                 HDC hdc = BeginPaint(hwnd, &ps);
@@ -1916,6 +1993,7 @@
 
                 EndPaint(hwnd, &ps);
             }
+            else DefWindowProc(hwnd, msg, wparam, lparam);
         }
         case WM_INPUT:
         {
@@ -1958,10 +2036,6 @@
         } break;
         case WM_MOUSEWHEEL: CORE.Input.Mouse.currentWheelMove.y = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break;
         case WM_MOUSEHWHEEL: CORE.Input.Mouse.currentWheelMove.x = ((float)GET_WHEEL_DELTA_WPARAM(wparam))/WHEEL_DELTA; break;
-        case WM_APP_UPDATE_WINDOW_SIZE:
-        {
-            //UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, platform.appScreenWidth, platform.appScreenHeight, CORE.Window.flags);
-        } break;
 
         default: result = DefWindowProcW(hwnd, msg, wparam, lparam); // Message passed directly for execution (default behaviour)
     }
@@ -1994,7 +2068,7 @@
     {
         CORE.Input.Keyboard.currentKeyState[key] = state;
 
-        if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = true;
+        if ((key == CORE.Input.Keyboard.exitKey) && (state == 1)) CORE.Window.shouldClose = true;
     }
     else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam);
 
@@ -2013,8 +2087,11 @@
 static void HandleRawInput(LPARAM lparam)
 {
     RAWINPUT input = { 0 };
+    UINT inputSize = 0;
 
-    UINT inputSize = sizeof(input);
+    if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &inputSize, sizeof(RAWINPUTHEADER)) != 0) return;
+    if (inputSize > sizeof(input)) return;
+
     UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER));
 
     if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError());
@@ -2025,8 +2102,8 @@
 
     if (input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) TRACELOG(LOG_ERROR, "TODO: handle virtual desktop mouse inputs!");
 
-    // Trick to keep the mouse position at 0,0 and instead move
-    // the previous position so we can still get a proper mouse delta
+    // Trick to keep the mouse position at (0,0) and instead move
+    // the previous position so a proper mouse delta can still be retrieved
     //CORE.Input.Mouse.previousPosition.x -= input.data.mouse.lLastX;
     //CORE.Input.Mouse.previousPosition.y -= input.data.mouse.lLastY;
     //if (CORE.Input.Mouse.currentPosition.x != 0) abort();
@@ -2043,12 +2120,10 @@
     GetClientRect(hwnd, &rect);
     SIZE clientSize = { rect.right, rect.bottom };
 
-    // TODO: Update framebuffer on resize
     CORE.Window.currentFbo.width = (int)clientSize.cx;
     CORE.Window.currentFbo.height = (int)clientSize.cy;
-    //SetupViewport(0, 0, clientSize.cx, clientSize.cy);
-
     SetupViewport(clientSize.cx, clientSize.cy);
+
     CORE.Window.resizedLastFrame = true;
     float dpiScale = ((float)GetDpiForWindow(hwnd))/96.0f;
     bool highdpi = !!(CORE.Window.flags & FLAG_WINDOW_HIGHDPI);
@@ -2066,6 +2141,10 @@
 
     CORE.Window.screenScale = MatrixScale( (float)CORE.Window.render.width/CORE.Window.screen.width,
         (float)CORE.Window.render.height/CORE.Window.screen.height, 1.0f);
+
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    swResize(clientSize.cx, clientSize.cy);
+#endif
 }
 
 // Update window style
@@ -2090,10 +2169,10 @@
     // Minimized takes precedence over maximized
     Mized currentMized = MIZED_NONE;
     Mized desiredMized = MIZED_NONE;
-    if (CORE.Window.flags & WS_MINIMIZE) currentMized = MIZED_MIN;
-    else if (CORE.Window.flags & WS_MAXIMIZE) currentMized = MIZED_MAX;
-    if (desiredFlags & WS_MINIMIZE) currentMized = MIZED_MIN;
-    else if (desiredFlags & WS_MAXIMIZE) currentMized = MIZED_MAX;
+    if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) currentMized = MIZED_MIN;
+    else if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) currentMized = MIZED_MAX;
+    if (desiredFlags & FLAG_WINDOW_MINIMIZED) desiredMized = MIZED_MIN;
+    else if (desiredFlags & FLAG_WINDOW_MAXIMIZED) desiredMized = MIZED_MAX;
 
     if (currentMized != desiredMized)
     {
@@ -2109,10 +2188,41 @@
 // Sanitize flags
 static unsigned SanitizeFlags(int mode, unsigned flags)
 {
-    if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE))
+    if (flags & FLAG_WINDOW_MAXIMIZED)
     {
-        TRACELOG(LOG_WARNING, "WIN32: WINDOW: Borderless windows mode overriding maximized window flag");
-        flags &= ~FLAG_WINDOW_MAXIMIZED;
+        if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
+        {
+            TRACELOG(LOG_WARNING, "WIN32: WINDOW: Borderless windows mode overriding maximized window flag");
+            flags &= ~FLAG_WINDOW_MAXIMIZED;
+        }
+
+        if (~flags & FLAG_WINDOW_RESIZABLE)
+        {
+            if (!(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+            {
+                TRACELOG(LOG_WARNING, "WIN32: WINDOW: Cannot maximize a non-resizable window");
+                flags &= ~FLAG_WINDOW_MAXIMIZED;
+            }
+            else if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
+            {
+                TRACELOG(LOG_WARNING, "WIN32: WINDOW: Cannot set window as non-resizable when maximized");
+                flags |= FLAG_WINDOW_RESIZABLE;
+            }
+        }
+        else if (!(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+        {
+            if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)
+            {
+                // Window needs to be unminimized before it can be maximized since minimizing takes precedence
+                flags &= ~FLAG_WINDOW_MINIMIZED;
+            }
+            else if ((flags & FLAG_WINDOW_MINIMIZED) && !(CORE.Window.flags & FLAG_WINDOW_MINIMIZED))
+            {
+                TRACELOG(LOG_WARNING, "WIN32: WINDOW: Cannot minimize and maximize a window in the same frame");
+                flags &= ~FLAG_WINDOW_MINIMIZED;
+                flags &= ~FLAG_WINDOW_MAXIMIZED;
+            }
+        }
     }
 
     if (mode == 1)
@@ -2135,24 +2245,24 @@
 // window. This function will continue to perform these update operations so long as
 // the state continues to change
 //
-// This design takes care of many odd corner cases. For example, if you want to restore
-// a window that was previously maximized AND minimized and you want to remove both these
-// flags, you actually need to call ShowWindow with SW_RESTORE twice. Another example is
-// if you have a maximized window, if the undecorated flag is modified then we'd need to
-// update the window style, but updating the style would mean the window size would change
-// causing the window to lose its Maximized state which would mean we'd need to update the
-// window size and then update the window style a second time to restore that maximized
+// 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 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
+// needs to be updated, followed by the update of window style, a second time, to restore that maximized
 // state. This implementation is able to handle any/all of these special situations with a
-// retry loop that continues until we either reach the desired state or the state stops changing
+// retry loop that continues until either the desired state is reached or the state stops changing
 static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
 {
-    // Flags that just apply immediately without needing any operations
+    // Flags that apply immediately without needing any operations
     CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE);
 
-    int vsync = (CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0;
+    int vsync = (desiredFlags & FLAG_VSYNC_HINT)? 1 : 0;
     if (wglSwapIntervalEXT)
     {
-        (*wglSwapIntervalEXT)(vsync);
+        wglSwapIntervalEXT(vsync);
         if (vsync) CORE.Window.flags |= FLAG_VSYNC_HINT;
         else CORE.Window.flags &= ~FLAG_VSYNC_HINT;
     }
diff --git a/raylib/src/platforms/rcore_drm.c b/raylib/src/platforms/rcore_drm.c
--- a/raylib/src/platforms/rcore_drm.c
+++ b/raylib/src/platforms/rcore_drm.c
@@ -58,14 +58,14 @@
 #include <linux/joystick.h> // Linux: Joystick support library
 
 // WARNING: Both 'linux/input.h' and 'raylib.h' define KEY_F12
-// To avoid conflict with the capturing code in rcore.c we undefine the macro KEY_F12,
+// To avoid conflict with the capturing code in rcore.c, undefine the macro KEY_F12,
 // so the enum KEY_F12 from raylib is used
 #undef KEY_F12
 
 #include <xf86drm.h>        // Direct Rendering Manager user-level library interface
 #include <xf86drmMode.h>    // Direct Rendering Manager mode setting (KMS) interface
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     #include <gbm.h>            // Generic Buffer Management (native platform for EGL on DRM)
     #include "EGL/egl.h"        // Native platform windowing system interface
     #include "EGL/eglext.h"     // EGL extensions
@@ -79,8 +79,12 @@
     #include <poll.h>       // Required for: drmHandleEvent() poll
     #include <errno.h>      // Required for: EBUSY, EAGAIN
 
-    #define MAX_DRM_CACHED_BUFFERS  3
-#endif // SUPPORT_DRM_CACHE
+    // NOTE: Some drivers rotate more buffers than others, mesa uses 3 but the
+    // ARM Mali blob on RK3326 uses 4. A buffer beyond this count can not get a
+    // framebuffer and the display stops updating for good, so this must not be
+    // lower than any driver in use
+    #define MAX_DRM_CACHED_BUFFERS  4
+#endif
 
 #ifndef EGL_OPENGL_ES3_BIT
     #define EGL_OPENGL_ES3_BIT  0x40
@@ -97,7 +101,7 @@
 
 #define DEFAULT_EVDEV_PATH "/dev/input/"    // Path to the linux input events
 
-// Actually biggest key is KEY_CNT but we only really map the keys up to KEY_ALS_TOGGLE
+// Actually biggest key is KEY_CNT but only mapping keys up to KEY_ALS_TOGGLE
 #define KEYMAP_SIZE KEY_ALS_TOGGLE
 
 //----------------------------------------------------------------------------------
@@ -110,8 +114,11 @@
     drmModeCrtc *crtc;                  // CRT Controller
     int modeIndex;                      // Index of the used mode of connector->modes
     uint32_t prevFB;                    // Previous DRM framebufer (during frame swapping)
+#if defined(SUPPORT_DRM_CACHE)
+    bool fbCacheFullReported;           // Framebuffer cache exhaustion already reported
+#endif
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     struct gbm_device *gbmDevice;       // GBM device
     struct gbm_surface *gbmSurface;     // GBM surface
     struct gbm_bo *prevBO;              // Previous GBM buffer object (during frame swapping)
@@ -160,7 +167,7 @@
 static volatile int fbCacheCount = 0;
 static volatile bool pendingFlip = false;
 static bool crtcSet = false;
-#endif // SUPPORT_DRM_CACHE
+#endif
 
 //----------------------------------------------------------------------------------
 // Global Variables Definition
@@ -183,14 +190,14 @@
     0, 27, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 8, 0, 113, 119, 101, 114,
     116, 121, 117, 105, 111, 112, 0, 0, 13, 0, 97, 115, 100, 102, 103, 104, 106, 107, 108, 59,
     39, 96, 0, 92, 122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 32
-    // LUT currently incomplete, just mapped the most essential keys
+    // LUT currently incomplete, only mapped the most essential keys
 };
 
 // This is the map used to map any keycode returned from linux to a raylib code from 'raylib.h'
 // NOTE: Use short here to save a little memory
 static const short linuxToRaylibMap[KEYMAP_SIZE] = {
-    // We don't map those with designated initialization, because we would getting
-    // into loads of naming conflicts
+    // Don't map with designated initialization,
+    // it will geenrate many naming conflicts
     0,   256, 49,  50,  51,  52,  53,  54,
     55,  56,  57,  48,  45,  61,  259, 258,
     81,  87,  69,  82,  84,  89,  85,  73,
@@ -253,7 +260,7 @@
 int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
 void ClosePlatform(void);        // Close platform
 
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
+#if SUPPORT_SSH_KEYBOARD_RPI
 static void InitKeyboard(void);                 // Initialize raw keyboard system
 static void RestoreKeyboard(void);              // Restore keyboard system
 static void ProcessKeyboard(void);              // Process keyboard events
@@ -266,9 +273,12 @@
 static void PollGamepadEvents(void);            // Process evdev gamepad events
 static void PollMouseEvents(void);              // Process evdev mouse events
 
+// Not used by software rendering.
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
 static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode);                               // Search matching DRM mode in connector's mode list
 static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced);      // Search exactly matching DRM connector mode in connector's list
 static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced);    // Search the nearest matching DRM connector mode in connector's list
+#endif
 
 static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
 
@@ -561,13 +571,13 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     // Set cursor position in the middle
@@ -577,7 +587,7 @@
     CORE.Input.Mouse.cursorLocked = false;
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     // Set cursor position in the middle
@@ -621,8 +631,19 @@
     }
 
     // Create new entry if cache not full
-    if (fbCacheCount >= MAX_DRM_CACHED_BUFFERS) return 0; // FB cache full
+    if (fbCacheCount >= MAX_DRM_CACHED_BUFFERS)
+    {
+        // NOTE: Once this happens no page flip is ever scheduled again and the
+        // screen freezes while the game keeps running, so say it out loud once
+        if (!platform.fbCacheFullReported)
+        {
+            platform.fbCacheFullReported = true;
+            TRACELOG(LOG_WARNING, "DISPLAY: DRM: Framebuffer cache full (%i buffers), display will stop updating", MAX_DRM_CACHED_BUFFERS);
+        }
 
+        return 0; // FB cache full
+    }
+
     uint32_t handle = gbm_bo_get_handle(bo).u32;
     uint32_t stride = gbm_bo_get_stride(bo);
     uint32_t width = gbm_bo_get_width(bo);
@@ -764,9 +785,9 @@
     // Attempt page flip
     // NOTE: rmModePageFlip() schedules a buffer-flip for the next vblank and then notifies us about it
     // It takes a CRTC-id, fb-id and an arbitrary data-pointer and then schedules the page-flip
-    // This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and we can call drmHandleEvent()
-    // This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer that we passed to drmModePageFlip()
-    // We simply call modeset_draw_dev() then so the next frame is rendered... returns immediately
+    // This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and drmHandleEvent() can be called
+    // This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer passed to drmModePageFlip()
+    // Simply call modeset_draw_dev() then so the next frame is rendered... returns immediately
     if (drmModePageFlip(platform.fd, platform.crtc->crtc_id, fbId, DRM_MODE_PAGE_FLIP_EVENT, platform.prevBO))
     {
         if (errno == EBUSY) errCnt[3]++; // Display busy - skip flip
@@ -796,7 +817,7 @@
 // Swap back buffer with front buffer (screen drawing)
 void SwapScreenBuffer(void)
 {
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Hardware rendering buffer swap with EGL
     eglSwapBuffers(platform.device, platform.surface);
 
@@ -837,14 +858,8 @@
     uint32_t height = mode->vdisplay;
 
     // Dumb buffers use a fixed format based on bpp
-#if SW_COLOR_BUFFER_BITS == 24
     const uint32_t bpp = 32;    // 32 bits per pixel (XRGB8888 format)
     const uint32_t depth = 24;  // Color depth, here only 24 bits, alpha is not used
-#else
-    // REVIEW: Not sure how it will be interpreted (RGB or RGBA?)
-    const uint32_t bpp = SW_COLOR_BUFFER_BITS;
-    const uint32_t depth = SW_COLOR_BUFFER_BITS;
-#endif
 
     // Create a dumb buffer for software rendering
     struct drm_mode_create_dumb creq = { 0 };
@@ -899,7 +914,7 @@
 
     // Copy the software rendered buffer to the dumb buffer with scaling if needed
     // NOTE: RLSW will make a simple copy if the dimensions match
-    swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
+    swBlitPixels(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
 
     // Unmap the buffer
     munmap(dumbBuffer, creq.size);
@@ -915,7 +930,7 @@
         {
             TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources");
             drmModeRmFB(platform.fd, fb);
-            struct drm_mode_destroy_dumb dreq = {0};
+            struct drm_mode_destroy_dumb dreq = { 0 };
             dreq.handle = creq.handle;
             drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
             return;
@@ -955,7 +970,7 @@
         {
             TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found");
             drmModeRmFB(platform.fd, fb);
-            struct drm_mode_destroy_dumb dreq = {0};
+            struct drm_mode_destroy_dumb dreq = { 0 };
             dreq.handle = creq.handle;
             drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
             return;
@@ -971,7 +986,7 @@
         TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
 
         drmModeRmFB(platform.fd, fb);
-        struct drm_mode_destroy_dumb dreq = {0};
+        struct drm_mode_destroy_dumb dreq = { 0 };
         dreq.handle = creq.handle;
         drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
         return;
@@ -989,7 +1004,7 @@
     // Clean up previous dumb buffer
     if (platform.prevDumbHandle)
     {
-        struct drm_mode_destroy_dumb dreq = {0};
+        struct drm_mode_destroy_dumb dreq = { 0 };
         dreq.handle = platform.prevDumbHandle;
         drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
     }
@@ -1009,18 +1024,16 @@
     double time = 0.0;
     struct timespec ts = { 0 };
     clock_gettime(CLOCK_MONOTONIC, &ts);
-    unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
+    unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
 
-    time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
+    time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
 
     return time;
 }
 
 // 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
 void OpenURL(const char *url)
 {
     TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
@@ -1047,7 +1060,6 @@
 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
@@ -1066,9 +1078,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -1077,7 +1089,7 @@
     CORE.Input.Keyboard.charPressedQueueCount = 0;
 
     // Reset last gamepad button/axis registered state
-    CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
+    CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
     //CORE.Input.Gamepad.axisCount = 0;
 
     // Register previous keys states
@@ -1089,8 +1101,8 @@
 
     PollKeyboardEvents();
 
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
-    // NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here
+#if SUPPORT_SSH_KEYBOARD_RPI
+    // NOTE: Keyboard reading could be done using input_event(s) or read from stdin, both methods are used here
     // stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
     if (!platform.eventKeyboardMode) ProcessKeyboard();
 #endif
@@ -1124,7 +1136,7 @@
     // NOTE: For DRM touchscreen devices, this mapping is disabled to avoid false touch detection
     // CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
 
-    // Handle the mouse/touch/gestures events:
+    // Handle the mouse/touch/gestures events
     PollMouseEvents();
 }
 
@@ -1141,7 +1153,7 @@
     platform.crtc = NULL;
     platform.prevFB = 0;
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     platform.gbmDevice = NULL;
     platform.gbmSurface = NULL;
     platform.prevBO = NULL;
@@ -1225,8 +1237,8 @@
         // WARNING: Accept CONNECTED, UNKNOWN and even those without encoder_id connectors for software mode
         if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0))
         {
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
-            // For hardware rendering, we need an encoder_id
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
+            // For hardware rendering, an encoder_id is needed
             if (con->encoder_id)
             {
                 TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected with encoder", i);
@@ -1235,7 +1247,7 @@
             }
             else TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i);
 #else
-            // For software rendering, we can accept even without encoder_id
+            // For software rendering, accept even without encoder_id
             TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i);
             platform.connector = con;
             break;
@@ -1257,7 +1269,7 @@
         return -1;
     }
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
     if (!enc)
     {
@@ -1368,7 +1380,7 @@
     drmModeFreeResources(res);
     res = NULL;
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Hardware rendering initialization with EGL
     platform.gbmDevice = gbm_create_device(platform.fd);
     if (!platform.gbmDevice)
@@ -1429,11 +1441,11 @@
     if ((eglClientExtensions != NULL) && (strstr(eglClientExtensions, "EGL_EXT_platform_base") != NULL))
     {
         PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
-        
+
         if (eglGetPlatformDisplayEXT != NULL) platform.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, platform.gbmDevice, NULL);
     }
 
-    // In case extension not found or display could not be retrieved, try useing legacy version
+    // In case extension not found or display could not be retrieved, try using legacy version
     if (platform.device == EGL_NO_DISPLAY) platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice);
 #endif
     if (platform.device == EGL_NO_DISPLAY)
@@ -1450,7 +1462,9 @@
         return -1;
     }
 
-    if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs))
+    // 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());
         return -1;
@@ -1469,7 +1483,7 @@
     if (!eglChooseConfig(platform.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs))
     {
         TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError());
-        free(configs);
+        RL_FREE(configs);
         return -1;
     }
 
@@ -1535,7 +1549,7 @@
         return -1;
     }
 
-    // At this point we need to manage render size vs screen size
+    // At this point, manage render size vs screen size
     // NOTE: This function use and modify global module variables:
     //  -> CORE.Window.screen.width/CORE.Window.screen.height
     //  -> CORE.Window.render.width/CORE.Window.render.height
@@ -1556,12 +1570,6 @@
         CORE.Window.render.height = CORE.Window.screen.height;
         CORE.Window.currentFbo.width = CORE.Window.render.width;
         CORE.Window.currentFbo.height = CORE.Window.render.height;
-
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
-        TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
-        TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
-        TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
-        TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
     }
     else
     {
@@ -1573,7 +1581,7 @@
     // NOTE: GL procedures address loader is required to load extensions
     rlLoadExtensions(eglGetProcAddress);
 #else
-    // At this point we need to manage render size vs screen size
+    // At this point, manage render size vs screen size
     // NOTE: This function use and modify global module variables:
     //  -> CORE.Window.screen.width/CORE.Window.screen.height
     //  -> CORE.Window.render.width/CORE.Window.render.height
@@ -1587,17 +1595,18 @@
     CORE.Window.render.height = CORE.Window.screen.height;
     CORE.Window.currentFbo.width = CORE.Window.render.width;
     CORE.Window.currentFbo.height = CORE.Window.render.height;
+#endif
 
-    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully (Software Rendering)");
+    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+        FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
     TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
     TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
     TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
     TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
-#endif
 
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
 
-    // If graphic device is no properly initialized, we end program
+    // If graphic device is no properly initialized, end program
     if (!CORE.Window.ready)
     {
         TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device");
@@ -1614,7 +1623,7 @@
     //----------------------------------------------------------------------------
     // Initialize timing system
     //----------------------------------------------------------------------------
-    // NOTE: timming system must be initialized before the input events system
+    // NOTE: timing system must be initialized before the input events system
     InitTimer();
     //----------------------------------------------------------------------------
 
@@ -1622,7 +1631,7 @@
     //----------------------------------------------------------------------------
     InitEvdevInput();   // Evdev inputs initialization
 
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
+#if SUPPORT_SSH_KEYBOARD_RPI
     InitKeyboard();     // Keyboard init (stdin)
 #endif
     //----------------------------------------------------------------------------
@@ -1658,7 +1667,7 @@
         platform.prevFB = 0;
     }
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     if (platform.prevBO)
     {
         gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
@@ -1698,7 +1707,7 @@
         platform.fd = -1;
     }
 
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Close surface, context and display
     if (platform.device != EGL_NO_DISPLAY)
     {
@@ -1742,11 +1751,11 @@
     }
 }
 
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
+#if SUPPORT_SSH_KEYBOARD_RPI
 // Initialize Keyboard system (using standard input)
 static void InitKeyboard(void)
 {
-    // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor,
+    // NOTE: Read directly from Standard Input (stdin) - STDIN_FILENO file descriptor,
     // Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE
 
     // Save terminal keyboard settings
@@ -1830,7 +1839,7 @@
             if (bufferByteCount == 1) CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] = 1;
             else
             {
-                if (keysBuffer[i + 1] == 0x5b)    // Special function key
+                if (keysBuffer[i + 1] == 0x5b) // Special function key
                 {
                     if ((keysBuffer[i + 2] == 0x5b) || (keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32))
                     {
@@ -1901,7 +1910,7 @@
         }
     }
 }
-#endif  // SUPPORT_SSH_KEYBOARD_RPI
+#endif // SUPPORT_SSH_KEYBOARD_RPI
 
 // Initialize user input from evdev(/dev/input/event<N>)
 // this means mouse, keyboard or gamepad devices
@@ -1947,7 +1956,8 @@
                 (strncmp("mouse", entity->d_name, strlen("mouse")) == 0))       // Search for devices named "mouse*"
             {
                 snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
-                ConfigureEvdevDevice(path);                                     // Configure the device if appropriate
+
+                ConfigureEvdevDevice(path); // Configure the device if appropriate
             }
         }
 
@@ -1979,8 +1989,8 @@
         return;
     }
 
-    // At this point we have a connection to the device, but we don't yet know what the device is
-    // It could be many things, even as simple as a power button...
+    // At this point, a connection to the device has been stablished, but still left to know what the device is,
+    // it could be many things, even as simple as a power button...
     //-------------------------------------------------------------------------------------------------------
 
     // Identify the device
@@ -1991,8 +2001,8 @@
     } absinfo[ABS_CNT] = { 0 };
 
     // These flags aren't really a one of
-    // Some devices could have properties we assosciate with keyboards as well as properties
-    // we assosciate with mice
+    // Some devices could have properties associated with keyboards
+    // as well as properties associated with mice
     bool isKeyboard = false;
     bool isMouse = false;
     bool isTouch = false;
@@ -2028,11 +2038,10 @@
             TEST_BIT(keyBits, BTN_TOOL_FINGER) ||
             TEST_BIT(keyBits, BTN_TOUCH))) isTouch = true;
 
-        // Absolute mice should really only exist with VMWare, but it shouldn't
-        // matter if we support them
+        // Absolute mice should really only exist with VMWare
         else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
 
-        // If any of the common joystick axes are present, we assume it's a gamepad
+        // If any of the common joystick axes are present, assume it's a gamepad
         else
         {
             for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
@@ -2057,7 +2066,7 @@
     {
         ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits);
 
-        // If it has any of the gamepad or touch features we tested so far, it's not a mouse
+        // If it has any of the gamepad or touch features tested so far, it's not a mouse
         if (!isTouch &&
             !isGamepad &&
             TEST_BIT(relBits, REL_X) &&
@@ -2068,12 +2077,12 @@
     if (TEST_BIT(evBits, EV_KEY))
     {
         // The first 32 keys as defined in input-event-codes.h are pretty much
-        // exclusive to keyboards, so we can test them using a mask
+        // exclusive to keyboards, so they can be tested using a mask
         // Leave out the first bit to not test KEY_RESERVED
         const unsigned long mask = 0xFFFFFFFE;
         if ((keyBits[0] & mask) == mask) isKeyboard = true;
 
-        // If we find any of the common gamepad buttons we assume it's a gamepad
+        // If any of the common gamepad buttons is found, assume it's a gamepad
         else
         {
             for (int button = BTN_JOYSTICK; button < BTN_DIGI; ++button)
@@ -2149,14 +2158,11 @@
 
         if (absAxisCount > 0)
         {
-            // TODO / NOTE
-            // So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
+            // TODO: Review GamepadAxis enum matching
+            // So gamepad axes (as in the actual linux joydev.c) are simply enumerated
             // and (at least for some input drivers like xpat) it's convention to use
-            // ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
-            // shoulder buttons
-            // If these are now enumerated you get LJOY_X, LJOY_Y, LEFT_SHOULDERB, RJOY_X, ...
-            // That means they don't match the GamepadAxis enum
-            // This could be fixed
+            // ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the shoulder buttons
+            // If these are now enumerated, it results to LJOY_X, LJOY_Y, LEFT_SHOULDERB, RJOY_X, ...
             int axisIndex = 0;
             for (int axis = ABS_X; axis < ABS_PRESSURE; axis++)
             {
@@ -2200,8 +2206,8 @@
         // Check if the event is a key event
         if (event.type != EV_KEY) continue;
 
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
-        // If the event was a key, we know a working keyboard is connected, so disable the SSH keyboard
+#if SUPPORT_SSH_KEYBOARD_RPI
+        // If the event was a key, assume a working keyboard is connected, so disable the SSH keyboard
         platform.eventKeyboardMode = true;
 #endif
         // Keyboard keys appear for codes 1 to 255, ignore everthing else
@@ -2210,7 +2216,7 @@
             // Lookup the scancode in the keymap to get a keycode
             keycode = linuxToRaylibMap[event.code];
 
-            // Make sure we got a valid keycode
+            // Make sure a valid keycode is obtained
             if ((keycode > 0) && (keycode < MAX_KEYBOARD_KEYS))
             {
                 // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
@@ -2384,8 +2390,8 @@
                 {
                     platform.touchPosition[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
 
-                    // If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
-                    // Only set to MOVE if we haven't already detected a DOWN or UP event this frame
+                    // If this slot is active, it's a move; If not, update the buffer for when it becomes active
+                    // Only set to MOVE if a DOWN or UP event has not been detected this frame
                     if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2;    // TOUCH_ACTION_MOVE
                 }
             }
@@ -2396,8 +2402,8 @@
                 {
                     platform.touchPosition[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
 
-                    // If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
-                    // Only set to MOVE if we haven't already detected a DOWN or UP event this frame
+                    // If this slot is active, it's a move; If not, update the buffer for when it becomes active
+                    // Only set to MOVE if a DOWN or UP event have not been detected this frame
                     if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2;    // TOUCH_ACTION_MOVE
                 }
             }
@@ -2422,7 +2428,7 @@
                         platform.touchPosition[platform.touchSlot].y = -1;
                         platform.touchId[platform.touchSlot] = -1;
 
-                        // Force UP action if we haven't already set a DOWN action
+                        // Force UP action if DOWN action has not already been set
                         // (DOWN takes priority over UP if both happen in one frame, though rare)
                         if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
                     }
@@ -2556,7 +2562,7 @@
             CORE.Input.Touch.pointId[i] = -1;
         }
 
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
         if (touchAction > -1)
         {
             GestureEvent gestureEvent = { 0 };
@@ -2576,6 +2582,7 @@
     }
 }
 
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE)
 // Search matching DRM mode in connector's mode list
 static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode)
 {
@@ -2664,12 +2671,13 @@
 
     return nearestIndex;
 }
+#endif
 
 // Compute framebuffer size relative to screen size and display size
 // NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
 static void SetupFramebuffer(int width, int height)
 {
-    // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
+    // Calculate CORE.Window.render.width and CORE.Window.render.height, using the display size (input params) and the desired screen size (global var)
     if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
     {
         TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
@@ -2697,8 +2705,8 @@
         float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
         CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
 
-        // NOTE: We render to full display resolution!
-        // We just need to calculate above parameters for downscale matrix and offsets
+        // NOTE: Rendering to full display resolution,
+        // calculate above parameters for downscale matrix and offsets
         CORE.Window.render.width = CORE.Window.display.width;
         CORE.Window.render.height = CORE.Window.display.height;
 
diff --git a/raylib/src/platforms/rcore_memory.c b/raylib/src/platforms/rcore_memory.c
--- a/raylib/src/platforms/rcore_memory.c
+++ b/raylib/src/platforms/rcore_memory.c
@@ -55,7 +55,7 @@
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-// Platform-specific required data for timming (Win32)
+// Platform-specific required data for timing (Win32)
 #if defined(_WIN32)
 typedef struct _LARGE_INTEGER { int64_t QuadPart; } LARGE_INTEGER;
 __declspec(dllimport) int __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
@@ -91,7 +91,7 @@
 // Module Internal Functions Declaration
 //----------------------------------------------------------------------------------
 #if !defined(_WIN32)
-static int kbhit(void);                         // Check if a key has been pressed
+static int kbhit(void);                         // Check if key has been pressed
 static char getch(void) { return getchar(); }   // Get pressed character
 #endif
 
@@ -324,13 +324,13 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     // Set cursor position in the middle
@@ -339,7 +339,7 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     // Set cursor position in the middle
@@ -364,14 +364,18 @@
 {
     double time = 0.0;
 #if defined(_WIN32)
-    LARGE_INTEGER now = { 0 };
-    QueryPerformanceCounter(&now);
-    return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
+    LARGE_INTEGER currentTicks = { 0 };
+    QueryPerformanceCounter(&currentTicks);
+
+    time = (double)(currentTicks.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
 #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
     struct timespec ts = { 0 };
     clock_gettime(CLOCK_MONOTONIC, &ts);
-    unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
-    time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
+    unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
+
+    time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
+#elif defined(PICO_RP2350)
+    time = (double)to_ms_since_boot(get_absolute_time())/1000.0;
 #endif
     return time;
 }
@@ -416,7 +420,6 @@
 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
@@ -435,9 +438,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -474,7 +477,7 @@
     if (kbhit())
     {
         int key = getch();
-        if (key == 27) CORE.Window.shouldClose = true; // KEY_SCAPE
+        if (key == 27) CORE.Window.shouldClose = true; // KEY_ESCAPE
     }
 }
 
@@ -486,9 +489,9 @@
 int InitPlatform(void)
 {
     // Memory framebuffer can only work with software renderer
-    if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
+    if (rlGetVersion() != RL_OPENGL_SOFTWARE)
     {
-        TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_11_SOFTWARE)");
+        TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_SOFTWARE)");
         TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
         return -1;
     }
@@ -499,7 +502,7 @@
     }
     //----------------------------------------------------------------------------
 
-    // If everything work as expected, we can continue
+    // If everything worked as expected, continue
     CORE.Window.render.width = CORE.Window.screen.width;
     CORE.Window.render.height = CORE.Window.screen.height;
     CORE.Window.currentFbo.width = CORE.Window.render.width;
@@ -558,7 +561,7 @@
 // Module Internal Functions Definition
 //----------------------------------------------------------------------------------
 #if !defined(_WIN32)
-// Check if a key has been pressed
+// Check if key has been pressed
 static int kbhit(void)
 {
     struct termios oldt = { 0 };
diff --git a/raylib/src/platforms/rcore_template.c b/raylib/src/platforms/rcore_template.c
--- a/raylib/src/platforms/rcore_template.c
+++ b/raylib/src/platforms/rcore_template.c
@@ -303,13 +303,13 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     CORE.Input.Mouse.cursorHidden = true;
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     // Set cursor position in the middle
@@ -318,7 +318,7 @@
     CORE.Input.Mouse.cursorHidden = false;
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     // Set cursor position in the middle
@@ -341,24 +341,33 @@
 double GetTime(void)
 {
     double time = 0.0;
-    
+
     struct timespec ts = { 0 };
     clock_gettime(CLOCK_MONOTONIC, &ts);
-    unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
-    time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
+    unsigned long long nanoSeconds = (unsigned long long)ts.tv_sec*1000000000LLU + (unsigned long long)ts.tv_nsec;
 
+    time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
+
     return time;
 }
 
 // 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(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");
+    }
     else
     {
         // TODO: Load url using default browser
@@ -386,7 +395,6 @@
 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
@@ -405,9 +413,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -459,7 +467,7 @@
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
     {
         // TODO: Enable MSAA
-        
+
         TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
     }
 
@@ -475,12 +483,6 @@
         CORE.Window.render.height = CORE.Window.screen.height;
         CORE.Window.currentFbo.width = CORE.Window.render.width;
         CORE.Window.currentFbo.height = CORE.Window.render.height;
-
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
-        TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
-        TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
-        TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
-        TRACELOG(LOG_INFO, "    > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
     }
     else
     {
@@ -489,13 +491,14 @@
     }
     //----------------------------------------------------------------------------
 
-    // If everything work as expected, we can continue
+    // If everything worked as expected, continue
     CORE.Window.render.width = CORE.Window.screen.width;
     CORE.Window.render.height = CORE.Window.screen.height;
     CORE.Window.currentFbo.width = CORE.Window.render.width;
     CORE.Window.currentFbo.height = CORE.Window.render.height;
 
-    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+    TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+        FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
     TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
     TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
     TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
diff --git a/raylib/src/platforms/rcore_web.c b/raylib/src/platforms/rcore_web.c
--- a/raylib/src/platforms/rcore_web.c
+++ b/raylib/src/platforms/rcore_web.c
@@ -76,8 +76,7 @@
 
     char canvasId[64];                  // Keep current canvas id where wasm app is running
                                         // NOTE: Useful when trying to run multiple wasms in different canvases in same webpage
-
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     unsigned int *pixels;               // Pointer to pixel data buffer (RGBA 32bit format)
 #endif
 } PlatformData;
@@ -173,7 +172,7 @@
     // and encapsulating one frame execution on a UpdateDrawFrame() function,
     // allowing the browser to manage execution asynchronously
 
-    // Optionally we can manage the time we give-control-back-to-browser if required,
+    // Optionally, time to give-control-back-to-browser can be managed here,
     // but it seems below line could generate stuttering on some browsers
     emscripten_sleep(12);
 
@@ -316,15 +315,16 @@
         // 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
         EM_ASM
         (
+            const canvasId = UTF8ToString($0);
             setTimeout(function()
             {
                 Module.requestFullscreen(false, true);
                 setTimeout(function()
                 {
-                    canvas.style.width="unset";
+                    document.querySelector(canvasId).style.width="unset";
                 }, 100);
             }, 100);
-        );
+        , platform.canvasId);
         FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
     }
 }
@@ -800,34 +800,103 @@
     else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
 }
 
+// Async EM_JS to be able to await clickboard read asynchronous function
+EM_ASYNC_JS(void, RequestClipboardData, (void), {
+    if (navigator.clipboard && window.isSecureContext)
+    {
+        let items = await navigator.clipboard.read();
+        for (const item of items)
+        {
+            // Check if this item contains plain text or image
+            if (item.types.includes("text/plain"))
+            {
+                const blob = await item.getType("text/plain");
+                const text = await blob.text();
+                window._lastClipboardString = text;
+            }
+            else if (item.types.find(t => t.startsWith("image/")))
+            {
+                const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
+                const bitmap = await createImageBitmap(blob);
+
+                const canvas = document.createElement('canvas');
+                canvas.width = bitmap.width;
+                canvas.height = bitmap.height;
+                const ctx = canvas.getContext('2d');
+                ctx.drawImage(bitmap, 0, 0);
+
+                const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
+
+                // Store image and data for the Fetch function
+                window._lastImgWidth = canvas.width;
+                window._lastImgHeight = canvas.height;
+                window._lastImgData = imgData;
+            }
+        }
+    }
+    else console.warn("Clipboard read() requires HTTPS/Localhost");
+});
+
+// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
+EM_JS(char *, GetLastPastedText, (void), {
+    var str = window._lastClipboardString || "";
+    var length = lengthBytesUTF8(str) + 1;
+    if (length > 1)
+    {
+        var ptr = _malloc(length);
+        stringToUTF8(str, ptr, length);
+        return ptr;
+    }
+    return 0;
+});
+
+// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
+EM_JS(unsigned char *, GetLastPastedImage, (int *width, int *height), {
+    if (window._lastImgData)
+    {
+        const data = window._lastImgData;
+        if (data.length > 0)
+        {
+            const ptr = _malloc(data.length);
+            HEAPU8.set(data, ptr);
+
+            // Set the width and height via the pointers passed from C
+            // HEAP32 handles the 4-byte integers
+            if (width)  setValue(width, window._lastImgWidth,  'i32');
+            if (height) setValue(height, window._lastImgHeight, 'i32');
+
+            // Clear the JS buffer so there is no need to fetch the same image twice
+            window._lastImgData = null;
+
+            return ptr;
+        }
+    }
+
+    return 0;
+});
+
 // Get clipboard text content
 // NOTE: returned string is allocated and freed by GLFW
 const char *GetClipboardText(void)
 {
-/*
-    // Accessing clipboard data from browser is tricky due to security reasons
-    // The method to use is navigator.clipboard.readText() but this is an asynchronous method
-    // that will return at some moment after the function is called with the required data
-    emscripten_run_script_string("navigator.clipboard.readText() \
-        .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
-        .catch(err => { console.error('Failed to read clipboard contents: ', err); });"
-    );
-
-    // The main issue is getting that data, one approach could be using ASYNCIFY and wait
-    // for the data but it requires adding Asyncify emscripten library on compilation
-
-    // Another approach could be just copy the data in a HTML text field and try to retrieve it
-    // later on if available... and clean it for future accesses
-*/
-    return NULL;
+    RequestClipboardData();
+    return GetLastPastedText();
 }
 
 // Get clipboard image
 Image GetClipboardImage(void)
 {
     Image image = { 0 };
-
-    TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
+    int w = 0, h = 0;
+    RequestClipboardData();
+    unsigned char* data = GetLastPastedImage(&w, &h);
+    if (data != NULL) {
+        image.data = data;
+        image.width = w;
+        image.height = h;
+        image.mipmaps = 1;
+        image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+    }
 
     return image;
 }
@@ -843,7 +912,7 @@
     }
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     if (!CORE.Input.Mouse.cursorHidden)
@@ -854,7 +923,7 @@
     }
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     emscripten_exit_pointerlock();
@@ -865,7 +934,7 @@
     // NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     emscripten_request_pointerlock(platform.canvasId, 1);
@@ -879,7 +948,7 @@
 // Swap back buffer with front buffer (screen drawing)
 void SwapScreenBuffer(void)
 {
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Update framebuffer
     rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
 
@@ -893,7 +962,8 @@
         const canvas = Module.canvas;
         const ctx = canvas.getContext('2d');
 
-        if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) {
+        if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height))
+        {
             Module.__img = ctx.createImageData(width, height);
         }
 
@@ -915,13 +985,14 @@
 double GetTime(void)
 {
     double time = glfwGetTime();   // Elapsed time since glfwInit()
+
     return time;
 }
 
 // Open URL with default system browser (if available)
-// NOTE: This function is only safe to use if you control the URL given
+// NOTE: This function is only safe to use if the provided URL is safe
 // 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
+// Avoid calling this function with user input non-validated strings
 void OpenURL(const char *url)
 {
     // Security check to (partially) avoid malicious code on target platform
@@ -953,8 +1024,8 @@
         if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME;
         duration *= 1000.0f; // Convert duration to ms
 
-        // Note: At the moment (2024.10.21) Chrome, Edge, Opera, Safari, Android Chrome, Android Webview only support the vibrationActuator API,
-        //       and Firefox only supports the hapticActuators API
+        // NOTE: At the moment (2024.10.21) Chrome, Edge, Opera, Safari, Android Chrome, Android Webview only support the vibrationActuator API,
+        // and Firefox only supports the hapticActuators API
         EM_ASM({
             try
             {
@@ -976,7 +1047,6 @@
 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;
 
@@ -1005,9 +1075,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -1016,7 +1086,7 @@
     CORE.Input.Keyboard.charPressedQueueCount = 0;
 
     // Reset last gamepad button/axis registered state
-    CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
+    CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
     //CORE.Input.Gamepad.axisCount = 0;
 
     // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
@@ -1058,7 +1128,7 @@
         // Register previous gamepad button states
         for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
 
-        EmscriptenGamepadEvent gamepadState;
+        EmscriptenGamepadEvent gamepadState = { 0 };
 
         int result = emscripten_get_gamepad_status(i, &gamepadState);
 
@@ -1091,7 +1161,7 @@
                     default: break;
                 }
 
-                if (button + 1 != 0)   // Check for valid button
+                if (button + 1 != 0) // Check for valid button
                 {
                     if (gamepadState.digitalButton[j] == 1)
                     {
@@ -1208,7 +1278,7 @@
         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
         glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE);
-#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
+#if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
         glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Enable OpenGL Debug Context
 #endif
     }
@@ -1234,13 +1304,13 @@
     // Init fullscreen toggle required var:
     platform.ourFullscreen = false;
 
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Avoid creating a WebGL canvas, avoid calling glfwCreateWindow()
     emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
     EM_ASM({
-        const canvas = document.getElementById("canvas");
+        const canvas = document.querySelector(UTF8ToString($0));
         Module.canvas = canvas;
-    });
+    }, platform.canvasId);
 
     // Load memory framebuffer with desired screen size
     // NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
@@ -1250,11 +1320,11 @@
 #else
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
     {
-        // remember center for switchinging from fullscreen to window
+        // Remember center for switchinging from fullscreen to window
         if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
         {
-            // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed
-            // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11
+            // If screen width/height equal to the display, it's not possible to
+            // calculate the window position for toggling full-screened/windowed
             CORE.Window.position.x = CORE.Window.display.width/4;
             CORE.Window.position.y = CORE.Window.display.height/4;
         }
@@ -1351,7 +1421,8 @@
         CORE.Window.currentFbo.width = fbWidth;
         CORE.Window.currentFbo.height = fbHeight;
 
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+            FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
@@ -1365,7 +1436,7 @@
 
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
 
-    // If graphic device is no properly initialized, we end program
+    // If graphic device is no properly initialized, end program
     if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
 
     // Load OpenGL extensions
@@ -1473,15 +1544,15 @@
 // GLFW3: Called on windows minimized/restored
 static void WindowIconifyCallback(GLFWwindow *window, int iconified)
 {
-    if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);   // The window was iconified
-    else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);           // The window was restored
+    if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);  // The window was iconified
+    else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);          // The window was restored
 }
 
 // GLFW3: Called on windows get/lose focus
 static void WindowFocusCallback(GLFWwindow *window, int focused)
 {
-    if (focused) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);   // The window was focused
-    else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);           // The window lost focus
+    if (focused) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);  // The window was focused
+    else FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);            // The window lost focus
 }
 
 // GLFW3: Called on file-drop over the window
@@ -1489,7 +1560,7 @@
 {
     if (count > 0)
     {
-        // In case previous dropped filepaths have not been freed, we free them
+        // In case previous dropped filepaths have not been freed, free them
         if (CORE.Window.dropFileCount > 0)
         {
             for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
@@ -1500,14 +1571,14 @@
             CORE.Window.dropFilepaths = NULL;
         }
 
-        // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
+        // WARNING: Paths are freed by GLFW when the callback returns, an internal copy must freed
         CORE.Window.dropFileCount = count;
         CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
 
         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]);
         }
     }
 }
@@ -1517,7 +1588,7 @@
 {
     if (key < 0) return;    // Security check, macOS fn key generates -1
 
-    // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1
+    // WARNING: GLFW could return GLFW_REPEAT, it needs to be considered as 1
     // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
     if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
     else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
@@ -1562,7 +1633,7 @@
     CORE.Input.Mouse.currentButtonState[button] = action;
     CORE.Input.Touch.currentTouchState[button] = action;
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -1603,7 +1674,7 @@
         CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -1719,7 +1790,7 @@
     double canvasWidth = 0.0;
     double canvasHeight = 0.0;
     // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
-    // we are looking for actual CSS size: canvas.style.width and canvas.style.height
+    // actual CSS size needs to be considered: canvas.style.width and canvas.style.height
     // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
     emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
 
@@ -1739,14 +1810,14 @@
         else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
     }
 
-    // Update mouse position if we detect a single touch
+    // Update mouse position when single touch detected
     if (CORE.Input.Touch.pointCount == 1)
     {
         CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x;
         CORE.Input.Mouse.currentPosition.y = CORE.Input.Touch.position[0].y;
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     GestureEvent gestureEvent = { 0 };
     gestureEvent.pointCount = CORE.Input.Touch.pointCount;
 
@@ -1798,8 +1869,8 @@
 // Emscripten: Called on fullscreen change events
 static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
 {
-    // NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
-    //       2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
+    // NOTE 1: Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
+    // NOTE 2: Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
     if (platform.ourFullscreen) platform.ourFullscreen = false;
     else
     {
diff --git a/raylib/src/platforms/rcore_web_emscripten.c b/raylib/src/platforms/rcore_web_emscripten.c
--- a/raylib/src/platforms/rcore_web_emscripten.c
+++ b/raylib/src/platforms/rcore_web_emscripten.c
@@ -42,6 +42,7 @@
 **********************************************************************************************/
 
 #include <emscripten/emscripten.h>      // Emscripten functionality for C
+#include <emscripten/dom_pk_codes.h>    // Emscripten physical keyboard codes
 #include <emscripten/html5.h>           // Emscripten HTML5 library
 
 #include <sys/time.h>   // Required for: timespec, nanosleep(), select() - POSIX
@@ -54,6 +55,9 @@
     #define _POSIX_C_SOURCE 199309L     // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
 #endif
 
+#define DOM_PK_CODE_MAPPED_NUM          128
+#define DOM_PK_CODE_EXTENDED_OFFSET     0xE000
+
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
@@ -70,9 +74,121 @@
 
 static PlatformData platform = { 0 };   // Platform specific data
 
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
+static const KeyboardKey mapDomCodeToKey[DOM_PK_CODE_MAPPED_NUM] = {
+    [DOM_PK_ESCAPE] = KEY_ESCAPE,
+    [DOM_PK_0] = KEY_ZERO,
+    [DOM_PK_1] = KEY_ONE,
+    [DOM_PK_2] = KEY_TWO,
+    [DOM_PK_3] = KEY_THREE,
+    [DOM_PK_4] = KEY_FOUR,
+    [DOM_PK_5] = KEY_FIVE,
+    [DOM_PK_6] = KEY_SIX,
+    [DOM_PK_7] = KEY_SEVEN,
+    [DOM_PK_8] = KEY_EIGHT,
+    [DOM_PK_9] = KEY_NINE,
+    [DOM_PK_MINUS] = KEY_MINUS,
+    [DOM_PK_EQUAL] = KEY_EQUAL,
+    [DOM_PK_BACKSPACE] = KEY_BACKSPACE,
+    [DOM_PK_TAB] = KEY_TAB,
+    [DOM_PK_Q] = KEY_Q,
+    [DOM_PK_W] = KEY_W,
+    [DOM_PK_E] = KEY_E,
+    [DOM_PK_R] = KEY_R,
+    [DOM_PK_T] = KEY_T,
+    [DOM_PK_Y] = KEY_Y,
+    [DOM_PK_U] = KEY_U,
+    [DOM_PK_I] = KEY_I,
+    [DOM_PK_O] = KEY_O,
+    [DOM_PK_P] = KEY_P,
+    [DOM_PK_BRACKET_LEFT] = KEY_LEFT_BRACKET,
+    [DOM_PK_BRACKET_RIGHT] = KEY_RIGHT_BRACKET,
+    [DOM_PK_ENTER] = KEY_ENTER,
+    [DOM_PK_CONTROL_LEFT] = KEY_LEFT_CONTROL,
+    [DOM_PK_A] = KEY_A,
+    [DOM_PK_S] = KEY_S,
+    [DOM_PK_D] = KEY_D,
+    [DOM_PK_F] = KEY_F,
+    [DOM_PK_G] = KEY_G,
+    [DOM_PK_H] = KEY_H,
+    [DOM_PK_J] = KEY_J,
+    [DOM_PK_K] = KEY_K,
+    [DOM_PK_L] = KEY_L,
+    [DOM_PK_SEMICOLON] = KEY_SEMICOLON,
+    [DOM_PK_QUOTE] = KEY_APOSTROPHE,
+    [DOM_PK_BACKQUOTE] = KEY_GRAVE,
+    [DOM_PK_SHIFT_LEFT] = KEY_LEFT_SHIFT,
+    [DOM_PK_BACKSLASH] = KEY_BACKSLASH,
+    [DOM_PK_Z] = KEY_Z,
+    [DOM_PK_X] = KEY_X,
+    [DOM_PK_C] = KEY_C,
+    [DOM_PK_V] = KEY_V,
+    [DOM_PK_B] = KEY_B,
+    [DOM_PK_N] = KEY_N,
+    [DOM_PK_M] = KEY_M,
+    [DOM_PK_COMMA] = KEY_COMMA,
+    [DOM_PK_PERIOD] = KEY_PERIOD,
+    [DOM_PK_SLASH] = KEY_SLASH,
+    [DOM_PK_SHIFT_RIGHT] = KEY_RIGHT_SHIFT,
+    [DOM_PK_NUMPAD_MULTIPLY] = KEY_KP_MULTIPLY,
+    [DOM_PK_ALT_LEFT] = KEY_LEFT_ALT,
+    [DOM_PK_SPACE] = KEY_SPACE,
+    [DOM_PK_CAPS_LOCK] = KEY_CAPS_LOCK,
+    [DOM_PK_F1] = KEY_F1,
+    [DOM_PK_F2] = KEY_F2,
+    [DOM_PK_F3] = KEY_F3,
+    [DOM_PK_F4] = KEY_F4,
+    [DOM_PK_F5] = KEY_F5,
+    [DOM_PK_F6] = KEY_F6,
+    [DOM_PK_F7] = KEY_F7,
+    [DOM_PK_F8] = KEY_F8,
+    [DOM_PK_F9] = KEY_F9,
+    [DOM_PK_F10] = KEY_F10,
+    [DOM_PK_PAUSE] = KEY_PAUSE,
+    [DOM_PK_SCROLL_LOCK] = KEY_SCROLL_LOCK,
+    [DOM_PK_NUMPAD_7] = KEY_KP_7,
+    [DOM_PK_NUMPAD_8] = KEY_KP_8,
+    [DOM_PK_NUMPAD_9] = KEY_KP_9,
+    [DOM_PK_NUMPAD_SUBTRACT] = KEY_KP_SUBTRACT,
+    [DOM_PK_NUMPAD_4] = KEY_KP_4,
+    [DOM_PK_NUMPAD_5] = KEY_KP_5,
+    [DOM_PK_NUMPAD_6] = KEY_KP_6,
+    [DOM_PK_NUMPAD_ADD] = KEY_KP_ADD,
+    [DOM_PK_NUMPAD_1] = KEY_KP_1,
+    [DOM_PK_NUMPAD_2] = KEY_KP_2,
+    [DOM_PK_NUMPAD_3] = KEY_KP_3,
+    [DOM_PK_NUMPAD_0] = KEY_KP_0,
+    [DOM_PK_NUMPAD_DECIMAL] = KEY_KP_DECIMAL,
+    [DOM_PK_PRINT_SCREEN] = KEY_PRINT_SCREEN,
+    [DOM_PK_F11] = KEY_F11,
+    [DOM_PK_F12] = KEY_F12,
+    [DOM_PK_NUMPAD_EQUAL] = KEY_KP_EQUAL,
+    [DOM_PK_NUMPAD_COMMA] = KEY_KP_DECIMAL
+};
+
+// Emscripten places keys with extended scan codes (right-side modifiers, navigation and some keypad keys) in the 0xE0xx range
+static const KeyboardKey mapDomCodeToKeyExtended[DOM_PK_CODE_MAPPED_NUM] = {
+    [DOM_PK_NUMPAD_ENTER - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_KP_ENTER,
+    [DOM_PK_CONTROL_RIGHT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_RIGHT_CONTROL,
+    [DOM_PK_AUDIO_VOLUME_DOWN - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_VOLUME_DOWN,
+    [DOM_PK_AUDIO_VOLUME_UP - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_VOLUME_UP,
+    [DOM_PK_NUMPAD_DIVIDE - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_KP_DIVIDE,
+    [DOM_PK_ALT_RIGHT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_RIGHT_ALT,
+    [DOM_PK_NUM_LOCK - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_NUM_LOCK,
+    [DOM_PK_HOME - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_HOME,
+    [DOM_PK_ARROW_UP - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_UP,
+    [DOM_PK_PAGE_UP - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_PAGE_UP,
+    [DOM_PK_ARROW_LEFT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_LEFT,
+    [DOM_PK_ARROW_RIGHT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_RIGHT,
+    [DOM_PK_END - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_END,
+    [DOM_PK_ARROW_DOWN - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_DOWN,
+    [DOM_PK_PAGE_DOWN - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_PAGE_DOWN,
+    [DOM_PK_INSERT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_INSERT,
+    [DOM_PK_DELETE - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_DELETE,
+    [DOM_PK_META_LEFT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_LEFT_SUPER,
+    [DOM_PK_META_RIGHT - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_RIGHT_SUPER,
+    [DOM_PK_CONTEXT_MENU - DOM_PK_CODE_EXTENDED_OFFSET] = KEY_KB_MENU
+};
+
 static const char cursorLUT[11][12] = {
     "default",     // 0  MOUSE_CURSOR_DEFAULT
     "default",     // 1  MOUSE_CURSOR_ARROW
@@ -110,6 +226,8 @@
 static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
 static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
 
+static KeyboardKey ConvertKeyboardEventToKey(const EmscriptenKeyboardEvent *keyboardEvent);
+
 // JS: Set the canvas id provided by the module configuration
 EM_JS(void, SetCanvasIdJs, (char *out, int outSize), {
     var canvasId = "#" + Module.canvas.id;
@@ -137,7 +255,7 @@
     // and encapsulating one frame execution on a UpdateDrawFrame() function,
     // allowing the browser to manage execution asynchronously
 
-    // Optionally we can manage the time we give-control-back-to-browser if required,
+    // NOTE: Optionally, time can be managed, giving control back-to-browser as required,
     // but it seems below line could generate stuttering on some browsers
     emscripten_sleep(12);
 
@@ -280,15 +398,16 @@
         // 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
         EM_ASM
         (
+            const canvasId = UTF8ToString($0);
             setTimeout(function()
             {
                 Module.requestFullscreen(false, true);
                 setTimeout(function()
                 {
-                    canvas.style.width="unset";
+                    document.querySelector(canvasId).style.width="unset";
                 }, 100);
             }, 100);
-        );
+        , platform.canvasId);
         FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
     }
 }
@@ -632,7 +751,7 @@
     // 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;
@@ -778,36 +897,103 @@
     else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
 }
 
+// Async EM_JS to be able to await clickboard read asynchronous function
+EM_ASYNC_JS(void, RequestClipboardData, (void), {
+    if (navigator.clipboard && window.isSecureContext)
+    {
+        let items = await navigator.clipboard.read();
+        for (const item of items)
+        {
+            // Check if this item contains plain text or image
+            if (item.types.includes("text/plain"))
+            {
+                const blob = await item.getType("text/plain");
+                const text = await blob.text();
+                window._lastClipboardString = text;
+            }
+            else if (item.types.find(t => t.startsWith("image/")))
+            {
+                const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
+                const bitmap = await createImageBitmap(blob);
+
+                const canvas = document.createElement('canvas');
+                canvas.width = bitmap.width;
+                canvas.height = bitmap.height;
+                const ctx = canvas.getContext('2d');
+                ctx.drawImage(bitmap, 0, 0);
+
+                const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
+
+                // Store image and data for the Fetch function
+                window._lastImgWidth = canvas.width;
+                window._lastImgHeight = canvas.height;
+                window._lastImgData = imgData;
+            }
+        }
+    }
+    else console.warn("Clipboard read() requires HTTPS/Localhost");
+});
+
+// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
+EM_JS(char *, GetLastPastedText, (void), {
+    var str = window._lastClipboardString || "";
+    var length = lengthBytesUTF8(str) + 1;
+    if (length > 1)
+    {
+        var ptr = _malloc(length);
+        stringToUTF8(str, ptr, length);
+        return ptr;
+    }
+    return 0;
+});
+
+// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
+EM_JS(unsigned char *, GetLastPastedImage, (int *width, int *height), {
+    if (window._lastImgData)
+    {
+        const data = window._lastImgData;
+        if (data.length > 0)
+        {
+            const ptr = _malloc(data.length);
+            HEAPU8.set(data, ptr);
+
+            // Set the width and height via the pointers passed from C
+            // HEAP32 handles the 4-byte integers
+            if (width)  setValue(width, window._lastImgWidth,  'i32');
+            if (height) setValue(height, window._lastImgHeight, 'i32');
+
+            // Clear the JS buffer so there is no need to fetch the same image twice
+            window._lastImgData = null;
+
+            return ptr;
+        }
+    }
+
+    return 0;
+});
+
 // Get clipboard text content
 // NOTE: returned string is allocated and freed by GLFW
 const char *GetClipboardText(void)
 {
-/*
-    // Accessing clipboard data from browser is tricky due to security reasons
-    // The method to use is navigator.clipboard.readText() but this is an asynchronous method
-    // that will return at some moment after the function is called with the required data
-    emscripten_run_script_string("navigator.clipboard.readText() \
-        .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
-        .catch(err => { console.error('Failed to read clipboard contents: ', err); });"
-    );
-
-    // The main issue is getting that data, one approach could be using ASYNCIFY and wait
-    // for the data but it requires adding Asyncify emscripten library on compilation
-
-    // Another approach could be just copy the data in a HTML text field and try to retrieve it
-    // later on if available... and clean it for future accesses
-*/
-    return NULL;
+    RequestClipboardData();
+    return GetLastPastedText();
 }
 
 // Get clipboard image
 Image GetClipboardImage(void)
 {
     Image image = { 0 };
-
-    // NOTE: In theory, the new navigator.clipboard.read() can be used to return arbitrary data from clipboard (2024)
-    // REF: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read
-    TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
+    int w = 0, h = 0;
+    RequestClipboardData();
+    unsigned char* data = GetLastPastedImage(&w, &h);
+    if (data != NULL) {
+        image.data = data;
+        image.width = w;
+        image.height = h;
+        image.mipmaps = 1;
+        image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+    }
 
     return image;
 }
@@ -823,7 +1009,7 @@
     }
 }
 
-// Hides mouse cursor
+// Hide mouse cursor
 void HideCursor(void)
 {
     if (!CORE.Input.Mouse.cursorHidden)
@@ -834,7 +1020,7 @@
     }
 }
 
-// Enables cursor (unlock cursor)
+// Enable cursor (unlock cursor)
 void EnableCursor(void)
 {
     emscripten_exit_pointerlock();
@@ -845,7 +1031,7 @@
     // NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
 }
 
-// Disables cursor (lock cursor)
+// Disable cursor (lock cursor)
 void DisableCursor(void)
 {
     emscripten_request_pointerlock(platform.canvasId, 1);
@@ -859,7 +1045,7 @@
 // Swap back buffer with front buffer (screen drawing)
 void SwapScreenBuffer(void)
 {
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Update framebuffer
     rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
 
@@ -874,7 +1060,8 @@
         //const canvas = Module['canvas'];
         const ctx = canvas.getContext('2d');
 
-        if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) {
+        if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height))
+        {
             Module.__img = ctx.createImageData(width, height);
         }
 
@@ -893,26 +1080,28 @@
 // Get elapsed time measure in seconds since InitTimer()
 double GetTime(void)
 {
-    double time = 0.0;
-    /*
-    struct timespec ts = { 0 };
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
-    time = (double)(nanoSeconds - CORE.Time.base)*1e-9;  // Elapsed time since InitTimer()
-    */
-    time = emscripten_get_now()*1000.0;
+    double time = emscripten_get_now()/1000.0;
 
     return time;
 }
 
 // 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
+// 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(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");
+    }
     else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
 }
 
@@ -981,9 +1170,9 @@
 // Register all input events
 void PollInputEvents(void)
 {
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     // NOTE: Gestures update must be called every frame to reset gestures correctly
-    // because ProcessGestureEvent() is just called on an event, not every frame
+    // because ProcessGestureEvent() is called on an event, not every frame
     UpdateGestures();
 #endif
 
@@ -992,7 +1181,7 @@
     CORE.Input.Keyboard.charPressedQueueCount = 0;
 
     // Reset last gamepad button/axis registered state
-    CORE.Input.Gamepad.lastButtonPressed = 0;       // GAMEPAD_BUTTON_UNKNOWN
+    CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
     //CORE.Input.Gamepad.axisCount = 0;
 
     // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
@@ -1063,7 +1252,7 @@
                     default: break;
                 }
 
-                if (button + 1 != 0)   // Check for valid button
+                if (button + 1 != 0) // Check for valid button
                 {
                     if (gamepadState.digitalButton[j] == 1)
                     {
@@ -1126,7 +1315,7 @@
     if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) attribs.antialias = EM_TRUE;
 
     // Check selection OpenGL version
-    if (rlGetVersion() == RL_OPENGL_11_SOFTWARE)
+    if (rlGetVersion() == RL_OPENGL_SOFTWARE)
     {
         // Avoid creating a WebGL canvas, create 2d canvas for software rendering
         emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
@@ -1183,7 +1372,8 @@
         CORE.Window.currentFbo.width = fbWidth;
         CORE.Window.currentFbo.height = fbHeight;
 
-        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+        TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully %s",
+            FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)? "(HighDPI)" : "");
         TRACELOG(LOG_INFO, "    > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
         TRACELOG(LOG_INFO, "    > Screen size:  %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
         TRACELOG(LOG_INFO, "    > Render size:  %i x %i", CORE.Window.render.width, CORE.Window.render.height);
@@ -1319,8 +1509,12 @@
 
     switch (eventType)
     {
-        case EMSCRIPTEN_EVENT_BLUR: FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); break; // The canvas lost focus
-        case EMSCRIPTEN_EVENT_FOCUS: FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); break;
+        case EMSCRIPTEN_EVENT_BLUR:
+        {
+            FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
+            memset(CORE.Input.Keyboard.currentKeyState, 0, sizeof(CORE.Input.Keyboard.currentKeyState));
+        } break;
+        case EMSCRIPTEN_EVENT_FOCUS: FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); break;
         default: consumed = 0; break;
     }
 
@@ -1358,7 +1552,7 @@
 {
     if (count > 0)
     {
-        // In case previous dropped filepaths have not been freed, we free them
+        // In case previous dropped filepaths have not been freed, free them
         if (CORE.Window.dropFileCount > 0)
         {
             for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
@@ -1369,65 +1563,88 @@
             CORE.Window.dropFilepaths = NULL;
         }
 
-        // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
+        // WARNING: Paths are freed by GLFW when the callback returns, an internal copy should be kept
         CORE.Window.dropFileCount = count;
         CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
 
         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]);
         }
     }
 }
 */
 
+// Emscripten keyboard event to raylib key mapping
+static KeyboardKey ConvertKeyboardEventToKey(const EmscriptenKeyboardEvent *keyboardEvent)
+{
+    DOM_PK_CODE_TYPE code = emscripten_compute_dom_pk_code(keyboardEvent->code);
+    KeyboardKey key = KEY_NULL;
+
+    if ((code > DOM_PK_UNKNOWN) && (code < DOM_PK_CODE_MAPPED_NUM)) key = mapDomCodeToKey[code];
+    else if ((code >= DOM_PK_CODE_EXTENDED_OFFSET) && (code < (DOM_PK_CODE_EXTENDED_OFFSET + DOM_PK_CODE_MAPPED_NUM)))
+    {
+        key = mapDomCodeToKeyExtended[code - DOM_PK_CODE_EXTENDED_OFFSET];
+    }
+
+    return key;
+}
+
 // Emscripten: Called on key events
-// TODO: keyCodes should be mapped to raylib/GLFW3 Key values
 static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData)
 {
+    KeyboardKey key = ConvertKeyboardEventToKey(keyboardEvent);
+    EM_BOOL preventDefault = 1;
+
     switch (eventType)
     {
-        case EMSCRIPTEN_EVENT_KEYPRESS:
-        {
-            if (keyboardEvent->repeat) CORE.Input.Keyboard.keyRepeatInFrame[keyboardEvent->keyCode] = 1;
-        } break;
         case EMSCRIPTEN_EVENT_KEYDOWN:
         {
-            CORE.Input.Keyboard.currentKeyState[keyboardEvent->keyCode] = 1;
+            if (key != KEY_NULL)
+            {
+                // Check if there is space available in the key queue
+                if ((!keyboardEvent->repeat) && (CORE.Input.Keyboard.currentKeyState[key] == 0) &&
+                    (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE))
+                {
+                    CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;
+                    CORE.Input.Keyboard.keyPressedQueueCount++;
+                }
+
+                CORE.Input.Keyboard.currentKeyState[key] = 1;
+
+                if (keyboardEvent->repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
+
+                // Check the exit key to set close window
+                if ((key == CORE.Input.Keyboard.exitKey) && !keyboardEvent->repeat) CORE.Window.shouldClose = true;
+            }
+
+            // Allow printable keydown events so the browser can emit the keypress event used to collect characters
+            preventDefault = ((key == KEY_BACKSPACE) || (key == KEY_TAB) ||
+                (key == KEY_INSERT) || (key == KEY_DELETE) ||
+                (key == KEY_HOME) || (key == KEY_END) ||
+                (key == KEY_PAGE_UP) || (key == KEY_PAGE_DOWN) ||
+                (key == KEY_LEFT) || (key == KEY_RIGHT) ||
+                (key == KEY_UP) || (key == KEY_DOWN) ||
+                ((key >= KEY_F1) && (key <= KEY_F12)) || keyboardEvent->ctrlKey);
         } break;
         case EMSCRIPTEN_EVENT_KEYUP:
         {
-            CORE.Input.Keyboard.currentKeyState[keyboardEvent->keyCode] = 0;
+            if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0;
         } break;
+        case EMSCRIPTEN_EVENT_KEYPRESS:
+        {
+            // Check if there is space available in the queue for characters to be added
+            if ((keyboardEvent->charCode > 0) && (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE))
+            {
+                CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = keyboardEvent->charCode;
+                CORE.Input.Keyboard.charPressedQueueCount++;
+            }
+        } break;
         default: break;
     }
 
-    // TODO: Add char codes
-    //unsigned int charCode
-    // Check if there is space available in the queue for characters to be added
-    /*
-    if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
-    {
-        // Add character to the queue
-        CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = keyboardEvent->charCode;
-        CORE.Input.Keyboard.charPressedQueueCount++;
-    }
-    */
-    /*
-    // Check if there is space available in the key queue
-    if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (eventType == EMSCRIPTEN_EVENT_KEYPRESS))
-    {
-        // Add character to the queue
-        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keyboardEvent->keyCode;
-        CORE.Input.Keyboard.keyPressedQueueCount++;
-    }
-
-    // Check the exit key to set close window
-    //if ((keyboardEvent->keyCode == CORE.Input.Keyboard.exitKey) && (eventType == EMSCRIPTEN_EVENT_KEYPRESS)) CORE.Window.shouldClose = true;
-    */
-
-    return 1; // The event was consumed by the callback handler
+    return preventDefault;
 }
 
 // Emscripten: Called on mouse input events
@@ -1435,8 +1652,16 @@
 {
     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
@@ -1455,7 +1680,7 @@
         default: break;
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -1483,7 +1708,8 @@
     if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent);
 #endif
 
-    return 1; // The event was consumed by the callback handler
+    // Don't prevent default to allow focusing on canvas
+    return 0;
 }
 
 // Emscripten: Called on mouse move events
@@ -1497,37 +1723,23 @@
     else
     {
         // Get mouse position in canvas CSS pixels
-        float mouseCssX = (float)mouseEvent->canvasX;
-        float mouseCssY = (float)mouseEvent->canvasY;
+        float mouseCssX = (float)mouseEvent->targetX;
+        float mouseCssY = (float)mouseEvent->targetY;
 
         // Get canvas sizes
         double cssWidth = 0.0;
         double cssHeight = 0.0;
         emscripten_get_element_css_size(platform.canvasId, &cssWidth, &cssHeight);
 
-        int fbWidth = 0;
-        int fbHeight = 0;
-        emscripten_get_canvas_element_size(platform.canvasId, &fbWidth, &fbHeight);
-
-        // Convert CSS to framebuffer coordinates
-        float scaleX = (float)fbWidth/(float)cssWidth;
-        float scaleY = (float)fbHeight/(float)cssHeight;
-
-        int mouseX = (int)(mouseCssX*scaleX);
-        int mouseY = (int)(mouseCssY*scaleY);
-
-        CORE.Input.Mouse.currentPosition.x = mouseX;//(float)mouseEvent->canvasX;
-        CORE.Input.Mouse.currentPosition.y = mouseY;//(float)mouseEvent->canvasY;
-
-        // Shorter alternative:
-        //double dpr = emscripten_get_device_pixel_ratio();
-        //int mouseX = (int)(e->canvasX*dpr);
-        //int mouseY = (int)(e->canvasY*dpr);
+        float normalizedX = mouseCssX/(float)cssWidth;
+        float normalizedY = mouseCssY/(float)cssHeight;
+        CORE.Input.Mouse.currentPosition.x = normalizedX*(float)CORE.Window.screen.width;
+        CORE.Input.Mouse.currentPosition.y = normalizedY*(float)CORE.Window.screen.height;
 
         CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+#if SUPPORT_GESTURES_SYSTEM && SUPPORT_MOUSE_GESTURES
     // Process mouse events as touches to be able to use mouse-gestures
     GestureEvent gestureEvent = { 0 };
 
@@ -1559,7 +1771,7 @@
     if (eventType == EMSCRIPTEN_EVENT_WHEEL)
     {
         CORE.Input.Mouse.currentWheelMove.x = (float)wheelEvent->deltaX;
-        CORE.Input.Mouse.currentWheelMove.y = (float)wheelEvent->deltaY;
+        CORE.Input.Mouse.currentWheelMove.y = -(float)wheelEvent->deltaY;
     }
 
     return 1; // The event was consumed by the callback handler
@@ -1610,7 +1822,7 @@
     double canvasWidth = 0.0;
     double canvasHeight = 0.0;
     // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
-    // we are looking for actual CSS size: canvas.style.width and canvas.style.height
+    // looking for actual CSS size: canvas.style.width and canvas.style.height
     // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
     emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
 
@@ -1630,14 +1842,14 @@
         else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
     }
 
-    // Update mouse position if we detect a single touch
+    // Update mouse position if a single touch is detected
     if (CORE.Input.Touch.pointCount == 1)
     {
         CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x;
         CORE.Input.Mouse.currentPosition.y = CORE.Input.Touch.position[0].y;
     }
 
-#if defined(SUPPORT_GESTURES_SYSTEM)
+#if SUPPORT_GESTURES_SYSTEM
     GestureEvent gestureEvent = { 0 };
     gestureEvent.pointCount = CORE.Input.Touch.pointCount;
 
diff --git a/raylib/src/raudio.c b/raylib/src/raudio.c
--- a/raylib/src/raudio.c
+++ b/raylib/src/raudio.c
@@ -11,22 +11,22 @@
 *       - Play/Stop/Pause/Resume loaded audio
 *
 *   CONFIGURATION:
-*       #define SUPPORT_MODULE_RAUDIO
+*       #define SUPPORT_MODULE_RAUDIO       1
 *           raudio module is included in the build
 *
 *       #define RAUDIO_STANDALONE
 *           Define to use the module as standalone library (independently of raylib)
 *           Required types and functions are defined in the same module
 *
-*       #define SUPPORT_FILEFORMAT_WAV
-*       #define SUPPORT_FILEFORMAT_OGG
-*       #define SUPPORT_FILEFORMAT_MP3
-*       #define SUPPORT_FILEFORMAT_QOA
-*       #define SUPPORT_FILEFORMAT_FLAC
-*       #define SUPPORT_FILEFORMAT_XM
-*       #define SUPPORT_FILEFORMAT_MOD
+*       #define SUPPORT_FILEFORMAT_WAV      1
+*       #define SUPPORT_FILEFORMAT_OGG      1
+*       #define SUPPORT_FILEFORMAT_MP3      1
+*       #define SUPPORT_FILEFORMAT_QOA      1
+*       #define SUPPORT_FILEFORMAT_FLAC     0
+*       #define SUPPORT_FILEFORMAT_XM       1
+*       #define SUPPORT_FILEFORMAT_MOD      1
 *           Selected desired fileformats to be supported for loading. Some of those formats are
-*           supported by default, to remove support, just comment unrequired #define in this module
+*           supported by default, to remove support, #define as 0 in this module or your build system
 *
 *   DEPENDENCIES:
 *       miniaudio.h  - Audio device management lib (https://github.com/mackron/miniaudio)
@@ -77,7 +77,7 @@
     #include "config.h"         // Defines module configuration flags
 #endif
 
-#if defined(SUPPORT_MODULE_RAUDIO) || defined(RAUDIO_STANDALONE)
+#if SUPPORT_MODULE_RAUDIO || defined(RAUDIO_STANDALONE)
 
 #if defined(_WIN32)
 // To avoid conflicting windows.h symbols with raylib, some flags are defined
@@ -200,7 +200,7 @@
     #endif
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
     #define DRWAV_MALLOC RL_MALLOC
     #define DRWAV_REALLOC RL_REALLOC
     #define DRWAV_FREE RL_FREE
@@ -209,12 +209,12 @@
     #include "external/dr_wav.h"        // WAV loading functions
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
     // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE
     #include "external/stb_vorbis.c"    // OGG loading functions
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
     #define DRMP3_MALLOC RL_MALLOC
     #define DRMP3_REALLOC RL_REALLOC
     #define DRMP3_FREE RL_FREE
@@ -223,7 +223,7 @@
     #include "external/dr_mp3.h"        // MP3 loading functions
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
     #define QOA_MALLOC RL_MALLOC
     #define QOA_FREE RL_FREE
 
@@ -243,7 +243,7 @@
     #endif
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
     #define DRFLAC_MALLOC RL_MALLOC
     #define DRFLAC_REALLOC RL_REALLOC
     #define DRFLAC_FREE RL_FREE
@@ -253,7 +253,7 @@
     #include "external/dr_flac.h"       // FLAC loading functions
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
     #define JARXM_MALLOC RL_MALLOC
     #define JARXM_FREE RL_FREE
 
@@ -270,7 +270,7 @@
     #endif
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_MOD)
+#if SUPPORT_FILEFORMAT_MOD
     #define JARMOD_MALLOC RL_MALLOC
     #define JARMOD_FREE RL_FREE
 
@@ -290,11 +290,18 @@
 #ifndef AUDIO_DEVICE_SAMPLE_RATE
     #define AUDIO_DEVICE_SAMPLE_RATE           0    // Device output sample rate
 #endif
+#ifndef AUDIO_DEVICE_PERIOD_SIZE_IN_FRAMES
+    #define AUDIO_DEVICE_PERIOD_SIZE_IN_FRAMES 0    // Device latency. 0 defaults to 10ms
+#endif
 
 #ifndef MAX_AUDIO_BUFFER_POOL_CHANNELS
     #define MAX_AUDIO_BUFFER_POOL_CHANNELS    16    // Audio pool channels
 #endif
 
+#ifndef AUDIO_BUFFER_RESIDUAL_CAPACITY
+    #define AUDIO_BUFFER_RESIDUAL_CAPACITY     8    // In PCM frames, for resampling and pitch shifting
+#endif
+
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
@@ -337,13 +344,15 @@
 // 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 int converterResidualCount;    // The number of valid frames sitting in converterResidual
 
     AudioCallback callback;         // Audio buffer callback for buffer filling on audio threads
     rAudioProcessor *processor;     // Audio processor
 
     float volume;                   // Audio buffer volume
     float pitch;                    // Audio buffer pitch
-    float pan;                      // Audio buffer pan (0.0f to 1.0f)
+    float pan;                      // Audio buffer pan (-1.0f to 1.0f)
 
     bool playing;                   // Audio buffer state: AUDIO_PLAYING
     bool paused;                    // Audio buffer state: AUDIO_PAUSED
@@ -369,7 +378,7 @@
     rAudioProcessor *prev;          // Previous audio processor on the list
 };
 
-#define AudioBuffer rAudioBuffer    // HACK: To avoid CoreAudio (macOS) symbol collision
+#define AudioBuffer rAudioBuffer    // WARNING: Renamed to avoid symbol collision with CoreAudio (macOS) AudioBuffer type
 
 // Audio data context
 typedef struct AudioData {
@@ -397,7 +406,7 @@
     // NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
     // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
     // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
-    // In case of music-stalls, just increase this number
+    // In case of music-stalls, increase this number
     .Buffer.defaultSize = 0,
     .mixedProcessor = NULL
 };
@@ -425,6 +434,7 @@
 static const char *GetFileNameWithoutExt(const char *filePath);     // Get filename string without extension (uses static string)
 
 static unsigned char *LoadFileData(const char *fileName, int *dataSize);    // Load file data as byte array (read)
+static void UnloadFileData(unsigned char *data);                     // Unload file data allocated by LoadFileData()
 static bool SaveFileData(const char *fileName, void *data, int dataSize);   // Save data to file from byte array (write)
 static bool SaveFileText(const char *fileName, char *text);         // Save text data to file (write), string must be '\0' terminated
 #endif
@@ -471,12 +481,12 @@
     config.playback.pDeviceID = NULL;  // NULL for the default playback AUDIO.System.device
     config.playback.format = AUDIO_DEVICE_FORMAT;
     config.playback.channels = AUDIO_DEVICE_CHANNELS;
-    config.capture.pDeviceID = NULL;  // NULL for the default capture AUDIO.System.device
-    config.capture.format = ma_format_s16;
-    config.capture.channels = 1;
     config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
+    config.periodSizeInFrames = AUDIO_DEVICE_PERIOD_SIZE_IN_FRAMES;
     config.dataCallback = OnSendAudioDataToDevice;
     config.pUserData = NULL;
+    config.noPreSilencedOutputBuffer = true;    // raylib pre-silences the output buffer manually
+    config.noFixedSizedCallback = true;         // raylib does not require fixed sized callback guarantees. This bypasses an internal intermediary buffer
 
     result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
     if (result != MA_SUCCESS)
@@ -486,8 +496,9 @@
         return;
     }
 
-    // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
-    // want to look at something a bit smarter later on to keep everything real-time, if that's necessary
+    // Mixing happens on a separate thread which means synchronization is needed
+    // A mutex is used here to make things simple, but may want to look at something
+    // a bit smarter later on to keep everything real-time, if that's necessary
     if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS)
     {
         TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing");
@@ -522,8 +533,9 @@
 {
     if (AUDIO.System.isReady)
     {
-        ma_mutex_uninit(&AUDIO.System.lock);
+        // Stop the device first (joins the callback thread) before destroying the mutex it locks
         ma_device_uninit(&AUDIO.System.device);
+        ma_mutex_uninit(&AUDIO.System.lock);
         ma_context_uninit(&AUDIO.System.context);
 
         AUDIO.System.isReady = false;
@@ -586,6 +598,15 @@
         return NULL;
     }
 
+    // A cache for use by the converter is necessary when resampling because
+    // when generating output frames a different number of input frames will
+    // be consumed. Any residual input frames need to be kept track of to
+    // ensure there are no discontinuities. Since raylib supports pitch
+    // shifting, which is done through resampling, a cache will always be
+    // required. This will be kept relatively small to avoid too much wastage
+    audioBuffer->converterResidualCount = 0;
+    audioBuffer->converterResidual = (unsigned char*)RL_CALLOC(AUDIO_BUFFER_RESIDUAL_CAPACITY*ma_get_bytes_per_frame(format, channels), 1);
+
     // Init audio buffer values
     audioBuffer->volume = 1.0f;
     audioBuffer->pitch = 1.0f;
@@ -621,6 +642,7 @@
     {
         UntrackAudioBuffer(buffer);
         ma_data_converter_uninit(&buffer->converter, NULL);
+        RL_FREE(buffer->converterResidual);
         RL_FREE(buffer->data);
         RL_FREE(buffer);
     }
@@ -701,11 +723,11 @@
     if ((buffer != NULL) && (pitch > 0.0f))
     {
         ma_mutex_lock(&AUDIO.System.lock);
-        // Pitching is just an adjustment of the sample rate
+        // Pitching is an adjustment of the sample rate
         // Note that this changes the duration of the sound:
         //  - higher pitches will make the sound faster
         //  - lower pitches make it slower
-        ma_uint32 outputSampleRate = (ma_uint32)((float)buffer->converter.sampleRateOut/pitch);
+        ma_uint32 outputSampleRate = (ma_uint32)((float)AUDIO.System.device.sampleRate/pitch);
         ma_data_converter_set_rate(&buffer->converter, buffer->converter.sampleRateIn, outputSampleRate);
 
         buffer->pitch = pitch;
@@ -789,7 +811,7 @@
     Wave wave = { 0 };
 
     if (false) { }
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
     else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
     {
         drwav wav = { 0 };
@@ -801,9 +823,9 @@
             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: We are forcing conversion to 16bit sample size on reading
+            // NOTE: Forcing conversion to 16bit sample size on reading
             drwav_read_pcm_frames_s16(&wav, wave.frameCount, (drwav_int16 *)wave.data);
         }
         else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data");
@@ -811,7 +833,7 @@
         drwav_uninit(&wav);
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
     else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0))
     {
         stb_vorbis *oggData = stb_vorbis_open_memory((unsigned char *)fileData, dataSize, NULL, NULL);
@@ -824,22 +846,22 @@
             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! we ask for number of shorts, not bytes!)
+            // 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);
             stb_vorbis_close(oggData);
         }
         else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data");
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
     else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
     {
         drmp3_config config = { 0 };
-        unsigned long long int totalFrameCount = 0;
+        unsigned long long totalFrameCount = 0;
 
-        // NOTE: We are forcing conversion to 32bit float sample size on reading
+        // NOTE: Forcing conversion to 32bit float sample size on reading
         wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL);
         wave.sampleSize = 32;
 
@@ -847,13 +869,13 @@
         {
             wave.channels = config.channels;
             wave.sampleRate = config.sampleRate;
-            wave.frameCount = (int)totalFrameCount;
+            wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
         }
         else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data");
 
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
     else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0))
     {
         qoa_desc qoa = { 0 };
@@ -872,16 +894,16 @@
 
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
     else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
     {
-        unsigned long long int totalFrameCount = 0;
+        unsigned long long totalFrameCount = 0;
 
-        // NOTE: We are forcing conversion to 16bit sample size on reading
+        // NOTE: Forcing conversion to 16bit sample size on reading
         wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
         wave.sampleSize = 16;
 
-        if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount;
+        if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount; // WARNING: Potential loss of data
         else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
     }
 #endif
@@ -892,7 +914,7 @@
     return wave;
 }
 
-// Checks if wave data is valid (data loaded and parameters)
+// Check if wave data is valid (data loaded and parameters)
 bool IsWaveValid(Wave wave)
 {
     bool result = false;
@@ -914,7 +936,7 @@
 
     Sound sound = LoadSoundFromWave(wave);
 
-    UnloadWave(wave);       // Sound is loaded, we can unload wave
+    UnloadWave(wave); // Sound is loaded, wave can be unloaded
 
     return sound;
 }
@@ -927,9 +949,9 @@
 
     if (wave.data != NULL)
     {
-        // When using miniaudio we need to do our own mixing
-        // To simplify this we need convert the format of each sound to be consistent with
-        // the format used to open the playback AUDIO.System.device. We can do this two ways:
+        // When using miniaudio mixing needs to b done manually
+        // To simplify this, the format of each sound needs to be converted to be consistent with
+        // the format used to open the playback AUDIO.System.device. It can be done in two ways:
         //
         //   1) Convert the whole sound in one go at load time (here)
         //   2) Convert the audio data in chunks at mixing time
@@ -943,26 +965,24 @@
         if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed to get frame count for format conversion");
 
         AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, frameCount, AUDIO_BUFFER_USAGE_STATIC);
-        if (audioBuffer == NULL)
+        if (audioBuffer != NULL)
         {
-            TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
-            return sound; // early return to avoid dereferencing the audioBuffer null pointer
-        }
-
-        frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
-        if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion");
+            frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
+            if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion");
 
-        sound.frameCount = frameCount;
-        sound.stream.sampleRate = AUDIO.System.device.sampleRate;
-        sound.stream.sampleSize = 32;
-        sound.stream.channels = AUDIO_DEVICE_CHANNELS;
-        sound.stream.buffer = audioBuffer;
+            sound.frameCount = frameCount;
+            sound.stream.sampleRate = AUDIO.System.device.sampleRate;
+            sound.stream.sampleSize = 32;
+            sound.stream.channels = AUDIO_DEVICE_CHANNELS;
+            sound.stream.buffer = audioBuffer;
+        }
+        else TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
     }
 
     return sound;
 }
 
-// Clone sound from existing sound data, clone does not own wave data
+// Load sound alias, clone sound from existing sound data, clone does not own wave data
 // NOTE: Wave data must be unallocated manually and will be shared across all clones
 Sound LoadSoundAlias(Sound source)
 {
@@ -972,31 +992,29 @@
     {
         AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);
 
-        if (audioBuffer == NULL)
+        if (audioBuffer != NULL)
         {
-            TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
-            return sound; // Early return to avoid dereferencing the audioBuffer null pointer
-        }
-
-        audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
-        audioBuffer->data = source.stream.buffer->data;
+            audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
+            audioBuffer->data = source.stream.buffer->data;
 
-        // Initalize the buffer as if it was new
-        audioBuffer->volume = 1.0f;
-        audioBuffer->pitch = 1.0f;
-        audioBuffer->pan = 0.0f; // Center
+            // Initalize the buffer as if it was new
+            audioBuffer->volume = 1.0f;
+            audioBuffer->pitch = 1.0f;
+            audioBuffer->pan = 0.0f; // Center
 
-        sound.frameCount = source.frameCount;
-        sound.stream.sampleRate = AUDIO.System.device.sampleRate;
-        sound.stream.sampleSize = 32;
-        sound.stream.channels = AUDIO_DEVICE_CHANNELS;
-        sound.stream.buffer = audioBuffer;
+            sound.frameCount = source.frameCount;
+            sound.stream.sampleRate = AUDIO.System.device.sampleRate;
+            sound.stream.sampleSize = 32;
+            sound.stream.channels = AUDIO_DEVICE_CHANNELS;
+            sound.stream.buffer = audioBuffer;
+        }
+        else TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
     }
 
     return sound;
 }
 
-// Checks if a sound is valid (data loaded and buffers initialized)
+// Check if sound is valid (data loaded and buffers initialized)
 bool IsSoundValid(Sound sound)
 {
     bool result = false;
@@ -1026,11 +1044,12 @@
 
 void UnloadSoundAlias(Sound alias)
 {
-    // Untrack and unload just the sound buffer, not the sample data, it is shared with the source for the alias
+    // Untrack and unload the sound buffer, not the sample data, it is shared with the source for the alias
     if (alias.stream.buffer != NULL)
     {
         UntrackAudioBuffer(alias.stream.buffer);
         ma_data_converter_uninit(&alias.stream.buffer->converter, NULL);
+        RL_FREE(alias.stream.buffer->converterResidual);
         RL_FREE(alias.stream.buffer);
     }
 }
@@ -1051,10 +1070,10 @@
 // Export wave data to file
 bool ExportWave(Wave wave, const char *fileName)
 {
-    bool success = false;
+    bool result = false;
 
     if (false) { }
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
     else if (IsFileExtension(fileName, ".wav"))
     {
         drwav wav = { 0 };
@@ -1068,16 +1087,16 @@
 
         void *fileData = NULL;
         size_t fileDataSize = 0;
-        success = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL);
-        if (success) success = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data);
+        result = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL);
+        if (result) result = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data);
         drwav_result result = drwav_uninit(&wav);
 
-        if (result == DRWAV_SUCCESS) success = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize);
+        if (result == DRWAV_SUCCESS) result = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize);
 
         drwav_free(fileData, NULL);
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
     else if (IsFileExtension(fileName, ".qoa"))
     {
         if (wave.sampleSize == 16)
@@ -1088,7 +1107,7 @@
             qoa.samples = wave.frameCount;
 
             int bytesWritten = qoa_write(fileName, (const short *)wave.data, &qoa);
-            if (bytesWritten > 0) success = true;
+            if (bytesWritten > 0) result = true;
         }
         else TRACELOG(LOG_WARNING, "AUDIO: Wave data must be 16 bit per sample for QOA format export");
     }
@@ -1097,19 +1116,19 @@
     {
         // Export raw sample data (without header)
         // NOTE: It's up to the user to track wave parameters
-        success = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
+        result = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
     }
 
-    if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName);
+    if (result) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName);
     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave data", fileName);
 
-    return success;
+    return result;
 }
 
 // Export wave sample data to code (.h)
 bool ExportWaveAsCode(Wave wave, const char *fileName)
 {
-    bool success = false;
+    bool result = false;
 
 #ifndef TEXT_BYTES_PER_LINE
     #define TEXT_BYTES_PER_LINE     20
@@ -1136,7 +1155,7 @@
 
     // 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
@@ -1163,14 +1182,14 @@
     }
 
     // NOTE: Text data length exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
+    result = SaveFileText(fileName, txtData);
 
     RL_FREE(txtData);
 
-    if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName);
+    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName);
     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave as code", fileName);
 
-    return success;
+    return result;
 }
 
 // Play a sound
@@ -1197,7 +1216,7 @@
     StopAudioBuffer(sound.stream.buffer);
 }
 
-// Check if a sound is playing
+// Check if sound is playing
 bool IsSoundPlaying(Sound sound)
 {
     bool result = false;
@@ -1240,7 +1259,7 @@
         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)
@@ -1335,7 +1354,7 @@
     bool musicLoaded = false;
 
     if (false) { }
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
     else if (IsFileExtension(fileName, ".wav"))
     {
         drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
@@ -1359,7 +1378,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
     else if (IsFileExtension(fileName, ".ogg"))
     {
         // Open ogg audio stream
@@ -1374,9 +1393,9 @@
             // OGG bit rate defaults to 16 bit, it's enough for compressed format
             music.stream = LoadAudioStream(info.sample_rate, 16, info.channels);
 
-            // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
+            // WARNING: It seems this function returns length in frames, not samples, so multiply by channels
             music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
-            music.looping = true;   // Looping enabled by default
+            music.looping = true; // Looping enabled by default
             musicLoaded = true;
         }
         else
@@ -1385,7 +1404,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
     else if (IsFileExtension(fileName, ".mp3"))
     {
         drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
@@ -1406,7 +1425,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
     else if (IsFileExtension(fileName, ".qoa"))
     {
         qoaplay_desc *ctxQoa = qoaplay_open(fileName);
@@ -1415,8 +1434,8 @@
         {
             music.ctxType = MUSIC_AUDIO_QOA;
             music.ctxData = ctxQoa;
-            // NOTE: We are loading samples are 32bit float normalized data, so,
-            // we configure the output audio stream to also use float 32bit
+            // NOTE: Loading samples as 32bit float normalized data, so,
+            // configure the output audio stream to also use float 32bit
             music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels);
             music.frameCount = ctxQoa->info.samples;
             music.looping = true;   // Looping enabled by default
@@ -1425,7 +1444,7 @@
         else{} //No uninit required
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
     else if (IsFileExtension(fileName, ".flac"))
     {
         drflac *ctxFlac = drflac_open_file(fileName, NULL);
@@ -1447,7 +1466,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
     else if (IsFileExtension(fileName, ".xm"))
     {
         jar_xm_context_t *ctxXm = NULL;
@@ -1467,7 +1486,7 @@
             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, AUDIO_DEVICE_CHANNELS);
             music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);    // NOTE: Always 2 channels (stereo)
             music.looping = true;   // Looping enabled by default
-            jar_xm_reset(ctxXm);    // Make sure we start at the beginning of the song
+            jar_xm_reset(ctxXm);    // Make sure to start at the beginning of the song
             musicLoaded = true;
         }
         else
@@ -1476,7 +1495,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_MOD)
+#if SUPPORT_FILEFORMAT_MOD
     else if (IsFileExtension(fileName, ".mod"))
     {
         jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t));
@@ -1527,7 +1546,7 @@
     bool musicLoaded = false;
 
     if (false) { }
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
     else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
     {
         drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
@@ -1553,7 +1572,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
     else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0))
     {
         // Open ogg audio stream
@@ -1568,7 +1587,7 @@
             // OGG bit rate defaults to 16 bit, it's enough for compressed format
             music.stream = LoadAudioStream(info.sample_rate, 16, info.channels);
 
-            // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
+            // WARNING: It seems this function returns length in frames, not samples, so multiply by channels
             music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
             music.looping = true;   // Looping enabled by default
             musicLoaded = true;
@@ -1579,7 +1598,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
     else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
     {
         drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
@@ -1601,7 +1620,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
     else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0))
     {
         qoaplay_desc *ctxQoa = NULL;
@@ -1614,8 +1633,9 @@
         {
             music.ctxType = MUSIC_AUDIO_QOA;
             music.ctxData = ctxQoa;
-            // NOTE: We are loading samples are 32bit float normalized data, so,
-            // we configure the output audio stream to also use float 32bit
+
+            // NOTE: Loading samples are 32bit float normalized data, so,
+            // configure the output audio stream to also use float 32bit
             music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels);
             music.frameCount = ctxQoa->info.samples;
             music.looping = true;   // Looping enabled by default
@@ -1624,7 +1644,7 @@
         else{} //No uninit required
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
     else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
     {
         drflac *ctxFlac = drflac_open_memory((const void *)data, dataSize, NULL);
@@ -1646,7 +1666,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
     else if ((strcmp(fileType, ".xm") == 0) || (strcmp(fileType, ".XM") == 0))
     {
         jar_xm_context_t *ctxXm = NULL;
@@ -1665,7 +1685,7 @@
             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, 2);
             music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);    // NOTE: Always 2 channels (stereo)
             music.looping = true;   // Looping enabled by default
-            jar_xm_reset(ctxXm);    // Make sure we start at the beginning of the song
+            jar_xm_reset(ctxXm);    // Make sure to start at the beginning of the song
 
             musicLoaded = true;
         }
@@ -1675,7 +1695,7 @@
         }
     }
 #endif
-#if defined(SUPPORT_FILEFORMAT_MOD)
+#if SUPPORT_FILEFORMAT_MOD
     else if ((strcmp(fileType, ".mod") == 0) || (strcmp(fileType, ".MOD") == 0))
     {
         jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_MALLOC(sizeof(jar_mod_context_t));
@@ -1685,8 +1705,7 @@
 
         // Copy data to allocated memory for default UnloadMusicStream
         unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize);
-        int it = dataSize/sizeof(unsigned char);
-        for (int i = 0; i < it; i++) newData[i] = data[i];
+        for (int i = 0; i < dataSize; i++) newData[i] = data[i];
 
         // Memory loaded version for jar_mod_load_file()
         if (dataSize && (dataSize < 32*1024*1024))
@@ -1733,7 +1752,7 @@
     return music;
 }
 
-// Checks if a music stream is valid (context and buffers initialized)
+// Check if music stream is valid (context and buffers initialized)
 bool IsMusicValid(Music music)
 {
     return ((music.ctxData != NULL) &&          // Validate context loaded
@@ -1746,30 +1765,32 @@
 // Unload music stream
 void UnloadMusicStream(Music music)
 {
+    if (IsMusicStreamPlaying(music)) StopMusicStream(music);
+
     UnloadAudioStream(music.stream);
 
     if (music.ctxData != NULL)
     {
         if (false) { }
-#if defined(SUPPORT_FILEFORMAT_WAV)
-        else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
+#if SUPPORT_FILEFORMAT_WAV
+        else if (music.ctxType == MUSIC_AUDIO_WAV) { drwav_uninit((drwav *)music.ctxData); RL_FREE(music.ctxData); }
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
         else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
         else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
         else if (music.ctxType == MUSIC_AUDIO_QOA) qoaplay_close((qoaplay_desc *)music.ctxData);
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
-        else if (music.ctxType == MUSIC_AUDIO_FLAC) { drflac_close((drflac *)music.ctxData); drflac_free((drflac *)music.ctxData, NULL); }
+#if SUPPORT_FILEFORMAT_FLAC
+        else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_close((drflac *)music.ctxData);
 #endif
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
         else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
 #endif
-#if defined(SUPPORT_FILEFORMAT_MOD)
+#if SUPPORT_FILEFORMAT_MOD
         else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
 #endif
     }
@@ -1800,25 +1821,25 @@
 
     switch (music.ctxType)
     {
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
         case MUSIC_AUDIO_WAV: drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
         case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
         case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
         case MUSIC_AUDIO_QOA: qoaplay_rewind((qoaplay_desc *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
         case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
         case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_MOD)
+#if SUPPORT_FILEFORMAT_MOD
         case MUSIC_MODULE_MOD: jar_mod_seek_start((jar_mod_context_t *)music.ctxData); break;
 #endif
         default: break;
@@ -1835,26 +1856,26 @@
 
     switch (music.ctxType)
     {
-#if defined(SUPPORT_FILEFORMAT_WAV)
+#if SUPPORT_FILEFORMAT_WAV
         case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, positionInFrames); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_OGG)
+#if SUPPORT_FILEFORMAT_OGG
         case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_MP3)
+#if SUPPORT_FILEFORMAT_MP3
         case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_QOA)
+#if SUPPORT_FILEFORMAT_QOA
         case MUSIC_AUDIO_QOA:
         {
             int qoaFrame = positionInFrames/QOA_FRAME_LEN;
             qoaplay_seek_frame((qoaplay_desc *)music.ctxData, qoaFrame); // Seeks to QOA frame, not PCM frame
 
-            // We need to compute QOA frame number and update positionInFrames
+            // Compute QOA frame number and update positionInFrames
             positionInFrames = ((qoaplay_desc *)music.ctxData)->sample_position;
         } break;
 #endif
-#if defined(SUPPORT_FILEFORMAT_FLAC)
+#if SUPPORT_FILEFORMAT_FLAC
         case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break;
 #endif
         default: break;
@@ -1877,7 +1898,7 @@
 
     unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2;
 
-    // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in
+    // On first call of this function, lazily pre-allocated a temp buffer to read audio files/memory data in
     int frameSize = music.stream.channels*music.stream.sampleSize/8;
     unsigned int pcmSize = subBufferSizeInFrames*frameSize;
 
@@ -1918,7 +1939,7 @@
 
         switch (music.ctxType)
         {
-        #if defined(SUPPORT_FILEFORMAT_WAV)
+        #if SUPPORT_FILEFORMAT_WAV
             case MUSIC_AUDIO_WAV:
             {
                 if (music.stream.sampleSize == 16)
@@ -1945,7 +1966,7 @@
                 }
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_OGG)
+        #if SUPPORT_FILEFORMAT_OGG
             case MUSIC_AUDIO_OGG:
             {
                 while (true)
@@ -1958,7 +1979,7 @@
                 }
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_MP3)
+        #if SUPPORT_FILEFORMAT_MP3
             case MUSIC_AUDIO_MP3:
             {
                 while (true)
@@ -1971,7 +1992,7 @@
                 }
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_QOA)
+        #if SUPPORT_FILEFORMAT_QOA
             case MUSIC_AUDIO_QOA:
             {
                 unsigned int frameCountRead = qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream);
@@ -1988,7 +2009,7 @@
                 */
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_FLAC)
+        #if SUPPORT_FILEFORMAT_FLAC
             case MUSIC_AUDIO_FLAC:
             {
                 while (true)
@@ -2001,10 +2022,10 @@
                 }
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_XM)
+        #if SUPPORT_FILEFORMAT_XM
             case MUSIC_MODULE_XM:
             {
-                // NOTE: Internally we consider 2 channels generation, so sampleCount/2
+                // NOTE: Internally considering 2 channels generation, so sampleCount/2
                 if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream);
                 else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream);
                 else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream);
@@ -2012,10 +2033,10 @@
 
             } break;
         #endif
-        #if defined(SUPPORT_FILEFORMAT_MOD)
+        #if SUPPORT_FILEFORMAT_MOD
             case MUSIC_MODULE_MOD:
             {
-                // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
+                // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples desired, so sampleCount/2
                 jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0);
                 //jar_mod_seek_start((jar_mod_context_t *)music.ctxData);
 
@@ -2048,7 +2069,7 @@
     SetAudioBufferPitch(music.stream.buffer, pitch);
 }
 
-// Set pan for a music
+// Set pan for music
 void SetMusicPan(Music music, float pan)
 {
     SetAudioBufferPan(music.stream.buffer, pan);
@@ -2070,7 +2091,7 @@
     float secondsPlayed = 0.0f;
     if (music.stream.buffer != NULL)
     {
-#if defined(SUPPORT_FILEFORMAT_XM)
+#if SUPPORT_FILEFORMAT_XM
         if (music.ctxType == MUSIC_MODULE_XM)
         {
             uint64_t framesPlayed = 0;
@@ -2136,7 +2157,7 @@
     return stream;
 }
 
-// Checks if an audio stream is valid (buffers initialized)
+// Check if an audio stream is valid (buffers initialized)
 bool IsAudioStreamValid(AudioStream stream)
 {
     return ((stream.buffer != NULL) &&    // Validate stream buffer
@@ -2166,12 +2187,15 @@
 // Check if any audio stream buffers requires refill
 bool IsAudioStreamProcessed(AudioStream stream)
 {
-    if (stream.buffer == NULL) return false;
-
     bool result = false;
-    ma_mutex_lock(&AUDIO.System.lock);
-    result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1];
-    ma_mutex_unlock(&AUDIO.System.lock);
+
+    if (stream.buffer != NULL)
+    {
+        ma_mutex_lock(&AUDIO.System.lock);
+        result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1];
+        ma_mutex_unlock(&AUDIO.System.lock);
+    }
+
     return result;
 }
 
@@ -2242,7 +2266,7 @@
 
 // Add processor to audio stream. Contrary to buffers, the order of processors is important
 // The new processor must be added at the end. As there aren't supposed to be a lot of processors attached to
-// a given stream, we iterate through the list to find the end. That way we don't need a pointer to the last element
+// a given stream, iterate through the list to find the end. That way there is no need to keep a pointer to the last element
 void AttachAudioStreamProcessor(AudioStream stream, AudioCallback process)
 {
     ma_mutex_lock(&AUDIO.System.lock);
@@ -2295,7 +2319,7 @@
 
 // Add processor to audio pipeline. Order of processors is important
 // Works the same way as {Attach,Detach}AudioStreamProcessor() functions, except
-// these two work on the already mixed output just before sending it to the sound hardware
+// these two work on the already mixed output before sending it to the sound hardware
 void AttachAudioMixedProcessor(AudioCallback process)
 {
     ma_mutex_lock(&AUDIO.System.lock);
@@ -2358,6 +2382,9 @@
 // Reads audio data from an AudioBuffer object in internal format
 static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount)
 {
+    // Don't read anything if the sound is not playing
+    if (!audioBuffer->playing) return 0;
+
     // Using audio buffer callback
     if (audioBuffer->callback)
     {
@@ -2373,20 +2400,20 @@
     if (currentSubBufferIndex > 1) return 0;
 
     // Another thread can update the processed state of buffers, so
-    // we just take a copy here to try and avoid potential synchronization problems
+    // take a copy here to try and avoid potential synchronization problems
     bool isSubBufferProcessed[2] = { 0 };
     isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
     isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
 
     ma_uint32 frameSizeInBytes = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
 
-    // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0
+    // Fill out every frame until a buffer that's marked as processed is found, then fill the remainder with 0
     ma_uint32 framesRead = 0;
     while (1)
     {
-        // We break from this loop differently depending on the buffer's usage
-        //  - For static buffers, we simply fill as much data as we can
-        //  - For streaming buffers we only fill half of the buffer that are processed
+        // Break from this loop differently depending on the buffer's usage
+        //  - For static buffers, simply fill as much data as possible
+        //  - For streaming buffers, only fill half of the buffer that are processed
         //    Unprocessed halves must keep their audio data in-tact
         if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
         {
@@ -2418,7 +2445,7 @@
         audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->sizeInFrames;
         framesRead += framesToRead;
 
-        // If we've read to the end of the buffer, mark it as processed
+        // If the end of the buffer is read, mark it as processed
         if (framesToRead == framesRemainingInOutputBuffer)
         {
             audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
@@ -2426,7 +2453,7 @@
 
             currentSubBufferIndex = (currentSubBufferIndex + 1)%2;
 
-            // We need to break from this loop if we're not looping
+            // Break from this loop if looping not enabled
             if (!audioBuffer->looping)
             {
                 StopAudioBufferInLockedState(audioBuffer);
@@ -2441,8 +2468,8 @@
     {
         memset((unsigned char *)framesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes);
 
-        // For static buffers we can fill the remaining frames with silence for safety, but we don't want
-        // to report those frames as "read". The reason for this is that the caller uses the return value
+        // For static buffers, fill the remaining frames with silence for safety, but don't report those
+        // frames as "read"; The reason for this is that the caller uses the return value
         // to know whether a non-looping sound has finished playback
         if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining;
     }
@@ -2453,39 +2480,76 @@
 // Reads audio data from an AudioBuffer object in device format, returned data will be in a format appropriate for mixing
 static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
 {
-    // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which
-    // should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important
-    // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
-    // frames. This can be achieved with ma_data_converter_get_required_input_frame_count()
+    // NOTE: Continuously converting data from the AudioBuffer's internal format to the mixing format,
+    // which should be defined by the output format of the data converter
+    // This is done until frameCount frames have been output
+    ma_uint32 bpf = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
     ma_uint8 inputBuffer[4096] = { 0 };
-    ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
+    ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/bpf;
 
     ma_uint32 totalOutputFramesProcessed = 0;
     while (totalOutputFramesProcessed < frameCount)
     {
+        float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut);
         ma_uint64 outputFramesToProcessThisIteration = frameCount - totalOutputFramesProcessed;
-        ma_uint64 inputFramesToProcessThisIteration = 0;
+        //ma_uint64 inputFramesToProcessThisIteration = 0;
 
-        (void)ma_data_converter_get_required_input_frame_count(&audioBuffer->converter, outputFramesToProcessThisIteration, &inputFramesToProcessThisIteration);
-        if (inputFramesToProcessThisIteration > inputBufferFrameCap)
+        // Process any residual input frames from the previous read first
+        if (audioBuffer->converterResidualCount > 0)
         {
-            inputFramesToProcessThisIteration = inputBufferFrameCap;
+            ma_uint64 inputFramesProcessedThisIteration = audioBuffer->converterResidualCount;
+            ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
+            ma_data_converter_process_pcm_frames(&audioBuffer->converter, audioBuffer->converterResidual, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
+
+            // Make sure the data in the cache is consumed, this can be optimized to use a cursor instead of a memmove()
+            memmove(audioBuffer->converterResidual, audioBuffer->converterResidual + inputFramesProcessedThisIteration*bpf, (size_t)(AUDIO_BUFFER_RESIDUAL_CAPACITY - inputFramesProcessedThisIteration)*bpf);
+            audioBuffer->converterResidualCount -= (ma_uint32)inputFramesProcessedThisIteration; // Safe cast
+
+            totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast
         }
+        else
+        {
+            // Getting here means there are no residual frames from the previous read
+            // Fresh data can now be pulled from the AudioBuffer and processed
+            //
+            // A best guess needs to be used made to determine how many input frames to pull from the buffer
+            // There are three possible outcomes: 1) exact; 2) underestimated; 3) overestimated
+            //
+            // When the guess is exactly correct or underestimated there is nothing special to handle,
+            // it'll be handled naturally by the loop
+            //
+            // When the guess is overestimated, that's when it gets more complicated
+            // In this case, any overflow needs to be stored in a buffer for later processing by the next read
+            ma_uint32 estimatedInputFrameCount = (ma_uint32)(((float)audioBuffer->converter.resampler.sampleRateIn / audioBuffer->converter.resampler.sampleRateOut)*outputFramesToProcessThisIteration);
+            if (estimatedInputFrameCount == 0) estimatedInputFrameCount = 1; // Make sure at least one input frame is read
+            if (estimatedInputFrameCount > inputBufferFrameCap) estimatedInputFrameCount = inputBufferFrameCap;
 
-        float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut);
+            ma_uint32 inputFramesInInternalFormatCount = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, estimatedInputFrameCount);
 
-        // At this point we can convert the data to our mixing format
-        ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration);
-        ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
-        ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
+            ma_uint64 inputFramesProcessedThisIteration = inputFramesInInternalFormatCount;
+            ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
+            ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
 
-        totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast
+            totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration;
 
-        if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration) break;  // Ran out of input data
+            if (inputFramesInInternalFormatCount > inputFramesProcessedThisIteration)
+            {
+                // Getting here means the estimated input frame count was overestimated
+                // The residual needs be stored for later use
+                ma_uint64 residualFrameCount = inputFramesInInternalFormatCount - inputFramesProcessedThisIteration;
 
-        // This should never be hit, but added here for safety
-        // Ensures we get out of the loop when no input nor output frames are processed
-        if ((inputFramesProcessedThisIteration == 0) && (outputFramesProcessedThisIteration == 0)) break;
+                // A safety check to make sure the capacity of the residual cache is not exceeded
+                if (residualFrameCount > AUDIO_BUFFER_RESIDUAL_CAPACITY)
+                {
+                    residualFrameCount = AUDIO_BUFFER_RESIDUAL_CAPACITY;
+                }
+
+                memcpy(audioBuffer->converterResidual, inputBuffer + inputFramesProcessedThisIteration*bpf, (size_t)(residualFrameCount*bpf));
+                audioBuffer->converterResidualCount = (unsigned int)residualFrameCount;
+            }
+
+            if (inputFramesInInternalFormatCount < estimatedInputFrameCount) break;  // Reached the end of the sound
+        }
     }
 
     return totalOutputFramesProcessed;
@@ -2498,11 +2562,11 @@
 {
     (void)pDevice;
 
-    // Mixing is basically just an accumulation, we need to initialize the output buffer to 0
+    // Mixing is basically an accumulation, need to initialize the output buffer to 0
     memset(pFramesOut, 0, frameCount*pDevice->playback.channels*ma_get_bytes_per_sample(pDevice->playback.format));
 
     // Using a mutex here for thread-safety which makes things not real-time
-    // This is unlikely to be necessary for this project, but may want to consider how you might want to avoid this
+    // This is unlikely to be necessary for this project, but it can be reconsidered
     ma_mutex_lock(&AUDIO.System.lock);
     {
         for (AudioBuffer *audioBuffer = AUDIO.Buffer.first; audioBuffer != NULL; audioBuffer = audioBuffer->next)
@@ -2516,7 +2580,7 @@
             {
                 if (framesRead >= frameCount) break;
 
-                // Just read as much data as we can from the stream
+                // Read as much data as possible from the stream
                 ma_uint32 framesToRead = (frameCount - framesRead);
 
                 while (framesToRead > 0)
@@ -2555,7 +2619,7 @@
                         break;
                     }
 
-                    // If we weren't able to read all the frames we requested, break
+                    // If all the frames requested can't be read, break
                     if (framesJustRead < framesToReadRightNow)
                     {
                         if (!audioBuffer->looping)
@@ -2565,7 +2629,7 @@
                         }
                         else
                         {
-                            // Should never get here, but just for safety,
+                            // Should never get here, but for safety,
                             // move the cursor position back to the start and continue the loop
                             audioBuffer->frameCursorPos = 0;
                             continue;
@@ -2573,8 +2637,8 @@
                     }
                 }
 
-                // If for some reason we weren't able to read every frame we'll need to break from the loop
-                // Not doing this could theoretically put us into an infinite loop
+                // If for some reason is not possible to read every frame, the loop needs to be broken
+                // Not doing this could theoretically eend up into an infinite loop
                 if (framesToRead > 0) break;
             }
         }
@@ -2590,14 +2654,14 @@
     ma_mutex_unlock(&AUDIO.System.lock);
 }
 
-// Main mixing function, pretty simple in this project, just an accumulation
+// Main mixing function, pretty simple in this project, only an accumulation
 // NOTE: framesOut is both an input and an output, it is initially filled with zeros outside of this function
 static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer)
 {
     const float localVolume = buffer->volume;
     const ma_uint32 channels = AUDIO.System.device.playback.channels;
 
-    if (channels == 2)  // We consider panning
+    if (channels == 2) // Consider panning
     {
         const float right = (buffer->pan + 1.0f)/2.0f; // Normalize: [-1..1] -> [0..1]
         const float left = 1.0f - right;
@@ -2617,7 +2681,7 @@
             frameIn += 2;
         }
     }
-    else  // We do not consider panning
+    else  // Do not consider panning
     {
         for (ma_uint32 frame = 0; frame < frameCount; frame++)
         {
@@ -2678,7 +2742,7 @@
             }
             else
             {
-                // Just update whichever sub-buffer is processed
+                // Update whichever sub-buffer is processed
                 subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1;
             }
 
@@ -2764,7 +2828,7 @@
     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
 
@@ -2772,7 +2836,7 @@
     {
         if (fileName[i] == '.')
         {
-            // NOTE: We break on first '.' found
+            // NOTE: Break on first '.' found
             fileName[i] = '\0';
             break;
         }
@@ -2803,7 +2867,7 @@
             {
                 data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
 
-                // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
+                // NOTE: fread() returns number of read elements instead of bytes, so reading [1 byte, size elements]
                 unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
                 *dataSize = count;
 
@@ -2821,9 +2885,17 @@
     return data;
 }
 
+// Unload file data allocated by LoadFileData()
+static void UnloadFileData(unsigned char *data)
+{
+    RL_FREE(data);
+}
+
 // Save data to file from buffer
 static bool SaveFileData(const char *fileName, void *data, int dataSize)
 {
+    bool result = true;
+
     if (fileName != NULL)
     {
         FILE *file = fopen(fileName, "wb");
@@ -2841,21 +2913,23 @@
         else
         {
             TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
-            return false;
+            result = false;
         }
     }
     else
     {
         TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-        return false;
+        result = false;
     }
 
-    return true;
+    return result;
 }
 
 // Save text data to file (write), string must be '\0' terminated
 static bool SaveFileText(const char *fileName, char *text)
 {
+    bool result = true;
+
     if (fileName != NULL)
     {
         FILE *file = fopen(fileName, "wt");
@@ -2873,19 +2947,19 @@
         else
         {
             TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
-            return false;
+            result = false;
         }
     }
     else
     {
         TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-        return false;
+        result = false;
     }
 
-    return true;
+    return result;
 }
 #endif
 
 #undef AudioBuffer
 
-#endif      // SUPPORT_MODULE_RAUDIO
+#endif // SUPPORT_MODULE_RAUDIO
diff --git a/raylib/src/raylib.h b/raylib/src/raylib.h
--- a/raylib/src/raylib.h
+++ b/raylib/src/raylib.h
@@ -1,16 +1,16 @@
 /**********************************************************************************************
 *
-*   raylib v5.6-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
+*   raylib v6.1-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
 *
 *   FEATURES:
 *       - NO external dependencies, all required libraries included with raylib
-*       - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly,
-*                        MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5
+*       - Multiplatform: Windows, Linux, macOS, FreeBSD, Web, Android, Raspberry Pi, DRM native...
 *       - Written in plain C code (C99) in PascalCase/camelCase notation
 *       - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile)
-*       - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
+*       - Software renderer optional, for systems with no GPU: [rlsw]
+*       - Custom OpenGL abstraction layer (usable as standalone module): [rlgl]
 *       - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts)
-*       - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC)
+*       - Many texture formats supported, including compressed formats (DXT, ETC, ASTC)
 *       - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more!
 *       - Flexible Materials system, supporting classic maps and PBR maps
 *       - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF)
@@ -26,23 +26,23 @@
 *       - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2)
 *       - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2)
 *
-*   DEPENDENCIES (included):
-*       [rcore][GLFW] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input
-*       [rcore][RGFW] rgfw (ColleagueRiley - github.com/ColleagueRiley/RGFW) for window/context management and input
-*       [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading
+*   DEPENDENCIES:
+*       [rcore] Depends on the selected platform backend, check rcore.c header for details
+*       [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL extensions loading
 *       [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management
 *
 *   OPTIONAL DEPENDENCIES (included):
 *       [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
 *       [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
 *       [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation
-*       [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image manage
-*       [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
-*       [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG)
-*       [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms
-*       [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation
-*       [rtext] stb_truetype (Sean Barret) for ttf fonts loading
-*       [rtext] stb_rect_pack (Sean Barret) for rectangles packing
+*       [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image management
+*       [rtextures] stb_image (Sean Barrett) for images loading (BMP, TGA, PNG, JPEG, HDR...)
+*       [rtextures] stb_image_write (Sean Barrett) for image writing (BMP, TGA, PNG, JPG)
+*       [rtextures] stb_image_resize2 (Sean Barrett) for image resizing algorithms
+*       [rtextures] stb_perlin (Sean Barrett) for Perlin Noise image generation
+*       [rtextures] rltexgpu (Ramon Santamaria) for GPU-compressed texture formats
+*       [rtext] stb_truetype (Sean Barrett) for ttf fonts loading
+*       [rtext] stb_rect_pack (Sean Barrett) for rectangles packing
 *       [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
 *       [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
 *       [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF)
@@ -51,10 +51,10 @@
 *       [raudio] dr_wav (David Reid) for WAV audio file loading
 *       [raudio] dr_flac (David Reid) for FLAC audio file loading
 *       [raudio] dr_mp3 (David Reid) for MP3 audio file loading
-*       [raudio] stb_vorbis (Sean Barret) for OGG audio loading
+*       [raudio] stb_vorbis (Sean Barrett) for OGG audio loading
 *       [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading
 *       [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading
-*       [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio manage
+*       [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio management
 *
 *
 *   LICENSE: zlib/libpng
@@ -86,10 +86,10 @@
 
 #include <stdarg.h>     // Required for: va_list - Only used by TraceLogCallback
 
-#define RAYLIB_VERSION_MAJOR 5
-#define RAYLIB_VERSION_MINOR 6
+#define RAYLIB_VERSION_MAJOR 6
+#define RAYLIB_VERSION_MINOR 1
 #define RAYLIB_VERSION_PATCH 0
-#define RAYLIB_VERSION  "5.6-dev"
+#define RAYLIB_VERSION  "6.1-dev"
 
 // Function specifiers in case library is build/used as a shared library
 // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
@@ -160,7 +160,7 @@
 // NOTE: Set some defines with some data types declared by raylib
 // Other modules (raymath, rlgl) also require some of those types, so,
 // to be able to use those other modules as standalone (not depending on raylib)
-// this defines are very useful for internal check and avoid type (re)definitions
+// this defines are useful for internal check and avoid type (re)definitions
 #define RL_COLOR_TYPE
 #define RL_RECTANGLE_TYPE
 #define RL_VECTOR2_TYPE
@@ -203,12 +203,14 @@
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 // Boolean type
+#if !defined(__cplusplus)
 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
     #include <stdbool.h>
-#elif !defined(__cplusplus) && !defined(bool)
+#elif !defined(bool)
     typedef enum bool { false = 0, true = !false } bool;
     #define RL_BOOL_TYPE
 #endif
+#endif
 
 // Vector2, 2 components
 typedef struct Vector2 {
@@ -336,7 +338,7 @@
 typedef struct Camera2D {
     Vector2 offset;         // Camera offset (screen space offset from window origin)
     Vector2 target;         // Camera target (world space target point that is mapped to screen space offset)
-	float rotation;         // Camera rotation in degrees (pivots around target)
+    float rotation;         // Camera rotation in degrees (pivots around target)
     float zoom;             // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale
 } Camera2D;
 
@@ -351,16 +353,18 @@
     float *texcoords2;      // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)
     float *normals;         // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
     float *tangents;        // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
-    unsigned char *colors;      // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
-    unsigned short *indices;    // Vertex indices (in case vertex data comes indexed)
+    unsigned char *colors;  // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
+    unsigned short *indices; // Vertex indices (in case vertex data comes indexed)
 
-    // Animation vertex data
+    // Skin data for animation
+    int boneCount;          // Number of bones (MAX: 256 bones)
+    unsigned char *boneIndices; // Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6)
+    float *boneWeights;     // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)
+
+    // Runtime animation vertex data (CPU skinning)
+    // NOTE: In case of GPU skinning, not used, pointers are NULL
     float *animVertices;    // Animated vertex positions (after bones transformations)
     float *animNormals;     // Animated normals (after bones transformations)
-    unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)
-    float *boneWeights;     // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)
-    Matrix *boneMatrices;   // Bones animated transformation matrices
-    int boneCount;          // Number of bones
 
     // OpenGL identifiers
     unsigned int vaoId;     // OpenGL Vertex Array Object id
@@ -394,12 +398,22 @@
     Vector3 scale;          // Scale
 } Transform;
 
+// Anim pose, an array of Transform[]
+typedef Transform *ModelAnimPose;
+
 // Bone, skeletal animation bone
 typedef struct BoneInfo {
     char name[32];          // Bone name
     int parent;             // Bone parent
 } BoneInfo;
 
+// Skeleton, animation bones hierarchy
+typedef struct ModelSkeleton {
+    unsigned int boneCount; // Number of bones
+    BoneInfo *bones;        // Bones information (skeleton)
+    ModelAnimPose bindPose; // Bones base transformation (Transform[])
+} ModelSkeleton;
+
 // Model, meshes, materials and animation data
 typedef struct Model {
     Matrix transform;       // Local transform matrix
@@ -411,18 +425,20 @@
     int *meshMaterial;      // Mesh material number
 
     // Animation data
-    int boneCount;          // Number of bones
-    BoneInfo *bones;        // Bones information (skeleton)
-    Transform *bindPose;    // Bones base transformation (pose)
+    ModelSkeleton skeleton; // Skeleton for animation
+
+    // Runtime animation data (CPU/GPU skinning)
+    ModelAnimPose currentPose; // Current animation pose (Transform[])
+    Matrix *boneMatrices;   // Bones animated transformation matrices
 } Model;
 
-// ModelAnimation
+// ModelAnimation, contains a full animation sequence
 typedef struct ModelAnimation {
-    int boneCount;          // Number of bones
-    int frameCount;         // Number of animation frames
-    BoneInfo *bones;        // Bones information (skeleton)
-    Transform **framePoses; // Poses array by frame
     char name[32];          // Animation name
+
+    unsigned int boneCount; // Number of bones (per pose)
+    int keyframeCount;      // Number of animation key frames
+    ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose]
 } ModelAnimation;
 
 // Ray, ray for raycasting
@@ -512,7 +528,6 @@
 
 // File path list
 typedef struct FilePathList {
-    unsigned int capacity;          // Filepaths max entries
     unsigned int count;             // Filepaths entries count
     char **paths;                   // Filepaths entries
 } FilePathList;
@@ -721,7 +736,7 @@
 
 // Gamepad buttons
 typedef enum {
-    GAMEPAD_BUTTON_UNKNOWN = 0,         // Unknown button, just for error checking
+    GAMEPAD_BUTTON_UNKNOWN = 0,         // Unknown button, for error checking
     GAMEPAD_BUTTON_LEFT_FACE_UP,        // Gamepad left DPAD up button
     GAMEPAD_BUTTON_LEFT_FACE_RIGHT,     // Gamepad left DPAD right button
     GAMEPAD_BUTTON_LEFT_FACE_DOWN,      // Gamepad left DPAD down button
@@ -770,6 +785,8 @@
 #define MATERIAL_MAP_SPECULAR     MATERIAL_MAP_METALNESS
 
 // Shader location index
+// NOTE: Some locations are tried to be set automatically on shader loading,
+// but only if default attributes/uniforms names are found, check config.h for names
 typedef enum {
     SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position
     SHADER_LOC_VERTEX_TEXCOORD01,   // Shader location: vertex attribute: texcoord01
@@ -792,15 +809,15 @@
     SHADER_LOC_MAP_ROUGHNESS,       // Shader location: sampler2d texture: roughness
     SHADER_LOC_MAP_OCCLUSION,       // Shader location: sampler2d texture: occlusion
     SHADER_LOC_MAP_EMISSION,        // Shader location: sampler2d texture: emission
-    SHADER_LOC_MAP_HEIGHT,          // Shader location: sampler2d texture: height
+    SHADER_LOC_MAP_HEIGHT,          // Shader location: sampler2d texture: heightmap
     SHADER_LOC_MAP_CUBEMAP,         // Shader location: samplerCube texture: cubemap
     SHADER_LOC_MAP_IRRADIANCE,      // Shader location: samplerCube texture: irradiance
     SHADER_LOC_MAP_PREFILTER,       // Shader location: samplerCube texture: prefilter
     SHADER_LOC_MAP_BRDF,            // Shader location: sampler2d texture: brdf
-    SHADER_LOC_VERTEX_BONEIDS,      // Shader location: vertex attribute: boneIds
-    SHADER_LOC_VERTEX_BONEWEIGHTS,  // Shader location: vertex attribute: boneWeights
-    SHADER_LOC_BONE_MATRICES,       // Shader location: array of matrices uniform: boneMatrices
-    SHADER_LOC_VERTEX_INSTANCE_TX   // Shader location: vertex attribute: instanceTransform
+    SHADER_LOC_VERTEX_BONEIDS,      // Shader location: vertex attribute: bone indices
+    SHADER_LOC_VERTEX_BONEWEIGHTS,  // Shader location: vertex attribute: bone weights
+    SHADER_LOC_MATRIX_BONETRANSFORMS, // Shader location: matrix attribute: bone transforms (animation)
+    SHADER_LOC_VERTEX_INSTANCETRANSFORM // Shader location: vertex attribute: instance transforms
 } ShaderLocationIndex;
 
 #define SHADER_LOC_MAP_DIFFUSE      SHADER_LOC_MAP_ALBEDO
@@ -864,7 +881,7 @@
 // NOTE 1: Filtering considers mipmaps if available in the texture
 // NOTE 2: Filter is accordingly set for minification and magnification
 typedef enum {
-    TEXTURE_FILTER_POINT = 0,               // No filter, just pixel approximation
+    TEXTURE_FILTER_POINT = 0,               // No filter, pixel approximation
     TEXTURE_FILTER_BILINEAR,                // Linear filtering
     TEXTURE_FILTER_TRILINEAR,               // Trilinear filtering (linear with mipmaps)
     TEXTURE_FILTER_ANISOTROPIC_4X,          // Anisotropic filtering 4x
@@ -948,10 +965,10 @@
 
 // Callbacks to hook some internal functions
 // WARNING: These callbacks are intended for advanced users
-typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);  // Logging: Redirect trace log messages
-typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize);    // FileIO: Load binary data
-typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize);   // FileIO: Save binary data
-typedef char *(*LoadFileTextCallback)(const char *fileName);            // FileIO: Load text data
+typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
+typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
+typedef bool (*SaveFileDataCallback)(const char *fileName, const void *data, int dataSize); // FileIO: Save binary data
+typedef char *(*LoadFileTextCallback)(const char *fileName);                  // FileIO: Load text data
 typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
 
 //------------------------------------------------------------------------------------
@@ -1019,23 +1036,23 @@
 RLAPI void DisableEventWaiting(void);                             // Disable waiting for events on EndDrawing(), automatic events polling
 
 // Cursor-related functions
-RLAPI void ShowCursor(void);                                      // Shows cursor
-RLAPI void HideCursor(void);                                      // Hides cursor
+RLAPI void ShowCursor(void);                                      // Show cursor
+RLAPI void HideCursor(void);                                      // Hide cursor
 RLAPI bool IsCursorHidden(void);                                  // Check if cursor is not visible
-RLAPI void EnableCursor(void);                                    // Enables cursor (unlock cursor)
-RLAPI void DisableCursor(void);                                   // Disables cursor (lock cursor)
+RLAPI void EnableCursor(void);                                    // Enable cursor (unlock cursor)
+RLAPI void DisableCursor(void);                                   // Disable cursor (lock cursor)
 RLAPI bool IsCursorOnScreen(void);                                // Check if cursor is on the screen
 
 // Drawing-related functions
-RLAPI void ClearBackground(Color color);                          // Set background color (framebuffer clear color)
-RLAPI void BeginDrawing(void);                                    // Setup canvas (framebuffer) to start drawing
-RLAPI void EndDrawing(void);                                      // End canvas drawing and swap buffers (double buffering)
+RLAPI void ClearBackground(Color color);                          // Clear background (framebuffer) to color
+RLAPI void BeginDrawing(void);                                    // Begin canvas (framebuffer) drawing
+RLAPI void EndDrawing(void);                                      // End canvas (framebuffer) drawing and swap buffers (double buffering)
 RLAPI void BeginMode2D(Camera2D camera);                          // Begin 2D mode with custom camera (2D)
-RLAPI void EndMode2D(void);                                       // Ends 2D mode with custom camera
+RLAPI void EndMode2D(void);                                       // End 2D mode with custom camera
 RLAPI void BeginMode3D(Camera3D camera);                          // Begin 3D mode with custom camera (3D)
-RLAPI void EndMode3D(void);                                       // Ends 3D mode and returns to default 2D orthographic mode
+RLAPI void EndMode3D(void);                                       // End 3D mode and returns to default 2D orthographic mode
 RLAPI void BeginTextureMode(RenderTexture2D target);              // Begin drawing to render texture
-RLAPI void EndTextureMode(void);                                  // Ends drawing to render texture
+RLAPI void EndTextureMode(void);                                  // End drawing to render texture
 RLAPI void BeginShaderMode(Shader shader);                        // Begin custom shader drawing
 RLAPI void EndShaderMode(void);                                   // End custom shader drawing (use default shader)
 RLAPI void BeginBlendMode(int mode);                              // Begin blending mode (alpha, additive, multiplied, subtract, custom)
@@ -1053,23 +1070,22 @@
 // NOTE: Shader functionality is not available on OpenGL 1.1
 RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName);   // Load shader from files and bind default locations
 RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
-RLAPI bool IsShaderValid(Shader shader);                                   // Check if a shader is valid (loaded on GPU)
+RLAPI bool IsShaderValid(Shader shader);                                   // Check if shader is valid (loaded on GPU)
 RLAPI int GetShaderLocation(Shader shader, const char *uniformName);       // Get shader uniform location
 RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName);  // Get shader attribute location
-RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType);               // Set shader uniform value
-RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count);   // Set shader uniform value vector
-RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat);         // Set shader uniform value (matrix 4x4)
+RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
+RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector
+RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat);  // Set shader uniform value (matrix 4x4)
 RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d)
 RLAPI void UnloadShader(Shader shader);                                    // Unload shader from GPU memory (VRAM)
 
 // Screen-space-related functions
-#define GetMouseRay GetScreenToWorldRay     // Compatibility hack for previous raylib versions
 RLAPI Ray GetScreenToWorldRay(Vector2 position, Camera camera);         // Get a ray trace from screen position (i.e mouse)
 RLAPI Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height); // Get a ray trace from screen position (i.e mouse) in a viewport
-RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera);        // Get the screen space position for a 3d world space position
-RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position
-RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera);    // Get the screen space position for a 2d camera world space position
-RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera);    // Get the world space position for a 2d camera screen space position
+RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera);        // Get screen space position for a 3d world space position
+RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get sized screen space position for a 3d world space position
+RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera);    // Get screen space position for a 2d camera world space position
+RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera);    // Get world space position for a 2d camera screen space position
 RLAPI Matrix GetCameraMatrix(Camera camera);                            // Get camera transform matrix (view matrix)
 RLAPI Matrix GetCameraMatrix2D(Camera2D camera);                        // Get camera 2d transform matrix
 
@@ -1095,7 +1111,7 @@
 
 // Misc. functions
 RLAPI void TakeScreenshot(const char *fileName);                // Takes a screenshot of current screen (filename extension defines format)
-RLAPI void SetConfigFlags(unsigned int flags);                  // Setup init configuration flags (view FLAGS)
+RLAPI void SetConfigFlags(unsigned int flags);                  // Set up init configuration flags (view FLAGS)
 RLAPI void OpenURL(const char *url);                            // Open URL with default system browser (if available)
 
 // Logging system
@@ -1103,7 +1119,7 @@
 RLAPI void TraceLog(int logLevel, const char *text, ...);       // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
 RLAPI void SetTraceLogCallback(TraceLogCallback callback);      // Set custom trace log
 
-// Memory management, using internal allocators 
+// Memory management, using internal allocators
 RLAPI void *MemAlloc(unsigned int size);                        // Internal memory allocator
 RLAPI void *MemRealloc(void *ptr, unsigned int size);           // Internal memory reallocator
 RLAPI void MemFree(void *ptr);                                  // Internal memory free
@@ -1111,7 +1127,7 @@
 // File system management functions
 RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
 RLAPI void UnloadFileData(unsigned char *data);                     // Unload file data allocated by LoadFileData()
-RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success
+RLAPI bool SaveFileData(const char *fileName, const void *data, int dataSize); // Save data to file from byte array (write), returns true on success
 RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
 RLAPI char *LoadFileText(const char *fileName);                     // Load text data from file (read), returns a '\0' terminated string
 RLAPI void UnloadFileText(char *text);                              // Unload file text data allocated by LoadFileText()
@@ -1124,44 +1140,49 @@
 RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback);  // Set custom file text data loader
 RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback);  // Set custom file text data saver
 
-RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists)
-RLAPI int FileRemove(const char *fileName);                         // Remove file (if exists)
-RLAPI int FileCopy(const char *srcPath, const char *dstPath);       // Copy file from one path to another, dstPath created if it doesn't exist
-RLAPI int FileMove(const char *srcPath, const char *dstPath);       // Move file from one directory to another, dstPath created if it doesn't exist
-RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file
-RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file
+RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists), returns 0 on success
+RLAPI int FileRemove(const char *fileName);                         // Remove file (if exists), returns 0 on success
+RLAPI int FileCopy(const char *srcPath, const char *dstPath);       // Copy file from one path to another, dstPath created if it doesn't exist, returns 0 on success
+RLAPI int FileMove(const char *srcPath, const char *dstPath);       // Move file from one directory to another, dstPath created if it doesn't exist, returns 0 on success
+RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file, returns 0 on success
+RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file, returns -1 if index not found or index otherwise
 RLAPI bool FileExists(const char *fileName);                        // Check if file exists
-RLAPI bool DirectoryExists(const char *dirPath);                    // Check if a directory path exists
+RLAPI bool DirectoryExists(const char *dirPath);                    // Check if directory path exists
 RLAPI bool IsFileExtension(const char *fileName, const char *ext);  // Check file extension (recommended include point: .png, .wav)
+RLAPI bool IsFileHidden(const char *filePath);                      // Check if file path (file or directory) is hidden by OS
 RLAPI int GetFileLength(const char *fileName);                      // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
 RLAPI long GetFileModTime(const char *fileName);                    // Get file modification time (last write time)
 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 bool ChangeDirectory(const char *dirPath);                    // Change working directory, return true on success
-RLAPI bool IsPathFile(const char *path);                            // Check if a given path is a file or a directory
+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
-RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
+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*'
 RLAPI void UnloadDirectoryFiles(FilePathList files);                // Unload filepaths
-RLAPI bool IsFileDropped(void);                                     // Check if a file has been dropped into window
+RLAPI bool IsFileDropped(void);                                     // Check if file has been dropped into window
 RLAPI FilePathList LoadDroppedFiles(void);                          // Load dropped filepaths
 RLAPI void UnloadDroppedFiles(FilePathList files);                  // Unload dropped filepaths
+RLAPI unsigned int GetDirectoryFileCount(const char *dirPath);      // Get the file count in a directory
+RLAPI unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs); // 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
 
 // Compression/Encoding functionality
 RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize);        // Compress data (DEFLATE algorithm), memory must be MemFree()
 RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize);  // Decompress data (DEFLATE algorithm), memory must be MemFree()
 RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize);               // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
 RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize);                             // Decode Base64 string (expected NULL terminated), memory must be MemFree()
-RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize);       // Compute CRC32 hash code
-RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize);        // Compute MD5 hash code, returns static int[4] (16 bytes)
-RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize);       // Compute SHA1 hash code, returns static int[5] (20 bytes)
-RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize);     // Compute SHA256 hash code, returns static int[8] (32 bytes)
+RLAPI unsigned int ComputeCRC32(const unsigned char *data, int dataSize); // Compute CRC32 hash code
+RLAPI unsigned int *ComputeMD5(const unsigned char *data, int dataSize);  // Compute MD5 hash code, returns static int[4] (16 bytes)
+RLAPI unsigned int *ComputeSHA1(const unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
+RLAPI unsigned int *ComputeSHA256(const unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes)
 
 // Automation events functionality
 RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
@@ -1178,23 +1199,23 @@
 //------------------------------------------------------------------------------------
 
 // Input-related functions: keyboard
-RLAPI bool IsKeyPressed(int key);                             // Check if a key has been pressed once
-RLAPI bool IsKeyPressedRepeat(int key);                       // Check if a key has been pressed again
-RLAPI bool IsKeyDown(int key);                                // Check if a key is being pressed
-RLAPI bool IsKeyReleased(int key);                            // Check if a key has been released once
-RLAPI bool IsKeyUp(int key);                                  // Check if a key is NOT being pressed
+RLAPI bool IsKeyPressed(int key);                             // Check if key has been pressed once
+RLAPI bool IsKeyPressedRepeat(int key);                       // Check if key has been pressed again
+RLAPI bool IsKeyDown(int key);                                // Check if key is being pressed
+RLAPI bool IsKeyReleased(int key);                            // Check if key has been released once
+RLAPI bool IsKeyUp(int key);                                  // Check if key is NOT being pressed
 RLAPI int GetKeyPressed(void);                                // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
 RLAPI int GetCharPressed(void);                               // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
 RLAPI const char *GetKeyName(int key);                        // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)
 RLAPI void SetExitKey(int key);                               // Set a custom key to exit program (default is ESC)
 
 // Input-related functions: gamepads
-RLAPI bool IsGamepadAvailable(int gamepad);                   // Check if a gamepad is available
+RLAPI bool IsGamepadAvailable(int gamepad);                   // Check if gamepad is available
 RLAPI const char *GetGamepadName(int gamepad);                // Get gamepad internal name id
-RLAPI bool IsGamepadButtonPressed(int gamepad, int button);   // Check if a gamepad button has been pressed once
-RLAPI bool IsGamepadButtonDown(int gamepad, int button);      // Check if a gamepad button is being pressed
-RLAPI bool IsGamepadButtonReleased(int gamepad, int button);  // Check if a gamepad button has been released once
-RLAPI bool IsGamepadButtonUp(int gamepad, int button);        // Check if a gamepad button is NOT being pressed
+RLAPI bool IsGamepadButtonPressed(int gamepad, int button);   // Check if gamepad button has been pressed once
+RLAPI bool IsGamepadButtonDown(int gamepad, int button);      // Check if gamepad button is being pressed
+RLAPI bool IsGamepadButtonReleased(int gamepad, int button);  // Check if gamepad button has been released once
+RLAPI bool IsGamepadButtonUp(int gamepad, int button);        // Check if gamepad button is NOT being pressed
 RLAPI int GetGamepadButtonPressed(void);                      // Get the last gamepad button pressed
 RLAPI int GetGamepadAxisCount(int gamepad);                   // Get axis count for a gamepad
 RLAPI float GetGamepadAxisMovement(int gamepad, int axis);    // Get movement value for a gamepad axis
@@ -1202,10 +1223,10 @@
 RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
 
 // Input-related functions: mouse
-RLAPI bool IsMouseButtonPressed(int button);                  // Check if a mouse button has been pressed once
-RLAPI bool IsMouseButtonDown(int button);                     // Check if a mouse button is being pressed
-RLAPI bool IsMouseButtonReleased(int button);                 // Check if a mouse button has been released once
-RLAPI bool IsMouseButtonUp(int button);                       // Check if a mouse button is NOT being pressed
+RLAPI bool IsMouseButtonPressed(int button);                  // Check if mouse button has been pressed once
+RLAPI bool IsMouseButtonDown(int button);                     // Check if mouse button is being pressed
+RLAPI bool IsMouseButtonReleased(int button);                 // Check if mouse button has been released once
+RLAPI bool IsMouseButtonUp(int button);                       // Check if mouse button is NOT being pressed
 RLAPI int GetMouseX(void);                                    // Get mouse position X
 RLAPI int GetMouseY(void);                                    // Get mouse position Y
 RLAPI Vector2 GetMousePosition(void);                         // Get mouse position XY
@@ -1221,14 +1242,14 @@
 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
 
 //------------------------------------------------------------------------------------
 // Gestures and Touch Handling Functions (Module: rgestures)
 //------------------------------------------------------------------------------------
 RLAPI void SetGesturesEnabled(unsigned int flags);            // Enable a set of gestures using flags
-RLAPI bool IsGestureDetected(unsigned int gesture);           // Check if a gesture have been detected
+RLAPI bool IsGestureDetected(unsigned int gesture);           // Check if gesture has been detected
 RLAPI int GetGestureDetected(void);                           // Get latest detected gesture
 RLAPI float GetGestureHoldDuration(void);                     // Get gesture hold time in seconds
 RLAPI Vector2 GetGestureDragVector(void);                     // Get gesture drag vector
@@ -1248,7 +1269,7 @@
 // Set texture and rectangle to be used on shapes drawing
 // NOTE: It can be useful when using basic shapes and one single font,
 // defining a font char white rectangle would allow drawing everything in a single draw call
-RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
+RLAPI void SetShapesTexture(Texture2D texture, Rectangle rec); // Set texture and rectangle to be used on shapes drawing
 RLAPI Texture2D GetShapesTexture(void);                 // Get texture that is used for shapes drawing
 RLAPI Rectangle GetShapesTextureRectangle(void);        // Get texture source rectangle that is used for shapes drawing
 
@@ -1261,38 +1282,44 @@
 RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color);                            // Draw lines sequence (using gl lines)
 RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color);                   // Draw line segment cubic-bezier in-out interpolation
 RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color);   // Draw a dashed line
-RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color);                              // Draw a color-filled circle
-RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color);      // Draw a piece of a circle
-RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
-RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer);         // Draw a gradient-filled circle
-RLAPI void DrawCircleV(Vector2 center, float radius, Color color);                                       // Draw a color-filled circle (Vector version)
-RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);                         // Draw circle outline
-RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color);                                  // Draw circle outline (Vector version)
-RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color);             // Draw ellipse
-RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color);                      // Draw ellipse (Vector version)
-RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color);        // Draw ellipse outline
-RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color);                 // Draw ellipse outline (Vector version)
-RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
-RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color);    // Draw ring outline
+RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                                // Draw a color-filled triangle, counter-clockwise vertex order
+RLAPI void DrawTriangleGradient(Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3);       // Draw triangle with interpolated colors, counter-clockwise vertex/color order
+RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                           // Draw triangle outline, counter-clockwise vertex order
+RLAPI void DrawTriangleLinesEx(Vector2 v1, Vector2 v2, Vector2 v3, float thick, Color color);            // Draw triangle outline with line thickness, counter-clockwise vertex order
+RLAPI void DrawTriangleFan(const Vector2 *points, int pointCount, Color color);                          // Draw a triangle fan defined by points (first vertex is the center)
+RLAPI void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color);                        // Draw a triangle strip defined by points
 RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color);                        // Draw a color-filled rectangle
 RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color);                                  // Draw a color-filled rectangle (Vector version)
 RLAPI void DrawRectangleRec(Rectangle rec, Color color);                                                 // Draw a color-filled rectangle
 RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color);                 // Draw a color-filled rectangle with pro parameters
 RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom);   // Draw a vertical-gradient-filled rectangle
 RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right);   // Draw a horizontal-gradient-filled rectangle
-RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
+RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4);       // Draw a gradient-filled rectangle with custom vertex colors, counter-clockwise color order
 RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color);                   // Draw rectangle outline
-RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color);                            // Draw rectangle outline with extended parameters
+RLAPI void DrawRectangleLinesEx(Rectangle rec, float thick, Color color);                                // Draw rectangle outline with line thickness
 RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color);              // Draw rectangle with rounded edges
 RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color);         // Draw rectangle lines with rounded edges
-RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline
-RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                                // Draw a color-filled triangle (vertex in counter-clockwise order!)
-RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);                           // Draw triangle outline (vertex in counter-clockwise order!)
-RLAPI void DrawTriangleFan(const Vector2 *points, int pointCount, Color color);                          // Draw a triangle fan defined by points (first vertex is the center)
-RLAPI void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color);                        // Draw a triangle strip defined by points
-RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color);               // Draw a regular polygon (Vector version)
+RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color); // Draw rectangle lines with rounded edges outline and line thickness
+RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color);               // Draw a polygon of n sides
 RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color);          // Draw a polygon outline of n sides
-RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters
+RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float thick, Color color); // Draw a polygon outline of n sides with line thickness
+RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color);                              // Draw a color-filled circle
+RLAPI void DrawCircleV(Vector2 center, float radius, Color color);                                       // Draw a color-filled circle (Vector version)
+RLAPI void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer);                   // Draw a gradient-filled circle
+RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle
+RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline
+RLAPI void DrawCircleSectorLinesEx(Vector2 center, float radius, float startAngle, float endAngle, int segments, float thick, Color color); // Draw circle sector outline with thickness
+RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);                         // Draw circle outline
+RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color);                                  // Draw circle outline (Vector version)
+RLAPI void DrawCircleLinesEx(Vector2 center, float radius, float thick, Color color);                    // Draw circle outline with line thickness
+RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color);             // Draw ellipse
+RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color);                      // Draw ellipse (Vector version)
+RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color);        // Draw ellipse outline
+RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color);                 // Draw ellipse outline (Vector version)
+RLAPI void DrawEllipseLinesEx(Vector2 center, float radiusH, float radiusV, float thick, Color color);   // Draw ellipse outline with line thickness
+RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
+RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
+RLAPI void DrawRingLinesEx(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, float thick, Color color); // Draw ring outline with line thickness
 
 // Splines drawing functions
 RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color);            // Draw spline: Linear, minimum 2 points
@@ -1306,18 +1333,18 @@
 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
-RLAPI Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t);                     // Get (evaluate) spline point: Quadratic Bezier
+RLAPI Vector2 GetSplinePointBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float t);                // Get (evaluate) spline point: Quadratic Bezier
 RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t);        // Get (evaluate) spline point: Cubic Bezier
 
 // Basic shapes collision detection functions
 RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2);                                           // Check collision between two rectangles
 RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2);        // Check collision between two circles
 RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec);                         // Check collision between circle and rectangle
-RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2);               // Check if circle collides with a line created betweeen two points [p1] and [p2]
+RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2);               // Check if circle collides with a line created between two points [p1] and [p2]
 RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec);                                         // Check if point is inside rectangle
 RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius);                       // Check if point is inside circle
 RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3);               // Check if point is inside a triangle
@@ -1338,11 +1365,11 @@
 RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer
 RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize);      // Load image from memory buffer, fileType refers to extension: i.e. '.png'
 RLAPI Image LoadImageFromTexture(Texture2D texture);                                                     // Load image from GPU texture data
-RLAPI Image LoadImageFromScreen(void);                                                                   // Load image from screen buffer and (screenshot)
+RLAPI Image LoadImageFromScreen(void);                                                                   // Load image from screen buffer (screenshot)
 RLAPI bool IsImageValid(Image image);                                                                    // Check if an image is valid (data and parameters)
 RLAPI void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 RLAPI bool ExportImage(Image image, const char *fileName);                                               // Export image data to file, returns true on success
-RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize);              // Export image to memory buffer
+RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize);              // Export image to memory buffer, memory must be MemFree()
 RLAPI bool ExportImageAsCode(Image image, const char *fileName);                                         // Export image as code file defining an array of bytes, returns true on success
 
 // Image generation functions
@@ -1384,7 +1411,7 @@
 RLAPI void ImageColorTint(Image *image, Color color);                                                    // Modify image color: tint
 RLAPI void ImageColorInvert(Image *image);                                                               // Modify image color: invert
 RLAPI void ImageColorGrayscale(Image *image);                                                            // Modify image color: grayscale
-RLAPI void ImageColorContrast(Image *image, float contrast);                                             // Modify image color: contrast (-100 to 100)
+RLAPI void ImageColorContrast(Image *image, int contrast);                                               // Modify image color: contrast (-100 to 100)
 RLAPI void ImageColorBrightness(Image *image, int brightness);                                           // Modify image color: brightness (-255 to 255)
 RLAPI void ImageColorReplace(Image *image, Color color, Color replace);                                  // Modify image color: replace color
 RLAPI Color *LoadImageColors(Image image);                                                               // Load color data from image as a Color array (RGBA - 32bit)
@@ -1396,28 +1423,38 @@
 
 // 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
 RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color);                          // Draw line within an image (Vector version)
 RLAPI void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color);              // Draw a line defining thickness within an image
+RLAPI void ImageDrawLineStrip(Image *dst, const Vector2 *points, int pointCount, Color color);           // Draw a lines sequence within an image
+RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);               // Draw triangle within an image
+RLAPI void ImageDrawTriangleGradient(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
+RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);          // Draw triangle outline within an image
+RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color);         // Draw a triangle fan defined by points within an image (first vertex is the center)
+RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color);       // Draw a triangle strip defined by points within an image
+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
 RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color);                   // Draw circle outline within an image (Vector version)
-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 ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color);                   // Draw rectangle lines within an image
-RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);               // Draw triangle within an image
-RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
-RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color);          // Draw triangle outline within an image
-RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color);               // Draw a triangle fan defined by points within an image (first vertex is the center)
-RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color);             // Draw a triangle strip defined by points within an image
-RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint);             // Draw a source image within a destination image (tint applied to source)
+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
@@ -1425,9 +1462,10 @@
 RLAPI Texture2D LoadTextureFromImage(Image image);                                                       // Load texture from image data
 RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout);                                        // Load cubemap from image, multiple image cubemap layouts supported
 RLAPI RenderTexture2D LoadRenderTexture(int width, int height);                                          // Load texture for rendering (framebuffer)
-RLAPI bool IsTextureValid(Texture2D texture);                                                            // Check if a texture is valid (loaded in GPU)
+RLAPI RenderTexture2D LoadRenderTextureEx(int width, int height, int format);                            // Load texture for rendering (framebuffer), with specific format
+RLAPI bool IsTextureValid(Texture2D texture);                                                            // Check if texture is valid (loaded in GPU)
 RLAPI void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory (VRAM)
-RLAPI bool IsRenderTextureValid(RenderTexture2D target);                                                 // Check if a render texture is valid (loaded in GPU)
+RLAPI bool IsRenderTextureValid(RenderTexture2D target);                                                 // Check if render texture is valid (loaded in GPU)
 RLAPI void UnloadRenderTexture(RenderTexture2D target);                                                  // Unload render texture from GPU memory (VRAM)
 RLAPI void UpdateTexture(Texture2D texture, const void *pixels);                                         // Update GPU texture with new data (pixels should be able to fill texture)
 RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels);                       // Update GPU texture rectangle with new data (pixels and rec should fit in texture)
@@ -1440,10 +1478,10 @@
 // Texture drawing functions
 RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint);                               // Draw a Texture2D
 RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);                                // Draw a Texture2D with position defined as Vector2
-RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);  // Draw a Texture2D with extended parameters
-RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint);            // Draw a part of a texture defined by a rectangle
-RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
-RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
+RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);  // Draw a Texture2D with rotation and scale
+RLAPI void DrawTextureRec(Texture2D texture, Rectangle rec, Vector2 position, Color tint);               // Draw a part of a texture defined by a rectangle
+RLAPI void DrawTexturePro(Texture2D texture, Rectangle srcrec, Rectangle dstrec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation
+RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dstrec, Vector2 origin, float rotation, Color tint); // Draw a texture (or part of it) that stretches or shrinks nicely
 
 // Color/pixel related functions
 RLAPI bool ColorIsEqual(Color col1, Color col2);                            // Check if two colors are equal
@@ -1460,7 +1498,7 @@
 RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint);              // Get src alpha-blended into dst color with tint
 RLAPI Color ColorLerp(Color color1, Color color2, float factor);            // Get color lerp interpolation between two colors, factor [0.0f..1.0f]
 RLAPI Color GetColor(unsigned int hexValue);                                // Get Color structure from hexadecimal value
-RLAPI Color GetPixelColor(void *srcPtr, int format);                        // Get Color from a source pixel pointer of certain format
+RLAPI Color GetPixelColor(const void *srcPtr, int format);                  // Get Color from a source pixel pointer of certain format
 RLAPI void SetPixelColor(void *dstPtr, Color color, int format);            // Set color formatted into destination pixel pointer
 RLAPI int GetPixelDataSize(int width, int height, int format);              // Get pixel data size in bytes for certain format
 
@@ -1471,10 +1509,10 @@
 // Font loading/unloading functions
 RLAPI Font GetFontDefault(void);                                                            // Get the default Font
 RLAPI Font LoadFont(const char *fileName);                                                  // Load font from file into GPU memory (VRAM)
-RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // 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
+RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // 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
 RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar);                        // Load font from Image (XNA style)
 RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
-RLAPI bool IsFontValid(Font font);                                                          // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
+RLAPI bool IsFontValid(Font font);                                                          // Check if font is valid (font data loaded, WARNING: GPU texture not checked)
 RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type, int *glyphCount); // Load font data for further use
 RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
 RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount);                               // Unload font chars info data (RAM)
@@ -1487,12 +1525,13 @@
 RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
 RLAPI void DrawTextPro(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)
 RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
-RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
+RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple characters (codepoint)
 
 // Text font info functions
 RLAPI void SetTextLineSpacing(int spacing);                                                 // Set vertical line spacing when drawing with line-breaks
 RLAPI int MeasureText(const char *text, int fontSize);                                      // Measure string width for default font
 RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing);    // Measure string size for Font
+RLAPI Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, float fontSize, float spacing); // Measure string size for an existing array of codepoints for Font
 RLAPI int GetGlyphIndex(Font font, int codepoint);                                          // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
 RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint);                                     // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found
 RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint);                                 // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
@@ -1510,19 +1549,22 @@
 
 // Text strings management functions (no UTF-8 strings, only byte chars)
 // WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use
-// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree()
+// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree()
 RLAPI char **LoadTextLines(const char *text, int *count);                                   // Load text as separate lines ('\n')
 RLAPI void UnloadTextLines(char **text, int lineCount);                                     // Unload text lines
 RLAPI int TextCopy(char *dst, const char *src);                                             // Copy one string to another, returns bytes copied
-RLAPI bool TextIsEqual(const char *text1, const char *text2);                               // Check if two text string are equal
+RLAPI bool TextIsEqual(const char *text1, const char *text2);                               // Check if two text strings are equal
 RLAPI unsigned int TextLength(const char *text);                                            // Get text length, checks for '\0' ending
 RLAPI const char *TextFormat(const char *text, ...);                                        // Text formatting with variables (sprintf() style)
 RLAPI const char *TextSubtext(const char *text, int position, int length);                  // Get a piece of a text string
 RLAPI const char *TextRemoveSpaces(const char *text);                                       // Remove text spaces, concat words
 RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end);           // Get text between two strings
-RLAPI char *TextReplace(const char *text, const char *search, const char *replacement);     // Replace text string (WARNING: memory must be freed!)
-RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (WARNING: memory must be freed!)
-RLAPI char *TextInsert(const char *text, const char *insert, int position);                 // Insert text in a position (WARNING: memory must be freed!)
+RLAPI char *TextReplace(const char *text, const char *search, const char *replacement);     // Replace text string with new string
+RLAPI char *TextReplaceAlloc(const char *text, const char *search, const char *replacement); // Replace text string with new string, memory must be MemFree()
+RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings
+RLAPI char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings, memory must be MemFree()
+RLAPI char *TextInsert(const char *text, const char *insert, int position);                 // Insert text in a defined byte position
+RLAPI char *TextInsertAlloc(const char *text, const char *insert, int position);            // Insert text in a defined byte position, memory must be MemFree()
 RLAPI char *TextJoin(char **textList, int count, const char *delimiter);                    // Join text strings with delimiter
 RLAPI char **TextSplit(const char *text, char delimiter, int *count);                       // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings
 RLAPI void TextAppend(char *text, const char *append, int *position);                       // Append text at specific position and move cursor
@@ -1543,21 +1585,21 @@
 RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color);                                    // Draw a line in 3D world space
 RLAPI void DrawPoint3D(Vector3 position, Color color);                                                   // Draw a point in 3D space, actually a small line
 RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
-RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color);                              // Draw a color-filled triangle (vertex in counter-clockwise order!)
+RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color);                              // Draw a color-filled triangle, counter-clockwise vertex order
 RLAPI void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color);                      // Draw a triangle strip defined by points
 RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color);             // Draw cube
 RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color);                                       // Draw cube (Vector version)
 RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color);        // Draw cube wires
 RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color);                                  // Draw cube wires (Vector version)
 RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color);                                     // Draw sphere
-RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color);            // Draw sphere with extended parameters
+RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color);            // Draw sphere with defined rings and slices
 RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color);         // Draw sphere wires
-RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
+RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color); // Draw a cylinder/cone
 RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos
-RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
+RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color); // Draw a cylinder/cone wires
 RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos
-RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
-RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
+RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
+RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
 RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);                                      // Draw a plane XZ
 RLAPI void DrawRay(Ray ray, Color color);                                                                // Draw a ray line
 RLAPI void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0))
@@ -1569,21 +1611,19 @@
 // Model management functions
 RLAPI Model LoadModel(const char *fileName);                                                // Load model from files (meshes and materials)
 RLAPI Model LoadModelFromMesh(Mesh mesh);                                                   // Load model from generated mesh (default material)
-RLAPI bool IsModelValid(Model model);                                                       // Check if a model is valid (loaded in GPU, VAO/VBOs)
+RLAPI bool IsModelValid(Model model);                                                       // Check if model is valid (loaded in GPU, VAO/VBOs)
 RLAPI void UnloadModel(Model model);                                                        // Unload model (including meshes) from memory (RAM and/or VRAM)
 RLAPI BoundingBox GetModelBoundingBox(Model model);                                         // Compute model bounding box limits (considers all meshes)
 
 // Model drawing functions
 RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint);               // Draw a model (with texture if set)
-RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
+RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with custom transform
 RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint);          // Draw a model wires (with texture if set)
-RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
-RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
-RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters
+RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires with custom transform
 RLAPI void DrawBoundingBox(BoundingBox box, Color color);                                   // Draw bounding box (wires)
-RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint);   // Draw a billboard texture
-RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
-RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
+RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
+RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by rectangle
+RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source rectangle with scaling and rotation
 
 // Mesh management functions
 RLAPI void UploadMesh(Mesh *mesh, bool dynamic);                                            // Upload mesh vertex data in GPU and provide VAO/VBO ids
@@ -1612,16 +1652,15 @@
 // Material loading/unloading functions
 RLAPI Material *LoadMaterials(const char *fileName, int *materialCount);                    // Load materials from model file
 RLAPI Material LoadMaterialDefault(void);                                                   // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
-RLAPI bool IsMaterialValid(Material material);                                              // Check if a material is valid (shader assigned, map textures loaded in GPU)
+RLAPI bool IsMaterialValid(Material material);                                              // Check if material is valid (shader assigned, map textures loaded in GPU)
 RLAPI void UnloadMaterial(Material material);                                               // Unload material from GPU memory (VRAM)
 RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture);          // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
 RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId);                  // Set material for a mesh
 
 // Model animations loading/unloading functions
 RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount);            // Load model animations from file
-RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame);               // Update model animation pose (CPU)
-RLAPI void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame);          // Update model animation mesh bone matrices (GPU skinning)
-RLAPI void UnloadModelAnimation(ModelAnimation anim);                                       // Unload animation data
+RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, float frame);             // Update model animation pose (vertex buffers and bone matrices)
+RLAPI void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend); // Update model animation pose, blending two animations
 RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount);                // Unload animation array data
 RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim);                         // Check model animation skeleton match
 
@@ -1650,15 +1689,15 @@
 // Wave/Sound loading/unloading functions
 RLAPI Wave LoadWave(const char *fileName);                            // Load wave data from file
 RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
-RLAPI bool IsWaveValid(Wave wave);                                    // Checks if wave data is valid (data loaded and parameters)
+RLAPI bool IsWaveValid(Wave wave);                                    // Check if wave data is valid (data loaded and parameters)
 RLAPI Sound LoadSound(const char *fileName);                          // Load sound from file
 RLAPI Sound LoadSoundFromWave(Wave wave);                             // Load sound from wave data
-RLAPI Sound LoadSoundAlias(Sound source);                             // Create a new sound that shares the same sample data as the source sound, does not own the sound data
-RLAPI bool IsSoundValid(Sound sound);                                 // Checks if a sound is valid (data loaded and buffers initialized)
-RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
+RLAPI Sound LoadSoundAlias(Sound source);                             // Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data
+RLAPI bool IsSoundValid(Sound sound);                                 // Check if sound is valid (data loaded and buffers initialized)
+RLAPI void UpdateSound(Sound sound, const void *data, int frameCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
 RLAPI void UnloadWave(Wave wave);                                     // Unload wave data
 RLAPI void UnloadSound(Sound sound);                                  // Unload sound
-RLAPI void UnloadSoundAlias(Sound alias);                             // Unload a sound alias (does not deallocate sample data)
+RLAPI void UnloadSoundAlias(Sound alias);                             // Unload sound alias (does not deallocate sample data)
 RLAPI bool ExportWave(Wave wave, const char *fileName);               // Export wave data to file, returns true on success
 RLAPI bool ExportWaveAsCode(Wave wave, const char *fileName);         // Export wave sample data to code (.h), returns true on success
 
@@ -1667,7 +1706,7 @@
 RLAPI void StopSound(Sound sound);                                    // Stop playing a sound
 RLAPI void PauseSound(Sound sound);                                   // Pause a sound
 RLAPI void ResumeSound(Sound sound);                                  // Resume a paused sound
-RLAPI bool IsSoundPlaying(Sound sound);                               // Check if a sound is currently playing
+RLAPI bool IsSoundPlaying(Sound sound);                               // Check if sound is currently playing
 RLAPI void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 RLAPI void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 RLAPI void SetSoundPan(Sound sound, float pan);                       // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
@@ -1680,24 +1719,24 @@
 // Music management functions
 RLAPI Music LoadMusicStream(const char *fileName);                    // Load music stream from file
 RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
-RLAPI bool IsMusicValid(Music music);                                 // Checks if a music stream is valid (context and buffers initialized)
+RLAPI bool IsMusicValid(Music music);                                 // Check if music stream is valid (context and buffers initialized)
 RLAPI void UnloadMusicStream(Music music);                            // Unload music stream
 RLAPI void PlayMusicStream(Music music);                              // Start music playing
 RLAPI bool IsMusicStreamPlaying(Music music);                         // Check if music is playing
-RLAPI void UpdateMusicStream(Music music);                            // Updates buffers for music streaming
+RLAPI void UpdateMusicStream(Music music);                            // Update buffers for music streaming
 RLAPI void StopMusicStream(Music music);                              // Stop music playing
 RLAPI void PauseMusicStream(Music music);                             // Pause music playing
 RLAPI void ResumeMusicStream(Music music);                            // Resume playing paused music
 RLAPI void SeekMusicStream(Music music, float position);              // Seek music to a position (in seconds)
 RLAPI void SetMusicVolume(Music music, float volume);                 // Set volume for music (1.0 is max level)
-RLAPI void SetMusicPitch(Music music, float pitch);                   // Set pitch for a music (1.0 is base level)
-RLAPI void SetMusicPan(Music music, float pan);                       // Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
+RLAPI void SetMusicPitch(Music music, float pitch);                   // Set pitch for music (1.0 is base level)
+RLAPI void SetMusicPan(Music music, float pan);                       // Set pan for music (-1.0 left, 0.0 center, 1.0 right)
 RLAPI float GetMusicTimeLength(Music music);                          // Get music time length (in seconds)
 RLAPI float GetMusicTimePlayed(Music music);                          // Get current music time played (in seconds)
 
 // AudioStream management functions
 RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
-RLAPI bool IsAudioStreamValid(AudioStream stream);                    // Checks if an audio stream is valid (buffers initialized)
+RLAPI bool IsAudioStreamValid(AudioStream stream);                    // Check if an audio stream is valid (buffers initialized)
 RLAPI void UnloadAudioStream(AudioStream stream);                     // Unload audio stream and free memory
 RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
 RLAPI bool IsAudioStreamProcessed(AudioStream stream);                // Check if any audio stream buffers requires refill
@@ -1708,7 +1747,7 @@
 RLAPI void StopAudioStream(AudioStream stream);                       // Stop audio stream
 RLAPI void SetAudioStreamVolume(AudioStream stream, float volume);    // Set volume for audio stream (1.0 is max level)
 RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch);      // Set pitch for audio stream (1.0 is base level)
-RLAPI void SetAudioStreamPan(AudioStream stream, float pan);          // Set pan for audio stream (0.5 is centered)
+RLAPI void SetAudioStreamPan(AudioStream stream, float pan);          // Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right)
 RLAPI void SetAudioStreamBufferSizeDefault(int size);                 // Default size for new audio streams
 RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
 
diff --git a/raylib/src/raymath.h b/raylib/src/raymath.h
--- a/raylib/src/raymath.h
+++ b/raylib/src/raymath.h
@@ -1,6 +1,6 @@
 /**********************************************************************************************
 *
-*   raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
+*   raymath v2.0 - Math functions to work with Vector2, Vector3, Vector4, Matrix and Quaternions
 *
 *   CONVENTIONS:
 *     - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
@@ -15,7 +15,7 @@
 *     - Functions use always a "result" variable for return (except C++ operators)
 *     - Functions are always defined inline
 *     - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
-*     - No compound literals used to make sure libray is compatible with C++
+*     - No compound literals used to make sure the library is compatible with C++
 *
 *   CONFIGURATION:
 *       #define RAYMATH_IMPLEMENTATION
@@ -30,7 +30,7 @@
 *       #define RAYMATH_DISABLE_CPP_OPERATORS
 *           Disables C++ operator overloads for raymath types.
 *
-*       #define RAYMATH_USE_SIMD_INTRINSICS
+*       #define RAYMATH_USE_SIMD_INTRINSICS   1
 *           Try to enable SIMD intrinsics for MatrixMultiply()
 *           Note that users enabling it must be aware of the target platform where application will
 *           run to support the selected SIMD intrinsic, for now, only SSE is supported
@@ -66,11 +66,11 @@
 // Function specifiers definition
 #if defined(RAYMATH_IMPLEMENTATION)
     #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
-        #define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll)
+        #define RMAPI __declspec(dllexport) extern inline    // Building raylib as a Win32 shared library (.dll)
     #elif defined(BUILD_LIBTYPE_SHARED)
-        #define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib)
+        #define RMAPI __attribute__((visibility("default"))) // Building raylib as a Unix shared library (.so/.dylib)
     #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
-        #define RMAPI __declspec(dllimport)         // We are using raylib as a Win32 shared library (.dll)
+        #define RMAPI __declspec(dllimport)                  // Using raylib as a Win32 shared library (.dll)
     #else
         #define RMAPI extern inline // Provide external definition
     #endif
@@ -164,20 +164,26 @@
 #endif
 
 // NOTE: Helper types to be used instead of array return types for *ToFloat functions
+#if !defined(RL_FLOAT3_TYPE)
 typedef struct float3 {
     float v[3];
 } float3;
+#define RL_FLOAT3_TYPE
+#endif
 
+#if !defined(RL_FLOAT16_TYPE)
 typedef struct float16 {
     float v[16];
 } float16;
+#define RL_FLOAT16_TYPE
+#endif
 
 #include <math.h>       // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf()
 
-#if defined(RAYMATH_USE_SIMD_INTRINSICS)
+#if RAYMATH_USE_SIMD_INTRINSICS
     // SIMD is used on the most costly raymath function MatrixMultiply()
     // NOTE: Only SSE intrinsics support implemented
-    // TODO: Consider support for other SIMD instrinsics:
+    // TODO: Consider support for other SIMD intrinsics:
     //  - SSEx, AVX, AVX2, FMA, NEON, RVV
     /*
     #if defined(__SSE4_2__)
@@ -561,15 +567,9 @@
     {
         length = sqrtf(length);
 
-        float scale = 1;    // By default, 1 as the neutral element.
-        if (length < min)
-        {
-            scale = min/length;
-        }
-        else if (length > max)
-        {
-            scale = max/length;
-        }
+        float scale = 1; // By default, 1 as the neutral element
+        if (length < min) scale = min/length;
+        else if (length > max) scale = max/length;
 
         result.x = v.x*scale;
         result.y = v.y*scale;
@@ -595,7 +595,7 @@
 // v: normalized direction of the incoming ray
 // n: normalized normal vector of the interface of two optical media
 // r: ratio of the refractive index of the medium from where the ray comes
-//    to the refractive index of the medium on the other side of the surface
+// to the refractive index of the medium on the other side of the surface
 RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r)
 {
     Vector2 result = { 0 };
@@ -1083,7 +1083,7 @@
 }
 
 // Projects a Vector3 from screen space into object space
-// NOTE: We are avoiding calling other raymath functions despite available
+// NOTE: Self-contained function, no other raymath functions are called
 RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
 {
     Vector3 result = { 0 };
@@ -1151,7 +1151,7 @@
     // Create quaternion from source point
     Quaternion quat = { source.x, source.y, source.z, 1.0f };
 
-    // Multiply quat point by unprojecte matrix
+    // Multiply quat point by unprojected matrix
     Quaternion qtransformed = {     // QuaternionTransform(quat, matViewProjInv)
         matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
         matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
@@ -1209,15 +1209,9 @@
     {
         length = sqrtf(length);
 
-        float scale = 1;    // By default, 1 as the neutral element.
-        if (length < min)
-        {
-            scale = min/length;
-        }
-        else if (length > max)
-        {
-            scale = max/length;
-        }
+        float scale = 1; // By default, 1 as the neutral element
+        if (length < min) scale = min/length;
+        else if (length > max) scale = max/length;
 
         result.x = v.x*scale;
         result.y = v.y*scale;
@@ -1245,7 +1239,7 @@
 // v: normalized direction of the incoming ray
 // n: normalized normal vector of the interface of two optical media
 // r: ratio of the refractive index of the medium from where the ray comes
-//    to the refractive index of the medium on the other side of the surface
+// to the refractive index of the medium on the other side of the surface
 RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r)
 {
     Vector3 result = { 0 };
@@ -1270,19 +1264,21 @@
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Vector4 math
 //----------------------------------------------------------------------------------
-
+// Get  vector zero
 RMAPI Vector4 Vector4Zero(void)
 {
     Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f };
     return result;
 }
 
+// Get vector one
 RMAPI Vector4 Vector4One(void)
 {
     Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f };
     return result;
 }
 
+// Add two vectors
 RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2)
 {
     Vector4 result = {
@@ -1294,6 +1290,7 @@
     return result;
 }
 
+// Add value to vector components
 RMAPI Vector4 Vector4AddValue(Vector4 v, float add)
 {
     Vector4 result = {
@@ -1305,6 +1302,7 @@
     return result;
 }
 
+// Substract vectors
 RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2)
 {
     Vector4 result = {
@@ -1316,6 +1314,7 @@
     return result;
 }
 
+// Substract value from vector components
 RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add)
 {
     Vector4 result = {
@@ -1327,18 +1326,21 @@
     return result;
 }
 
+// Vector length
 RMAPI float Vector4Length(Vector4 v)
 {
     float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w));
     return result;
 }
 
+// Vector square length
 RMAPI float Vector4LengthSqr(Vector4 v)
 {
     float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w);
     return result;
 }
 
+// Vectors dot product
 RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2)
 {
     float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w);
@@ -1364,6 +1366,7 @@
     return result;
 }
 
+// Scale vector components by value (multiply)
 RMAPI Vector4 Vector4Scale(Vector4 v, float scale)
 {
     Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale };
@@ -1517,7 +1520,7 @@
              a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
 */
     // Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion),
-    // previous operation can be simplified to 40 multiplications, decreasing matrix 
+    // previous operation can be simplified to 40 multiplications, decreasing matrix
     // size from 4x4 to 2x2 using minors
 
     // Cache the matrix values (speed optimization)
@@ -1680,20 +1683,20 @@
 RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
 {
     Matrix result = { 0 };
-    
+
 #if defined(RAYMATH_SSE_ENABLED)
     // Load left side and right side
     __m128 c0 = _mm_set_ps(right.m12, right.m8,  right.m4,  right.m0);
     __m128 c1 = _mm_set_ps(right.m13, right.m9,  right.m5,  right.m1);
     __m128 c2 = _mm_set_ps(right.m14, right.m10, right.m6,  right.m2);
     __m128 c3 = _mm_set_ps(right.m15, right.m11, right.m7,  right.m3);
-    
+
     // Transpose so c0..c3 become *rows* of the right matrix in semantic order
     _MM_TRANSPOSE4_PS(c0, c1, c2, c3);
 
     float tmp[4] = { 0 };
     __m128 row;
-    
+
     // Row 0 of result: [m0, m1, m2, m3]
     row  = _mm_mul_ps(_mm_set1_ps(left.m0),  c0);
     row  = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m1),  c1));
@@ -1759,6 +1762,19 @@
     return result;
 }
 
+// Multiply matrix components by value
+RMAPI Matrix MatrixMultiplyValue(Matrix left, float value)
+{
+    Matrix result = {
+        left.m0*value, left.m4*value, left.m8*value, left.m12*value,
+        left.m1*value, left.m5*value, left.m9*value, left.m13*value,
+        left.m2*value, left.m6*value, left.m10*value, left.m14*value,
+        left.m3*value, left.m7*value, left.m11*value, left.m15*value
+    };
+
+    return result;
+}
+
 // Get translation matrix
 RMAPI Matrix MatrixTranslate(float x, float y, float z)
 {
@@ -2363,13 +2379,13 @@
 {
     Quaternion result = { 0 };
 
-    float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z);    // Vector3DotProduct(from, to)
+    float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to)
     Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to)
 
     result.x = cross.x;
     result.y = cross.y;
     result.z = cross.z;
-    result.w = 1.0f + cos2Theta;
+    result.w = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta) + cos2Theta;
 
     // QuaternionNormalize(q);
     // NOTE: Normalize to essentially nlerp the original and identity to 0.5
@@ -2489,19 +2505,14 @@
 {
     Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
 
-    float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
+    float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
 
-    if (axisLength != 0.0f)
+    if (length != 0.0f)
     {
         angle *= 0.5f;
 
-        float length = 0.0f;
-        float ilength = 0.0f;
-
         // Vector3Normalize(axis)
-        length = axisLength;
-        if (length == 0.0f) length = 1.0f;
-        ilength = 1.0f/length;
+        float ilength = 1.0f/length;
         axis.x *= ilength;
         axis.y *= ilength;
         axis.z *= ilength;
@@ -2556,8 +2567,8 @@
     }
     else
     {
-        // This occurs when the angle is zero.
-        // Not a problem: just set an arbitrary normalized axis.
+        // This occurs when the angle is zero
+        // Not a problem, set an arbitrary normalized axis
         resAxis.x = 1.0f;
     }
 
@@ -2661,16 +2672,16 @@
     right = Vector3RotateByQuaternion(right, rotation);
     up = Vector3RotateByQuaternion(up, rotation);
     forward = Vector3RotateByQuaternion(forward, rotation);
-    
+
     // Set result matrix output
-	Matrix result = {
-		right.x, up.x, forward.x, translation.x,
-		right.y, up.y, forward.y, translation.y,
-		right.z, up.z, forward.z, translation.z,
-		0.0f, 0.0f, 0.0f, 1.0f
-	};
+    Matrix result = {
+        right.x, up.x, forward.x, translation.x,
+        right.y, up.y, forward.y, translation.y,
+        right.z, up.z, forward.z, translation.z,
+        0.0f, 0.0f, 0.0f, 1.0f
+    };
 
-	return result;
+    return result;
 }
 
 // Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
@@ -2684,10 +2695,10 @@
     translation->y = mat.m13;
     translation->z = mat.m14;
 
-    // Matrix Columns - Rotation will be extracted into here.
-    Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
+    // Matrix Columns - Rotation will be extracted into here
+    Vector3 matColumns[3] = {{ mat.m0, mat.m4, mat.m8 },
                              { mat.m1, mat.m5, mat.m9 },
-                             { mat.m2, mat.m6, mat.m10 } };
+                             { mat.m2, mat.m6, mat.m10 }};
 
     // Shear Parameters XY, XZ, and YZ (extract and ignored)
     float shear[3] = { 0 };
@@ -2702,14 +2713,14 @@
         stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x));
         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]);
@@ -2719,7 +2730,7 @@
     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
     }
 
@@ -2733,12 +2744,12 @@
     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
     }
 
-    // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
+    // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1
     if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
     {
         scl = Vector3Negate(scl);
@@ -2791,6 +2802,11 @@
     return lhs;
 }
 
+inline Vector2 operator * (const float& lhs, const Vector2& rhs)
+{
+    return Vector2Scale(rhs, lhs);
+}
+
 inline Vector2 operator * (const Vector2& lhs, const float& rhs)
 {
     return Vector2Scale(lhs, rhs);
@@ -2885,6 +2901,11 @@
     return lhs;
 }
 
+inline Vector3 operator * (const float& lhs, const Vector3& rhs)
+{
+    return Vector3Scale(rhs, lhs);
+}
+
 inline Vector3 operator * (const Vector3& lhs, const float& rhs)
 {
     return Vector3Scale(lhs, rhs);
@@ -2980,6 +3001,11 @@
     return lhs;
 }
 
+inline Vector4 operator * (const float& lhs, const Vector4& rhs)
+{
+    return Vector4Scale(rhs, lhs);
+}
+
 inline Vector4 operator * (const Vector4& lhs, const float& rhs)
 {
     return Vector4Scale(lhs, rhs);
@@ -3073,6 +3099,11 @@
 }
 
 // Matrix operators
+static constexpr Matrix MatrixUnit = { 1, 0, 0, 0,
+                                       0, 1, 0, 0,
+                                       0, 0, 1, 0,
+                                       0, 0, 0, 1 };
+
 inline Matrix operator + (const Matrix& lhs, const Matrix& rhs)
 {
     return MatrixAdd(lhs, rhs);
@@ -3105,7 +3136,19 @@
     lhs = MatrixMultiply(lhs, rhs);
     return lhs;
 }
+
+inline Matrix operator * (const Matrix& lhs, const float value)
+{
+    return MatrixMultiplyValue(lhs, value);
+}
+
+inline const Matrix& operator *= (Matrix& lhs, const float value)
+{
+    lhs = MatrixMultiplyValue(lhs, value);
+    return lhs;
+}
+
 //-------------------------------------------------------------------------------
-#endif  // C++ operators
+#endif // C++ operators
 
-#endif  // RAYMATH_H
+#endif // RAYMATH_H
diff --git a/raylib/src/rcamera.h b/raylib/src/rcamera.h
--- a/raylib/src/rcamera.h
+++ b/raylib/src/rcamera.h
@@ -54,9 +54,9 @@
         #if defined(__TINYC__)
             #define __declspec(x) __attribute__((x))
         #endif
-        #define RLAPI __declspec(dllexport)     // We are building the library as a Win32 shared library (.dll)
+        #define RLAPI __declspec(dllexport)     // Building the library as a Win32 shared library (.dll)
     #elif defined(USE_LIBTYPE_SHARED)
-        #define RLAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
+        #define RLAPI __declspec(dllimport)     // Using the library as a Win32 shared library (.dll)
     #endif
 #endif
 
@@ -103,7 +103,7 @@
         Vector3 position;       // Camera position
         Vector3 target;         // Camera target it looks-at
         Vector3 up;             // Camera up vector (rotation over its axis)
-        float fovy;             // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
+        float fovy;             // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic
         int projection;         // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
     } Camera3D;
 
@@ -191,7 +191,7 @@
                             // IsKeyDown()
                             // IsKeyPressed()
                             // GetFrameTime()
-                            
+
 #include <math.h>           // Required for: fabsf()
 
 //----------------------------------------------------------------------------------
@@ -199,7 +199,7 @@
 //----------------------------------------------------------------------------------
 #define CAMERA_MOVE_SPEED                           5.4f       // Units per second
 #define CAMERA_ROTATION_SPEED                       0.03f
-#define CAMERA_PAN_SPEED                            0.2f
+#define CAMERA_PAN_SPEED                            2.0f
 
 // Camera mouse movement sensitivity
 #define CAMERA_MOUSE_MOVE_SENSITIVITY               0.003f
@@ -352,7 +352,7 @@
 // Rotates the camera around its right vector, pitch is "looking up and down"
 //  - lockView prevents camera overrotation (aka "somersaults")
 //  - rotateAroundTarget defines if rotation is around target or around its position
-//  - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
+//  - rotateUp rotates the up direction as well (typically only useful in CAMERA_FREE)
 // NOTE: [angle] must be provided in radians
 void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
 {
@@ -364,8 +364,8 @@
 
     if (lockView)
     {
-        // In these camera modes we clamp the Pitch angle
-        // to allow only viewing straight up or down.
+        // In these camera modes, clamp the Pitch angle
+        // to allow only viewing straight up or down
 
         // Clamp view up
         float maxAngleUp = Vector3Angle(up, targetPosition);
@@ -460,7 +460,6 @@
     if (mode == CAMERA_CUSTOM) {}
     else if (mode == CAMERA_ORBITAL)
     {
-        // Orbital can just orbit
         Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed);
         Vector3 view = Vector3Subtract(camera->position, camera->target);
         view = Vector3Transform(view, rotation);
diff --git a/raylib/src/rcore.c b/raylib/src/rcore.c
--- a/raylib/src/rcore.c
+++ b/raylib/src/rcore.c
@@ -17,4651 +17,4686 @@
 *           - Linux (X11/Wayland desktop mode)
 *           - macOS/OSX (x64, arm64)
 *           - Others (not tested)
-*       > PLATFORM_WEB_RGFW:
-*           - HTML5 (WebAssembly)
-*       > PLATFORM_WEB:
-*           - HTML5 (WebAssembly)
-*       > PLATFORM_DRM:
-*           - Raspberry Pi 0-5 (DRM/KMS)
-*           - Linux DRM subsystem (KMS mode)
-*       > PLATFORM_ANDROID:
-*           - Android (ARM, ARM64)
-*       > PLATFORM_DESKTOP_WIN32 (Native Win32):
-*           - Windows (Win32, Win64)
-*       > PLATFORM_MEMORY
-*           - Memory framebuffer output, using software renderer, no OS required
-*   CONFIGURATION:
-*       #define SUPPORT_DEFAULT_FONT (default)
-*           Default font is loaded on window initialization to be available for the user to render simple text
-*           NOTE: If enabled, uses external module functions to load default raylib font (module: text)
-*
-*       #define SUPPORT_CAMERA_SYSTEM
-*           Camera module is included (rcamera.h) and multiple predefined cameras are available:
-*               free, 1st/3rd person, orbital, custom
-*
-*       #define SUPPORT_GESTURES_SYSTEM
-*           Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
-*
-*       #define SUPPORT_MOUSE_GESTURES
-*           Mouse gestures are directly mapped like touches and processed by gestures system
-*
-*       #define SUPPORT_BUSY_WAIT_LOOP
-*           Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
-*
-*       #define SUPPORT_PARTIALBUSY_WAIT_LOOP
-*           Use a partial-busy wait loop, in this case frame sleeps for most of the time and runs a busy-wait-loop at the end
-*
-*       #define SUPPORT_SCREEN_CAPTURE
-*           Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
-*
-*       #define SUPPORT_COMPRESSION_API
-*           Support CompressData() and DecompressData() functions, those functions use zlib implementation
-*           provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
-*           for linkage
-*
-*       #define SUPPORT_AUTOMATION_EVENTS
-*           Support automatic events recording and playing, useful for automated testing systems or AI based game playing
-*
-*   DEPENDENCIES:
-*       raymath  - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
-*       camera   - Multiple 3D camera modes (free, orbital, 1st person, 3rd person)
-*       gestures - Gestures system for touch-ready devices (or simulated from mouse inputs)
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
-*
-*   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.
-*
-**********************************************************************************************/
-
-//----------------------------------------------------------------------------------
-// Feature Test Macros required for this module
-//----------------------------------------------------------------------------------
-#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_XOPEN_SOURCE < 500)
-    #undef _XOPEN_SOURCE
-    #define _XOPEN_SOURCE 500       // Required for: readlink if compiled with c99 without GNU extensions
-#endif
-
-#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_POSIX_C_SOURCE < 199309L)
-    #undef _POSIX_C_SOURCE
-    #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without GNU extensions
-#endif
-
-#include "raylib.h"                 // Declares module functions
-
-#include "config.h"                 // Defines module configuration flags
-
-#include <stdlib.h>                 // Required for: srand(), rand(), atexit(), exit()
-#include <stdio.h>                  // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
-#include <string.h>                 // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat()
-#include <stdarg.h>                 // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
-#include <time.h>                   // Required for: time() [Used in InitTimer()]
-#include <math.h>                   // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
-
-#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB)
-    #define SW_GL_FRAMEBUFFER_COPY_BGRA false
-#endif
-#define RLGL_IMPLEMENTATION
-#include "rlgl.h"                   // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-
-#define RAYMATH_IMPLEMENTATION
-#include "raymath.h"                // Vector2, Vector3, Quaternion and Matrix functionality
-
-#if defined(SUPPORT_GESTURES_SYSTEM)
-    #define RGESTURES_IMPLEMENTATION
-    #include "rgestures.h"          // Gestures detection functionality
-#endif
-
-#if defined(SUPPORT_CAMERA_SYSTEM)
-    #define RCAMERA_IMPLEMENTATION
-    #include "rcamera.h"            // Camera system functionality
-#endif
-
-#if defined(SUPPORT_COMPRESSION_API)
-    #define SINFL_IMPLEMENTATION
-    #define SINFL_NO_SIMD
-    #include "external/sinfl.h"     // Deflate (RFC 1951) decompressor
-
-    #define SDEFL_IMPLEMENTATION
-    #include "external/sdefl.h"     // Deflate (RFC 1951) compressor
-#endif
-
-#if defined(SUPPORT_RPRAND_GENERATOR)
-    #define RPRAND_IMPLEMENTATION
-    #include "external/rprand.h"
-#endif
-
-#if defined(__linux__) && !defined(_GNU_SOURCE)
-    #define _GNU_SOURCE
-#endif
-
-// Platform specific defines to handle GetApplicationDirectory()
-#if defined(_WIN32)
-    #if !defined(MAX_PATH)
-        #define MAX_PATH 260
-    #endif
-
-    struct HINSTANCE__;
-    #if defined(__cplusplus)
-    extern "C" {
-    #endif
-    __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize);
-    __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize);
-    __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
-    __declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
-    __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
-    #if defined(__cplusplus)
-    }
-    #endif
-#elif defined(__linux__)
-    #include <unistd.h>
-#elif defined(__FreeBSD__)
-    #include <sys/types.h>
-    #include <sys/sysctl.h>
-    #include <unistd.h>
-#elif defined(__APPLE__)
-    #include <sys/syslimits.h>
-    #include <mach-o/dyld.h>
-#endif // OSs
-
-#define _CRT_INTERNAL_NONSTDC_NAMES  1
-#include <sys/stat.h>               // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()]
-
-#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
-    #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-
-#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
-    #define DIRENT_MALLOC RL_MALLOC
-    #define DIRENT_FREE RL_FREE
-
-    #include "external/dirent.h"    // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
-#else
-    #include <dirent.h>             // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
-#endif
-
-#if defined(_WIN32)
-    #include <io.h>                 // Required for: _access() [Used in FileExists()]
-    #include <direct.h>             // Required for: _getch(), _chdir(), _mkdir()
-    #define GETCWD _getcwd          // NOTE: MSDN recommends not to use getcwd(), chdir()
-    #define CHDIR _chdir
-    #define MKDIR(dir) _mkdir(dir)
-    #define ACCESS(fn) _access(fn, 0)
-#else
-    #include <unistd.h>             // Required for: getch(), chdir(), mkdir(), access()
-    #define GETCWD getcwd
-    #define CHDIR chdir
-    #define MKDIR(dir) mkdir(dir, 0777)
-    #define ACCESS(fn) access(fn, F_OK)
-#endif
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#ifndef MAX_TRACELOG_MSG_LENGTH
-    #define MAX_TRACELOG_MSG_LENGTH      256        // Max length of one trace-log message
-#endif
-
-#ifndef MAX_FILEPATH_CAPACITY
-    #define MAX_FILEPATH_CAPACITY       8192        // Maximum capacity for filepath
-#endif
-#ifndef MAX_FILEPATH_LENGTH
-    #if defined(_WIN32)
-        #define MAX_FILEPATH_LENGTH      256        // On Win32, MAX_PATH = 260 (limits.h) but Windows 10, Version 1607 enables long paths...
-    #else
-        #define MAX_FILEPATH_LENGTH     4096        // On Linux, PATH_MAX = 4096 by default (limits.h)
-    #endif
-#endif
-
-#ifndef MAX_KEYBOARD_KEYS
-    #define MAX_KEYBOARD_KEYS            512        // Maximum number of keyboard keys supported
-#endif
-#ifndef MAX_MOUSE_BUTTONS
-    #define MAX_MOUSE_BUTTONS              8        // Maximum number of mouse buttons supported
-#endif
-#ifndef MAX_GAMEPADS
-    #define MAX_GAMEPADS                   4        // Maximum number of gamepads supported
-#endif
-#ifndef MAX_GAMEPAD_NAME_LENGTH
-    #define MAX_GAMEPAD_NAME_LENGTH      128        // Maximum number of characters in a gamepad name (byte size)
-#endif
-#ifndef MAX_GAMEPAD_AXES
-    #define MAX_GAMEPAD_AXES               8        // Maximum number of axes supported (per gamepad)
-#endif
-#ifndef MAX_GAMEPAD_BUTTONS
-    #define MAX_GAMEPAD_BUTTONS           32        // Maximum number of buttons supported (per gamepad)
-#endif
-#ifndef MAX_GAMEPAD_VIBRATION_TIME
-    #define MAX_GAMEPAD_VIBRATION_TIME     2.0f     // Maximum vibration time in seconds
-#endif
-#ifndef MAX_TOUCH_POINTS
-    #define MAX_TOUCH_POINTS               8        // Maximum number of touch points supported
-#endif
-#ifndef MAX_KEY_PRESSED_QUEUE
-    #define MAX_KEY_PRESSED_QUEUE         16        // Maximum number of keys in the key input queue
-#endif
-#ifndef MAX_CHAR_PRESSED_QUEUE
-    #define MAX_CHAR_PRESSED_QUEUE        16        // Maximum number of characters in the char input queue
-#endif
-
-#ifndef MAX_DECOMPRESSION_SIZE
-    #define MAX_DECOMPRESSION_SIZE        64        // Maximum size allocated for decompression in MB
-#endif
-
-#ifndef MAX_AUTOMATION_EVENTS
-    #define MAX_AUTOMATION_EVENTS      16384        // Maximum number of automation events to record
-#endif
-
-#ifndef DIRECTORY_FILTER_TAG
-    #define DIRECTORY_FILTER_TAG       "DIR"        // Name tag used to request directory inclusion on directory scan
-#endif                                              // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx()
-
-// Flags operation macros
-#define FLAG_SET(n, f) ((n) |= (f))
-#define FLAG_CLEAR(n, f) ((n) &= ~(f))
-#define FLAG_TOGGLE(n, f) ((n) ^= (f))
-#define FLAG_IS_SET(n, f) (((n) & (f)) == (f))
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-typedef struct { int x; int y; } Point;
-typedef struct { unsigned int width; unsigned int height; } Size;
-
-// Core global state context data
-typedef struct CoreData {
-    struct {
-        const char *title;                  // Window text title const pointer
-        unsigned int flags;                 // Configuration flags (bit based), keeps window state
-        bool ready;                         // Check if window has been initialized successfully
-        bool shouldClose;                   // Check if window set for closing
-        bool resizedLastFrame;              // Check if window has been resized last frame
-        bool eventWaiting;                  // Wait for events before ending frame
-        bool usingFbo;                      // Using FBO (RenderTexture) for rendering instead of default framebuffer
-
-        Size display;                       // Display width and height (monitor, device-screen, LCD, ...)
-        Size screen;                        // Screen current width and height
-        Point position;                     // Window current position
-        Size previousScreen;                // Screen previous width and height (required on fullscreen/borderless-windowed toggle)
-        Point previousPosition;             // Window previous position (required on fullscreeen/borderless-windowed toggle)
-        Size render;                        // Screen framebuffer width and height
-        Point renderOffset;                 // Screen framebuffer render offset (Not required anymore?)
-        Size currentFbo;                    // Current framebuffer render width and height (depends on active render texture)
-        Size screenMin;                     // Screen minimum width and height (for resizable window)
-        Size screenMax;                     // Screen maximum width and height (for resizable window)
-        Matrix screenScale;                 // Matrix to scale screen (framebuffer rendering)
-
-        char **dropFilepaths;               // Store dropped files paths pointers (provided by GLFW)
-        unsigned int dropFileCount;         // Count dropped files strings
-
-    } Window;
-    struct {
-        const char *basePath;               // Base path for data storage
-
-    } Storage;
-    struct {
-        struct {
-            int exitKey;                    // Default exit key
-            char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
-            char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
-
-            // NOTE: Since key press logic involves comparing previous vs currrent key state,
-            // key repeats needs to be handled specially
-            char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame
-
-            int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
-            int keyPressedQueueCount;       // Input keys queue count
-
-            int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
-            int charPressedQueueCount;      // Input characters queue count
-
-        } Keyboard;
-        struct {
-            Vector2 offset;                 // Mouse offset
-            Vector2 scale;                  // Mouse scaling
-            Vector2 currentPosition;        // Mouse position on screen
-            Vector2 previousPosition;       // Previous mouse position
-            Vector2 lockedPosition;         // Mouse position when locked
-
-            int cursor;                     // Tracks current mouse cursor
-            bool cursorHidden;              // Track if cursor is hidden
-            bool cursorLocked;              // Track if cursor is locked (disabled)
-            bool cursorOnScreen;            // Tracks if cursor is inside client area
-
-            char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
-            char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
-            Vector2 currentWheelMove;       // Registers current mouse wheel variation
-            Vector2 previousWheelMove;      // Registers previous mouse wheel variation
-
-        } Mouse;
-        struct {
-            int pointCount;                                 // Number of touch points active
-            int pointId[MAX_TOUCH_POINTS];                  // Point identifiers
-            Vector2 position[MAX_TOUCH_POINTS];             // Touch position on screen
-            Vector2 previousPosition[MAX_TOUCH_POINTS];     // Previous touch position on screen
-            char currentTouchState[MAX_TOUCH_POINTS];       // Registers current touch state
-            char previousTouchState[MAX_TOUCH_POINTS];      // Registers previous touch state
-
-        } Touch;
-        struct {
-            int lastButtonPressed;          // Register last gamepad button pressed
-            int axisCount[MAX_GAMEPADS];    // Register number of available gamepad axes
-            bool ready[MAX_GAMEPADS];       // Flag to know if gamepad is ready
-            char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH];               // Gamepad name holder
-            char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS];     // Current gamepad buttons state
-            char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS];    // Previous gamepad buttons state
-            float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES];                // Gamepad axes state
-
-        } Gamepad;
-    } Input;
-    struct {
-        double current;                     // Current time measure
-        double previous;                    // Previous time measure
-        double update;                      // Time measure for frame update
-        double draw;                        // Time measure for frame draw
-        double frame;                       // Time measure for one frame
-        double target;                      // Desired time for one frame, if 0 not applied
-        unsigned long long int base;        // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM)
-        unsigned int frameCounter;          // Frame counter
-
-    } Time;
-} CoreData;
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-RLAPI const char *raylib_version = RAYLIB_VERSION;  // raylib version exported symbol, required for some bindings
-
-CoreData CORE = { 0 };                              // Global CORE state context
-
-static int logTypeLevel = LOG_INFO;                 // Minimum log type level
-
-static TraceLogCallback traceLog = NULL;            // TraceLog callback function pointer
-static LoadFileDataCallback loadFileData = NULL;    // LoadFileData callback function pointer
-static SaveFileDataCallback saveFileData = NULL;    // SaveFileText callback function pointer
-static LoadFileTextCallback loadFileText = NULL;    // LoadFileText callback function pointer
-static SaveFileTextCallback saveFileText = NULL;    // SaveFileText callback function pointer
-
-#if defined(SUPPORT_SCREEN_CAPTURE)
-static int screenshotCounter = 0;                   // Screenshots counter
-#endif
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-// Automation events type
-typedef enum AutomationEventType {
-    EVENT_NONE = 0,
-    // Input events
-    INPUT_KEY_UP,                   // param[0]: key
-    INPUT_KEY_DOWN,                 // param[0]: key
-    INPUT_KEY_PRESSED,              // param[0]: key
-    INPUT_KEY_RELEASED,             // param[0]: key
-    INPUT_MOUSE_BUTTON_UP,          // param[0]: button
-    INPUT_MOUSE_BUTTON_DOWN,        // param[0]: button
-    INPUT_MOUSE_POSITION,           // param[0]: x, param[1]: y
-    INPUT_MOUSE_WHEEL_MOTION,       // param[0]: x delta, param[1]: y delta
-    INPUT_GAMEPAD_CONNECT,          // param[0]: gamepad
-    INPUT_GAMEPAD_DISCONNECT,       // param[0]: gamepad
-    INPUT_GAMEPAD_BUTTON_UP,        // param[0]: button
-    INPUT_GAMEPAD_BUTTON_DOWN,      // param[0]: button
-    INPUT_GAMEPAD_AXIS_MOTION,      // param[0]: axis, param[1]: delta
-    INPUT_TOUCH_UP,                 // param[0]: id
-    INPUT_TOUCH_DOWN,               // param[0]: id
-    INPUT_TOUCH_POSITION,           // param[0]: x, param[1]: y
-    INPUT_GESTURE,                  // param[0]: gesture
-    // Window events
-    WINDOW_CLOSE,                   // no params
-    WINDOW_MAXIMIZE,                // no params
-    WINDOW_MINIMIZE,                // no params
-    WINDOW_RESIZE,                  // param[0]: width, param[1]: height
-    // Custom events
-    ACTION_TAKE_SCREENSHOT,         // no params
-    ACTION_SETTARGETFPS             // param[0]: fps
-} AutomationEventType;
-
-// Event type to config events flags
-// WARNING: Not used at the moment
-typedef enum {
-    EVENT_INPUT_KEYBOARD    = 0,
-    EVENT_INPUT_MOUSE       = 1,
-    EVENT_INPUT_GAMEPAD     = 2,
-    EVENT_INPUT_TOUCH       = 4,
-    EVENT_INPUT_GESTURE     = 8,
-    EVENT_WINDOW            = 16,
-    EVENT_CUSTOM            = 32
-} EventType;
-
-// Event type name strings, required for export
-static const char *autoEventTypeName[] = {
-    "EVENT_NONE",
-    "INPUT_KEY_UP",
-    "INPUT_KEY_DOWN",
-    "INPUT_KEY_PRESSED",
-    "INPUT_KEY_RELEASED",
-    "INPUT_MOUSE_BUTTON_UP",
-    "INPUT_MOUSE_BUTTON_DOWN",
-    "INPUT_MOUSE_POSITION",
-    "INPUT_MOUSE_WHEEL_MOTION",
-    "INPUT_GAMEPAD_CONNECT",
-    "INPUT_GAMEPAD_DISCONNECT",
-    "INPUT_GAMEPAD_BUTTON_UP",
-    "INPUT_GAMEPAD_BUTTON_DOWN",
-    "INPUT_GAMEPAD_AXIS_MOTION",
-    "INPUT_TOUCH_UP",
-    "INPUT_TOUCH_DOWN",
-    "INPUT_TOUCH_POSITION",
-    "INPUT_GESTURE",
-    "WINDOW_CLOSE",
-    "WINDOW_MAXIMIZE",
-    "WINDOW_MINIMIZE",
-    "WINDOW_RESIZE",
-    "ACTION_TAKE_SCREENSHOT",
-    "ACTION_SETTARGETFPS"
-};
-
-/*
-// Automation event (24 bytes)
-// NOTE: Opaque struct, internal to raylib
-struct AutomationEvent {
-    unsigned int frame;                 // Event frame
-    unsigned int type;                  // Event type (AutomationEventType)
-    int params[4];                      // Event parameters (if required)
-};
-*/
-
-static AutomationEventList *currentEventList = NULL;        // Current automation events list, set by user, keep internal pointer
-static bool automationEventRecording = false;               // Recording automation events flag
-//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
-#endif
-//-----------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-// NOTE: Those functions are common for all platforms!
-//----------------------------------------------------------------------------------
-
-#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
-extern void LoadFontDefault(void);      // [Module: text] Loads default font on InitWindow()
-extern void UnloadFontDefault(void);    // [Module: text] Unloads default font from GPU memory
-#endif
-
-extern int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
-extern void ClosePlatform(void);        // Close platform
-
-static void InitTimer(void);                                // Initialize timer, hi-resolution if available (required by InitPlatform())
-static void SetupViewport(int width, int height);           // Set viewport for a provided width and height
-
-static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter);   // Scan all files and directories in a base path
-static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *list, const char *filter);  // Scan all files and directories recursively from a base path
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-static void RecordAutomationEvent(void); // Record frame events (to internal events array)
-#endif
-
-#if defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)
-// NOTE: We declare Sleep() function symbol to avoid including windows.h (kernel32.lib linkage required)
-__declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime()
-#endif
-
-#if !defined(SUPPORT_MODULE_RTEXT)
-const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
-#endif // !SUPPORT_MODULE_RTEXT
-
-#if defined(PLATFORM_DESKTOP)
-    #define PLATFORM_DESKTOP_GLFW
-#endif
-
-// We're using '#pragma message' because '#warning' is not adopted by MSVC
-#if defined(SUPPORT_CLIPBOARD_IMAGE)
-    #if !defined(SUPPORT_MODULE_RTEXTURES)
-        #pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
-    #endif
-
-    // It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
-    #if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
-        #pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
-    #endif
-
-    // From what I've tested applications on Wayland saves images on clipboard as PNG
-    #if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
-        #pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
-    #endif
-#endif // SUPPORT_CLIPBOARD_IMAGE
-
-// Include platform-specific submodules
-#if defined(PLATFORM_DESKTOP_GLFW)
-    #include "platforms/rcore_desktop_glfw.c"
-#elif defined(PLATFORM_DESKTOP_SDL)
-    #include "platforms/rcore_desktop_sdl.c"
-#elif (defined(PLATFORM_DESKTOP_RGFW) || defined(PLATFORM_WEB_RGFW))
-    #include "platforms/rcore_desktop_rgfw.c"
-#elif defined(PLATFORM_DESKTOP_WIN32)
-    #include "platforms/rcore_desktop_win32.c"
-#elif defined(PLATFORM_WEB)
-    #include "platforms/rcore_web.c"
-#elif defined(PLATFORM_DRM)
-    #include "platforms/rcore_drm.c"
-#elif defined(PLATFORM_ANDROID)
-    #include "platforms/rcore_android.c"
-#elif defined(PLATFORM_MEMORY)
-    #include "platforms/rcore_memory.c"
-#else
-    // TODO: Include your custom platform backend!
-    // i.e software rendering backend or console backend!
-    #pragma message ("WARNING: No [rcore] platform defined")
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Window and Graphics Device
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//bool WindowShouldClose(void)
-//void ToggleFullscreen(void)
-//void ToggleBorderlessWindowed(void)
-//void MaximizeWindow(void)
-//void MinimizeWindow(void)
-//void RestoreWindow(void)
-
-//void SetWindowState(unsigned int flags)
-//void ClearWindowState(unsigned int flags)
-
-//void SetWindowIcon(Image image)
-//void SetWindowIcons(Image *images, int count)
-//void SetWindowTitle(const char *title)
-//void SetWindowPosition(int x, int y)
-//void SetWindowMonitor(int monitor)
-//void SetWindowMinSize(int width, int height)
-//void SetWindowMaxSize(int width, int height)
-//void SetWindowSize(int width, int height)
-//void SetWindowOpacity(float opacity)
-//void SetWindowFocused(void)
-//void *GetWindowHandle(void)
-//Vector2 GetWindowPosition(void)
-//Vector2 GetWindowScaleDPI(void)
-
-//int GetMonitorCount(void)
-//int GetCurrentMonitor(void)
-//int GetMonitorWidth(int monitor)
-//int GetMonitorHeight(int monitor)
-//int GetMonitorPhysicalWidth(int monitor)
-//int GetMonitorPhysicalHeight(int monitor)
-//int GetMonitorRefreshRate(int monitor)
-//Vector2 GetMonitorPosition(int monitor)
-//const char *GetMonitorName(int monitor)
-
-//void SetClipboardText(const char *text)
-//const char *GetClipboardText(void)
-
-//void ShowCursor(void)
-//void HideCursor(void)
-//void EnableCursor(void)
-//void DisableCursor(void)
-
-// Initialize window and OpenGL context
-void InitWindow(int width, int height, const char *title)
-{
-    TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
-
-#if defined(PLATFORM_DESKTOP_GLFW)
-    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (GLFW)");
-#elif defined(PLATFORM_DESKTOP_SDL)
-    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (SDL)");
-#elif defined(PLATFORM_DESKTOP_RGFW)
-    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (RGFW)");
-#elif defined(PLATFORM_DESKTOP_WIN32)
-    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (WIN32)");
-#elif defined(PLATFORM_WEB_RGFW)
-    TRACELOG(LOG_INFO, "Platform backend: WEB (RGFW) (HTML5)");
-#elif defined(PLATFORM_WEB)
-    TRACELOG(LOG_INFO, "Platform backend: WEB (HTML5)");
-#elif defined(PLATFORM_DRM)
-    TRACELOG(LOG_INFO, "Platform backend: NATIVE DRM");
-#elif defined(PLATFORM_ANDROID)
-    TRACELOG(LOG_INFO, "Platform backend: ANDROID");
-#elif defined(PLATFORM_MEMORY)
-    TRACELOG(LOG_INFO, "Platform backend: MEMORY (No OS)");
-#else
-    // TODO: Include your custom platform backend!
-    // i.e software rendering backend or console backend!
-    TRACELOG(LOG_INFO, "Platform backend: CUSTOM");
-#endif
-
-    TRACELOG(LOG_INFO, "Supported raylib modules:");
-    TRACELOG(LOG_INFO, "    > rcore:..... loaded (mandatory)");
-    TRACELOG(LOG_INFO, "    > rlgl:...... loaded (mandatory)");
-#if defined(SUPPORT_MODULE_RSHAPES)
-    TRACELOG(LOG_INFO, "    > rshapes:... loaded (optional)");
-#else
-    TRACELOG(LOG_INFO, "    > rshapes:... not loaded (optional)");
-#endif
-#if defined(SUPPORT_MODULE_RTEXTURES)
-    TRACELOG(LOG_INFO, "    > rtextures:. loaded (optional)");
-#else
-    TRACELOG(LOG_INFO, "    > rtextures:. not loaded (optional)");
-#endif
-#if defined(SUPPORT_MODULE_RTEXT)
-    TRACELOG(LOG_INFO, "    > rtext:..... loaded (optional)");
-#else
-    TRACELOG(LOG_INFO, "    > rtext:..... not loaded (optional)");
-#endif
-#if defined(SUPPORT_MODULE_RMODELS)
-    TRACELOG(LOG_INFO, "    > rmodels:... loaded (optional)");
-#else
-    TRACELOG(LOG_INFO, "    > rmodels:... not loaded (optional)");
-#endif
-#if defined(SUPPORT_MODULE_RAUDIO)
-    TRACELOG(LOG_INFO, "    > raudio:.... loaded (optional)");
-#else
-    TRACELOG(LOG_INFO, "    > raudio:.... not loaded (optional)");
-#endif
-
-    // Initialize window data
-    CORE.Window.screen.width = width;
-    CORE.Window.screen.height = height;
-    CORE.Window.currentFbo.width = CORE.Window.screen.width;
-    CORE.Window.currentFbo.height = CORE.Window.screen.height;
-
-    CORE.Window.eventWaiting = false;
-    CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
-    if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
-
-    // Initialize global input state
-    memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
-    CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
-    CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
-    CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
-    CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
-
-    // Initialize platform
-    //--------------------------------------------------------------
-    int result = InitPlatform();
-
-    if (result != 0)
-    {
-        TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform");
-        return;
-    }
-    //--------------------------------------------------------------
-
-    // Initialize rlgl default data (buffers and shaders)
-    // NOTE: Current fbo size stored as globals in rlgl for convenience
-    rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
-
-    // Setup default viewport
-    SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
-
-#if defined(SUPPORT_MODULE_RTEXT)
-    #if defined(SUPPORT_DEFAULT_FONT)
-        // Load default font
-        // WARNING: External function: Module required: rtext
-        LoadFontDefault();
-        #if defined(SUPPORT_MODULE_RSHAPES)
-        // Set font white rectangle for shapes drawing, so shapes and text can be batched together
-        // WARNING: rshapes module is required, if not available, default internal white rectangle is used
-        Rectangle rec = GetFontDefault().recs[95];
-        if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
-        {
-            // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
-            SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
-        }
-        else
-        {
-            // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
-            SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
-        }
-        #endif
-    #endif
-#else
-    #if defined(SUPPORT_MODULE_RSHAPES)
-    // Set default texture and rectangle to be used for shapes drawing
-    // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
-    Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
-    SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f });    // WARNING: Module required: rshapes
-    #endif
-#endif
-
-    CORE.Time.frameCounter = 0;
-    CORE.Window.shouldClose = false;
-
-    // Initialize random seed
-    SetRandomSeed((unsigned int)time(NULL));
-
-    TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory());
-}
-
-// Close window and unload OpenGL context
-void CloseWindow(void)
-{
-#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
-    UnloadFontDefault();        // WARNING: Module required: rtext
-#endif
-
-    rlglClose();                // De-init rlgl
-
-    // De-initialize platform
-    //--------------------------------------------------------------
-    ClosePlatform();
-    //--------------------------------------------------------------
-
-    CORE.Window.ready = false;
-    TRACELOG(LOG_INFO, "Window closed successfully");
-}
-
-// Check if window has been initialized successfully
-bool IsWindowReady(void)
-{
-    return CORE.Window.ready;
-}
-
-// Check if window is currently fullscreen
-bool IsWindowFullscreen(void)
-{
-    return FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
-}
-
-// Check if window is currently hidden
-bool IsWindowHidden(void)
-{
-    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
-}
-
-// Check if window has been minimized
-bool IsWindowMinimized(void)
-{
-    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
-}
-
-// Check if window has been maximized
-bool IsWindowMaximized(void)
-{
-    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
-}
-
-// Check if window has the focus
-bool IsWindowFocused(void)
-{
-    return !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
-}
-
-// Check if window has been resizedLastFrame
-bool IsWindowResized(void)
-{
-    return CORE.Window.resizedLastFrame;
-}
-
-// Check if one specific window flag is enabled
-bool IsWindowState(unsigned int flag)
-{
-    return FLAG_IS_SET(CORE.Window.flags, flag);
-}
-
-// Get current screen width
-int GetScreenWidth(void)
-{
-    return CORE.Window.screen.width;
-}
-
-// Get current screen height
-int GetScreenHeight(void)
-{
-    return CORE.Window.screen.height;
-}
-
-// Get current render width which is equal to screen width*dpi scale
-int GetRenderWidth(void)
-{
-    int width = 0;
-
-    if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width;
-    else width = CORE.Window.render.width;
-
-    return width;
-}
-
-// Get current screen height which is equal to screen height*dpi scale
-int GetRenderHeight(void)
-{
-    int height = 0;
-
-    if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height;
-    else height = CORE.Window.render.height;
-
-    return height;
-}
-
-// Enable waiting for events on EndDrawing(), no automatic event polling
-void EnableEventWaiting(void)
-{
-    CORE.Window.eventWaiting = true;
-}
-
-// Disable waiting for events on EndDrawing(), automatic events polling
-void DisableEventWaiting(void)
-{
-    CORE.Window.eventWaiting = false;
-}
-
-// Check if cursor is not visible
-bool IsCursorHidden(void)
-{
-    return CORE.Input.Mouse.cursorHidden;
-}
-
-// Check if cursor is on the current screen
-bool IsCursorOnScreen(void)
-{
-    return CORE.Input.Mouse.cursorOnScreen;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Screen Drawing
-//----------------------------------------------------------------------------------
-
-// Set background color (framebuffer clear color)
-void ClearBackground(Color color)
-{
-    rlClearColor(color.r, color.g, color.b, color.a);   // Set clear color
-    rlClearScreenBuffers();                             // Clear current framebuffers
-}
-
-// Setup canvas (framebuffer) to start drawing
-void BeginDrawing(void)
-{
-    // WARNING: Previously to BeginDrawing() other render textures drawing could happen,
-    // consequently the measure for update vs draw is not accurate (only the total frame time is accurate)
-
-    CORE.Time.current = GetTime();      // Number of elapsed seconds since InitTimer()
-    CORE.Time.update = CORE.Time.current - CORE.Time.previous;
-    CORE.Time.previous = CORE.Time.current;
-
-    rlLoadIdentity();                   // Reset current matrix (modelview)
-    rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling
-
-    //rlTranslatef(0.375, 0.375, 0);    // HACK to have 2D pixel-perfect drawing on OpenGL 1.1
-                                        // NOTE: Not required with OpenGL 3.3+
-}
-
-// End canvas drawing and swap buffers (double buffering)
-void EndDrawing(void)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    if (automationEventRecording) RecordAutomationEvent();    // Event recording
-#endif
-
-#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
-    SwapScreenBuffer();                  // Copy back buffer to front buffer (screen)
-
-    // Frame time control system
-    CORE.Time.current = GetTime();
-    CORE.Time.draw = CORE.Time.current - CORE.Time.previous;
-    CORE.Time.previous = CORE.Time.current;
-
-    CORE.Time.frame = CORE.Time.update + CORE.Time.draw;
-
-    // Wait for some milliseconds...
-    if (CORE.Time.frame < CORE.Time.target)
-    {
-        WaitTime(CORE.Time.target - CORE.Time.frame);
-
-        CORE.Time.current = GetTime();
-        double waitTime = CORE.Time.current - CORE.Time.previous;
-        CORE.Time.previous = CORE.Time.current;
-
-        CORE.Time.frame += waitTime;    // Total frame time: update + draw + wait
-    }
-
-    PollInputEvents();      // Poll user events (before next frame update)
-#endif
-
-#if defined(SUPPORT_SCREEN_CAPTURE)
-    if (IsKeyPressed(KEY_F12))
-    {
-        TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
-        screenshotCounter++;
-    }
-#endif  // SUPPORT_SCREEN_CAPTURE
-
-    CORE.Time.frameCounter++;
-}
-
-// Initialize 2D mode with custom camera (2D)
-void BeginMode2D(Camera2D camera)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlLoadIdentity();               // Reset current matrix (modelview)
-
-    // Apply 2d camera transformation to modelview
-    rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
-}
-
-// Ends 2D mode with custom camera
-void EndMode2D(void)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlLoadIdentity();               // Reset current matrix (modelview)
-
-    if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
-}
-
-// Initializes 3D mode with custom camera (3D)
-void BeginMode3D(Camera camera)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
-    rlPushMatrix();                 // Save previous matrix, which contains the settings for the 2d ortho projection
-    rlLoadIdentity();               // Reset current matrix (projection)
-
-    float aspect = (float)CORE.Window.currentFbo.width/(float)CORE.Window.currentFbo.height;
-
-    // NOTE: zNear and zFar values are important when computing depth buffer values
-    if (camera.projection == CAMERA_PERSPECTIVE)
-    {
-        // Setup perspective projection
-        double top = rlGetCullDistanceNear()*tan(camera.fovy*0.5*DEG2RAD);
-        double right = top*aspect;
-
-        rlFrustum(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
-    {
-        // Setup orthographic projection
-        double top = camera.fovy/2.0;
-        double right = top*aspect;
-
-        rlOrtho(-right, right, -top,top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-
-    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
-    rlLoadIdentity();               // Reset current matrix (modelview)
-
-    // Setup Camera view
-    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
-    rlMultMatrixf(MatrixToFloat(matView));      // Multiply modelview matrix by view matrix (camera)
-
-    rlEnableDepthTest();            // Enable DEPTH_TEST for 3D
-}
-
-// Ends 3D mode and returns to default 2D orthographic mode
-void EndMode3D(void)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
-    rlPopMatrix();                  // Restore previous matrix (projection) from matrix stack
-
-    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
-    rlLoadIdentity();               // Reset current matrix (modelview)
-
-    if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
-
-    rlDisableDepthTest();           // Disable DEPTH_TEST for 2D
-}
-
-// Initializes render texture for drawing
-void BeginTextureMode(RenderTexture2D target)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlEnableFramebuffer(target.id); // Enable render target
-
-    // Set viewport and RLGL internal framebuffer size
-    rlViewport(0, 0, target.texture.width, target.texture.height);
-    rlSetFramebufferWidth(target.texture.width);
-    rlSetFramebufferHeight(target.texture.height);
-
-    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
-    rlLoadIdentity();               // Reset current matrix (projection)
-
-    // Set orthographic projection to current framebuffer size
-    // NOTE: Configured top-left corner as (0, 0)
-    rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f);
-
-    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
-    rlLoadIdentity();               // Reset current matrix (modelview)
-
-    //rlScalef(0.0f, -1.0f, 0.0f);  // Flip Y-drawing (?)
-
-    // Setup current width/height for proper aspect ratio
-    // calculation when using BeginTextureMode()
-    CORE.Window.currentFbo.width = target.texture.width;
-    CORE.Window.currentFbo.height = target.texture.height;
-    CORE.Window.usingFbo = true;
-}
-
-// Ends drawing to render texture
-void EndTextureMode(void)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlDisableFramebuffer();         // Disable render target (fbo)
-
-    // Set viewport to default framebuffer size
-    SetupViewport(CORE.Window.render.width, CORE.Window.render.height);
-
-    // Go back to the modelview state from BeginDrawing since we are back to the default FBO
-    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
-    rlLoadIdentity();               // Reset current matrix (modelview)
-    rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
-
-    // Reset current fbo to screen size
-    CORE.Window.currentFbo.width = CORE.Window.render.width;
-    CORE.Window.currentFbo.height = CORE.Window.render.height;
-    CORE.Window.usingFbo = false;
-}
-
-// Begin custom shader mode
-void BeginShaderMode(Shader shader)
-{
-    rlSetShader(shader.id, shader.locs);
-}
-
-// End custom shader mode (returns to default shader)
-void EndShaderMode(void)
-{
-    rlSetShader(rlGetShaderIdDefault(), rlGetShaderLocsDefault());
-}
-
-// Begin blending mode (alpha, additive, multiplied, subtract, custom)
-// NOTE: Blend modes supported are enumerated in BlendMode enum
-void BeginBlendMode(int mode)
-{
-    rlSetBlendMode(mode);
-}
-
-// End blending mode (reset to default: alpha blending)
-void EndBlendMode(void)
-{
-    rlSetBlendMode(BLEND_ALPHA);
-}
-
-// Begin scissor mode (define screen area for following drawing)
-// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left
-void BeginScissorMode(int x, int y, int width, int height)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-
-    rlEnableScissorTest();
-
-#if defined(__APPLE__)
-    if (!CORE.Window.usingFbo)
-    {
-        Vector2 scale = GetWindowScaleDPI();
-        rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
-    }
-#else
-    if (!CORE.Window.usingFbo && FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
-    {
-        Vector2 scale = GetWindowScaleDPI();
-        rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
-    }
-#endif
-    else
-    {
-        rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
-    }
-}
-
-// End scissor mode
-void EndScissorMode(void)
-{
-    rlDrawRenderBatchActive();      // Update and draw internal render batch
-    rlDisableScissorTest();
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: VR Stereo Rendering
-//----------------------------------------------------------------------------------
-
-// Begin VR drawing configuration
-void BeginVrStereoMode(VrStereoConfig config)
-{
-    rlEnableStereoRender();
-
-    // Set stereo render matrices
-    rlSetMatrixProjectionStereo(config.projection[0], config.projection[1]);
-    rlSetMatrixViewOffsetStereo(config.viewOffset[0], config.viewOffset[1]);
-}
-
-// End VR drawing process (and desktop mirror)
-void EndVrStereoMode(void)
-{
-    rlDisableStereoRender();
-}
-
-// Load VR stereo config for VR simulator device parameters
-VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device)
-{
-    VrStereoConfig config = { 0 };
-
-    if (rlGetVersion() != RL_OPENGL_11)
-    {
-        // Compute aspect ratio
-        float aspect = ((float)device.hResolution*0.5f)/(float)device.vResolution;
-
-        // Compute lens parameters
-        float lensShift = (device.hScreenSize*0.25f - device.lensSeparationDistance*0.5f)/device.hScreenSize;
-        config.leftLensCenter[0] = 0.25f + lensShift;
-        config.leftLensCenter[1] = 0.5f;
-        config.rightLensCenter[0] = 0.75f - lensShift;
-        config.rightLensCenter[1] = 0.5f;
-        config.leftScreenCenter[0] = 0.25f;
-        config.leftScreenCenter[1] = 0.5f;
-        config.rightScreenCenter[0] = 0.75f;
-        config.rightScreenCenter[1] = 0.5f;
-
-        // Compute distortion scale parameters
-        // NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
-        float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
-        float lensRadiusSq = lensRadius*lensRadius;
-        float distortionScale = device.lensDistortionValues[0] +
-                                device.lensDistortionValues[1]*lensRadiusSq +
-                                device.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq +
-                                device.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq;
-
-        float normScreenWidth = 0.5f;
-        float normScreenHeight = 1.0f;
-        config.scaleIn[0] = 2.0f/normScreenWidth;
-        config.scaleIn[1] = 2.0f/normScreenHeight/aspect;
-        config.scale[0] = normScreenWidth*0.5f/distortionScale;
-        config.scale[1] = normScreenHeight*0.5f*aspect/distortionScale;
-
-        // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance)
-        // ...but with lens distortion it is increased (see Oculus SDK Documentation)
-        float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance);     // Really need distortionScale?
-       // float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance);
-
-        // Compute camera projection matrices
-        float projOffset = 4.0f*lensShift;      // Scaled to projection space coordinates [-1..1]
-        Matrix proj = MatrixPerspective(fovy, aspect, rlGetCullDistanceNear(), rlGetCullDistanceFar());
-
-        config.projection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f));
-        config.projection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f));
-
-        // Compute camera transformation matrices
-        // NOTE: Camera movement might seem more natural if we model the head
-        // Our axis of rotation is the base of our head, so we might want to add
-        // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions
-        config.viewOffset[0] = MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f);
-        config.viewOffset[1] = MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f);
-
-        // Compute eyes Viewports
-        /*
-        config.eyeViewportRight[0] = 0;
-        config.eyeViewportRight[1] = 0;
-        config.eyeViewportRight[2] = device.hResolution/2;
-        config.eyeViewportRight[3] = device.vResolution;
-
-        config.eyeViewportLeft[0] = device.hResolution/2;
-        config.eyeViewportLeft[1] = 0;
-        config.eyeViewportLeft[2] = device.hResolution/2;
-        config.eyeViewportLeft[3] = device.vResolution;
-        */
-    }
-    else TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1");
-
-    return config;
-}
-
-// Unload VR stereo config properties
-void UnloadVrStereoConfig(VrStereoConfig config)
-{
-    TRACELOG(LOG_INFO, "UnloadVrStereoConfig not implemented in rcore.c");
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Shaders Management
-//----------------------------------------------------------------------------------
-
-// Load shader from files and bind default locations
-// NOTE: If shader string is NULL, using default vertex/fragment shaders
-Shader LoadShader(const char *vsFileName, const char *fsFileName)
-{
-    Shader shader = { 0 };
-
-    char *vShaderStr = NULL;
-    char *fShaderStr = NULL;
-
-    if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
-    if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
-
-    if ((vShaderStr == NULL) && (fShaderStr == NULL)) TRACELOG(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader");
-
-    shader = LoadShaderFromMemory(vShaderStr, fShaderStr);
-
-    UnloadFileText(vShaderStr);
-    UnloadFileText(fShaderStr);
-
-    return shader;
-}
-
-// Load shader from code strings and bind default locations
-Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
-{
-    Shader shader = { 0 };
-
-    shader.id = rlLoadShaderCode(vsCode, fsCode);
-
-    if (shader.id == 0)
-    {
-        // Shader could not be loaded but we still load the location points to avoid potential crashes
-        // NOTE: All locations set to -1 (no location)
-        shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
-        for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
-    }
-    else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
-    else if (shader.id > 0)
-    {
-        // After custom shader loading, we TRY to set default location names
-        // Default shader attribute locations have been binded before linking:
-        //  - vertex position location    = 0
-        //  - vertex texcoord location    = 1
-        //  - vertex normal location      = 2
-        //  - vertex color location       = 3
-        //  - vertex tangent location     = 4
-        //  - vertex texcoord2 location   = 5
-        //  - vertex boneIds location     = 6
-        //  - vertex boneWeights location = 7
-
-        // NOTE: If any location is not found, loc point becomes -1
-
-        // Load shader locations array
-        // NOTE: All locations set to -1 (no location)
-        shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
-        for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
-
-        // Get handles to GLSL input attribute locations
-        shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
-        shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
-        shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
-        shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
-        shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
-        shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
-        shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);
-        shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
-        shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX);
-
-        // Get handles to GLSL uniform locations (vertex shader)
-        shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP);
-        shader.locs[SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW);
-        shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION);
-        shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL);
-        shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL);
-        shader.locs[SHADER_LOC_BONE_MATRICES] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES);
-
-        // Get handles to GLSL uniform locations (fragment shader)
-        shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR);
-        shader.locs[SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0);  // SHADER_LOC_MAP_ALBEDO
-        shader.locs[SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1); // SHADER_LOC_MAP_METALNESS
-        shader.locs[SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2);
-    }
-
-    return shader;
-}
-
-// Check if a shader is valid (loaded on GPU)
-bool IsShaderValid(Shader shader)
-{
-    return ((shader.id > 0) &&          // Validate shader id (GPU loaded successfully)
-            (shader.locs != NULL));     // Validate memory has been allocated for default shader locations
-
-    // The following locations are tried to be set automatically (locs[i] >= 0),
-    // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION
-    // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones
-
-    // Vertex shader attribute locations (default)
-    // shader.locs[SHADER_LOC_VERTEX_POSITION]      // Set by default internal shader
-    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]    // Set by default internal shader
-    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]
-    // shader.locs[SHADER_LOC_VERTEX_NORMAL]
-    // shader.locs[SHADER_LOC_VERTEX_TANGENT]
-    // shader.locs[SHADER_LOC_VERTEX_COLOR]         // Set by default internal shader
-
-    // Vertex shader uniform locations (default)
-    // shader.locs[SHADER_LOC_MATRIX_MVP]           // Set by default internal shader
-    // shader.locs[SHADER_LOC_MATRIX_VIEW]
-    // shader.locs[SHADER_LOC_MATRIX_PROJECTION]
-    // shader.locs[SHADER_LOC_MATRIX_MODEL]
-    // shader.locs[SHADER_LOC_MATRIX_NORMAL]
-
-    // Fragment shader uniform locations (default)
-    // shader.locs[SHADER_LOC_COLOR_DIFFUSE]        // Set by default internal shader
-    // shader.locs[SHADER_LOC_MAP_DIFFUSE]          // Set by default internal shader
-    // shader.locs[SHADER_LOC_MAP_SPECULAR]
-    // shader.locs[SHADER_LOC_MAP_NORMAL]
-}
-
-// Unload shader from GPU memory (VRAM)
-void UnloadShader(Shader shader)
-{
-    if (shader.id != rlGetShaderIdDefault())
-    {
-        rlUnloadShaderProgram(shader.id);
-
-        // NOTE: If shader loading failed, it should be 0
-        RL_FREE(shader.locs);
-    }
-}
-
-// Get shader uniform location
-int GetShaderLocation(Shader shader, const char *uniformName)
-{
-    return rlGetLocationUniform(shader.id, uniformName);
-}
-
-// Get shader attribute location
-int GetShaderLocationAttrib(Shader shader, const char *attribName)
-{
-    return rlGetLocationAttrib(shader.id, attribName);
-}
-
-// Set shader uniform value
-void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType)
-{
-    SetShaderValueV(shader, locIndex, value, uniformType, 1);
-}
-
-// Set shader uniform value vector
-void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count)
-{
-    if (locIndex > -1)
-    {
-        rlEnableShader(shader.id);
-        rlSetUniform(locIndex, value, uniformType, count);
-        //rlDisableShader();      // Avoid resetting current shader program, in case other uniforms are set
-    }
-}
-
-// Set shader uniform value (matrix 4x4)
-void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat)
-{
-    if (locIndex > -1)
-    {
-        rlEnableShader(shader.id);
-        rlSetUniformMatrix(locIndex, mat);
-        //rlDisableShader();
-    }
-}
-
-// Set shader uniform value for texture
-void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture)
-{
-    if (locIndex > -1)
-    {
-        rlEnableShader(shader.id);
-        rlSetUniformSampler(locIndex, texture.id);
-        //rlDisableShader();
-    }
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Screen-space Queries
-//----------------------------------------------------------------------------------
-
-// Get a ray trace from screen position (i.e mouse)
-Ray GetScreenToWorldRay(Vector2 position, Camera camera)
-{
-    Ray ray = GetScreenToWorldRayEx(position, camera, GetScreenWidth(), GetScreenHeight());
-
-    return ray;
-}
-
-// Get a ray trace from the screen position (i.e mouse) within a specific section of the screen
-Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height)
-{
-    Ray ray = { 0 };
-
-    // Calculate normalized device coordinates
-    // NOTE: y value is negative
-    float x = (2.0f*position.x)/(float)width - 1.0f;
-    float y = 1.0f - (2.0f*position.y)/(float)height;
-    float z = 1.0f;
-
-    // Store values in a vector
-    Vector3 deviceCoords = { x, y, z };
-
-    // Calculate view matrix from camera look at
-    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
-
-    Matrix matProj = MatrixIdentity();
-
-    if (camera.projection == CAMERA_PERSPECTIVE)
-    {
-        // Calculate projection matrix from perspective
-        matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
-    {
-        double aspect = (double)width/(double)height;
-        double top = camera.fovy/2.0;
-        double right = top*aspect;
-
-        // Calculate projection matrix from orthographic
-        matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-
-    // Unproject far/near points
-    Vector3 nearPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
-    Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
-
-    // Unproject the mouse cursor in the near plane
-    // We need this as the source position because orthographic projects,
-    // compared to perspective doesn't have a convergence point,
-    // meaning that the "eye" of the camera is more like a plane than a point
-    Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
-
-    // Calculate normalized direction vector
-    Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint));
-
-    if (camera.projection == CAMERA_PERSPECTIVE) ray.position = camera.position;
-    else if (camera.projection == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos;
-
-    // Apply calculated vectors to ray
-    ray.direction = direction;
-
-    return ray;
-}
-
-// Get transform matrix for camera
-Matrix GetCameraMatrix(Camera camera)
-{
-    Matrix mat = MatrixLookAt(camera.position, camera.target, camera.up);
-
-    return mat;
-}
-
-// Get camera 2d transform matrix
-Matrix GetCameraMatrix2D(Camera2D camera)
-{
-    Matrix matTransform = { 0 };
-    // The camera in world-space is set by
-    //   1. Move it to target
-    //   2. Rotate by -rotation and scale by (1/zoom)
-    //      When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller),
-    //      not for the camera getting bigger, hence the invert. Same deal with rotation
-    //   3. Move it by (-offset);
-    //      Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera)
-    //      we need to do it into opposite direction (inverse transform)
-
-    // Having camera transform in world-space, inverse of it gives the modelview transform
-    // Since (A*B*C)' = C'*B'*A', the modelview is
-    //   1. Move to offset
-    //   2. Rotate and Scale
-    //   3. Move by -target
-    Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f);
-    Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
-    Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
-    Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f);
-
-    matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
-
-    return matTransform;
-}
-
-// Get the screen space position from a 3d world space position
-Vector2 GetWorldToScreen(Vector3 position, Camera camera)
-{
-    Vector2 screenPosition = GetWorldToScreenEx(position, camera, GetScreenWidth(), GetScreenHeight());
-
-    return screenPosition;
-}
-
-// Get size position for a 3d world space position (useful for texture drawing)
-Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height)
-{
-    // Calculate projection matrix (from perspective instead of frustum
-    Matrix matProj = MatrixIdentity();
-
-    if (camera.projection == CAMERA_PERSPECTIVE)
-    {
-        // Calculate projection matrix from perspective
-        matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
-    {
-        double aspect = (double)width/(double)height;
-        double top = camera.fovy/2.0;
-        double right = top*aspect;
-
-        // Calculate projection matrix from orthographic
-        matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
-    }
-
-    // Calculate view matrix from camera look at (and transpose it)
-    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
-
-    // Convert world position vector to quaternion
-    Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
-
-    // Transform world position to view
-    worldPos = QuaternionTransform(worldPos, matView);
-
-    // Transform result to projection (clip space position)
-    worldPos = QuaternionTransform(worldPos, matProj);
-
-    // Calculate normalized device coordinates (inverted y)
-    Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
-
-    // Calculate 2d screen position vector
-    Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)width, (ndcPos.y + 1.0f)/2.0f*(float)height };
-
-    return screenPosition;
-}
-
-// Get the screen space position for a 2d camera world space position
-Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
-{
-    Matrix matCamera = GetCameraMatrix2D(camera);
-    Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera);
-
-    return (Vector2){ transform.x, transform.y };
-}
-
-// Get the world space position for a 2d camera screen space position
-Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
-{
-    Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
-    Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera);
-
-    return (Vector2){ transform.x, transform.y };
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Timming
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//double GetTime(void)
-
-// Set target FPS (maximum)
-void SetTargetFPS(int fps)
-{
-    if (fps < 1) CORE.Time.target = 0.0;
-    else CORE.Time.target = 1.0/(double)fps;
-
-    TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000.0f);
-}
-
-// Get current FPS
-// NOTE: We calculate an average framerate
-int GetFPS(void)
-{
-    int fps = 0;
-
-#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
-    #define FPS_CAPTURE_FRAMES_COUNT    30      // 30 captures
-    #define FPS_AVERAGE_TIME_SECONDS   0.5f     // 500 milliseconds
-    #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT)
-
-    static int index = 0;
-    static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 };
-    static float average = 0, last = 0;
-    float fpsFrame = GetFrameTime();
-
-    // if we reset the window, reset the FPS info
-    if (CORE.Time.frameCounter == 0)
-    {
-        average = 0;
-        last = 0;
-        index = 0;
-
-        for (int i = 0; i < FPS_CAPTURE_FRAMES_COUNT; i++) history[i] = 0;
-    }
-
-    if (fpsFrame == 0) return 0;
-
-    if ((GetTime() - last) > FPS_STEP)
-    {
-        last = (float)GetTime();
-        index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT;
-        average -= history[index];
-        history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
-        average += history[index];
-    }
-
-    fps = (int)roundf(1.0f/average);
-#endif
-
-    return fps;
-}
-
-// Get time in seconds for last frame drawn (delta time)
-float GetFrameTime(void)
-{
-    return (float)CORE.Time.frame;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Custom frame control
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//void SwapScreenBuffer(void);
-//void PollInputEvents(void);
-
-// Wait for some time (stop program execution)
-// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
-// take longer than expected... for that reason we use the busy wait loop
-// REF: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
-// REF: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
-void WaitTime(double seconds)
-{
-    if (seconds < 0) return;    // Security check
-
-#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
-    double destinationTime = GetTime() + seconds;
-#endif
-
-#if defined(SUPPORT_BUSY_WAIT_LOOP)
-    while (GetTime() < destinationTime) { }
-#else
-    #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
-        double sleepSeconds = seconds - seconds*0.05;  // NOTE: We reserve a percentage of the time for busy waiting
-    #else
-        double sleepSeconds = seconds;
-    #endif
-
-    // System halt functions
-    #if defined(_WIN32)
-        Sleep((unsigned long)(sleepSeconds*1000.0));
-    #endif
-    #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
-        struct timespec req = { 0 };
-        time_t sec = sleepSeconds;
-        long nsec = (sleepSeconds - sec)*1000000000L;
-        req.tv_sec = sec;
-        req.tv_nsec = nsec;
-
-        // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated
-        while (nanosleep(&req, &req) == -1) continue;
-    #endif
-    #if defined(__APPLE__)
-        usleep(sleepSeconds*1000000.0);
-    #endif
-
-    #if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
-        while (GetTime() < destinationTime) { }
-    #endif
-#endif
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Misc
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//void OpenURL(const char *url)
-
-// Set the seed for the random number generator
-void SetRandomSeed(unsigned int seed)
-{
-#if defined(SUPPORT_RPRAND_GENERATOR)
-    rprand_set_seed(seed);
-#else
-    srand(seed);
-#endif
-}
-
-// Get a random value between min and max included
-int GetRandomValue(int min, int max)
-{
-    int value = 0;
-
-    if (min > max)
-    {
-        int tmp = max;
-        max = min;
-        min = tmp;
-    }
-
-#if defined(SUPPORT_RPRAND_GENERATOR)
-    value = rprand_get_value(min, max);
-#else
-    // WARNING: Ranges higher than RAND_MAX will return invalid results
-    // More specifically, if (max - min) > INT_MAX there will be an overflow,
-    // and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold
-    // NOTE: Depending on the library it can be as low as 32767
-    if ((unsigned int)(max - min) > (unsigned int)RAND_MAX)
-    {
-        TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX);
-    }
-
-    // NOTE: This one-line approach produces a non-uniform distribution,
-    // as stated by Donald Knuth in the book The Art of Programming, so
-    // using below approach for more uniform results
-    //value = (rand()%(abs(max - min) + 1) + min);
-
-    // More uniform range solution
-    int range = (max - min) + 1;
-
-    // Degenerate/overflow case: fall back to min (same behavior as "always min" instead of UB)
-    if (range <= 0) value = min;
-    else
-    {
-        // Rejection sampling to get a uniform integer in [min, max]
-        unsigned long c = (unsigned long)RAND_MAX + 1UL;  // number of possible rand() results
-        unsigned long m = (unsigned long)range;           // size of the target interval
-        unsigned long t = c - (c%m);                    // largest multiple of m <= c
-        unsigned long r = 0;
-
-        for (;;)
-        {
-            r = (unsigned long)rand();
-            if (r < t) break;   // Only accept values within the fair region
-        }
-
-        value = min + (int)(r%m);
-    }
-#endif
-    return value;
-}
-
-// Load random values sequence, no values repeated, min and max included
-int *LoadRandomSequence(unsigned int count, int min, int max)
-{
-    int *values = NULL;
-
-#if defined(SUPPORT_RPRAND_GENERATOR)
-    values = rprand_load_sequence(count, min, max);
-#else
-    if (count > ((unsigned int)abs(max - min) + 1)) return values;  // Security check
-
-    values = (int *)RL_CALLOC(count, sizeof(int));
-
-    int value = 0;
-    bool dupValue = false;
-
-    for (int i = 0; i < (int)count;)
-    {
-        value = GetRandomValue(min, max);
-        dupValue = false;
-
-        for (int j = 0; j < i; j++)
-        {
-            if (values[j] == value)
-            {
-                dupValue = true;
-                break;
-            }
-        }
-
-        if (!dupValue)
-        {
-            values[i] = value;
-            i++;
-        }
-    }
-#endif
-    return values;
-}
-
-// Unload random values sequence
-void UnloadRandomSequence(int *sequence)
-{
-#if defined(SUPPORT_RPRAND_GENERATOR)
-    rprand_unload_sequence(sequence);
-#else
-    RL_FREE(sequence);
-#endif
-}
-
-// Takes a screenshot of current screen
-// NOTE: Provided fileName should not contain paths, saving to working directory
-void TakeScreenshot(const char *fileName)
-{
-#if defined(SUPPORT_MODULE_RTEXTURES)
-    // Security check to (partially) avoid malicious code
-    if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; }
-
-    // Apply a scale if we are doing HIGHDPI auto-scaling
-    Vector2 scale = { 1.0f, 1.0f };
-    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
-
-    unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
-    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);
-
-    ExportImage(image, path); // WARNING: Module required: rtextures
-    RL_FREE(imgData);
-
-    if (FileExists(path)) TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
-    else TRACELOG(LOG_WARNING, "SYSTEM: [%s] Screenshot could not be saved", path);
-#else
-    TRACELOG(LOG_WARNING,"IMAGE: ExportImage() requires module: rtextures");
-#endif
-}
-
-// Setup window configuration flags (view FLAGS)
-// NOTE: This function is expected to be called before window creation,
-// because it sets up some flags for the window creation process
-// To configure window states after creation, just use SetWindowState()
-void SetConfigFlags(unsigned int flags)
-{
-    if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead");
-
-    // Selected flags are set but not evaluated at this point,
-    // flag evaluation happens at InitWindow() or SetWindowState()
-    FLAG_SET(CORE.Window.flags, flags);
-}
-
-// void OpenURL(const char *url);   // Defined per platform
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Logging system
-//----------------------------------------------------------------------------------
-// Set the current threshold (minimum) log level
-void SetTraceLogLevel(int logType) { logTypeLevel = logType; }
-
-// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
-void TraceLog(int logType, const char *text, ...)
-{
-#if defined(SUPPORT_TRACELOG)
-    // Message has level below current threshold, don't emit
-    if ((logType < logTypeLevel) || (text == NULL)) return;
-
-    va_list args;
-    va_start(args, text);
-
-    if (traceLog)
-    {
-        traceLog(logType, text, args);
-        va_end(args);
-        return;
-    }
-
-#if defined(PLATFORM_ANDROID)
-    switch (logType)
-    {
-        case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break;
-        case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break;
-        case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break;
-        case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break;
-        case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break;
-        case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break;
-        default: break;
-    }
-#else
-    char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
-
-    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;
-        default: break;
-    }
-
-    unsigned int textLength = (unsigned int)strlen(text);
-    memcpy(buffer + strlen(buffer), text, (textLength < (MAX_TRACELOG_MSG_LENGTH - 12))? textLength : (MAX_TRACELOG_MSG_LENGTH - 12));
-    strcat(buffer, "\n");
-    vprintf(buffer, args);
-    fflush(stdout);
-#endif
-
-    va_end(args);
-
-    if (logType == LOG_FATAL) exit(EXIT_FAILURE);  // If fatal logging, exit program
-
-#endif  // SUPPORT_TRACELOG
-}
-
-// Set custom trace log
-void SetTraceLogCallback(TraceLogCallback callback)
-{ 
-    traceLog = callback;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Memory management
-//----------------------------------------------------------------------------------
-// Internal memory allocator
-// NOTE: Initializes to zero by default
-void *MemAlloc(unsigned int size)
-{
-    void *ptr = RL_CALLOC(size, 1);
-    return ptr;
-}
-
-// Internal memory reallocator
-void *MemRealloc(void *ptr, unsigned int size)
-{
-    void *ret = RL_REALLOC(ptr, size);
-    return ret;
-}
-
-// Internal memory free
-void MemFree(void *ptr)
-{
-    RL_FREE(ptr);
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: File System management
-//----------------------------------------------------------------------------------
-// Load data from file into a buffer
-unsigned char *LoadFileData(const char *fileName, int *dataSize)
-{
-    unsigned char *data = NULL;
-    *dataSize = 0;
-
-    if (fileName != NULL)
-    {
-        if (loadFileData)
-        {
-            data = loadFileData(fileName, dataSize);
-            return data;
-        }
-#if defined(SUPPORT_STANDARD_FILEIO)
-        FILE *file = fopen(fileName, "rb");
-
-        if (file != NULL)
-        {
-            // WARNING: On binary streams SEEK_END could not be found,
-            // using fseek() and ftell() could not work in some (rare) cases
-            fseek(file, 0, SEEK_END);
-            int size = ftell(file);     // WARNING: ftell() returns 'long int', maximum size returned is INT_MAX (2147483647 bytes)
-            fseek(file, 0, SEEK_SET);
-
-            if (size > 0)
-            {
-                data = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char));
-
-                if (data != NULL)
-                {
-                    // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
-                    size_t count = fread(data, sizeof(unsigned char), size, file);
-
-                    // WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
-                    // dataSize is unified along raylib as a 'int' type, so, for file-sizes > INT_MAX (2147483647 bytes) we have a limitation
-                    if (count > 2147483647)
-                    {
-                        TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName);
-
-                        RL_FREE(data);
-                        data = NULL;
-                    }
-                    else
-                    {
-                        *dataSize = (int)count;
-
-                        if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, dataSize, count);
-                        else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
-                    }
-                }
-                else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
-            }
-            else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
-
-            fclose(file);
-        }
-        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
-#else
-    TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
-    return data;
-}
-
-// Unload file data allocated by LoadFileData()
-void UnloadFileData(unsigned char *data)
-{
-    RL_FREE(data);
-}
-
-// Save data to file from buffer
-bool SaveFileData(const char *fileName, void *data, int dataSize)
-{
-    bool success = false;
-
-    if (fileName != NULL)
-    {
-        if (saveFileData)
-        {
-            return saveFileData(fileName, data, dataSize);
-        }
-#if defined(SUPPORT_STANDARD_FILEIO)
-        FILE *file = fopen(fileName, "wb");
-
-        if (file != NULL)
-        {
-            // WARNING: fwrite() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
-            // and expects a size_t input value but as dataSize is limited to INT_MAX (2147483647 bytes), there shouldn't be a problem
-            int count = (int)fwrite(data, sizeof(unsigned char), dataSize, file);
-
-            if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
-            else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
-            else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
-
-            int result = fclose(file);
-            if (result == 0) success = true;
-        }
-        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
-#else
-    TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
-    return success;
-}
-
-// Export data to code (.h), returns true on success
-bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName)
-{
-    bool success = false;
-
-#ifndef TEXT_BYTES_PER_LINE
-    #define TEXT_BYTES_PER_LINE     20
-#endif
-
-    // NOTE: Text data buffer size is estimated considering raw data size in bytes
-    // and requiring 6 char bytes for every byte: "0x00, "
-    char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
-
-    int byteCount = 0;
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes                  //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
-    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2026 Ramon Santamaria (@raysan5)                                //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
-
-    // Get file name from path
-    char varFileName[256] = { 0 };
-    strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
-    for (int i = 0; varFileName[i] != '\0'; i++)
-    {
-        // Convert variable name to uppercase
-        if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
-        // Replace non valid character for C identifier with '_'
-        else if (varFileName[i] == '.' || varFileName[i] == '-' || varFileName[i] == '?' || varFileName[i] == '!' || varFileName[i] == '+') { varFileName[i] = '_'; }
-    }
-
-    byteCount += sprintf(txtData + byteCount, "#define %s_DATA_SIZE     %i\n\n", varFileName, dataSize);
-
-    byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%s_DATA_SIZE] = { ", varFileName, varFileName);
-    for (int i = 0; i < (dataSize - 1); i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]);
-    byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]);
-
-    // NOTE: Text data size exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
-
-    RL_FREE(txtData);
-
-    if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
-    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
-
-    return success;
-}
-
-// Load text data from file, returns a '\0' terminated string
-// NOTE: text chars array should be freed manually
-char *LoadFileText(const char *fileName)
-{
-    char *text = NULL;
-
-    if (fileName != NULL)
-    {
-        if (loadFileText)
-        {
-            text = loadFileText(fileName);
-            return text;
-        }
-#if defined(SUPPORT_STANDARD_FILEIO)
-        FILE *file = fopen(fileName, "rt");
-
-        if (file != NULL)
-        {
-            // WARNING: When reading a file as 'text' file,
-            // text mode causes carriage return-linefeed translation...
-            // ...but using fseek() should return correct byte-offset
-            fseek(file, 0, SEEK_END);
-            unsigned int size = (unsigned int)ftell(file);
-            fseek(file, 0, SEEK_SET);
-
-            if (size > 0)
-            {
-                text = (char *)RL_CALLOC(size + 1, sizeof(char));
-
-                if (text != NULL)
-                {
-                    unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
-
-                    // WARNING: \r\n is converted to \n on reading, so,
-                    // read bytes count gets reduced by the number of lines
-                    if (count < size) text = (char *)RL_REALLOC(text, count + 1);
-
-                    // Zero-terminate the string
-                    text[count] = '\0';
-
-                    TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName);
-                }
-                else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
-            }
-            else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName);
-
-            fclose(file);
-        }
-        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
-#else
-    TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
-    return text;
-}
-
-// Unload file text data allocated by LoadFileText()
-void UnloadFileText(char *text)
-{
-    RL_FREE(text);
-}
-
-// Save text data to file (write), string must be '\0' terminated
-bool SaveFileText(const char *fileName, const char *text)
-{
-    bool success = false;
-
-    if (fileName != NULL)
-    {
-        if (saveFileText)
-        {
-            return saveFileText(fileName, text);
-        }
-#if defined(SUPPORT_STANDARD_FILEIO)
-        FILE *file = fopen(fileName, "wt");
-
-        if (file != NULL)
-        {
-            int count = fprintf(file, "%s", text);
-
-            if (count < 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
-            else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
-
-            int result = fclose(file);
-            if (result == 0) success = true;
-        }
-        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
-#else
-    TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
-    return success;
-}
-
-// File access custom callbacks
-// WARNING: Callbacks setup is intended for advanced users
-
-// Set custom file binary data loader
-void SetLoadFileDataCallback(LoadFileDataCallback callback)
-{
-    loadFileData = callback;
-}
-
-// Set custom file binary data saver
-void SetSaveFileDataCallback(SaveFileDataCallback callback)
-{
-    saveFileData = callback;
-}
-
-// Set custom file text data loader
-void SetLoadFileTextCallback(LoadFileTextCallback callback)
-{
-    loadFileText = callback;
-}
-
-// Set custom file text data saver
-void SetSaveFileTextCallback(SaveFileTextCallback callback)
-{
-    saveFileText = callback;
-}
-
-// Rename file (if exists)
-// NOTE: Only rename file name required, not full path
-int FileRename(const char *fileName, const char *fileRename)
-{
-    int result = 0;
-
-    if (FileExists(fileName))
-    {
-        result = rename(fileName, fileRename);
-    }
-    else result = -1;
-
-    return result;
-}
-
-// Remove file (if exists)
-int FileRemove(const char *fileName)
-{
-    int result = 0;
-
-    if (FileExists(fileName))
-    {
-        result = remove(fileName);
-    }
-    else result = -1;
-
-    return result;
-}
-
-// Copy file from one path to another
-// NOTE: If destination path does not exist, it is created!
-int FileCopy(const char *srcPath, const char *dstPath)
-{
-    int result = 0;
-    int srcDataSize = 0;
-    unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize);
-
-    // Create required paths if they do not exist
-    if (!DirectoryExists(GetDirectoryPath(dstPath)))
-        result = MakeDirectory(GetDirectoryPath(dstPath));
-
-    if (result == 0) // Directory created successfully (or already exists)
-    {
-        if ((srcFileData != NULL) && (srcDataSize > 0))
-            result = SaveFileData(dstPath, srcFileData, srcDataSize);
-    }
-
-    UnloadFileData(srcFileData);
-
-    return result;
-}
-
-// Move file from one directory to another
-// NOTE: If dst directories do not exists they are created
-int FileMove(const char *srcPath, const char *dstPath)
-{
-    int result = 0;
-
-    if (FileExists(srcPath))
-    {
-        FileCopy(srcPath, dstPath);
-        FileRemove(srcPath);
-    }
-    else result = -1;
-
-    return result;
-}
-
-// Replace text in an existing file
-// WARNING: DEPENDENCY: [rtext] module
-int FileTextReplace(const char *fileName, const char *search, const char *replacement)
-{
-    int result = 0;
-    char *fileText = NULL;
-    char *fileTextUpdated = { 0 };
-
-#if defined(SUPPORT_MODULE_RTEXT)
-    if (FileExists(fileName))
-    {
-        fileText = LoadFileText(fileName);
-        fileTextUpdated = TextReplace(fileText, search, replacement);
-        result = SaveFileText(fileName, fileTextUpdated);
-        MemFree(fileTextUpdated);
-        UnloadFileText(fileText);
-    }
-#else
-    TRACELOG(LOG_WARNING, "FILE: File text replace requires [rtext] module");
-#endif
-
-    return result;
-}
-
-// Find text index position in existing file
-// WARNING: DEPENDENCY: [rtext] module
-int FileTextFindIndex(const char *fileName, const char *search)
-{
-    int result = -1;
-
-    if (FileExists(fileName))
-    {
-        char *fileText = LoadFileText(fileName);
-        char *ptr = strstr(fileText, search);
-        if (ptr != NULL) result = (int)(ptr - fileText);
-        UnloadFileText(fileText);
-    }
-
-    return result;
-}
-
-// Check if the file exists
-bool FileExists(const char *fileName)
-{
-    bool result = false;
-
-    if (ACCESS(fileName) != -1) result = true;
-
-    // NOTE: Alternatively, stat() can be used instead of access()
-    //#include <sys/stat.h>
-    //struct stat statbuf;
-    //if (stat(filename, &statbuf) == 0) result = true;
-
-    return result;
-}
-
-// Check file extension
-bool IsFileExtension(const char *fileName, const char *ext)
-{
-    #define MAX_FILE_EXTENSIONS  32
-
-    bool result = false;
-    const char *fileExt = GetFileExtension(fileName);
-
-    // WARNING: fileExt points to last '.' on fileName string but it could happen
-    // that fileName is not correct: "myfile.png more text following\n"
-
-    if (fileExt != NULL)
-    {
-        int fileExtLength = (int)strlen(fileExt);
-        char fileExtLower[16] = { 0 };
-        char *fileExtLowerPtr = fileExtLower;
-        for (int i = 0; (i < fileExtLength) && (i < 16); i++)
-        {
-            // Copy and convert to lower-case
-            if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] =  fileExt[i] + 32;
-            else fileExtLower[i] =  fileExt[i];
-        }
-
-        int extCount = 1;
-        int extLength = (int)strlen(ext);
-        char *extList = (char *)RL_CALLOC(extLength + 1, 1);
-        char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
-        strncpy(extList, ext, extLength);
-        extListPtrs[0] = extList;
-
-        for (int i = 0; i < extLength; i++)
-        {
-            // Convert to lower-case if extension is upper-case
-            if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32;
-
-            // Get pointer to next extension and add null-terminator
-            if ((extList[i] == ';') && (extCount < (MAX_FILE_EXTENSIONS - 1)))
-            {
-                extList[i] = '\0';
-                extListPtrs[extCount] = extList + i + 1;
-                extCount++;
-            }
-        }
-
-        for (int i = 0; i < extCount; i++)
-        {
-            // Consider the case where extension provided
-            // does not start with the '.'
-            fileExtLowerPtr = fileExtLower;
-            if (extListPtrs[i][0] != '.') fileExtLowerPtr++;
-
-            if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0)
-            {
-                result = true;
-                break;
-            }
-        }
-
-        RL_FREE(extList);
-    }
-
-    return result;
-}
-
-// Check if a directory path exists
-bool DirectoryExists(const char *dirPath)
-{
-    bool result = false;
-    DIR *dir = opendir(dirPath);
-
-    if (dir != NULL)
-    {
-        result = true;
-        closedir(dir);
-    }
-
-    return result;
-}
-
-// Get file length in bytes
-// NOTE: GetFileSize() conflicts with windows.h
-int GetFileLength(const char *fileName)
-{
-    int size = 0;
-
-    // NOTE: On Unix-like systems, it can by used the POSIX system call: stat(),
-    // but depending on the platform that call could not be available
-    //struct stat result = { 0 };
-    //stat(fileName, &result);
-    //return result.st_size;
-
-    FILE *file = fopen(fileName, "rb");
-
-    if (file != NULL)
-    {
-        fseek(file, 0L, SEEK_END);
-        long int fileSize = ftell(file);
-
-        // Check for size overflow (INT_MAX)
-        if (fileSize > 2147483647) TRACELOG(LOG_WARNING, "[%s] File size overflows expected limit, do not use GetFileLength()", fileName);
-        else size = (int)fileSize;
-
-        fclose(file);
-    }
-
-    return size;
-}
-
-// Get file modification time (last write time)
-long GetFileModTime(const char *fileName)
-{
-    struct stat result = { 0 };
-    long modTime = 0;
-
-    if (stat(fileName, &result) == 0)
-    {
-        time_t mod = result.st_mtime;
-        modTime = (long)mod;
-    }
-
-    return modTime;
-}
-
-// Get pointer to extension for a filename string (includes the dot: .png)
-// WARNING: We just get the ptr but not the extension as a separate string
-const char *GetFileExtension(const char *fileName)
-{
-    const char *dot = strrchr(fileName, '.');
-
-    if (!dot || (dot == fileName)) return NULL;
-
-    return dot;
-}
-
-// String pointer reverse break: returns right-most occurrence of charset in s
-static const char *strprbrk(const char *text, const char *charset)
-{
-    const char *latestMatch = NULL;
-
-    for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
-
-    return latestMatch;
-}
-
-// Get pointer to filename for a path string
-const char *GetFileName(const char *filePath)
-{
-    const char *fileName = NULL;
-
-    if (filePath != NULL) fileName = strprbrk(filePath, "\\/");
-
-    if (fileName == NULL) return filePath;
-
-    return fileName + 1;
-}
-
-// Get filename string without extension (uses static string)
-const char *GetFileNameWithoutExt(const char *filePath)
-{
-    #define MAX_FILENAME_LENGTH     256
-
-    static char fileName[MAX_FILENAME_LENGTH] = { 0 };
-    memset(fileName, 0, MAX_FILENAME_LENGTH);
-
-    if (filePath != NULL)
-    {
-        strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path
-        int fileNameLenght = (int)strlen(fileName); // Get size in bytes
-
-        for (int i = fileNameLenght; i > 0; i--) // Reverse search '.'
-        {
-            if (fileName[i] == '.')
-            {
-                // NOTE: We break on first '.' found
-                fileName[i] = '\0';
-                break;
-            }
-        }
-    }
-
-    return fileName;
-}
-
-// Get directory for a given filePath
-const char *GetDirectoryPath(const char *filePath)
-{
-    /*
-    // NOTE: Directory separator is different in Windows and other platforms,
-    // fortunately, Windows also support the '/' separator, that's the one should be used
-    #if defined(_WIN32)
-        char separator = '\\';
-    #else
-        char separator = '/';
-    #endif
-    */
-    const char *lastSlash = NULL;
-    static char dirPath[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(dirPath, 0, MAX_FILEPATH_LENGTH);
-
-    // In case provided path does not contain a root drive letter (C:\, D:\) nor leading path separator (\, /),
-    // we add the current directory path to dirPath
-    if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))
-    {
-        // For security, we set starting path to current directory,
-        // obtained path will be concatenated to this
-        dirPath[0] = '.';
-        dirPath[1] = '/';
-    }
-
-    lastSlash = strprbrk(filePath, "\\/");
-    if (lastSlash)
-    {
-        if (lastSlash == filePath)
-        {
-            // The last and only slash is the leading one: path is in a root directory
-            dirPath[0] = filePath[0];
-            dirPath[1] = '\0';
-        }
-        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));
-            dirPath[strlen(filePath) - strlen(lastSlash) + (((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))? 2 : 0)] = '\0';  // Add '\0' manually
-        }
-    }
-
-    return dirPath;
-}
-
-// Get previous directory path for a given path
-const char *GetPrevDirectoryPath(const char *dirPath)
-{
-    static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
-    int dirPathLength = (int)strlen(dirPath);
-
-    if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH  - 1);
-
-    for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--)
-    {
-        if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
-        {
-            // Check for root: "C:\" or "/"
-            if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++;
-
-            strncpy(prevDirPath, dirPath, i);
-            break;
-        }
-    }
-
-    return prevDirPath;
-}
-
-// Get current working directory
-const char *GetWorkingDirectory(void)
-{
-    static char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(currentDir, 0, MAX_FILEPATH_LENGTH);
-
-    char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1);
-
-    return path;
-}
-
-const char *GetApplicationDirectory(void)
-{
-    static char appDir[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(appDir, 0, MAX_FILEPATH_LENGTH);
-
-#if defined(_WIN32)
-    int len = 0;
-
-    #if defined(UNICODE)
-    unsigned short widePath[MAX_PATH];
-    len = GetModuleFileNameW(NULL, (wchar_t *)widePath, MAX_PATH);
-    len = WideCharToMultiByte(0, 0, (wchar_t *)widePath, len, appDir, MAX_PATH, NULL, NULL);
-    #else
-    len = GetModuleFileNameA(NULL, appDir, MAX_PATH);
-    #endif
-
-    if (len > 0)
-    {
-        for (int i = len; i >= 0; --i)
-        {
-            if (appDir[i] == '\\')
-            {
-                appDir[i + 1] = '\0';
-                break;
-            }
-        }
-    }
-    else
-    {
-        appDir[0] = '.';
-        appDir[1] = '\\';
-    }
-
-#elif defined(__linux__)
-
-    unsigned int size = sizeof(appDir);
-    ssize_t len = readlink("/proc/self/exe", appDir, size);
-
-    if (len > 0)
-    {
-        for (int i = len; i >= 0; --i)
-        {
-            if (appDir[i] == '/')
-            {
-                appDir[i + 1] = '\0';
-                break;
-            }
-        }
-    }
-    else
-    {
-        appDir[0] = '.';
-        appDir[1] = '/';
-    }
-
-#elif defined(__APPLE__)
-
-    uint32_t size = sizeof(appDir);
-
-    if (_NSGetExecutablePath(appDir, &size) == 0)
-    {
-        int appDirLength = (int)strlen(appDir);
-        for (int i = appDirLength; i >= 0; --i)
-        {
-            if (appDir[i] == '/')
-            {
-                appDir[i + 1] = '\0';
-                break;
-            }
-        }
-    }
-    else
-    {
-        appDir[0] = '.';
-        appDir[1] = '/';
-    }
-
-#elif defined(__FreeBSD__)
-
-    size_t size = sizeof(appDir);
-    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
-
-    if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0)
-    {
-        int appDirLength = (int)strlen(appDir);
-        for (int i = appDirLength; i >= 0; --i)
-        {
-            if (appDir[i] == '/')
-            {
-                appDir[i + 1] = '\0';
-                break;
-            }
-        }
-    }
-    else
-    {
-        appDir[0] = '.';
-        appDir[1] = '/';
-    }
-
-#elif defined(__wasm__)
-
-    appDir[0] = '/';
-#endif
-
-    return appDir;
-}
-
-// Load directory filepaths
-// NOTE: Base path is prepended to the scanned filepaths
-// WARNING: Directory is scanned twice, first time to get files count
-// No recursive scanning is done!
-FilePathList LoadDirectoryFiles(const char *dirPath)
-{
-    FilePathList files = { 0 };
-    unsigned int fileCounter = 0;
-
-    struct dirent *entity;
-    DIR *dir = opendir(dirPath);
-
-    if (dir != NULL) // It's a directory
-    {
-        // SCAN 1: Count files
-        while ((entity = readdir(dir)) != NULL)
-        {
-            // NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths
-            if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0)) fileCounter++;
-        }
-
-        // Memory allocation for dirFileCount
-        files.capacity = fileCounter;
-        files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
-        for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
-
-        closedir(dir);
-
-        // SCAN 2: Read filepaths
-        // NOTE: Directory paths are also registered
-        ScanDirectoryFiles(dirPath, &files, NULL);
-
-        // Security check: read files.count should match fileCounter
-        if (files.count != files.capacity) TRACELOG(LOG_WARNING, "FILEIO: Read files count do not match capacity allocated");
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory");  // Maybe it's a file...
-
-    return files;
-}
-
-// Load directory filepaths with extension filtering and recursive directory scan
-// NOTE: On recursive loading we do not pre-scan for file count, we use MAX_FILEPATH_CAPACITY
-FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs)
-{
-    FilePathList files = { 0 };
-
-    files.capacity = MAX_FILEPATH_CAPACITY;
-    files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
-    for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
-
-    // WARNING: basePath is always prepended to scanned paths
-    if (scanSubdirs) ScanDirectoryFilesRecursively(basePath, &files, filter);
-    else ScanDirectoryFiles(basePath, &files, filter);
-
-    return files;
-}
-
-// Unload directory filepaths
-// WARNING: files.count is not reseted to 0 after unloading
-void UnloadDirectoryFiles(FilePathList files)
-{
-    if (files.paths != NULL)
-    {
-        for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
-
-        RL_FREE(files.paths);
-    }
-}
-
-// Create directories (including full path requested), returns 0 on success
-int MakeDirectory(const char *dirPath)
-{
-    if ((dirPath == NULL) || (dirPath[0] == '\0')) return -1; // Path is not valid
-    if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)
-
-    // Copy path string to avoid modifying original
-    int dirPathLength = (int)strlen(dirPath) + 1;
-    char *pathcpy = (char *)RL_CALLOC(dirPathLength, 1);
-    memcpy(pathcpy, dirPath, dirPathLength);
-
-    // Iterate over pathcpy, create each subdirectory as needed
-    for (int i = 0; (i < dirPathLength) && (pathcpy[i] != '\0'); i++)
-    {
-        if (pathcpy[i] == ':') i++;
-        else
-        {
-            if ((pathcpy[i] == '\\') || (pathcpy[i] == '/'))
-            {
-                pathcpy[i] = '\0';
-                if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
-                pathcpy[i] = '/';
-            }
-        }
-    }
-
-    // Create final directory
-    if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
-    RL_FREE(pathcpy);
-
-    // In case something failed and requested directory
-    // was not successfully created, return -1
-    if (!DirectoryExists(dirPath)) return -1;
-
-    return 0;
-}
-
-// Change working directory, returns true on success
-bool ChangeDirectory(const char *dirPath)
-{
-    bool result = CHDIR(dirPath);
-
-    if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dirPath);
-    else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dirPath);
-
-    return (result == 0);
-}
-
-// Check if a given path point to a file
-bool IsPathFile(const char *path)
-{
-    struct stat result = { 0 };
-    stat(path, &result);
-
-    return S_ISREG(result.st_mode);
-}
-
-// Check if fileName is valid for the platform/OS
-bool IsFileNameValid(const char *fileName)
-{
-    bool valid = true;
-
-    if ((fileName != NULL) && (fileName[0] != '\0'))
-    {
-        int fileNameLength = (int)strlen(fileName);
-        bool allPeriods = true;
-
-        for (int i = 0; i < fileNameLength; i++)
-        {
-            // Check invalid characters
-            if ((fileName[i] == '<') ||
-                (fileName[i] == '>') ||
-                (fileName[i] == ':') ||
-                (fileName[i] == '\"') ||
-                (fileName[i] == '/') ||
-                (fileName[i] == '\\') ||
-                (fileName[i] == '|') ||
-                (fileName[i] == '?') ||
-                (fileName[i] == '*')) { valid = false; break; }
-
-            // Check non-glyph characters
-            if ((unsigned char)fileName[i] < 32) { valid = false; break; }
-
-            // Check if filename is not all periods
-            if (fileName[i] != '.') allPeriods = false;
-        }
-
-        if (allPeriods) valid = false;
-
-/*
-        if (valid)
-        {
-            // Check invalid DOS names
-            if (fileNameLength >= 3)
-            {
-                if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'N')) ||   // CON
-                    ((fileName[0] == 'P') && (fileName[1] == 'R') && (fileName[2] == 'N')) ||   // PRN
-                    ((fileName[0] == 'A') && (fileName[1] == 'U') && (fileName[2] == 'X')) ||   // AUX
-                    ((fileName[0] == 'N') && (fileName[1] == 'U') && (fileName[2] == 'L'))) valid = false; // NUL
-            }
-
-            if (fileNameLength >= 4)
-            {
-                if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'M') && ((fileName[3] >= '0') && (fileName[3] <= '9'))) ||  // COM0-9
-                    ((fileName[0] == 'L') && (fileName[1] == 'P') && (fileName[2] == 'T') && ((fileName[3] >= '0') && (fileName[3] <= '9')))) valid = false; // LPT0-9
-            }
-        }
-*/
-    }
-
-    return valid;
-}
-
-// Check if a file has been dropped into window
-bool IsFileDropped(void)
-{
-    bool result = false;
-
-    if (CORE.Window.dropFileCount > 0) result = true;
-
-    return result;
-}
-
-// Load dropped filepaths
-FilePathList LoadDroppedFiles(void)
-{
-    FilePathList files = { 0 };
-
-    files.count = CORE.Window.dropFileCount;
-    files.paths = CORE.Window.dropFilepaths;
-
-    return files;
-}
-
-// Unload dropped filepaths
-void UnloadDroppedFiles(FilePathList files)
-{
-    // WARNING: files pointers are the same as internal ones
-
-    if (files.count > 0)
-    {
-        for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]);
-
-        RL_FREE(files.paths);
-
-        CORE.Window.dropFileCount = 0;
-        CORE.Window.dropFilepaths = NULL;
-    }
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Compression and Encoding
-//----------------------------------------------------------------------------------
-
-// Compress data (DEFLATE algorithm)
-unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize)
-{
-    #define COMPRESSION_QUALITY_DEFLATE  8
-
-    unsigned char *compData = NULL;
-
-#if defined(SUPPORT_COMPRESSION_API)
-    // Compress data and generate a valid DEFLATE stream
-    struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl));   // WARNING: Possible stack overflow, struct sdefl is almost 1MB
-    int bounds = sdefl_bound(dataSize);
-    compData = (unsigned char *)RL_CALLOC(bounds, 1);
-
-    *compDataSize = sdeflate(sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE);   // Compression level 8, same as stbiw
-    RL_FREE(sdefl);
-
-    TRACELOG(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize);
-#endif
-
-    return compData;
-}
-
-// Decompress data (DEFLATE algorithm)
-unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize)
-{
-    unsigned char *data = NULL;
-
-#if defined(SUPPORT_COMPRESSION_API)
-    // Decompress data from a valid DEFLATE stream
-    unsigned char *data0 = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
-    int size = sinflate(data0, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
-
-    // WARNING: RL_REALLOC can make (and leave) data copies in memory,
-    // that can be a security concern in case of compression of sensitive data
-    // So, we use a second buffer to copy data manually, wiping original buffer memory
-    data = (unsigned char *)RL_CALLOC(size, 1);
-    memcpy(data, data0, size);
-    memset(data0, 0, MAX_DECOMPRESSION_SIZE*1024*1024); // Wipe memory, is memset() safe?
-    RL_FREE(data0);
-
-    TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, size);
-
-    *dataSize = size;
-#endif
-
-    return data;
-}
-
-// Encode data to Base64 string
-// NOTE: Returned string includes NULL terminator, considered on outputSize
-char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
-{
-    // Base64 conversion table from RFC 4648 [0..63]
-    // NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters)
-    static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-    // Compute expected size and padding
-    int paddedSize = dataSize;
-    while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
-    int estimatedOutputSize = 4*(paddedSize/3);
-    int padding = paddedSize - dataSize;
-
-    // Adding null terminator to string
-    estimatedOutputSize += 1;
-
-    // Load some memory to store encoded string
-    char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
-    if (encodedData == NULL) return NULL;
-
-    int outputCount = 0;
-    for (int i = 0; i < dataSize;)
-    {
-        unsigned int octetA = 0;
-        unsigned int octetB = 0;
-        unsigned int octetC = 0;
-        unsigned int octetPack = 0;
-
-        octetA = data[i]; // Generates 2 sextets
-        octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
-        octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
-
-        octetPack = (octetA << 16) | (octetB << 8) | octetC;
-
-        encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
-        encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
-        encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
-        encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
-        outputCount += 4;
-        i += 3;
-    }
-
-    // Add required padding bytes
-    for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
-
-    // Add null terminator to string
-    encodedData[outputCount] = '\0';
-    outputCount++;
-
-    if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
-
-    *outputSize = estimatedOutputSize;
-    return encodedData;
-}
-
-// Decode Base64 string (expected NULL terminated)
-unsigned char *DecodeDataBase64(const char *text, int *outputSize)
-{
-    // Base64 decode table
-    // NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
-    // every character in the corresponding ASCII position
-    static const unsigned char base64DecodeTable[256] = {
-        ['A'] =  0, ['B'] =  1, ['C'] =  2, ['D'] =  3, ['E'] =  4, ['F'] =  5, ['G'] =  6, ['H'] =  7,
-        ['I'] =  8, ['J'] =  9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
-        ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
-        ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
-        ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
-        ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
-        ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
-        ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
-    };
-
-    *outputSize = 0;
-    if (text == NULL) return NULL;
-
-    // Compute expected size and padding
-    int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
-    int ending = dataSize - 1;
-    int padding = 0;
-    while (text[ending] == '=') { padding++; ending--; }
-    int estimatedOutputSize = 3*(dataSize/4) - padding;
-    int maxOutputSize = 3*(dataSize/4);
-
-    // Load some memory to store decoded data
-    // NOTE: Allocated enough size to include padding
-    unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
-    if (decodedData == NULL) return NULL;
-
-    int outputCount = 0;
-    for (int i = 0; i < dataSize;)
-    {
-        // Every 4 sixtets must generate 3 octets
-        if ((i + 2) >= dataSize)
-        {
-            TRACELOG(LOG_WARNING, "BASE64: Decoding error: Input data size is not valid");
-            break;
-        }
-
-        unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
-        unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
-        unsigned int sixtetC = (((i + 2) < dataSize) && (unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
-        unsigned int sixtetD = (((i + 3) < dataSize) && (unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
-
-        unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12)  | (sixtetC << 6) | sixtetD;
-
-        if ((outputCount + 3) > maxOutputSize)
-        {
-            TRACELOG(LOG_WARNING, "BASE64: Decoding error: Output data size is too small");
-            break;
-        }
-
-        decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
-        decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
-        decodedData[outputCount + 2] = octetPack & 0xff;
-        outputCount += 3;
-        i += 4;
-    }
-
-    if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
-
-    *outputSize = estimatedOutputSize;
-    return decodedData;
-}
-
-// Compute CRC32 hash code
-unsigned int ComputeCRC32(unsigned char *data, int dataSize)
-{
-    static unsigned int crcTable[256] = {
-        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
-        0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
-        0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
-        0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
-        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
-        0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
-        0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
-        0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
-        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
-        0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
-        0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
-        0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
-        0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
-        0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
-        0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
-        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
-        0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
-        0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
-    };
-
-    unsigned int crc = ~0u;
-
-    for (int i = 0; i < dataSize; i++) crc = (crc >> 8) ^ crcTable[data[i] ^ (crc & 0xff)];
-
-    return ~crc;
-}
-
-// Compute MD5 hash code
-// NOTE: Returns a static int[4] array (16 bytes)
-unsigned int *ComputeMD5(unsigned char *data, int dataSize)
-{
-    #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
-
-    static unsigned int hash[4] = { 0 };  // Hash to be returned
-
-    // WARNING: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
-
-    // NOTE: r specifies the per-round shift amounts
-    unsigned int r[] = {
-        7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
-        5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
-        4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
-        6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
-    };
-
-    // Using binary integer part of the sines of integers (in radians) as constants
-    unsigned int k[] = {
-        0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
-        0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
-        0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
-        0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
-        0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
-        0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
-        0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
-        0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
-        0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
-        0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
-        0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
-        0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
-        0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
-        0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
-        0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
-        0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
-    };
-
-    hash[0] = 0x67452301;
-    hash[1] = 0xefcdab89;
-    hash[2] = 0x98badcfe;
-    hash[3] = 0x10325476;
-
-    // Pre-processing: adding a single 1 bit
-    // Append '1' bit to message
-    // NOTE: The input bytes are considered as bits strings,
-    // where the first bit is the most significant bit of the byte
-
-    // Pre-processing: padding with zeros
-    // Append '0' bit until message length in bit 448 (mod 512)
-    // Append length mod (2 pow 64) to message
-
-    int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
-
-    unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
-    memcpy(msg, data, dataSize);
-    msg[dataSize] = 128; // Write the '1' bit
-
-    unsigned int bitsLen = 8*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))
-    {
-        // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
-        unsigned int *w = (unsigned int *)(msg + offset);
-
-        // Initialize hash value for this chunk
-        unsigned int a = hash[0];
-        unsigned int b = hash[1];
-        unsigned int c = hash[2];
-        unsigned int d = hash[3];
-
-        for (int i = 0; i < 64; i++)
-        {
-            unsigned int f = 0;
-            unsigned int g = 0;
-
-            if (i < 16)
-            {
-                f = (b & c) | ((~b) & d);
-                g = i;
-            }
-            else if (i < 32)
-            {
-                f = (d & b) | ((~d) & c);
-                g = (5*i + 1)%16;
-            }
-            else if (i < 48)
-            {
-                f = b ^ c ^ d;
-                g = (3*i + 5)%16;
-            }
-            else
-            {
-                f = c ^ (b | (~d));
-                g = (7*i)%16;
-            }
-
-            unsigned int temp = d;
-            d = c;
-            c = b;
-            b = b + ROTATE_LEFT((a + f + k[i] + w[g]), r[i]);
-            a = temp;
-        }
-
-        // Add chunk's hash to result so far
-        hash[0] += a;
-        hash[1] += b;
-        hash[2] += c;
-        hash[3] += d;
-    }
-
-    RL_FREE(msg);
-
-    return hash;
-}
-
-// Compute SHA-1 hash code
-// NOTE: Returns a static int[5] array (20 bytes)
-unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
-{
-    #define SHA1_ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
-
-    static unsigned int hash[5] = { 0 };  // Hash to be returned
-
-    // Initialize hash values
-    hash[0] = 0x67452301;
-    hash[1] = 0xEFCDAB89;
-    hash[2] = 0x98BADCFE;
-    hash[3] = 0x10325476;
-    hash[4] = 0xC3D2E1F0;
-
-    // Pre-processing: adding a single 1 bit
-    // Append '1' bit to message
-    // NOTE: The input bytes are considered as bits strings,
-    // where the first bit is the most significant bit of the byte
-
-    // Pre-processing: padding with zeros
-    // Append '0' bit until message length in bit 448 (mod 512)
-    // Append length mod (2 pow 64) to message
-
-    int newDataSize = ((((dataSize + 8)/64) + 1)*64);
-
-    unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
-    memcpy(msg, data, dataSize);
-    msg[dataSize] = 128; // Write the '1' bit
-
-    unsigned long long bitsLen = 8ULL * dataSize;
-    msg[newDataSize-1] = (unsigned char)(bitsLen);
-    msg[newDataSize-2] = (unsigned char)(bitsLen >> 8);
-    msg[newDataSize-3] = (unsigned char)(bitsLen >> 16);
-    msg[newDataSize-4] = (unsigned char)(bitsLen >> 24);
-    msg[newDataSize-5] = (unsigned char)(bitsLen >> 32);
-    msg[newDataSize-6] = (unsigned char)(bitsLen >> 40);
-    msg[newDataSize-7] = (unsigned char)(bitsLen >> 48);
-    msg[newDataSize-8] = (unsigned char)(bitsLen >> 56);
-
-    // Process the message in successive 512-bit chunks
-    for (int offset = 0; offset < newDataSize; offset += (512/8))
-    {
-        // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
-        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]);
-        }
-
-        // Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
-        for (int i = 16; i < 80; i++) w[i] = SHA1_ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
-
-        // Initialize hash value for this chunk
-        unsigned int a = hash[0];
-        unsigned int b = hash[1];
-        unsigned int c = hash[2];
-        unsigned int d = hash[3];
-        unsigned int e = hash[4];
-
-        for (int i = 0; i < 80; i++)
-        {
-            unsigned int f = 0;
-            unsigned int k = 0;
-
-            if (i < 20)
-            {
-                f = (b & c) | ((~b) & d);
-                k = 0x5A827999;
-            }
-            else if (i < 40)
-            {
-                f = b ^ c ^ d;
-                k = 0x6ED9EBA1;
-            }
-            else if (i < 60)
-            {
-                f = (b & c) | (b & d) | (c & d);
-                k = 0x8F1BBCDC;
-            }
-            else
-            {
-                f = b ^ c ^ d;
-                k = 0xCA62C1D6;
-            }
-
-            unsigned int temp = SHA1_ROTATE_LEFT(a, 5) + f + e + k + w[i];
-            e = d;
-            d = c;
-            c = SHA1_ROTATE_LEFT(b, 30);
-            b = a;
-            a = temp;
-        }
-
-        // Add this chunk's hash to result so far
-        hash[0] += a;
-        hash[1] += b;
-        hash[2] += c;
-        hash[3] += d;
-        hash[4] += e;
-    }
-
-    RL_FREE(msg);
-
-    return hash;
-}
-
-// Compute SHA-256 hash code
-// NOTE: Returns a static int[8] array (32 bytes)
-unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
-{
-    #define SHA256_ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int)*8) - c)))
-    #define SHA256_A0(x) (SHA256_ROTATE_RIGHT(x, 7) ^ SHA256_ROTATE_RIGHT(x, 18) ^ (x >> 3))
-    #define SHA256_A1(x) (SHA256_ROTATE_RIGHT(x, 17) ^ SHA256_ROTATE_RIGHT(x, 19) ^ (x >> 10))
-
-    static const unsigned int k[64] = {
-        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
-        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
-        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
-        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
-        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
-        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
-        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
-        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
-        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
-    };
-
-    static unsigned int hash[8] = { 0 };
-    hash[0] = 0x6A09e667;
-    hash[1] = 0xbb67ae85;
-    hash[2] = 0x3c6ef372;
-    hash[3] = 0xa54ff53a;
-    hash[4] = 0x510e527f;
-    hash[5] = 0x9b05688c;
-    hash[6] = 0x1f83d9ab;
-    hash[7] = 0x5be0cd19;
-
-    const unsigned long long int bitLen = ((unsigned long long int)dataSize)*8;
-    unsigned long long int paddedSize = dataSize + sizeof(dataSize);
-    paddedSize += (64 - (paddedSize%64));
-    unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char));
-
-    memcpy(buffer, data, dataSize);
-    buffer[dataSize] = 0x80;
-    for (int i = 1; i <= sizeof(bitLen); i++)
-    {
-        buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF;
-    }
-
-    for (unsigned long long int blockN = 0; blockN < paddedSize/64; blockN++)
-    {
-        unsigned int a = hash[0];
-        unsigned int b = hash[1];
-        unsigned int c = hash[2];
-        unsigned int d = hash[3];
-        unsigned int e = hash[4];
-        unsigned int f = hash[5];
-        unsigned int g = hash[6];
-        unsigned int h = hash[7];
-
-        unsigned char *block = buffer + (blockN*64);
-        unsigned int w[64] = { 0 };
-        for (int i = 0; i < 16; i++)
-        {
-            w[i] = ((unsigned int)block[i*4 + 0] << 24) |
-                   ((unsigned int)block[i*4 + 1] << 16) |
-                   ((unsigned int)block[i*4 + 2] << 8)  |
-                   ((unsigned int)block[i*4 + 3]);
-        }
-        for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16];
-
-        for (unsigned long long int t = 0; t < 64; t++)
-        {
-            unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25));
-            unsigned int ch = ((e & f) ^ (~e & g));
-            unsigned int t1 = (h + e1 + ch + k[t] + w[t]);
-            unsigned int e0 = (SHA256_ROTATE_RIGHT(a, 2) ^ SHA256_ROTATE_RIGHT(a, 13) ^ SHA256_ROTATE_RIGHT(a, 22));
-            unsigned int maj = ((a & b) ^ (a & c) ^ (b & c));
-            unsigned int t2 = e0 + maj;
-
-            h = g;
-            g = f;
-            f = e;
-            e = d + t1;
-            d = c;
-            c = b;
-            b = a;
-            a = t1 + t2;
-        }
-
-        hash[0] += a;
-        hash[1] += b;
-        hash[2] += c;
-        hash[3] += d;
-        hash[4] += e;
-        hash[5] += f;
-        hash[6] += g;
-        hash[7] += h;
-    }
-
-    RL_FREE(buffer);
-
-    return hash;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Automation Events Recording and Playing
-//----------------------------------------------------------------------------------
-
-// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
-AutomationEventList LoadAutomationEventList(const char *fileName)
-{
-    AutomationEventList list = { 0 };
-
-    // Allocate and empty automation event list, ready to record new events
-    list.events = (AutomationEvent *)RL_CALLOC(MAX_AUTOMATION_EVENTS, sizeof(AutomationEvent));
-    list.capacity = MAX_AUTOMATION_EVENTS;
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    if (fileName == NULL) TRACELOG(LOG_INFO, "AUTOMATION: New empty events list loaded successfully");
-    else
-    {
-        // Load automation events file (binary)
-        /*
-        //int dataSize = 0;
-        //unsigned char *data = LoadFileData(fileName, &dataSize);
-
-        FILE *raeFile = fopen(fileName, "rb");
-        unsigned char fileId[4] = { 0 };
-
-        fread(fileId, 1, 4, raeFile);
-
-        if ((fileId[0] == 'r') && (fileId[1] == 'A') && (fileId[2] == 'E') && (fileId[1] == ' '))
-        {
-            fread(&eventCount, sizeof(int), 1, raeFile);
-            TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount);
-            fread(events, sizeof(AutomationEvent), eventCount, raeFile);
-        }
-
-        fclose(raeFile);
-        */
-
-        // Load events file (text)
-        //unsigned char *buffer = LoadFileText(fileName);
-        FILE *raeFile = fopen(fileName, "rt");
-
-        if (raeFile != NULL)
-        {
-            unsigned int counter = 0;
-            char buffer[256] = { 0 };
-            char eventDesc[64] = { 0 };
-
-            char *result = fgets(buffer, 256, raeFile);
-            if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName);
-
-            while (!feof(raeFile))
-            {
-                switch (buffer[0])
-                {
-                    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);
-
-                        counter++;
-                    } break;
-                    default: break;
-                }
-
-                result = fgets(buffer, 256, raeFile);
-                if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName);
-            }
-
-            if (counter != list.count)
-            {
-                TRACELOG(LOG_WARNING, "AUTOMATION: Events read from file [%i] do not mach event count specified [%i]", counter, list.count);
-                list.count = counter;
-            }
-
-            fclose(raeFile);
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Events file loaded successfully");
-        }
-
-        TRACELOG(LOG_INFO, "AUTOMATION: Events loaded from file: %i", list.count);
-    }
-#endif
-    return list;
-}
-
-// Unload automation events list from file
-void UnloadAutomationEventList(AutomationEventList list)
-{
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    RL_FREE(list.events);
-#endif
-}
-
-// Export automation events list as text file
-bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
-{
-    bool success = false;
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    // Export events as binary file
-    // NOTE: Code not used, only for reference if required in the future
-    /*
-    if (list.count > 0)
-    {
-        int binarySize = 4 + sizeof(int) + sizeof(AutomationEvent)*list.count;
-        unsigned char *binBuffer = (unsigned char *)RL_CALLOC(binarySize, 1);
-        int offset = 0;
-        memcpy(binBuffer + offset, "rAE ", 4); 
-        offset += 4;
-        memcpy(binBuffer + offset, &list.count, sizeof(int)); 
-        offset += sizeof(int);
-        memcpy(binBuffer + offset, list.events, sizeof(AutomationEvent)*list.count);
-        offset += sizeof(AutomationEvent)*list.count;
-        
-        success = SaveFileData(TextFormat("%s.rae",fileName), binBuffer, binarySize);
-        RL_FREE(binBuffer);
-    }
-    */
-
-    // Export events as text
-    // NOTE: Save to memory buffer and SaveFileText()
-    char *txtData = (char *)RL_CALLOC(256*list.count + 2048, sizeof(char)); // 256 characters per line plus some header
-
-    int byteCount = 0;
-    byteCount += sprintf(txtData + byteCount, "#\n");
-    byteCount += sprintf(txtData + byteCount, "# Automation events exporter v1.0 - raylib automation events list\n");
-    byteCount += sprintf(txtData + byteCount, "#\n");
-    byteCount += sprintf(txtData + byteCount, "#    c <events_count>\n");
-    byteCount += sprintf(txtData + byteCount, "#    e <frame> <event_type> <param0> <param1> <param2> <param3> // <event_type_name>\n");
-    byteCount += sprintf(txtData + byteCount, "#\n");
-    byteCount += sprintf(txtData + byteCount, "# more info and bugs-report:  github.com/raysan5/raylib\n");
-    byteCount += sprintf(txtData + byteCount, "# feedback and support:       ray[at]raylib.com\n");
-    byteCount += sprintf(txtData + byteCount, "#\n");
-    byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2026 Ramon Santamaria (@raysan5)\n");
-    byteCount += sprintf(txtData + byteCount, "#\n\n");
-
-    // Add events data
-    byteCount += sprintf(txtData + byteCount, "c %i\n", list.count);
-    for (unsigned int i = 0; i < list.count; i++)
-    {
-        byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type,
-            list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]);
-    }
-
-    // NOTE: Text data size exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
-
-    RL_FREE(txtData);
-#endif
-
-    return success;
-}
-
-// Setup automation event list to record to
-void SetAutomationEventList(AutomationEventList *list)
-{
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    currentEventList = list;
-#endif
-}
-
-// Set automation event internal base frame to start recording
-void SetAutomationEventBaseFrame(int frame)
-{
-    CORE.Time.frameCounter = frame;
-}
-
-// Start recording automation events (AutomationEventList must be set)
-void StartAutomationEventRecording(void)
-{
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    automationEventRecording = true;
-#endif
-}
-
-// Stop recording automation events
-void StopAutomationEventRecording(void)
-{
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    automationEventRecording = false;
-#endif
-}
-
-// Play a recorded automation event
-void PlayAutomationEvent(AutomationEvent event)
-{
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-    // WARNING: When should event be played? After/before/replace PollInputEvents()? -> Up to the user!
-
-    if (!automationEventRecording)
-    {
-        switch (event.type)
-        {
-            // Input event
-            case INPUT_KEY_UP: CORE.Input.Keyboard.currentKeyState[event.params[0]] = false; break;             // param[0]: key
-            case INPUT_KEY_DOWN: {                                                                              // param[0]: key
-                CORE.Input.Keyboard.currentKeyState[event.params[0]] = true;
-
-                if (CORE.Input.Keyboard.previousKeyState[event.params[0]] == false)
-                {
-                    if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)
-                    {
-                        // Add character to the queue
-                        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = event.params[0];
-                        CORE.Input.Keyboard.keyPressedQueueCount++;
-                    }
-                }
-            } break;
-            case INPUT_MOUSE_BUTTON_UP: CORE.Input.Mouse.currentButtonState[event.params[0]] = false; break;    // param[0]: key
-            case INPUT_MOUSE_BUTTON_DOWN: CORE.Input.Mouse.currentButtonState[event.params[0]] = true; break;   // param[0]: key
-            case INPUT_MOUSE_POSITION:      // param[0]: x, param[1]: y
-            {
-                CORE.Input.Mouse.currentPosition.x = (float)event.params[0];
-                CORE.Input.Mouse.currentPosition.y = (float)event.params[1];
-            } break;
-            case INPUT_MOUSE_WHEEL_MOTION:  // param[0]: x delta, param[1]: y delta
-            {
-                CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0];
-                CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1];
-            } break;
-            case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[event.params[0]] = false; break;            // param[0]: id
-            case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[event.params[0]] = true; break;           // param[0]: id
-            case INPUT_TOUCH_POSITION:      // param[0]: id, param[1]: x, param[2]: y
-            {
-                CORE.Input.Touch.position[event.params[0]].x = (float)event.params[1];
-                CORE.Input.Touch.position[event.params[0]].y = (float)event.params[2];
-            } break;
-            case INPUT_GAMEPAD_CONNECT: CORE.Input.Gamepad.ready[event.params[0]] = true; break;                // param[0]: gamepad
-            case INPUT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[event.params[0]] = false; break;            // param[0]: gamepad
-            case INPUT_GAMEPAD_BUTTON_UP: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = false; break;    // param[0]: gamepad, param[1]: button
-            case INPUT_GAMEPAD_BUTTON_DOWN: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = true; break;   // param[0]: gamepad, param[1]: button
-            case INPUT_GAMEPAD_AXIS_MOTION: // param[0]: gamepad, param[1]: axis, param[2]: delta
-            {
-                CORE.Input.Gamepad.axisState[event.params[0]][event.params[1]] = ((float)event.params[2]/32768.0f);
-            } break;
-    #if defined(SUPPORT_GESTURES_SYSTEM)
-            case INPUT_GESTURE: GESTURES.current = event.params[0]; break;     // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
-    #endif
-            // Window event
-            case WINDOW_CLOSE: CORE.Window.shouldClose = true; break;
-            case WINDOW_MAXIMIZE: MaximizeWindow(); break;
-            case WINDOW_MINIMIZE: MinimizeWindow(); break;
-            case WINDOW_RESIZE: SetWindowSize(event.params[0], event.params[1]); break;
-
-            // Custom event
-    #if defined(SUPPORT_SCREEN_CAPTURE)
-            case ACTION_TAKE_SCREENSHOT:
-            {
-                TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
-                screenshotCounter++;
-            } break;
-    #endif
-            case ACTION_SETTARGETFPS: SetTargetFPS(event.params[0]); break;
-            default: break;
-        }
-
-        TRACELOG(LOG_INFO, "AUTOMATION PLAY: Frame: %i | Event type: %i | Event parameters: %i, %i, %i", event.frame, event.type, event.params[0], event.params[1], event.params[2]);
-    }
-#endif
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Input Handling: Keyboard
-//----------------------------------------------------------------------------------
-
-// Check if a key has been pressed once
-bool IsKeyPressed(int key)
-{
-
-    bool pressed = false;
-
-    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
-    {
-        if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true;
-    }
-
-    return pressed;
-}
-
-// Check if a key has been pressed again
-bool IsKeyPressedRepeat(int key)
-{
-    bool repeat = false;
-
-    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
-    {
-        if (CORE.Input.Keyboard.keyRepeatInFrame[key] == 1) repeat = true;
-    }
-
-    return repeat;
-}
-
-// Check if a key is being pressed (key held down)
-bool IsKeyDown(int key)
-{
-    bool down = false;
-
-    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
-    {
-        if (CORE.Input.Keyboard.currentKeyState[key] == 1) down = true;
-    }
-
-    return down;
-}
-
-// Check if a key has been released once
-bool IsKeyReleased(int key)
-{
-    bool released = false;
-
-    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
-    {
-        if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true;
-    }
-
-    return released;
-}
-
-// Check if a key is NOT being pressed (key not held down)
-bool IsKeyUp(int key)
-{
-    bool up = false;
-
-    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
-    {
-        if (CORE.Input.Keyboard.currentKeyState[key] == 0) up = true;
-    }
-
-    return up;
-}
-
-// Get the last key pressed
-int GetKeyPressed(void)
-{
-    int value = 0;
-
-    if (CORE.Input.Keyboard.keyPressedQueueCount > 0)
-    {
-        // Get character from the queue head
-        value = CORE.Input.Keyboard.keyPressedQueue[0];
-
-        // Shift elements 1 step toward the head
-        for (int i = 0; i < (CORE.Input.Keyboard.keyPressedQueueCount - 1); i++)
-            CORE.Input.Keyboard.keyPressedQueue[i] = CORE.Input.Keyboard.keyPressedQueue[i + 1];
-
-        // Reset last character in the queue
-        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount - 1] = 0;
-        CORE.Input.Keyboard.keyPressedQueueCount--;
-    }
-
-    return value;
-}
-
-// Get the last char pressed
-int GetCharPressed(void)
-{
-    int value = 0;
-
-    if (CORE.Input.Keyboard.charPressedQueueCount > 0)
-    {
-        // Get character from the queue head
-        value = CORE.Input.Keyboard.charPressedQueue[0];
-
-        // Shift elements 1 step toward the head
-        for (int i = 0; i < (CORE.Input.Keyboard.charPressedQueueCount - 1); i++)
-            CORE.Input.Keyboard.charPressedQueue[i] = CORE.Input.Keyboard.charPressedQueue[i + 1];
-
-        // Reset last character in the queue
-        CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount - 1] = 0;
-        CORE.Input.Keyboard.charPressedQueueCount--;
-    }
-
-    return value;
-}
-
-// Set a custom key to exit program
-// NOTE: default exitKey is set to ESCAPE
-void SetExitKey(int key)
-{
-    CORE.Input.Keyboard.exitKey = key;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Input Handling: Gamepad
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//int SetGamepadMappings(const char *mappings)
-
-// Check if a gamepad is available
-bool IsGamepadAvailable(int gamepad)
-{
-    bool result = false;
-
-    if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
-
-    return result;
-}
-
-// Get gamepad internal name id
-const char *GetGamepadName(int gamepad)
-{
-    return CORE.Input.Gamepad.name[gamepad];
-}
-
-// Check if a gamepad button has been pressed once
-bool IsGamepadButtonPressed(int gamepad, int button)
-{
-    bool pressed = false;
-
-    if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
-        (CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true;
-
-    return pressed;
-}
-
-// Check if a gamepad button is being pressed
-bool IsGamepadButtonDown(int gamepad, int button)
-{
-    bool down = false;
-
-    if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
-        (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) down = true;
-
-    return down;
-}
-
-// Check if a gamepad button has NOT been pressed once
-bool IsGamepadButtonReleased(int gamepad, int button)
-{
-    bool released = false;
-
-    if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
-        (CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true;
-
-    return released;
-}
-
-// Check if a gamepad button is NOT being pressed
-bool IsGamepadButtonUp(int gamepad, int button)
-{
-    bool up = false;
-
-    if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
-        (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) up = true;
-
-    return up;
-}
-
-// Get the last gamepad button pressed
-int GetGamepadButtonPressed(void)
-{
-    return CORE.Input.Gamepad.lastButtonPressed;
-}
-
-// Get gamepad axis count
-int GetGamepadAxisCount(int gamepad)
-{
-    return CORE.Input.Gamepad.axisCount[gamepad];
-}
-
-// Get axis movement vector for a gamepad
-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))
-    {
-        float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
-
-        if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
-    }
-
-    return value;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Input Handling: Mouse
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//void SetMousePosition(int x, int y)
-//void SetMouseCursor(int cursor)
-
-// Check if a mouse button has been pressed once
-bool IsMouseButtonPressed(int button)
-{
-    bool pressed = false;
-
-    if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true;
-
-    // Map touches to mouse buttons checking
-    if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true;
-
-    return pressed;
-}
-
-// Check if a mouse button is being pressed
-bool IsMouseButtonDown(int button)
-{
-    bool down = false;
-
-    if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true;
-
-    // NOTE: Touches are considered like mouse buttons
-    if (CORE.Input.Touch.currentTouchState[button] == 1) down = true;
-
-    return down;
-}
-
-// Check if a mouse button has been released once
-bool IsMouseButtonReleased(int button)
-{
-    bool released = false;
-
-    if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true;
-
-    // Map touches to mouse buttons checking
-    if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true;
-
-    return released;
-}
-
-// Check if a mouse button is NOT being pressed
-bool IsMouseButtonUp(int button)
-{
-    bool up = false;
-
-    if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true;
-
-    // NOTE: Touches are considered like mouse buttons
-    if (CORE.Input.Touch.currentTouchState[button] == 0) up = true;
-
-    return up;
-}
-
-// Get mouse position X
-int GetMouseX(void)
-{
-    int mouseX = (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
-    return mouseX;
-}
-
-// Get mouse position Y
-int GetMouseY(void)
-{
-    int mouseY = (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
-    return mouseY;
-}
-
-// Get mouse position XY
-Vector2 GetMousePosition(void)
-{
-    Vector2 position = { 0 };
-
-    position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
-    position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
-
-    return position;
-}
-
-// Get mouse delta between frames
-Vector2 GetMouseDelta(void)
-{
-    Vector2 delta = { 0 };
-
-    delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x;
-    delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y;
-
-    return delta;
-}
-
-// Set mouse offset
-// NOTE: Useful when rendering to different size targets
-void SetMouseOffset(int offsetX, int offsetY)
-{
-    CORE.Input.Mouse.offset = (Vector2){ (float)offsetX, (float)offsetY };
-}
-
-// Set mouse scaling
-// NOTE: Useful when rendering to different size targets
-void SetMouseScale(float scaleX, float scaleY)
-{
-    CORE.Input.Mouse.scale = (Vector2){ scaleX, scaleY };
-}
-
-// Get mouse wheel movement Y
-float GetMouseWheelMove(void)
-{
-    float result = 0.0f;
-
-    if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
-    else result = (float)CORE.Input.Mouse.currentWheelMove.y;
-
-    return result;
-}
-
-// Get mouse wheel movement X/Y as a vector
-Vector2 GetMouseWheelMoveV(void)
-{
-    Vector2 result = { 0 };
-
-    result = CORE.Input.Mouse.currentWheelMove;
-
-    return result;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition: Input Handling: Touch
-//----------------------------------------------------------------------------------
-
-// Get touch position X for touch point 0 (relative to screen size)
-int GetTouchX(void)
-{
-    int touchX = (int)CORE.Input.Touch.position[0].x;
-    return touchX;
-}
-
-// Get touch position Y for touch point 0 (relative to screen size)
-int GetTouchY(void)
-{
-    int touchY = (int)CORE.Input.Touch.position[0].y;
-    return touchY;
-}
-
-// Get touch position XY for a touch point index (relative to screen size)
-Vector2 GetTouchPosition(int index)
-{
-    Vector2 position = { -1.0f, -1.0f };
-
-    if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
-    else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
-
-    return position;
-}
-
-// Get touch point identifier for given index
-int GetTouchPointId(int index)
-{
-    int id = -1;
-
-    if (index < MAX_TOUCH_POINTS) id = CORE.Input.Touch.pointId[index];
-
-    return id;
-}
-
-// Get number of touch points
-int GetTouchPointCount(void)
-{
-    return CORE.Input.Touch.pointCount;
-}
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-
-// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
-//int InitPlatform(void)
-//void ClosePlatform(void)
-
-// Initialize hi-resolution timer
-void InitTimer(void)
-{
-    // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
-    // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
-    // High resolutions can also prevent the CPU power management system from entering power-saving modes
-    // Setting a higher resolution does not improve the accuracy of the high-resolution performance counter
-#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_DESKTOP_SDL)
-    timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
-#endif
-
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
-    struct timespec now = { 0 };
-
-    if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
-    {
-        CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
-    }
-    else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
-#endif
-
-    CORE.Time.previous = GetTime(); // Get time as double
-}
-
-// Set viewport for a provided width and height
-void SetupViewport(int width, int height)
-{
-    CORE.Window.render.width = width;
-    CORE.Window.render.height = height;
-
-    // Set viewport width and height
-    rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width, CORE.Window.render.height);
-
-    rlMatrixMode(RL_PROJECTION);        // Switch to projection matrix
-    rlLoadIdentity();                   // Reset current matrix (projection)
-
-    // Set orthographic projection to current framebuffer size
-    // NOTE: Configured top-left corner as (0, 0)
-    rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f);
-
-    rlMatrixMode(RL_MODELVIEW);         // Switch back to modelview matrix
-    rlLoadIdentity();                   // Reset current matrix (modelview)
-}
-
-// Scan all files and directories in a base path
-// WARNING: files.paths[] must be previously allocated and
-// contain enough space to store all required paths
-static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter)
-{
-    static char path[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(path, 0, MAX_FILEPATH_LENGTH);
-
-    struct dirent *dp = NULL;
-    DIR *dir = opendir(basePath);
-
-    if (dir != NULL)
-    {
-        while ((dp = readdir(dir)) != NULL)
-        {
-            if ((strcmp(dp->d_name, ".") != 0) &&
-                (strcmp(dp->d_name, "..") != 0))
-            {
-                // Construct new path from our base path
-            #if defined(_WIN32)
-                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
-            #else
-                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
-            #endif
-
-                if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
-                {
-                    TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
-                }
-                else if (filter != NULL)
-                {
-                    if (IsPathFile(path))
-                    {
-                        if (IsFileExtension(path, filter))
-                        {
-                            strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                            files->count++;
-                        }
-                    }
-                    else
-                    {
-                        if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)
-                        {
-                            strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                            files->count++;
-                        }
-                    }
-                }
-                else
-                {
-                    strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                    files->count++;
-                }
-            }
-        }
-
-        closedir(dir);
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
-}
-
-// Scan all files and directories recursively from a base path
-static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
-{
-    // WARNING: Path can not be static or it will be reused between recursive function calls!
-    char path[MAX_FILEPATH_LENGTH] = { 0 };
-    memset(path, 0, MAX_FILEPATH_LENGTH);
-
-    struct dirent *dp = NULL;
-    DIR *dir = opendir(basePath);
-
-    if (dir != NULL)
-    {
-        while (((dp = readdir(dir)) != NULL) && (files->count < files->capacity))
-        {
-            if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
-            {
-                // Construct new path from our base path
-            #if defined(_WIN32)
-                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
-            #else
-                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
-            #endif
-
-                if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
-                {
-                    TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
-                }
-                else if (IsPathFile(path))
-                {
-                    if (filter != NULL)
-                    {
-                        if (IsFileExtension(path, filter))
-                        {
-                            strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                            files->count++;
-                        }
-                    }
-                    else
-                    {
-                        strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                        files->count++;
-                    }
-
-                    if (files->count >= files->capacity)
-                    {
-                        TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
-                        break;
-                    }
-                }
-                else
-                {
-                    if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL))
-                    {
-                        strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
-                        files->count++;
-                    }
-
-                    if (files->count >= files->capacity)
-                    {
-                        TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
-                        break;
-                    }
-
-                    ScanDirectoryFilesRecursively(path, files, filter);
-                }
-            }
-        }
-
-        closedir(dir);
-    }
-    else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
-}
-
-#if defined(SUPPORT_AUTOMATION_EVENTS)
-// Automation event recording
-// Checking events in current frame and save them into currentEventList
-// NOTE: Recording is by default done at EndDrawing(), before PollInputEvents()
-static void RecordAutomationEvent(void)
-{
-    if (currentEventList->count == currentEventList->capacity) return;
-
-    // Keyboard input events recording
-    //-------------------------------------------------------------------------------------
-    for (int key = 0; key < MAX_KEYBOARD_KEYS; key++)
-    {
-        // Event type: INPUT_KEY_UP (only saved once)
-        if (CORE.Input.Keyboard.previousKeyState[key] && !CORE.Input.Keyboard.currentKeyState[key])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_KEY_UP;
-            currentEventList->events[currentEventList->count].params[0] = key;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-
-        // Event type: INPUT_KEY_DOWN
-        if (CORE.Input.Keyboard.currentKeyState[key])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_KEY_DOWN;
-            currentEventList->events[currentEventList->count].params[0] = key;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-    //-------------------------------------------------------------------------------------
-
-    // Mouse input currentEventList->events recording
-    //-------------------------------------------------------------------------------------
-    for (int button = 0; button < MAX_MOUSE_BUTTONS; button++)
-    {
-        // Event type: INPUT_MOUSE_BUTTON_UP
-        if (CORE.Input.Mouse.previousButtonState[button] && !CORE.Input.Mouse.currentButtonState[button])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_UP;
-            currentEventList->events[currentEventList->count].params[0] = button;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-
-        // Event type: INPUT_MOUSE_BUTTON_DOWN
-        if (CORE.Input.Mouse.currentButtonState[button])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_DOWN;
-            currentEventList->events[currentEventList->count].params[0] = button;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-
-    // Event type: INPUT_MOUSE_POSITION (only saved if changed)
-    if (((int)CORE.Input.Mouse.currentPosition.x != (int)CORE.Input.Mouse.previousPosition.x) ||
-        ((int)CORE.Input.Mouse.currentPosition.y != (int)CORE.Input.Mouse.previousPosition.y))
-    {
-        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-        currentEventList->events[currentEventList->count].type = INPUT_MOUSE_POSITION;
-        currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentPosition.x;
-        currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentPosition.y;
-        currentEventList->events[currentEventList->count].params[2] = 0;
-
-        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-        currentEventList->count++;
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-
-    // Event type: INPUT_MOUSE_WHEEL_MOTION
-    if (((int)CORE.Input.Mouse.currentWheelMove.x != (int)CORE.Input.Mouse.previousWheelMove.x) ||
-        ((int)CORE.Input.Mouse.currentWheelMove.y != (int)CORE.Input.Mouse.previousWheelMove.y))
-    {
-        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-        currentEventList->events[currentEventList->count].type = INPUT_MOUSE_WHEEL_MOTION;
-        currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;
-        currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;
-        currentEventList->events[currentEventList->count].params[2] = 0;
-
-        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_WHEEL_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-        currentEventList->count++;
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-    //-------------------------------------------------------------------------------------
-
-    // Touch input currentEventList->events recording
-    //-------------------------------------------------------------------------------------
-    for (int id = 0; id < MAX_TOUCH_POINTS; id++)
-    {
-        // Event type: INPUT_TOUCH_UP
-        if (CORE.Input.Touch.previousTouchState[id] && !CORE.Input.Touch.currentTouchState[id])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_UP;
-            currentEventList->events[currentEventList->count].params[0] = id;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-
-        // Event type: INPUT_TOUCH_DOWN
-        if (CORE.Input.Touch.currentTouchState[id])
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_DOWN;
-            currentEventList->events[currentEventList->count].params[0] = id;
-            currentEventList->events[currentEventList->count].params[1] = 0;
-            currentEventList->events[currentEventList->count].params[2] = 0;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-
-        // Event type: INPUT_TOUCH_POSITION         
-        if (((int)CORE.Input.Touch.position[id].x != (int)CORE.Input.Touch.previousPosition[id].x) ||
-            ((int)CORE.Input.Touch.position[id].y != (int)CORE.Input.Touch.previousPosition[id].y))
-        {
-            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_POSITION;
-            currentEventList->events[currentEventList->count].params[0] = id;
-            currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.position[id].x;
-            currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.position[id].y;
-
-            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-            currentEventList->count++;
-        }
-        
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-    //-------------------------------------------------------------------------------------
-
-    // Gamepad input currentEventList->events recording
-    //-------------------------------------------------------------------------------------
-    for (int gamepad = 0; gamepad < MAX_GAMEPADS; gamepad++)
-    {
-        // Event type: INPUT_GAMEPAD_CONNECT
-        /*
-        if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
-            (CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready
-        {
-            // TODO: Save gamepad connect event
-        }
-        */
-
-        // Event type: INPUT_GAMEPAD_DISCONNECT
-        /*
-        if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
-            (!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready
-        {
-            // TODO: Save gamepad disconnect event
-        }
-        */
-
-        for (int button = 0; button < MAX_GAMEPAD_BUTTONS; button++)
-        {
-            // Event type: INPUT_GAMEPAD_BUTTON_UP
-            if (CORE.Input.Gamepad.previousButtonState[gamepad][button] && !CORE.Input.Gamepad.currentButtonState[gamepad][button])
-            {
-                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_UP;
-                currentEventList->events[currentEventList->count].params[0] = gamepad;
-                currentEventList->events[currentEventList->count].params[1] = button;
-                currentEventList->events[currentEventList->count].params[2] = 0;
-
-                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-                currentEventList->count++;
-            }
-
-            if (currentEventList->count == currentEventList->capacity) return;    // Security check
-
-            // Event type: INPUT_GAMEPAD_BUTTON_DOWN
-            if (CORE.Input.Gamepad.currentButtonState[gamepad][button])
-            {
-                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_DOWN;
-                currentEventList->events[currentEventList->count].params[0] = gamepad;
-                currentEventList->events[currentEventList->count].params[1] = button;
-                currentEventList->events[currentEventList->count].params[2] = 0;
-
-                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-                currentEventList->count++;
-            }
-
-            if (currentEventList->count == currentEventList->capacity) return;    // Security check
-        }
-
-        for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
-        {
-            // Event type: INPUT_GAMEPAD_AXIS_MOTION
-            float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
-            if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
-            {
-                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_AXIS_MOTION;
-                currentEventList->events[currentEventList->count].params[0] = gamepad;
-                currentEventList->events[currentEventList->count].params[1] = axis;
-                currentEventList->events[currentEventList->count].params[2] = (int)(CORE.Input.Gamepad.axisState[gamepad][axis]*32768.0f);
-
-                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_AXIS_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-                currentEventList->count++;
-            }
-
-            if (currentEventList->count == currentEventList->capacity) return;    // Security check
-        }
-    }
-    //-------------------------------------------------------------------------------------
-
-#if defined(SUPPORT_GESTURES_SYSTEM)
-    // Gestures input currentEventList->events recording
-    //-------------------------------------------------------------------------------------
-    if (GESTURES.current != GESTURE_NONE)
-    {
-        // Event type: INPUT_GESTURE
-        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
-        currentEventList->events[currentEventList->count].type = INPUT_GESTURE;
-        currentEventList->events[currentEventList->count].params[0] = GESTURES.current;
-        currentEventList->events[currentEventList->count].params[1] = 0;
-        currentEventList->events[currentEventList->count].params[2] = 0;
-
-        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GESTURE | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
-        currentEventList->count++;
-
-        if (currentEventList->count == currentEventList->capacity) return;    // Security check
-    }
-    //-------------------------------------------------------------------------------------
-#endif
-}
-#endif
-
-#if !defined(SUPPORT_MODULE_RTEXT)
-// Formatting of text with variables to 'embed'
-// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
-const char *TextFormat(const char *text, ...)
-{
-#ifndef MAX_TEXTFORMAT_BUFFERS
-    #define MAX_TEXTFORMAT_BUFFERS      4        // Maximum number of static buffers for text formatting
-#endif
-#ifndef MAX_TEXT_BUFFER_LENGTH
-    #define MAX_TEXT_BUFFER_LENGTH   1024        // Maximum size of static text buffer
-#endif
-
-    // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
-    static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
-    static int index = 0;
-
-    char *currentBuffer = buffers[index];
-    memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
-
-    if (text != NULL)
-    {
-        va_list args;
-        va_start(args, text);
-        int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
-        va_end(args);
-
-        // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred
-        if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
-        {
-            // Inserting "..." at the end of the string to mark as truncated
-            char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
-            snprintf(truncBuffer, 4, "...");
-        }
-
-        index += 1; // Move to next buffer for next function call
-        if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
-    }
-
-    return currentBuffer;
-}
-
-#endif // !SUPPORT_MODULE_RTEXT
+*       > PLATFORM_DESKTOP_WIN32 (native Win32):
+*           - Windows (Win32, Win64)
+*       > PLATFORM_WEB (GLFW + Emscripten):
+*           - HTML5 (WebAssembly)
+*       > PLATFORM_WEB_EMSCRIPTEN (Emscripten):
+*           - HTML5 (WebAssembly)
+*       > PLATFORM_WEB_RGFW (Emscripten):
+*           - HTML5 (WebAssembly)
+*       > PLATFORM_DRM (native DRM):
+*           - Raspberry Pi 0-5 (DRM/KMS)
+*           - Linux DRM subsystem (KMS mode)
+*           - Embedded devices (with GPU)
+*       > PLATFORM_ANDROID (native NDK):
+*           - Android (ARM, ARM64)
+*       > PLATFORM_MEMORY
+*           - Memory framebuffer output, using software renderer, no OS required
+*
+*   CONFIGURATION:
+*       #define SUPPORT_CAMERA_SYSTEM       1
+*           Camera module is included (rcamera.h) and multiple predefined cameras are available:
+*               free, 1st/3rd person, orbital, custom
+*
+*       #define SUPPORT_GESTURES_SYSTEM     1
+*           Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
+*
+*       #define SUPPORT_MOUSE_GESTURES      1
+*           Mouse gestures are directly mapped like touches and processed by gestures system
+*
+*       #define SUPPORT_BUSY_WAIT_LOOP      1
+*           Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
+*
+*       #define SUPPORT_PARTIALBUSY_WAIT_LOOP 0
+*           Use a partial-busy wait loop, in this case frame sleeps for most of the time and runs a busy-wait-loop at the end
+*
+*       #define SUPPORT_SCREEN_CAPTURE      1
+*           Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
+*
+*       #define SUPPORT_COMPRESSION_API     1
+*           Support CompressData() and DecompressData() functions, those functions use zlib implementation
+*           provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
+*           for linkage
+*
+*       #define SUPPORT_AUTOMATION_EVENTS   1
+*           Support automatic events recording and playing, useful for automated testing systems or AI based game playing
+*
+*   DEPENDENCIES:
+*       raymath  - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
+*       camera   - Multiple 3D camera modes (free, orbital, 1st person, 3rd person)
+*       gestures - Gestures system for touch-ready devices (or simulated from mouse inputs)
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
+*
+*   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.
+*
+**********************************************************************************************/
+
+//----------------------------------------------------------------------------------
+// Feature Test Macros required for this module
+//----------------------------------------------------------------------------------
+#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_XOPEN_SOURCE < 500)
+    #undef _XOPEN_SOURCE
+    #define _XOPEN_SOURCE 500       // Required for: readlink if compiled with c99 without GNU extensions
+#endif
+
+#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_POSIX_C_SOURCE < 199309L)
+    #undef _POSIX_C_SOURCE
+    #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without GNU extensions
+#endif
+
+#include "raylib.h"                 // Declares module functions
+
+#include "config.h"                 // Defines module configuration flags
+
+#include <stdlib.h>                 // Required for: srand(), rand(), exit()
+#include <stdio.h>                  // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
+#include <string.h>                 // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat()
+#include <stdarg.h>                 // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
+
+#ifndef PICO_RP2350
+#include <time.h>                   // 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 <math.h>                   // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
+
+#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB)
+    #define SW_GL_FRAMEBUFFER_COPY_BGRA false
+#endif
+#define RLGL_IMPLEMENTATION
+#include "rlgl.h"                   // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
+
+#define RAYMATH_IMPLEMENTATION
+#include "raymath.h"                // Vector2, Vector3, Quaternion and Matrix functionality
+
+#if SUPPORT_GESTURES_SYSTEM
+    #define RGESTURES_IMPLEMENTATION
+    #include "rgestures.h"          // Gestures detection functionality
+#endif
+
+#if SUPPORT_CAMERA_SYSTEM
+    #define RCAMERA_IMPLEMENTATION
+    #include "rcamera.h"            // Camera system functionality
+#endif
+
+#if SUPPORT_COMPRESSION_API
+    #define SINFL_IMPLEMENTATION
+    #define SINFL_NO_SIMD
+    #include "external/sinfl.h"     // Deflate (RFC 1951) decompressor
+
+    #define SDEFL_IMPLEMENTATION
+    #include "external/sdefl.h"     // Deflate (RFC 1951) compressor
+#endif
+
+#if SUPPORT_RPRAND_GENERATOR
+    #define RPRAND_IMPLEMENTATION
+    #include "external/rprand.h"
+#endif
+
+#if defined(__linux__) && !defined(_GNU_SOURCE)
+    #define _GNU_SOURCE
+#endif
+
+// Platform specific defines to handle GetApplicationDirectory()
+#if defined(_WIN32)
+    #if !defined(MAX_PATH)
+        #define MAX_PATH 260
+    #endif
+
+    struct HINSTANCE__;
+    #if defined(__cplusplus)
+    extern "C" {
+    #endif
+    __declspec(dllimport) unsigned long __stdcall GetFileAttributesA(const char *lpFileName);
+    __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize);
+    __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize);
+    __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+    __declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
+    __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
+    #if defined(__cplusplus)
+    }
+    #endif
+#elif defined(__linux__)
+    #include <unistd.h>
+#elif defined(__FreeBSD__)
+    #include <sys/types.h>
+    #include <sys/sysctl.h>
+    #include <unistd.h>
+#elif defined(__APPLE__)
+    #include <sys/syslimits.h>
+    #include <mach-o/dyld.h>
+#endif
+
+#define _CRT_INTERNAL_NONSTDC_NAMES  1
+#include <sys/stat.h>               // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()]
+
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+    #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
+    #define DIRENT_MALLOC RL_MALLOC
+    #define DIRENT_FREE RL_FREE
+
+    #include "external/dirent.h"    // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
+#else
+    #include <dirent.h>             // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
+#endif
+
+#if defined(_WIN32)
+    #include <io.h>                 // Required for: _access() [Used in FileExists()]
+    #include <direct.h>             // Required for: _getch(), _chdir(), _mkdir()
+    #define GETCWD _getcwd          // NOTE: MSDN recommends not to use getcwd(), chdir()
+    #define CHDIR _chdir
+    #define MKDIR(dir) _mkdir(dir)
+    #define ACCESS(fn) _access(fn, 0)
+#else
+    #include <unistd.h>             // Required for: getch(), chdir(), mkdir(), access()
+    #define GETCWD getcwd
+    #define CHDIR chdir
+    #define MKDIR(dir) mkdir(dir, 0777)
+    #define ACCESS(fn) access(fn, F_OK)
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef MAX_TRACELOG_MSG_LENGTH
+    #define MAX_TRACELOG_MSG_LENGTH      256        // Max length of one trace-log message
+#endif
+
+#ifndef MAX_FILEPATH_CAPACITY
+    #define MAX_FILEPATH_CAPACITY       8192        // Maximum capacity for filepath
+#endif
+#ifndef MAX_FILEPATH_LENGTH
+    #if defined(_WIN32)
+        #define MAX_FILEPATH_LENGTH      256        // On Win32, MAX_PATH = 260 (limits.h) but Windows 10, Version 1607 enables long paths...
+    #else
+        #define MAX_FILEPATH_LENGTH     4096        // On Linux, PATH_MAX = 4096 by default (limits.h)
+    #endif
+#endif
+
+#ifndef MAX_KEYBOARD_KEYS
+    #define MAX_KEYBOARD_KEYS            512        // Maximum number of keyboard keys supported
+#endif
+#ifndef MAX_MOUSE_BUTTONS
+    #define MAX_MOUSE_BUTTONS              8        // Maximum number of mouse buttons supported
+#endif
+#ifndef MAX_GAMEPADS
+    #define MAX_GAMEPADS                   4        // Maximum number of gamepads supported
+#endif
+#ifndef MAX_GAMEPAD_NAME_LENGTH
+    #define MAX_GAMEPAD_NAME_LENGTH      128        // Maximum number of characters in a gamepad name (byte size)
+#endif
+#ifndef MAX_GAMEPAD_AXES
+    #define MAX_GAMEPAD_AXES               8        // Maximum number of axes supported (per gamepad)
+#endif
+#ifndef MAX_GAMEPAD_BUTTONS
+    #define MAX_GAMEPAD_BUTTONS           32        // Maximum number of buttons supported (per gamepad)
+#endif
+#ifndef MAX_GAMEPAD_VIBRATION_TIME
+    #define MAX_GAMEPAD_VIBRATION_TIME     2.0f     // Maximum vibration time in seconds
+#endif
+#ifndef MAX_TOUCH_POINTS
+    #define MAX_TOUCH_POINTS               8        // Maximum number of touch points supported
+#endif
+#ifndef MAX_KEY_PRESSED_QUEUE
+    #define MAX_KEY_PRESSED_QUEUE         16        // Maximum number of keys in the key input queue
+#endif
+#ifndef MAX_CHAR_PRESSED_QUEUE
+    #define MAX_CHAR_PRESSED_QUEUE        16        // Maximum number of characters in the char input queue
+#endif
+
+#ifndef MAX_DECOMPRESSION_SIZE
+    #define MAX_DECOMPRESSION_SIZE        64        // Maximum size allocated for decompression in MB
+#endif
+
+#ifndef MAX_AUTOMATION_EVENTS
+    #define MAX_AUTOMATION_EVENTS      16384        // Maximum number of automation events to record
+#endif
+
+// File and directory scan filters
+// NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
+// WARNING: Custom file filters can be specified but following raylib IsFileExtension() convention: ".png;.wav;.glb"
+#ifndef FILE_FILTER_TAG_ALL
+    #define FILE_FILTER_TAG_ALL        "*.*"        // Filter to include all file types and directories on scan
+#endif
+#ifndef FILE_FILTER_TAG_FILE_ONLY
+    #define FILE_FILTER_TAG_FILE_ONLY  "FILES*"     // Filter to include all file types on scan (no directories)
+#endif
+#ifndef FILE_FILTER_TAG_DIR_ONLY
+    #define FILE_FILTER_TAG_DIR_ONLY   "DIRS*"      // Filter to include only directories on scan
+#endif
+
+// Flags bitwise operation macros
+#define FLAG_SET(n, f) ((n) |= (f))
+#define FLAG_CLEAR(n, f) ((n) &= ~(f))
+#define FLAG_TOGGLE(n, f) ((n) ^= (f))
+#define FLAG_IS_SET(n, f) (((n) & (f)) == (f))
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct { int x; int y; } Point;
+typedef struct { unsigned int width; unsigned int height; } Size;
+
+// Core global state context data
+typedef struct CoreData {
+    struct {
+        const char *title;                  // Window text title const pointer
+        unsigned int flags;                 // Configuration flags (bit based), keeps window state
+        bool ready;                         // Check if window has been initialized successfully
+        bool shouldClose;                   // Check if window set for closing
+        bool resizedLastFrame;              // Check if window has been resized last frame
+        bool eventWaiting;                  // Wait for events before ending frame
+        bool usingFbo;                      // Using FBO (RenderTexture) for rendering instead of default framebuffer
+
+        Size display;                       // Display width and height (monitor, device-screen, LCD, ...)
+        Size screen;                        // Screen current width and height
+        Point position;                     // Window current position
+        Size previousScreen;                // Screen previous width and height (required on fullscreen/borderless-windowed toggle)
+        Point previousPosition;             // Window previous position (required on fullscreen/borderless-windowed toggle)
+        Size render;                        // Screen framebuffer width and height
+        Point renderOffset;                 // Screen framebuffer render offset (Not required anymore?)
+        Size currentFbo;                    // Current framebuffer render width and height (depends on active render texture)
+        Size screenMin;                     // Screen minimum width and height (for resizable window)
+        Size screenMax;                     // Screen maximum width and height (for resizable window)
+        Matrix screenScale;                 // Matrix to scale screen (framebuffer rendering)
+
+        char **dropFilepaths;               // Store dropped files paths pointers (provided by GLFW)
+        unsigned int dropFileCount;         // Count dropped files strings
+
+    } Window;
+    struct {
+        const char *basePath;               // Base path for data storage
+
+    } Storage;
+    struct {
+        struct {
+            int exitKey;                    // Default exit key
+            char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
+            char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
+
+            // NOTE: Since key press logic involves comparing previous vs current key state,
+            // key repeats needs to be handled specially
+            char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame
+
+            int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
+            int keyPressedQueueCount;       // Input keys queue count
+
+            int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
+            int charPressedQueueCount;      // Input characters queue count
+
+        } Keyboard;
+        struct {
+            Vector2 offset;                 // Mouse offset
+            Vector2 scale;                  // Mouse scaling
+            Vector2 currentPosition;        // Mouse position on screen
+            Vector2 previousPosition;       // Previous mouse position
+            Vector2 lockedPosition;         // Mouse position when locked
+
+            int cursor;                     // Tracks current mouse cursor
+            bool cursorHidden;              // Track if cursor is hidden
+            bool cursorLocked;              // Track if cursor is locked (disabled)
+            bool cursorOnScreen;            // Tracks if cursor is inside client area
+
+            char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
+            char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
+            Vector2 currentWheelMove;       // Registers current mouse wheel variation
+            Vector2 previousWheelMove;      // Registers previous mouse wheel variation
+
+        } Mouse;
+        struct {
+            int pointCount;                                 // Number of touch points active
+            int pointId[MAX_TOUCH_POINTS];                  // Point identifiers
+            Vector2 position[MAX_TOUCH_POINTS];             // Touch position on screen
+            Vector2 previousPosition[MAX_TOUCH_POINTS];     // Previous touch position on screen
+            char currentTouchState[MAX_TOUCH_POINTS];       // Registers current touch state
+            char previousTouchState[MAX_TOUCH_POINTS];      // Registers previous touch state
+
+        } Touch;
+        struct {
+            int lastButtonPressed;          // Register last gamepad button pressed
+            int axisCount[MAX_GAMEPADS];    // Register number of available gamepad axes
+            bool ready[MAX_GAMEPADS];       // Flag to know if gamepad is ready
+            char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH];               // Gamepad name holder
+            char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS];     // Current gamepad buttons state
+            char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS];    // Previous gamepad buttons state
+            float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES];                // Gamepad axes state
+
+        } Gamepad;
+    } Input;
+    struct {
+        double current;                     // Current time measure (seconds)
+        double previous;                    // Previous time measure (seconds)
+        double update;                      // Time measure for frame update (seconds)
+        double draw;                        // Time measure for frame draw (seconds)
+        double frame;                       // Time measure for one frame (seconds)
+        double target;                      // Desired time for one frame, if 0 not applied (seconds)
+        unsigned long long base;            // Base time measure for hi-res timer (ticks or nanoseconds)
+        unsigned int frameCounter;          // Frame counter (frames)
+
+    } Time;
+} CoreData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+RLAPI const char *raylib_version = RAYLIB_VERSION;  // raylib version exported symbol, required for some bindings
+
+CoreData CORE = { 0 };                              // Global CORE state context
+
+static int logTypeLevel = LOG_INFO;                 // Minimum log type level
+
+static TraceLogCallback traceLog = NULL;            // TraceLog callback function pointer
+static LoadFileDataCallback loadFileData = NULL;    // LoadFileData callback function pointer
+static SaveFileDataCallback saveFileData = NULL;    // SaveFileText callback function pointer
+static LoadFileTextCallback loadFileText = NULL;    // LoadFileText callback function pointer
+static SaveFileTextCallback saveFileText = NULL;    // SaveFileText callback function pointer
+
+#if SUPPORT_SCREEN_CAPTURE
+static int screenshotCounter = 0;                   // Screenshots counter
+#endif
+
+#if SUPPORT_AUTOMATION_EVENTS
+// Automation events type
+typedef enum AutomationEventType {
+    EVENT_NONE = 0,
+    // Input events
+    INPUT_KEY_UP,                   // param[0]: key
+    INPUT_KEY_DOWN,                 // param[0]: key
+    INPUT_KEY_PRESSED,              // param[0]: key
+    INPUT_KEY_RELEASED,             // param[0]: key
+    INPUT_MOUSE_BUTTON_UP,          // param[0]: button
+    INPUT_MOUSE_BUTTON_DOWN,        // param[0]: button
+    INPUT_MOUSE_POSITION,           // param[0]: x, param[1]: y
+    INPUT_MOUSE_WHEEL_MOTION,       // param[0]: x delta, param[1]: y delta
+    INPUT_GAMEPAD_CONNECT,          // param[0]: gamepad
+    INPUT_GAMEPAD_DISCONNECT,       // param[0]: gamepad
+    INPUT_GAMEPAD_BUTTON_UP,        // param[0]: button
+    INPUT_GAMEPAD_BUTTON_DOWN,      // param[0]: button
+    INPUT_GAMEPAD_AXIS_MOTION,      // param[0]: axis, param[1]: delta
+    INPUT_TOUCH_UP,                 // param[0]: id
+    INPUT_TOUCH_DOWN,               // param[0]: id
+    INPUT_TOUCH_POSITION,           // param[0]: x, param[1]: y
+    INPUT_GESTURE,                  // param[0]: gesture
+    // Window events
+    WINDOW_CLOSE,                   // no params
+    WINDOW_MAXIMIZE,                // no params
+    WINDOW_MINIMIZE,                // no params
+    WINDOW_RESIZE,                  // param[0]: width, param[1]: height
+    // Custom events
+    ACTION_TAKE_SCREENSHOT,         // no params
+    ACTION_SETTARGETFPS             // param[0]: fps
+} AutomationEventType;
+
+// Event type name strings, required for export
+static const char *autoEventTypeName[] = {
+    "EVENT_NONE",
+    "INPUT_KEY_UP",
+    "INPUT_KEY_DOWN",
+    "INPUT_KEY_PRESSED",
+    "INPUT_KEY_RELEASED",
+    "INPUT_MOUSE_BUTTON_UP",
+    "INPUT_MOUSE_BUTTON_DOWN",
+    "INPUT_MOUSE_POSITION",
+    "INPUT_MOUSE_WHEEL_MOTION",
+    "INPUT_GAMEPAD_CONNECT",
+    "INPUT_GAMEPAD_DISCONNECT",
+    "INPUT_GAMEPAD_BUTTON_UP",
+    "INPUT_GAMEPAD_BUTTON_DOWN",
+    "INPUT_GAMEPAD_AXIS_MOTION",
+    "INPUT_TOUCH_UP",
+    "INPUT_TOUCH_DOWN",
+    "INPUT_TOUCH_POSITION",
+    "INPUT_GESTURE",
+    "WINDOW_CLOSE",
+    "WINDOW_MAXIMIZE",
+    "WINDOW_MINIMIZE",
+    "WINDOW_RESIZE",
+    "ACTION_TAKE_SCREENSHOT",
+    "ACTION_SETTARGETFPS"
+};
+
+static AutomationEventList *currentEventList = NULL;        // Current automation events list, set by user, keep internal pointer
+static bool automationEventRecording = false;               // Recording automation events flag
+//static short automationEventEnabled = 0b0000001111111111; // TODO: Automation events enabled for recording/playing
+#endif
+//-----------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+// NOTE: Those functions are common for all platforms!
+//----------------------------------------------------------------------------------
+#if SUPPORT_MODULE_RTEXT
+extern void LoadFontDefault(void);      // [Module: text] Loads default font on InitWindow()
+extern void UnloadFontDefault(void);    // [Module: text] Unloads default font from GPU memory
+#endif
+
+extern int InitPlatform(void);          // Initialize platform (graphics, inputs and more)
+extern void ClosePlatform(void);        // Close platform
+
+static void InitTimer(void);                                // Initialize timer, hi-resolution if available (required by InitPlatform())
+static void SetupViewport(int width, int height);           // Set viewport for a provided width and height
+
+static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter, unsigned int expectedFileCount, bool scanSubdirs); // Scan all files and directories in a base path
+
+#if SUPPORT_AUTOMATION_EVENTS
+static void RecordAutomationEvent(void); // Record frame events (to internal events array)
+#endif
+
+#if defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)
+// NOTE: Declaring Sleep() function symbol to avoid including windows.h (kernel32.lib linkage required)
+__declspec(dllimport) void __stdcall Sleep(unsigned long msTimeout); // Required for: WaitTime()
+#endif
+
+#if !SUPPORT_MODULE_RTEXT
+const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
+#endif
+
+// NOTE: PLATFORM_DESKTOP defaults to GLFW backend
+#if defined(PLATFORM_DESKTOP)
+    #define PLATFORM_DESKTOP_GLFW
+#endif
+
+// Include platform-specific submodules
+#if defined(PLATFORM_DESKTOP_GLFW)
+    #include "platforms/rcore_desktop_glfw.c"
+#elif defined(PLATFORM_DESKTOP_SDL)
+    #include "platforms/rcore_desktop_sdl.c"
+#elif (defined(PLATFORM_DESKTOP_RGFW) || defined(PLATFORM_WEB_RGFW))
+    #include "platforms/rcore_desktop_rgfw.c"
+#elif defined(PLATFORM_DESKTOP_WIN32)
+    #include "platforms/rcore_desktop_win32.c"
+#elif defined(PLATFORM_WEB)
+    #include "platforms/rcore_web.c"
+#elif defined(PLATFORM_DRM)
+    #include "platforms/rcore_drm.c"
+#elif defined(PLATFORM_ANDROID)
+    #include "platforms/rcore_android.c"
+#elif defined(PLATFORM_MEMORY)
+    #include "platforms/rcore_memory.c"
+#else
+    // TODO: Include your custom platform backend!
+    // i.e software rendering backend or console backend!
+    #pragma message ("WARNING: No [rcore] platform defined")
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Window and Graphics Device
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//bool WindowShouldClose(void)
+//void ToggleFullscreen(void)
+//void ToggleBorderlessWindowed(void)
+//void MaximizeWindow(void)
+//void MinimizeWindow(void)
+//void RestoreWindow(void)
+
+//void SetWindowState(unsigned int flags)
+//void ClearWindowState(unsigned int flags)
+
+//void SetWindowIcon(Image image)
+//void SetWindowIcons(Image *images, int count)
+//void SetWindowTitle(const char *title)
+//void SetWindowPosition(int x, int y)
+//void SetWindowMonitor(int monitor)
+//void SetWindowMinSize(int width, int height)
+//void SetWindowMaxSize(int width, int height)
+//void SetWindowSize(int width, int height)
+//void SetWindowOpacity(float opacity)
+//void SetWindowFocused(void)
+//void *GetWindowHandle(void)
+//Vector2 GetWindowPosition(void)
+//Vector2 GetWindowScaleDPI(void)
+
+//int GetMonitorCount(void)
+//int GetCurrentMonitor(void)
+//int GetMonitorWidth(int monitor)
+//int GetMonitorHeight(int monitor)
+//int GetMonitorPhysicalWidth(int monitor)
+//int GetMonitorPhysicalHeight(int monitor)
+//int GetMonitorRefreshRate(int monitor)
+//Vector2 GetMonitorPosition(int monitor)
+//const char *GetMonitorName(int monitor)
+
+//void SetClipboardText(const char *text)
+//const char *GetClipboardText(void)
+
+//void ShowCursor(void)
+//void HideCursor(void)
+//void EnableCursor(void)
+//void DisableCursor(void)
+
+// Initialize window and OpenGL context
+void InitWindow(int width, int height, const char *title)
+{
+    TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
+
+#if defined(PLATFORM_DESKTOP_GLFW)
+    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (GLFW)");
+#elif defined(PLATFORM_DESKTOP_SDL)
+    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (SDL)");
+#elif defined(PLATFORM_DESKTOP_RGFW)
+    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (RGFW)");
+#elif defined(PLATFORM_DESKTOP_WIN32)
+    TRACELOG(LOG_INFO, "Platform backend: DESKTOP (WIN32)");
+#elif defined(PLATFORM_WEB_RGFW)
+    TRACELOG(LOG_INFO, "Platform backend: WEB (RGFW) (HTML5)");
+#elif defined(PLATFORM_WEB)
+    TRACELOG(LOG_INFO, "Platform backend: WEB (HTML5)");
+#elif defined(PLATFORM_DRM)
+    TRACELOG(LOG_INFO, "Platform backend: NATIVE DRM");
+#elif defined(PLATFORM_ANDROID)
+    TRACELOG(LOG_INFO, "Platform backend: ANDROID");
+#elif defined(PLATFORM_MEMORY)
+    TRACELOG(LOG_INFO, "Platform backend: MEMORY (No OS)");
+#else
+    // TODO: Include your custom platform backend!
+    // i.e software rendering backend or console backend!
+    TRACELOG(LOG_INFO, "Platform backend: CUSTOM");
+#endif
+
+    TRACELOG(LOG_INFO, "Supported raylib modules:");
+    TRACELOG(LOG_INFO, "    > rcore:..... loaded (mandatory)");
+    TRACELOG(LOG_INFO, "    > rlgl:...... loaded (mandatory)");
+#if SUPPORT_MODULE_RSHAPES
+    TRACELOG(LOG_INFO, "    > rshapes:... loaded (optional)");
+#else
+    TRACELOG(LOG_INFO, "    > rshapes:... not loaded (optional)");
+#endif
+#if SUPPORT_MODULE_RTEXTURES
+    TRACELOG(LOG_INFO, "    > rtextures:. loaded (optional)");
+#else
+    TRACELOG(LOG_INFO, "    > rtextures:. not loaded (optional)");
+#endif
+#if SUPPORT_MODULE_RTEXT
+    TRACELOG(LOG_INFO, "    > rtext:..... loaded (optional)");
+#else
+    TRACELOG(LOG_INFO, "    > rtext:..... not loaded (optional)");
+#endif
+#if SUPPORT_MODULE_RMODELS
+    TRACELOG(LOG_INFO, "    > rmodels:... loaded (optional)");
+#else
+    TRACELOG(LOG_INFO, "    > rmodels:... not loaded (optional)");
+#endif
+#if SUPPORT_MODULE_RAUDIO
+    TRACELOG(LOG_INFO, "    > raudio:.... loaded (optional)");
+#else
+    TRACELOG(LOG_INFO, "    > raudio:.... not loaded (optional)");
+#endif
+
+    // Initialize window data
+    CORE.Window.screen.width = width;
+    CORE.Window.screen.height = height;
+
+    CORE.Window.eventWaiting = false;
+    CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
+    if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
+
+    // Initialize global input state
+    memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
+    CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
+    CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
+    CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
+    CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
+
+    // Initialize platform
+    //--------------------------------------------------------------
+    int result = InitPlatform();
+
+    if (result != 0)
+    {
+        TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform");
+        return;
+    }
+
+    // Initialize render dimensions for embedded platforms
+    // NOTE: On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are set during window creation
+    // On embedded platforms with no window manager, InitPlatform() doesn't set these values, so they should be initialized
+    // here from screen dimensions (which are set from the InitWindow parameters)
+    if ((CORE.Window.render.width == 0) || (CORE.Window.render.height == 0))
+    {
+        CORE.Window.render.width = CORE.Window.screen.width;
+        CORE.Window.render.height = CORE.Window.screen.height;
+    }
+    //--------------------------------------------------------------
+
+    // Initialize rlgl default data (buffers and shaders)
+    // NOTE: Current fbo size stored as globals in rlgl for convenience
+    rlglInit(CORE.Window.render.width, CORE.Window.render.height);
+
+    // Setup default viewport
+    SetupViewport(CORE.Window.render.width, CORE.Window.render.height);
+
+#if SUPPORT_MODULE_RTEXT
+    // Load default font
+    // WARNING: External function: Module required: rtext
+    LoadFontDefault();
+    #if SUPPORT_MODULE_RSHAPES
+    // Set font white rectangle for shapes drawing, so shapes and text can be batched together
+    // WARNING: rshapes module is required, if not available, default internal white rectangle is used
+    Rectangle rec = GetFontDefault().recs[95];
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
+    {
+        // NOTE: Try to maximize rec padding to avoid pixel bleeding on MSAA filtering
+        SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
+    }
+    else
+    {
+        // NOTE: Set up a 1px padding on char rectangle to avoid pixel bleeding
+        SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
+    }
+    #endif
+#else
+    #if SUPPORT_MODULE_RSHAPES
+    // Set default texture and rectangle to be used for shapes drawing
+    // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
+    Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
+    SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f });    // WARNING: Module required: rshapes
+    #endif
+#endif
+
+    CORE.Time.frameCounter = 0;
+    CORE.Window.shouldClose = false;
+
+    // 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());
+}
+
+// Close window and unload OpenGL context
+void CloseWindow(void)
+{
+#if SUPPORT_MODULE_RTEXT
+    UnloadFontDefault();        // WARNING: Module required: rtext
+#endif
+
+    rlglClose();                // De-init rlgl
+
+    // De-initialize platform
+    //--------------------------------------------------------------
+    ClosePlatform();
+    //--------------------------------------------------------------
+
+    CORE.Window.ready = false;
+    TRACELOG(LOG_INFO, "Window closed successfully");
+}
+
+// Check if window has been initialized successfully
+bool IsWindowReady(void)
+{
+    return CORE.Window.ready;
+}
+
+// Check if window is currently fullscreen
+bool IsWindowFullscreen(void)
+{
+    return FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+}
+
+// Check if window is currently hidden
+bool IsWindowHidden(void)
+{
+    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
+}
+
+// Check if window has been minimized
+bool IsWindowMinimized(void)
+{
+    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
+}
+
+// Check if window has been maximized
+bool IsWindowMaximized(void)
+{
+    return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+}
+
+// Check if window has the focus
+bool IsWindowFocused(void)
+{
+    return !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
+}
+
+// Check if window has been resizedLastFrame
+bool IsWindowResized(void)
+{
+    return CORE.Window.resizedLastFrame;
+}
+
+// Check if one specific window flag is enabled
+bool IsWindowState(unsigned int flag)
+{
+    return FLAG_IS_SET(CORE.Window.flags, flag);
+}
+
+// Get current screen width
+int GetScreenWidth(void)
+{
+    return CORE.Window.screen.width;
+}
+
+// Get current screen height
+int GetScreenHeight(void)
+{
+    return CORE.Window.screen.height;
+}
+
+// Get current render width which is equal to screen width*dpi scale
+int GetRenderWidth(void)
+{
+    int width = 0;
+
+    if (CORE.Window.usingFbo) width = CORE.Window.currentFbo.width;
+    else width = CORE.Window.render.width;
+
+    return width;
+}
+
+// Get current screen height which is equal to screen height*dpi scale
+int GetRenderHeight(void)
+{
+    int height = 0;
+
+    if (CORE.Window.usingFbo) height = CORE.Window.currentFbo.height;
+    else height = CORE.Window.render.height;
+
+    return height;
+}
+
+// Enable waiting for events on EndDrawing(), no automatic event polling
+void EnableEventWaiting(void)
+{
+    CORE.Window.eventWaiting = true;
+}
+
+// Disable waiting for events on EndDrawing(), automatic events polling
+void DisableEventWaiting(void)
+{
+    CORE.Window.eventWaiting = false;
+}
+
+// Check if cursor is not visible
+bool IsCursorHidden(void)
+{
+    return CORE.Input.Mouse.cursorHidden;
+}
+
+// Check if cursor is on the current screen
+bool IsCursorOnScreen(void)
+{
+    return CORE.Input.Mouse.cursorOnScreen;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Screen Drawing
+//----------------------------------------------------------------------------------
+
+// Clear background (framebuffer) to color
+void ClearBackground(Color color)
+{
+    rlClearColor(color.r, color.g, color.b, color.a);   // Set clear color
+    rlClearScreenBuffers();                             // Clear current framebuffers
+}
+
+// Begin canvas (framebuffer) drawing
+void BeginDrawing(void)
+{
+    // WARNING: Previously to BeginDrawing() other render textures drawing could happen,
+    // consequently the measure for update vs draw is not accurate (only the total frame time is accurate)
+
+    CORE.Time.current = GetTime();      // Number of elapsed seconds since InitTimer()
+    CORE.Time.update = CORE.Time.current - CORE.Time.previous;
+    CORE.Time.previous = CORE.Time.current;
+
+    rlLoadIdentity();                   // Reset current matrix (modelview)
+    rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling
+
+    //rlTranslatef(0.375, 0.375, 0);    // HACK to have 2D pixel-perfect drawing on OpenGL 1.1
+                                        // NOTE: Not required with OpenGL 3.3+
+}
+
+// End canvas (framebuffer) drawing and swap buffers (double buffering)
+void EndDrawing(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+#if SUPPORT_AUTOMATION_EVENTS
+    if (automationEventRecording) RecordAutomationEvent();    // Event recording
+#endif
+
+#if !SUPPORT_CUSTOM_FRAME_CONTROL
+    SwapScreenBuffer();                  // Copy back buffer to front buffer (screen)
+
+    // Frame time control system
+    CORE.Time.current = GetTime();
+    CORE.Time.draw = CORE.Time.current - CORE.Time.previous;
+    CORE.Time.previous = CORE.Time.current;
+
+    CORE.Time.frame = CORE.Time.update + CORE.Time.draw;
+
+    // Wait for some milliseconds...
+    if (CORE.Time.frame < CORE.Time.target)
+    {
+        WaitTime(CORE.Time.target - CORE.Time.frame);
+
+        CORE.Time.current = GetTime();
+        double waitTime = CORE.Time.current - CORE.Time.previous;
+        CORE.Time.previous = CORE.Time.current;
+
+        CORE.Time.frame += waitTime;    // Total frame time: update + draw + wait
+    }
+
+    PollInputEvents();      // Poll user events (before next frame update)
+#endif
+
+#if SUPPORT_SCREEN_CAPTURE
+    if (IsKeyPressed(KEY_F12))
+    {
+        TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
+        screenshotCounter++;
+    }
+#endif
+
+    CORE.Time.frameCounter++;
+}
+
+// Initialize 2D mode with custom camera (2D)
+void BeginMode2D(Camera2D camera)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    // Apply 2d camera transformation to modelview
+    rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
+}
+
+// End 2D mode with custom camera
+void EndMode2D(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
+}
+
+// Initializes 3D mode with custom camera (3D)
+void BeginMode3D(Camera camera)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
+    rlPushMatrix();                 // Save previous matrix, which contains the settings for the 2d ortho projection
+    rlLoadIdentity();               // Reset current matrix (projection)
+
+    float aspect = (float)CORE.Window.currentFbo.width/(float)CORE.Window.currentFbo.height;
+
+    // NOTE: zNear and zFar values are important when computing depth buffer values
+    if (camera.projection == CAMERA_PERSPECTIVE)
+    {
+        // Setup perspective projection
+        double top = rlGetCullDistanceNear()*tan(camera.fovy*0.5*DEG2RAD);
+        double right = top*aspect;
+
+        rlFrustum(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
+    {
+        // Setup orthographic projection
+        double top = camera.fovy/2.0;
+        double right = top*aspect;
+
+        rlOrtho(-right, right, -top,top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+
+    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    // Setup Camera view
+    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+    rlMultMatrixf(MatrixToFloat(matView));      // Multiply modelview matrix by view matrix (camera)
+
+    rlEnableDepthTest();            // Enable DEPTH_TEST for 3D
+}
+
+// End 3D mode and returns to default 2D orthographic mode
+void EndMode3D(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
+    rlPopMatrix();                  // Restore previous matrix (projection) from matrix stack
+
+    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    if (rlGetActiveFramebuffer() == 0) rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
+
+    rlDisableDepthTest();           // Disable DEPTH_TEST for 2D
+}
+
+// Initializes render texture for drawing
+void BeginTextureMode(RenderTexture2D target)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlEnableFramebuffer(target.id); // Enable render target
+
+    // Set viewport and RLGL internal framebuffer size
+    rlViewport(0, 0, target.texture.width, target.texture.height);
+    rlSetFramebufferWidth(target.texture.width);
+    rlSetFramebufferHeight(target.texture.height);
+
+    rlMatrixMode(RL_PROJECTION);    // Switch to projection matrix
+    rlLoadIdentity();               // Reset current matrix (projection)
+
+    // Set orthographic projection to current framebuffer size
+    // NOTE: Configured top-left corner as (0, 0)
+    rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f);
+
+    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
+    rlLoadIdentity();               // Reset current matrix (modelview)
+
+    //rlScalef(0.0f, -1.0f, 0.0f);  // Flip Y-drawing (?)
+
+    // Setup current width/height for proper aspect ratio
+    // calculation when using BeginTextureMode()
+    CORE.Window.currentFbo.width = target.texture.width;
+    CORE.Window.currentFbo.height = target.texture.height;
+    CORE.Window.usingFbo = true;
+}
+
+// End drawing to render texture
+void EndTextureMode(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlDisableFramebuffer();         // Disable render target (fbo)
+
+    // Set viewport to default framebuffer size
+    SetupViewport(CORE.Window.render.width, CORE.Window.render.height);
+
+    // Go back to the modelview state from BeginDrawing, back to the main framebuffer
+    rlMatrixMode(RL_MODELVIEW);     // Switch back to modelview matrix
+    rlLoadIdentity();               // Reset current matrix (modelview)
+    rlMultMatrixf(MatrixToFloat(CORE.Window.screenScale)); // Apply screen scaling if required
+
+    // Reset current fbo to screen size
+    CORE.Window.currentFbo.width = CORE.Window.render.width;
+    CORE.Window.currentFbo.height = CORE.Window.render.height;
+    CORE.Window.usingFbo = false;
+}
+
+// Begin custom shader mode
+void BeginShaderMode(Shader shader)
+{
+    rlSetShader(shader.id, shader.locs);
+}
+
+// End custom shader mode (returns to default shader)
+void EndShaderMode(void)
+{
+    rlSetShader(rlGetShaderIdDefault(), rlGetShaderLocsDefault());
+}
+
+// Begin blending mode (alpha, additive, multiplied, subtract, custom)
+// NOTE: Blend modes supported are enumerated in BlendMode enum
+void BeginBlendMode(int mode)
+{
+    rlSetBlendMode(mode);
+}
+
+// End blending mode (reset to default: alpha blending)
+void EndBlendMode(void)
+{
+    rlSetBlendMode(BLEND_ALPHA);
+}
+
+// Begin scissor mode (define screen area for following drawing)
+// NOTE: Scissor rec refers to bottom-left corner, changing it to upper-left
+void BeginScissorMode(int x, int y, int width, int height)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+
+    rlEnableScissorTest();
+
+#if defined(__APPLE__)
+    if (!CORE.Window.usingFbo)
+    {
+        Vector2 scale = GetWindowScaleDPI();
+        rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
+    }
+#else
+    if (!CORE.Window.usingFbo && FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+    {
+        Vector2 scale = GetWindowScaleDPI();
+        rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
+    }
+#endif
+    else
+    {
+        rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height);
+    }
+}
+
+// End scissor mode
+void EndScissorMode(void)
+{
+    rlDrawRenderBatchActive();      // Update and draw internal render batch
+    rlDisableScissorTest();
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: VR Stereo Rendering
+//----------------------------------------------------------------------------------
+
+// Begin VR drawing configuration
+void BeginVrStereoMode(VrStereoConfig config)
+{
+    rlEnableStereoRender();
+
+    // Set stereo render matrices
+    rlSetMatrixProjectionStereo(config.projection[0], config.projection[1]);
+    rlSetMatrixViewOffsetStereo(config.viewOffset[0], config.viewOffset[1]);
+}
+
+// End VR drawing process (and desktop mirror)
+void EndVrStereoMode(void)
+{
+    rlDisableStereoRender();
+}
+
+// Load VR stereo config for VR simulator device parameters
+VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device)
+{
+    VrStereoConfig config = { 0 };
+
+    if (rlGetVersion() != RL_OPENGL_11)
+    {
+        // Compute aspect ratio
+        float aspect = ((float)device.hResolution*0.5f)/(float)device.vResolution;
+
+        // Compute lens parameters
+        float lensShift = (device.hScreenSize*0.25f - device.lensSeparationDistance*0.5f)/device.hScreenSize;
+        config.leftLensCenter[0] = 0.25f + lensShift;
+        config.leftLensCenter[1] = 0.5f;
+        config.rightLensCenter[0] = 0.75f - lensShift;
+        config.rightLensCenter[1] = 0.5f;
+        config.leftScreenCenter[0] = 0.25f;
+        config.leftScreenCenter[1] = 0.5f;
+        config.rightScreenCenter[0] = 0.75f;
+        config.rightScreenCenter[1] = 0.5f;
+
+        // Compute distortion scale parameters
+        // NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
+        float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
+        float lensRadiusSq = lensRadius*lensRadius;
+        float distortionScale = device.lensDistortionValues[0] +
+                                device.lensDistortionValues[1]*lensRadiusSq +
+                                device.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq +
+                                device.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq;
+
+        float normScreenWidth = 0.5f;
+        float normScreenHeight = 1.0f;
+        config.scaleIn[0] = 2.0f/normScreenWidth;
+        config.scaleIn[1] = 2.0f/normScreenHeight/aspect;
+        config.scale[0] = normScreenWidth*0.5f/distortionScale;
+        config.scale[1] = normScreenHeight*0.5f*aspect/distortionScale;
+
+        // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance)
+        // ...but with lens distortion it is increased (see Oculus SDK Documentation)
+        float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance);     // Really need distortionScale?
+       // float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance);
+
+        // Compute camera projection matrices
+        float projOffset = 4.0f*lensShift;      // Scaled to projection space coordinates [-1..1]
+        Matrix proj = MatrixPerspective(fovy, aspect, rlGetCullDistanceNear(), rlGetCullDistanceFar());
+
+        config.projection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f));
+        config.projection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f));
+
+        // Compute camera transformation matrices
+        // NOTE: Camera movement might seem more natural if modelling the head
+        // Axis of rotation is the base of the head, so adding some y (base of head to eye level
+        // and -z (center of head to eye protrusion) to the camera positions
+        config.viewOffset[0] = MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f);
+        config.viewOffset[1] = MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f);
+
+        // Compute eyes Viewports
+        /*
+        config.eyeViewportRight[0] = 0;
+        config.eyeViewportRight[1] = 0;
+        config.eyeViewportRight[2] = device.hResolution/2;
+        config.eyeViewportRight[3] = device.vResolution;
+
+        config.eyeViewportLeft[0] = device.hResolution/2;
+        config.eyeViewportLeft[1] = 0;
+        config.eyeViewportLeft[2] = device.hResolution/2;
+        config.eyeViewportLeft[3] = device.vResolution;
+        */
+    }
+    else TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1");
+
+    return config;
+}
+
+// Unload VR stereo config properties
+void UnloadVrStereoConfig(VrStereoConfig config)
+{
+    TRACELOG(LOG_INFO, "UnloadVrStereoConfig not implemented in rcore.c");
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Shaders Management
+//----------------------------------------------------------------------------------
+
+// Load shader from files and bind default locations
+// NOTE: If shader filename is NULL, using default vertex/fragment shaders
+Shader LoadShader(const char *vsFileName, const char *fsFileName)
+{
+    Shader shader = { 0 };
+
+    char *vShaderStr = NULL;
+    char *fShaderStr = NULL;
+
+    if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
+    if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
+
+    if ((vShaderStr == NULL) && (fShaderStr == NULL)) TRACELOG(LOG_WARNING, "SHADER: Shader files provided are not valid, using default shader");
+
+    shader = LoadShaderFromMemory(vShaderStr, fShaderStr);
+
+    UnloadFileText(vShaderStr);
+    UnloadFileText(fShaderStr);
+
+    return shader;
+}
+
+// Load shader from code strings and bind default locations
+Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
+{
+    Shader shader = { 0 };
+
+    shader.id = rlLoadShaderProgram(vsCode, fsCode);
+
+    if (shader.id == 0)
+    {
+        // Shader could not be loaded but still loading the location points to avoid potential crashes
+        // NOTE: All locations set to -1 (no location found)
+        shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
+        for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
+    }
+    else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
+    else if (shader.id > 0)
+    {
+        // After custom shader loading, trying to set default location names
+        // Default shader attribute locations have been binded before linking:
+        //  - vertex position location    = 0
+        //  - vertex texcoord location    = 1
+        //  - vertex normal location      = 2
+        //  - vertex color location       = 3
+        //  - vertex tangent location     = 4
+        //  - vertex texcoord2 location   = 5
+        //  - vertex boneIndices location = 6
+        //  - vertex boneWeights location = 7
+
+        // NOTE: If any location is not found, loc point becomes -1
+
+        // Load shader locations array
+        // NOTE: All locations set to -1 (no location)
+        shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
+        for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
+
+        // Get handles to GLSL input attribute locations
+        shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
+        shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
+        shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
+        shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
+        shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
+        shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
+        shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES);
+        shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
+        shader.locs[SHADER_LOC_VERTEX_INSTANCETRANSFORM] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM);
+
+        // Get handles to GLSL uniform locations (vertex shader)
+        shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP);
+        shader.locs[SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW);
+        shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION);
+        shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL);
+        shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL);
+        shader.locs[SHADER_LOC_MATRIX_BONETRANSFORMS] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES);
+
+        // Get handles to GLSL uniform locations (fragment shader)
+        shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR);
+        shader.locs[SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0);  // SHADER_LOC_MAP_ALBEDO
+        shader.locs[SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1); // SHADER_LOC_MAP_METALNESS
+        shader.locs[SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2);
+    }
+
+    return shader;
+}
+
+// Check if shader is valid (loaded on GPU)
+bool IsShaderValid(Shader shader)
+{
+    return ((shader.id > 0) &&          // Validate shader id (GPU loaded successfully)
+            (shader.locs != NULL));     // Validate memory has been allocated for default shader locations
+
+    // The following locations are tried to be set automatically (locs[i] >= 0),
+    // any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION
+    // NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones
+
+    // Vertex shader attribute locations (default)
+    // shader.locs[SHADER_LOC_VERTEX_POSITION]      // Set by default internal shader
+    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]    // Set by default internal shader
+    // shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]
+    // shader.locs[SHADER_LOC_VERTEX_NORMAL]
+    // shader.locs[SHADER_LOC_VERTEX_TANGENT]
+    // shader.locs[SHADER_LOC_VERTEX_COLOR]         // Set by default internal shader
+
+    // Vertex shader uniform locations (default)
+    // shader.locs[SHADER_LOC_MATRIX_MVP]           // Set by default internal shader
+    // shader.locs[SHADER_LOC_MATRIX_VIEW]
+    // shader.locs[SHADER_LOC_MATRIX_PROJECTION]
+    // shader.locs[SHADER_LOC_MATRIX_MODEL]
+    // shader.locs[SHADER_LOC_MATRIX_NORMAL]
+
+    // Fragment shader uniform locations (default)
+    // shader.locs[SHADER_LOC_COLOR_DIFFUSE]        // Set by default internal shader
+    // shader.locs[SHADER_LOC_MAP_DIFFUSE]          // Set by default internal shader
+    // shader.locs[SHADER_LOC_MAP_SPECULAR]
+    // shader.locs[SHADER_LOC_MAP_NORMAL]
+}
+
+// Unload shader from GPU memory (VRAM)
+void UnloadShader(Shader shader)
+{
+    if (shader.id != rlGetShaderIdDefault())
+    {
+        rlUnloadShaderProgram(shader.id);
+
+        // NOTE: If shader loading failed, it should be 0
+        RL_FREE(shader.locs);
+    }
+}
+
+// Get shader uniform location
+int GetShaderLocation(Shader shader, const char *uniformName)
+{
+    return rlGetLocationUniform(shader.id, uniformName);
+}
+
+// Get shader attribute location
+int GetShaderLocationAttrib(Shader shader, const char *attribName)
+{
+    return rlGetLocationAttrib(shader.id, attribName);
+}
+
+// Set shader uniform value
+void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType)
+{
+    SetShaderValueV(shader, locIndex, value, uniformType, 1);
+}
+
+// Set shader uniform value vector
+void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count)
+{
+    if (locIndex > -1)
+    {
+        rlEnableShader(shader.id);
+        rlSetUniform(locIndex, value, uniformType, count);
+        //rlDisableShader();      // Avoid resetting current shader program, in case other uniforms are set
+    }
+}
+
+// Set shader uniform value (matrix 4x4)
+void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat)
+{
+    if (locIndex > -1)
+    {
+        rlEnableShader(shader.id);
+        rlSetUniformMatrix(locIndex, mat);
+        //rlDisableShader();
+    }
+}
+
+// Set shader uniform value for texture
+void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture)
+{
+    if (locIndex > -1)
+    {
+        rlEnableShader(shader.id);
+        rlSetUniformSampler(locIndex, texture.id);
+        //rlDisableShader();
+    }
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Screen-space Queries
+//----------------------------------------------------------------------------------
+
+// Get a ray trace from screen position (i.e mouse)
+Ray GetScreenToWorldRay(Vector2 position, Camera camera)
+{
+    Ray ray = GetScreenToWorldRayEx(position, camera, GetScreenWidth(), GetScreenHeight());
+
+    return ray;
+}
+
+// Get a ray trace from the screen position (i.e mouse) within a specific section of the screen
+Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height)
+{
+    Ray ray = { 0 };
+
+    // Calculate normalized device coordinates
+    // NOTE: y value is negative
+    float x = (2.0f*position.x)/(float)width - 1.0f;
+    float y = 1.0f - (2.0f*position.y)/(float)height;
+    float z = 1.0f;
+
+    // Store values in a vector
+    Vector3 deviceCoords = { x, y, z };
+
+    // Calculate view matrix from camera look at
+    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+
+    Matrix matProj = MatrixIdentity();
+
+    if (camera.projection == CAMERA_PERSPECTIVE)
+    {
+        // Calculate projection matrix from perspective
+        matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
+    {
+        double aspect = (double)width/(double)height;
+        double top = camera.fovy/2.0;
+        double right = top*aspect;
+
+        // Calculate projection matrix from orthographic
+        matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+
+    // Unproject far/near points
+    Vector3 nearPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView);
+    Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
+
+    // Unproject the mouse cursor in the near plane
+    // It is needed as the source position because orthographic projects,
+    // compared to perspective doesn't have a convergence point,
+    // meaning that the "eye" of the camera is more like a plane than a point
+    Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
+
+    // Calculate normalized direction vector
+    Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint));
+
+    if (camera.projection == CAMERA_PERSPECTIVE) ray.position = camera.position;
+    else if (camera.projection == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos;
+
+    // Apply calculated vectors to ray
+    ray.direction = direction;
+
+    return ray;
+}
+
+// Get transform matrix for camera
+Matrix GetCameraMatrix(Camera camera)
+{
+    Matrix mat = MatrixLookAt(camera.position, camera.target, camera.up);
+
+    return mat;
+}
+
+// Get camera 2d transform matrix
+Matrix GetCameraMatrix2D(Camera2D camera)
+{
+    Matrix matTransform = { 0 };
+    // The camera in world-space is set by
+    //   1. Move it to target
+    //   2. Rotate by -rotation and scale by (1/zoom)
+    //      When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller),
+    //      not for the camera getting bigger, hence the invert. Same deal with rotation
+    //   3. Move it by (-offset);
+    //      Offset defines target transform relative to screen, but since effectively "moving" screen (camera)
+    //      it needs to be moved into opposite direction (inverse transform)
+
+    // Having camera transform in world-space, inverse of it gives the modelview transform
+    // Since (A*B*C)' = C'*B'*A', the modelview is
+    //   1. Move to offset
+    //   2. Rotate and Scale
+    //   3. Move by -target
+    Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f);
+    Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
+    Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
+    Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f);
+
+    matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
+
+    return matTransform;
+}
+
+// Get screen space position from a 3d world space position
+Vector2 GetWorldToScreen(Vector3 position, Camera camera)
+{
+    Vector2 screenPosition = GetWorldToScreenEx(position, camera, GetScreenWidth(), GetScreenHeight());
+
+    return screenPosition;
+}
+
+// Get sized screen space position for a 3d world space position (useful for texture drawing)
+Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height)
+{
+    // Calculate projection matrix (from perspective instead of frustum
+    Matrix matProj = MatrixIdentity();
+
+    if (camera.projection == CAMERA_PERSPECTIVE)
+    {
+        // Calculate projection matrix from perspective
+        matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)width/(double)height), rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+    else if (camera.projection == CAMERA_ORTHOGRAPHIC)
+    {
+        double aspect = (double)width/(double)height;
+        double top = camera.fovy/2.0;
+        double right = top*aspect;
+
+        // Calculate projection matrix from orthographic
+        matProj = MatrixOrtho(-right, right, -top, top, rlGetCullDistanceNear(), rlGetCullDistanceFar());
+    }
+
+    // Calculate view matrix from camera look at (and transpose it)
+    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+
+    // Convert world position vector to quaternion
+    Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
+
+    // Transform world position to view
+    worldPos = QuaternionTransform(worldPos, matView);
+
+    // Transform result to projection (clip space position)
+    worldPos = QuaternionTransform(worldPos, matProj);
+
+    // Calculate normalized device coordinates (inverted y)
+    Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
+
+    // Calculate 2d screen position vector
+    Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)width, (ndcPos.y + 1.0f)/2.0f*(float)height };
+
+    return screenPosition;
+}
+
+// Get screen space position for a 2d camera world space position
+Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
+{
+    Matrix matCamera = GetCameraMatrix2D(camera);
+    Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera);
+
+    return (Vector2){ transform.x, transform.y };
+}
+
+// Get world space position for a 2d camera screen space position
+Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
+{
+    Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
+    Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera);
+
+    return (Vector2){ transform.x, transform.y };
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Timing
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//double GetTime(void)
+
+// Set target FPS (maximum)
+void SetTargetFPS(int fps)
+{
+    if (fps < 1) CORE.Time.target = 0.0;
+    else CORE.Time.target = 1.0/(double)fps;
+
+    TRACELOG(LOG_INFO, "TIMER: Target time per frame: %02.03f milliseconds", (float)CORE.Time.target*1000.0f);
+}
+
+// Get current FPS
+// NOTE: Calculating an average framerate
+int GetFPS(void)
+{
+    int fps = 0;
+
+#if !SUPPORT_CUSTOM_FRAME_CONTROL
+    #define FPS_CAPTURE_FRAMES_COUNT    30      // 30 captures
+    #define FPS_AVERAGE_TIME_SECONDS   0.5f     // 500 milliseconds
+    #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT)
+
+    static int index = 0;
+    static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 };
+    static float average = 0, last = 0;
+    float fpsFrame = GetFrameTime();
+
+    // If reseting the window, reset the FPS info
+    if (CORE.Time.frameCounter == 0)
+    {
+        average = 0;
+        last = 0;
+        index = 0;
+
+        for (int i = 0; i < FPS_CAPTURE_FRAMES_COUNT; i++) history[i] = 0;
+    }
+
+    if (fpsFrame != 0)
+    {
+        if ((GetTime() - last) > FPS_STEP)
+        {
+            last = (float)GetTime();
+            index = (index + 1)%FPS_CAPTURE_FRAMES_COUNT;
+            average -= history[index];
+            history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
+            average += history[index];
+        }
+
+        fps = (int)roundf(1.0f/average);
+    }
+    else fps = 0;
+#endif
+
+    return fps;
+}
+
+// Get time in seconds for last frame drawn (delta time)
+float GetFrameTime(void)
+{
+    return (float)CORE.Time.frame;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Custom frame control
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//void SwapScreenBuffer(void);
+//void PollInputEvents(void);
+
+// Wait for some time (stop program execution)
+// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
+// take longer than expected... for that reason a busy wait loop is used
+// REF: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
+// REF: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
+void WaitTime(double seconds)
+{
+    if (seconds < 0) return;    // Security check
+
+#if SUPPORT_BUSY_WAIT_LOOP || SUPPORT_PARTIALBUSY_WAIT_LOOP
+    double destinationTime = GetTime() + seconds;
+#endif
+
+#if SUPPORT_BUSY_WAIT_LOOP
+    while (GetTime() < destinationTime) { }
+#else
+    #if SUPPORT_PARTIALBUSY_WAIT_LOOP
+        double sleepSeconds = seconds - seconds*0.05;  // NOTE: Reserve a percentage of the time for busy waiting
+    #else
+        double sleepSeconds = seconds;
+    #endif
+
+    // System halt functions
+    #if defined(_WIN32)
+        Sleep((unsigned long)(sleepSeconds*1000.0));
+    #endif
+    #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
+        struct timespec req = { 0 };
+        time_t sec = sleepSeconds;
+        long nsec = (sleepSeconds - sec)*1000000000L;
+        req.tv_sec = sec;
+        req.tv_nsec = nsec;
+
+        // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated
+        while (nanosleep(&req, &req) == -1) continue;
+    #endif
+    #if defined(__APPLE__)
+        usleep(sleepSeconds*1000000.0);
+    #endif
+
+    #if SUPPORT_PARTIALBUSY_WAIT_LOOP
+        while (GetTime() < destinationTime) { }
+    #endif
+#endif
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Misc
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//void OpenURL(const char *url)
+
+// Set the seed for the random number generator
+void SetRandomSeed(unsigned int seed)
+{
+#if SUPPORT_RPRAND_GENERATOR
+    rprand_set_seed(seed);
+#else
+    srand(seed);
+#endif
+}
+
+// Get a random value between min and max included
+int GetRandomValue(int min, int max)
+{
+    int value = 0;
+
+    if (min > max)
+    {
+        int tmp = max;
+        max = min;
+        min = tmp;
+    }
+
+#if SUPPORT_RPRAND_GENERATOR
+    value = rprand_get_value(min, max);
+#else
+    // WARNING: Ranges higher than RAND_MAX will return invalid results
+    // More specifically, if (max - min) > INT_MAX there will be an overflow,
+    // and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold
+    // NOTE: Depending on the library it can be as low as 32767
+    if ((unsigned int)(max - min) > (unsigned int)RAND_MAX)
+    {
+        TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX);
+    }
+
+    // NOTE: This one-line approach produces a non-uniform distribution,
+    // as stated by Donald Knuth in the book The Art of Programming, so
+    // using below approach for more uniform results
+    //value = (rand()%(abs(max - min) + 1) + min);
+
+    // More uniform range solution
+    int range = (max - min) + 1;
+
+    // Degenerate/overflow case: fall back to min (same behavior as "always min" instead of UB)
+    if (range <= 0) value = min;
+    else
+    {
+        // Rejection sampling to get a uniform integer in [min, max]
+        unsigned long c = (unsigned long)RAND_MAX + 1UL; // Number of possible results
+        unsigned long m = (unsigned long)range;          // Size of the target interval
+        unsigned long t = c - (c%m);                     // Largest multiple of m <= c
+        unsigned long r = 0;
+
+        for (;;)
+        {
+            r = (unsigned long)rand();
+            if (r < t) break;   // Only accept values within the fair region
+        }
+
+        value = min + (int)(r%m);
+    }
+#endif
+
+    return value;
+}
+
+// Load random values sequence, no values repeated, min and max included
+int *LoadRandomSequence(unsigned int count, int min, int max)
+{
+    int *values = NULL;
+
+#if SUPPORT_RPRAND_GENERATOR
+    values = rprand_load_sequence(count, min, max);
+#else
+    if (count > ((unsigned int)abs(max - min) + 1)) return values;  // Security check
+
+    values = (int *)RL_CALLOC(count, sizeof(int));
+
+    int value = 0;
+    bool dupValue = false;
+
+    for (int i = 0; i < (int)count;)
+    {
+        value = GetRandomValue(min, max);
+        dupValue = false;
+
+        for (int j = 0; j < i; j++)
+        {
+            if (values[j] == value)
+            {
+                dupValue = true;
+                break;
+            }
+        }
+
+        if (!dupValue)
+        {
+            values[i] = value;
+            i++;
+        }
+    }
+#endif
+
+    return values;
+}
+
+// Unload random values sequence
+void UnloadRandomSequence(int *sequence)
+{
+#if SUPPORT_RPRAND_GENERATOR
+    rprand_unload_sequence(sequence);
+#else
+    RL_FREE(sequence);
+#endif
+}
+
+// Takes a screenshot of current screen
+void TakeScreenshot(const char *fileName)
+{
+#if SUPPORT_MODULE_RTEXTURES
+    // Security check to (partially) avoid malicious code
+    if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; }
+
+    // Apply content scaling if required
+    Vector2 scale = { 1.0f, 1.0f };
+    if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
+
+    unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
+    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 };
+    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);
+
+    if (FileExists(path)) TRACELOG(LOG_INFO, "SYSTEM: [%s] Screenshot taken successfully", path);
+    else TRACELOG(LOG_WARNING, "SYSTEM: [%s] Screenshot could not be saved", path);
+#else
+    TRACELOG(LOG_WARNING,"IMAGE: ExportImage() requires module: rtextures");
+#endif
+}
+
+// Set up window configuration flags (view FLAGS)
+// NOTE: This function is expected to be called before window creation,
+// because it sets up some flags for the window creation process
+// To configure window states after creation, use SetWindowState()
+void SetConfigFlags(unsigned int flags)
+{
+    if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead");
+
+    // Selected flags are set but not evaluated at this point,
+    // flag evaluation happens at InitWindow() or SetWindowState()
+    FLAG_SET(CORE.Window.flags, flags);
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Logging system
+//----------------------------------------------------------------------------------
+// Set the current threshold (minimum) log level
+void SetTraceLogLevel(int logType) { logTypeLevel = logType; }
+
+// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
+void TraceLog(int logType, const char *text, ...)
+{
+#if SUPPORT_TRACELOG
+    // Message has level below current threshold, don't emit
+    if ((logType < logTypeLevel) || (text == NULL)) return;
+
+    va_list args;
+    va_start(args, text);
+
+    if (traceLog)
+    {
+        traceLog(logType, text, args);
+        va_end(args);
+        return;
+    }
+
+#if defined(PLATFORM_ANDROID)
+    switch (logType)
+    {
+        case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break;
+        case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break;
+        case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break;
+        case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break;
+        case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break;
+        case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break;
+        default: break;
+    }
+#else
+    char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
+
+    switch (logType)
+    {
+        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;
+    }
+
+    unsigned int textLength = (unsigned int)strlen(text);
+    memcpy(buffer + strlen(buffer), text, (textLength < (MAX_TRACELOG_MSG_LENGTH - 12))? textLength : (MAX_TRACELOG_MSG_LENGTH - 12));
+    strcat(buffer, "\n");
+    vprintf(buffer, args);
+    fflush(stdout);
+#endif
+
+    va_end(args);
+
+    if (logType == LOG_FATAL) exit(EXIT_FAILURE);  // If fatal logging, exit program
+#endif
+}
+
+// Set custom trace log
+void SetTraceLogCallback(TraceLogCallback callback)
+{
+    traceLog = callback;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Memory management
+//----------------------------------------------------------------------------------
+// Internal memory allocator
+// NOTE: Initializes to zero by default
+void *MemAlloc(unsigned int size)
+{
+    void *ptr = RL_CALLOC(size, 1);
+    return ptr;
+}
+
+// Internal memory reallocator
+void *MemRealloc(void *ptr, unsigned int size)
+{
+    void *ret = RL_REALLOC(ptr, size);
+    return ret;
+}
+
+// Internal memory free
+void MemFree(void *ptr)
+{
+    RL_FREE(ptr);
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: File System management
+//----------------------------------------------------------------------------------
+// Load data from file into a buffer
+unsigned char *LoadFileData(const char *fileName, int *dataSize)
+{
+    unsigned char *data = NULL;
+    *dataSize = 0;
+
+    if (fileName != NULL)
+    {
+        if (loadFileData) return loadFileData(fileName, dataSize);
+
+        FILE *file = fopen(fileName, "rb");
+
+        if (file != NULL)
+        {
+            // WARNING: On binary streams SEEK_END could not be found,
+            // using fseek() and ftell() could not work in some (rare) cases
+            fseek(file, 0, SEEK_END);
+            int size = ftell(file);     // WARNING: ftell() returns 'long int', maximum size returned is INT_MAX (2147483647 bytes)
+            fseek(file, 0, SEEK_SET);
+
+            if (size > 0)
+            {
+                data = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char));
+
+                if (data != NULL)
+                {
+                    // NOTE: fread() returns number of read elements instead of bytes, so reading [1 byte, size elements]
+                    size_t count = fread(data, sizeof(unsigned char), size, file);
+
+                    // WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
+                    // dataSize is unified along raylib as a 'int' type, so, for file-sizes >INT_MAX (2147483647 bytes) there is a limitation
+                    if (count > 2147483647)
+                    {
+                        TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName);
+
+                        RL_FREE(data);
+                        data = NULL;
+                    }
+                    else
+                    {
+                        *dataSize = (int)count;
+
+                        if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, *dataSize, size);
+                        else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
+                    }
+                }
+                else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
+            }
+            else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
+
+            fclose(file);
+        }
+        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+    return data;
+}
+
+// Unload file data allocated by LoadFileData()
+void UnloadFileData(unsigned char *data)
+{
+    RL_FREE(data);
+}
+
+// Save data to file from buffer
+bool SaveFileData(const char *fileName, const void *data, int dataSize)
+{
+    bool result = false;
+
+    if (fileName != NULL)
+    {
+        if (saveFileData) return saveFileData(fileName, data, dataSize);
+
+        FILE *file = fopen(fileName, "wb");
+
+        if (file != NULL)
+        {
+            // WARNING: fwrite() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
+            // and expects a size_t input value but as dataSize is limited to INT_MAX (2147483647 bytes), there shouldn't be a problem
+            int count = (int)fwrite(data, sizeof(unsigned char), dataSize, file);
+
+            if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
+            else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
+            else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
+
+            int closed = fclose(file);
+            if (closed == 0) result = true;
+        }
+        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+    return result;
+}
+
+// Export data to code (.h), returns true on success
+bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName)
+{
+    bool result = false;
+
+#ifndef TEXT_BYTES_PER_LINE
+    #define TEXT_BYTES_PER_LINE     20
+#endif
+
+    // NOTE: Text data buffer size is estimated considering raw data size in bytes
+    // and requiring 6 char bytes for every byte: "0x00, "
+    char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
+
+    int byteCount = 0;
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes                  //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
+    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2026 Ramon Santamaria (@raysan5)                                //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
+
+    // Get file name from path
+    char varFileName[256] = { 0 };
+    snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName));
+    for (int i = 0; varFileName[i] != '\0'; i++)
+    {
+        // Convert variable name to uppercase
+        if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
+        // Replace non valid character for C identifier with '_'
+        else if (varFileName[i] == '.' || varFileName[i] == '-' || varFileName[i] == '?' || varFileName[i] == '!' || varFileName[i] == '+') { varFileName[i] = '_'; }
+    }
+
+    byteCount += sprintf(txtData + byteCount, "#define %s_DATA_SIZE     %i\n\n", varFileName, dataSize);
+
+    byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%s_DATA_SIZE] = { ", varFileName, varFileName);
+    for (int i = 0; i < (dataSize - 1); i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]);
+    byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]);
+
+    // NOTE: Text data size exported is determined by '\0' (NULL) character
+    result = SaveFileText(fileName, txtData);
+
+    RL_FREE(txtData);
+
+    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
+    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
+
+    return result;
+}
+
+// Load text data from file, returns a '\0' terminated string
+// NOTE: text chars array should be freed manually
+char *LoadFileText(const char *fileName)
+{
+    char *text = NULL;
+
+    if (fileName != NULL)
+    {
+        if (loadFileText) return loadFileText(fileName);
+
+        FILE *file = fopen(fileName, "rt");
+
+        if (file != NULL)
+        {
+            // WARNING: When reading a file as 'text' file,
+            // text mode causes carriage return-linefeed translation...
+            // ...but using fseek() should return correct byte-offset
+            fseek(file, 0, SEEK_END);
+            unsigned int size = (unsigned int)ftell(file);
+            fseek(file, 0, SEEK_SET);
+
+            if (size > 0)
+            {
+                text = (char *)RL_CALLOC(size + 1, sizeof(char));
+
+                if (text != NULL)
+                {
+                    unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
+
+                    // WARNING: \r\n is converted to \n on reading, so,
+                    // read bytes count gets reduced by the number of lines
+                    if (count < size) text = (char *)RL_REALLOC(text, count + 1);
+
+                    // Zero-terminate the string
+                    text[count] = '\0';
+
+                    TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName);
+                }
+                else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
+            }
+            else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName);
+
+            fclose(file);
+        }
+        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+    return text;
+}
+
+// Unload file text data allocated by LoadFileText()
+void UnloadFileText(char *text)
+{
+    RL_FREE(text);
+}
+
+// Save text data to file (write), string must be '\0' terminated
+bool SaveFileText(const char *fileName, const char *text)
+{
+    bool result = false;
+
+    if (fileName != NULL)
+    {
+        if (saveFileText) return saveFileText(fileName, text);
+
+        FILE *file = fopen(fileName, "wt");
+
+        if (file != NULL)
+        {
+            int count = fprintf(file, "%s", text);
+
+            if (count < 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
+            else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
+
+            int closed = fclose(file);
+            if (closed == 0) result = true;
+        }
+        else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+    return result;
+}
+
+// File access custom callbacks
+// WARNING: Callbacks setup is intended for advanced users
+
+// Set custom file binary data loader
+void SetLoadFileDataCallback(LoadFileDataCallback callback)
+{
+    loadFileData = callback;
+}
+
+// Set custom file binary data saver
+void SetSaveFileDataCallback(SaveFileDataCallback callback)
+{
+    saveFileData = callback;
+}
+
+// Set custom file text data loader
+void SetLoadFileTextCallback(LoadFileTextCallback callback)
+{
+    loadFileText = callback;
+}
+
+// Set custom file text data saver
+void SetSaveFileTextCallback(SaveFileTextCallback callback)
+{
+    saveFileText = callback;
+}
+
+// Rename file (if exists)
+// NOTE: Only rename file name required, not full path
+int FileRename(const char *fileName, const char *fileRename)
+{
+    int result = -1;
+
+    if (FileExists(fileName))
+    {
+        result = rename(fileName, fileRename);
+    }
+
+    return result;
+}
+
+// Remove file (if exists)
+int FileRemove(const char *fileName)
+{
+    int result = -1;
+
+    if (FileExists(fileName))
+    {
+        result = remove(fileName);
+    }
+
+    return result;
+}
+
+// Copy file from one path to another
+// NOTE: If destination path does not exist, it is created!
+int FileCopy(const char *srcPath, const char *dstPath)
+{
+    int result = -1;
+    int srcDataSize = 0;
+    unsigned char *srcFileData = LoadFileData(srcPath, &srcDataSize);
+
+    // Create required paths if they do not exist
+    if (DirectoryExists(GetDirectoryPath(dstPath))) result = 0; // Already exists
+    else result = MakeDirectory(GetDirectoryPath(dstPath));
+
+    if (result == 0) // Directory created successfully or already exists
+    {
+        if ((srcFileData != NULL) && (srcDataSize > 0))
+        {
+            bool saved = SaveFileData(dstPath, srcFileData, srcDataSize);
+            if (saved) result = 0;
+        }
+    }
+
+    UnloadFileData(srcFileData);
+
+    return result;
+}
+
+// Move file from one directory to another
+// NOTE: If dst directories do not exists they are created
+int FileMove(const char *srcPath, const char *dstPath)
+{
+    int result = -1;
+
+    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)))
+            {
+                result = FileRemove(srcPath);
+                if (result != 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to remove source file after copy", srcPath);
+            }
+            else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to copy file to [%s]", srcPath, dstPath);
+        }
+    }
+	else TRACELOG(LOG_WARNING, "FILEIO: [%s] Source file does not exist", srcPath);
+
+    return result;
+}
+
+// Replace text in an existing file
+// WARNING: DEPENDENCY: [rtext] module
+int FileTextReplace(const char *fileName, const char *search, const char *replacement)
+{
+    int result = -1;
+
+#if SUPPORT_MODULE_RTEXT
+    char *fileText = NULL;
+    char *fileTextUpdated = { 0 };
+
+    if (FileExists(fileName))
+    {
+        fileText = LoadFileText(fileName);
+        fileTextUpdated = TextReplaceAlloc(fileText, search, replacement);
+        bool saved = SaveFileText(fileName, fileTextUpdated);
+        if (saved) result = 0;
+        MemFree(fileTextUpdated);
+        UnloadFileText(fileText);
+    }
+#else
+    TRACELOG(LOG_WARNING, "FILE: File text replace requires [rtext] module");
+#endif
+
+    return result;
+}
+
+// Find text index position in existing file
+// WARNING: DEPENDENCY: [rtext] module
+int FileTextFindIndex(const char *fileName, const char *search)
+{
+    int result = -1;
+
+    if (FileExists(fileName))
+    {
+        char *fileText = LoadFileText(fileName);
+        char *ptr = strstr(fileText, search);
+        if (ptr != NULL) result = (int)(ptr - fileText);
+        UnloadFileText(fileText);
+    }
+
+    return result;
+}
+
+// Check if the file exists
+bool FileExists(const char *fileName)
+{
+    bool result = false;
+
+    if ((fileName != NULL) && (ACCESS(fileName) != -1)) result = true;
+
+    // NOTE: Alternatively, stat() can be used instead of access()
+    //#include <sys/stat.h>
+    //struct stat statbuf;
+    //if (stat(filename, &statbuf) == 0) result = true;
+
+    return result;
+}
+
+// Check file extension
+bool IsFileExtension(const char *fileName, const char *ext)
+{
+    #define MAX_FILE_EXTENSIONS  32
+
+    bool result = false;
+    const char *fileExt = GetFileExtension(fileName);
+
+    // WARNING: fileExt points to last '.' on fileName string but it could happen
+    // that fileName is not correct: "myfile.png more text following\n"
+
+    if (fileExt != NULL)
+    {
+        int fileExtLength = (int)strlen(fileExt);
+        char fileExtLower[16] = { 0 };
+        for (int i = 0; (i < fileExtLength) && (i < 15); i++)
+        {
+            // Copy and convert to lower-case
+            if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] =  fileExt[i] + 32;
+            else fileExtLower[i] =  fileExt[i];
+        }
+
+        int extCount = 1;
+        int extLength = (int)strlen(ext);
+        char *extList = (char *)RL_CALLOC(extLength + 1, 1);
+        char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
+        memcpy(extList, ext, extLength);
+        extListPtrs[0] = extList;
+
+        for (int i = 0; i < extLength; i++)
+        {
+            // Convert to lower-case if extension is upper-case
+            if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32;
+
+            // Get pointer to next extension and add null-terminator
+            if (extList[i] == ';')
+            {
+                extList[i] = '\0';
+
+                if (extCount < MAX_FILE_EXTENSIONS)
+                {
+                    extListPtrs[extCount] = extList + i + 1;
+                    extCount++;
+                }
+            }
+        }
+
+        for (int i = 0; i < extCount; i++)
+        {
+            // Consider the case where extension provided
+            // does not start with the '.'
+            char *fileExtLowerPtr = fileExtLower;
+            if (extListPtrs[i][0] != '.') fileExtLowerPtr++;
+
+            if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0)
+            {
+                result = true;
+                break;
+            }
+        }
+
+        RL_FREE(extList);
+    }
+
+    return result;
+}
+
+// Check if file path (file or directory) is hidden by OS
+bool IsFileHidden(const char *filePath)
+{
+    bool result = false;
+#if defined(_WIN32)
+    unsigned long attribs = GetFileAttributesA(filePath);
+
+    // Check !INVALID_FILE_ATTRIBUTES and FILE_ATTRIBUTE_HIDDEN
+    if ((attribs != -1) && ((attribs & 0x2UL) != 0)) result = true;
+#else
+    const char *basePath = strrchr(filePath, '/');
+    basePath = (basePath? basePath + 1 : filePath);
+
+    if ((basePath[0] == '.') && (strcmp(basePath, ".") != 0) && (strcmp(basePath, "..") != 0)) result = true;
+#endif
+    return result;
+}
+
+// Check if directory path exists
+bool DirectoryExists(const char *dirPath)
+{
+    bool result = false;
+    DIR *dir = opendir(dirPath);
+
+    if (dir != NULL)
+    {
+        result = true;
+        closedir(dir);
+    }
+
+    return result;
+}
+
+// Get file length in bytes
+// NOTE: GetFileSize() conflicts with windows.h
+int GetFileLength(const char *fileName)
+{
+    int size = 0;
+
+    // NOTE: On Unix-like systems, it can by used the POSIX system call: stat(),
+    // but depending on the platform that call could not be available
+    //struct stat result = { 0 };
+    //stat(fileName, &result);
+    //return result.st_size;
+
+    FILE *file = fopen(fileName, "rb");
+
+    if (file != NULL)
+    {
+        fseek(file, 0L, SEEK_END);
+        long int fileSize = ftell(file);
+
+        // Check for size overflow (INT_MAX)
+        if (fileSize > 2147483647) TRACELOG(LOG_WARNING, "[%s] File size overflows expected limit, do not use GetFileLength()", fileName);
+        else size = (int)fileSize;
+
+        fclose(file);
+    }
+
+    return size;
+}
+
+// Get file modification time (last write time)
+long GetFileModTime(const char *fileName)
+{
+    struct stat result = { 0 };
+    long modTime = 0;
+
+    if (stat(fileName, &result) == 0)
+    {
+        time_t mod = result.st_mtime;
+        modTime = (long)mod;
+    }
+
+    return modTime;
+}
+
+// Get pointer to extension for a filename string (includes the dot: .png)
+// WARNING: Getting the pointer to the input string extension position (not a string copy)
+const char *GetFileExtension(const char *fileName)
+{
+    const char *dot = strrchr(fileName, '.');
+
+    if (!dot || (dot == fileName)) return NULL;
+
+    return dot;
+}
+
+// String pointer reverse break: returns right-most occurrence of charset in s
+static const char *strprbrk(const char *text, const char *charset)
+{
+    const char *latestMatch = NULL;
+
+    for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
+
+    return latestMatch;
+}
+
+// Get pointer to filename for a path string
+const char *GetFileName(const char *filePath)
+{
+    const char *fileName = NULL;
+
+    if (filePath != NULL) fileName = strprbrk(filePath, "\\/");
+
+    if (fileName == NULL) return filePath;
+
+    return fileName + 1;
+}
+
+// Get filename string without extension (uses static string)
+const char *GetFileNameWithoutExt(const char *filePath)
+{
+    #define MAX_FILENAME_LENGTH     256
+
+    static char fileName[MAX_FILENAME_LENGTH] = { 0 };
+    memset(fileName, 0, MAX_FILENAME_LENGTH);
+
+    if (filePath != NULL)
+    {
+        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 '.'
+        {
+            if (fileName[i] == '.')
+            {
+                // NOTE: Break on first '.' found
+                fileName[i] = '\0';
+                break;
+            }
+        }
+    }
+
+    return fileName;
+}
+
+// Get directory for a provided filePath
+const char *GetDirectoryPath(const char *filePath)
+{
+    /*
+    // NOTE: Directory separator is different in Windows and other platforms,
+    // fortunately, Windows also support the '/' separator, that's the one should be used
+    #if defined(_WIN32)
+        char separator = '\\';
+    #else
+        char separator = '/';
+    #endif
+    */
+    const char *lastSlash = NULL;
+    static char dirPath[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(dirPath, 0, MAX_FILEPATH_LENGTH);
+
+    // In case provided path does not contain a root drive letter (C:\, D:\)
+    // nor leading path separator (\, /), add the current directory path to dirPath
+    if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))
+    {
+        // For security, set starting path to current directory,
+        // obtained path will be concatenated to this
+        dirPath[0] = '.';
+        dirPath[1] = '/';
+    }
+
+    lastSlash = strprbrk(filePath, "\\/");
+    if (lastSlash)
+    {
+        if (lastSlash == filePath)
+        {
+            // The last and only slash is the leading one: path is in a root directory
+            dirPath[0] = filePath[0];
+            dirPath[1] = '\0';
+        }
+        else
+        {
+            char *dirPathPtr = dirPath;
+            if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) dirPathPtr += 2;     // Skip drive letter, "C:"
+            memcpy(dirPathPtr, filePath, strlen(filePath) - (strlen(lastSlash) - 1));
+            dirPath[strlen(filePath) - strlen(lastSlash) + (((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/'))? 2 : 0)] = '\0';  // Add '\0' manually
+        }
+    }
+
+    return dirPath;
+}
+
+// Get previous directory path for a provided path
+const char *GetPrevDirectoryPath(const char *dirPath)
+{
+    static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
+
+    const int lastIndex = (int)strlen(dirPath) - 1;
+    bool isFile = IsPathFile(dirPath);
+    for (int i = lastIndex; i >= 0; i--)
+    {
+        // If the character is a path separator.
+        if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
+        {
+            // If this character is a leading '/' (e.g. the '/' in "/usr") or
+            // part of a drive root (e.g. "C:\"), include it with the result.
+            if ((i == 0) || ((i == 2) && (dirPath[1] == ':'))) i += 1;
+            // If this character is a trailing path separator (e.g. the last
+            // '/' in "/usr/bin/" or the last '\' in "C:\raylib\"), continue.
+            else if (i == lastIndex) continue;
+
+            if (!isFile)
+            {
+                memcpy(prevDirPath, dirPath, i);
+                break;
+            }
+            else isFile = false;
+        }
+    }
+
+    return prevDirPath;
+}
+
+// Get current working directory
+const char *GetWorkingDirectory(void)
+{
+    static char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(currentDir, 0, MAX_FILEPATH_LENGTH);
+
+    char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH);
+
+    return path;
+}
+
+const char *GetApplicationDirectory(void)
+{
+    static char appDir[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(appDir, 0, MAX_FILEPATH_LENGTH);
+
+#if defined(_WIN32)
+    int len = 0;
+
+    #if defined(UNICODE)
+    unsigned short widePath[MAX_PATH];
+    len = GetModuleFileNameW(NULL, (wchar_t *)widePath, MAX_PATH);
+    len = WideCharToMultiByte(0, 0, (wchar_t *)widePath, len, appDir, MAX_PATH, NULL, NULL);
+    #else
+    len = GetModuleFileNameA(NULL, appDir, MAX_PATH);
+    #endif
+
+    if (len > 0)
+    {
+        for (int i = len; i >= 0; i--)
+        {
+            if (appDir[i] == '\\')
+            {
+                appDir[i + 1] = '\0';
+                break;
+            }
+        }
+    }
+    else
+    {
+        appDir[0] = '.';
+        appDir[1] = '\\';
+    }
+
+#elif defined(__linux__)
+
+    unsigned int size = sizeof(appDir);
+    ssize_t len = readlink("/proc/self/exe", appDir, size);
+
+    if (len > 0)
+    {
+        for (int i = len; i >= 0; i--)
+        {
+            if (appDir[i] == '/')
+            {
+                appDir[i + 1] = '\0';
+                break;
+            }
+        }
+    }
+    else
+    {
+        appDir[0] = '.';
+        appDir[1] = '/';
+    }
+
+#elif defined(__APPLE__)
+
+    uint32_t size = sizeof(appDir);
+
+    if (_NSGetExecutablePath(appDir, &size) == 0)
+    {
+        int appDirLength = (int)strlen(appDir);
+        for (int i = appDirLength; i >= 0; i--)
+        {
+            if (appDir[i] == '/')
+            {
+                appDir[i + 1] = '\0';
+                break;
+            }
+        }
+    }
+    else
+    {
+        appDir[0] = '.';
+        appDir[1] = '/';
+    }
+
+#elif defined(__FreeBSD__)
+
+    size_t size = sizeof(appDir);
+    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+
+    if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0)
+    {
+        int appDirLength = (int)strlen(appDir);
+        for (int i = appDirLength; i >= 0; i--)
+        {
+            if (appDir[i] == '/')
+            {
+                appDir[i + 1] = '\0';
+                break;
+            }
+        }
+    }
+    else
+    {
+        appDir[0] = '.';
+        appDir[1] = '/';
+    }
+
+#elif defined(__wasm__)
+
+    appDir[0] = '/';
+#endif
+
+    return appDir;
+}
+
+// Load directory filepaths
+// NOTE: Base path is prepended to the scanned filepaths
+// WARNING: Directory is scanned twice, first time to get paths count
+// Scanneed files and directories, no recursive/subdirs scanning
+FilePathList LoadDirectoryFiles(const char *dirPath)
+{
+    return LoadDirectoryFilesEx(dirPath, FILE_FILTER_TAG_ALL, false);
+}
+
+// Load directory filepaths with extension filtering and recursive directory scan
+// Use "*.*" to include all files and directories on scan
+// Use "FILES*" to include only files on scan
+// Use "DIRS*" to include only directories on scan
+// WARNING: Directory is scanned twice, first time to get paths count
+FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs)
+{
+    FilePathList files = { 0 };
+
+    if (DirectoryExists(basePath)) // It's a directory
+    {
+        if ((filter != NULL) && (filter[0] == '\0')) filter = NULL;
+
+        // SCAN 1: Count files
+        unsigned int fileCounter = GetDirectoryFileCountEx(basePath, filter, scanSubdirs);
+
+        // Memory allocation for dirFileCount
+        files.paths = (char **)RL_CALLOC(fileCounter, sizeof(char *));
+        for (unsigned int i = 0; i < fileCounter; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+
+        // SCAN 2: Read filepaths
+        // WARNING: basePath is always prepended to scanned paths
+        ScanDirectoryFiles(basePath, &files, filter, fileCounter, scanSubdirs);
+
+        // Security check: read files.count should match fileCounter
+        if (files.count != fileCounter)
+        {
+            TRACELOG(LOG_WARNING, "FILEIO: Read files count (%u) does not match capacity allocated (%u)", files.count, fileCounter);
+            files.count = fileCounter; // Avoid memory leak when unloading this FilePathList
+        }
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);  // Maybe it's a file...
+
+    return files;
+}
+
+// Unload directory filepaths
+// WARNING: files.count is not reseted to 0 after unloading
+void UnloadDirectoryFiles(FilePathList files)
+{
+    if (files.paths != NULL)
+    {
+        for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]);
+
+        RL_FREE(files.paths);
+    }
+}
+
+// Create directories (including full path requested), returns 0 on success
+int MakeDirectory(const char *dirPath)
+{
+    if ((dirPath == NULL) || (dirPath[0] == '\0')) return -1; // Path is not valid
+    if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)
+
+    // Copy path string to avoid modifying original
+    int dirPathLength = (int)strlen(dirPath) + 1;
+    char *pathcpy = (char *)RL_CALLOC(dirPathLength, 1);
+    memcpy(pathcpy, dirPath, dirPathLength);
+
+    // Iterate over pathcpy, create each subdirectory as needed
+    for (int i = 0; (i < dirPathLength) && (pathcpy[i] != '\0'); i++)
+    {
+        if (pathcpy[i] == ':') i++;
+        else
+        {
+            if ((pathcpy[i] == '\\') || (pathcpy[i] == '/'))
+            {
+                pathcpy[i] = '\0';
+                if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
+                pathcpy[i] = '/';
+            }
+        }
+    }
+
+    // Create final directory
+    if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
+    RL_FREE(pathcpy);
+
+    // In case something failed and requested directory
+    // was not successfully created, return -1
+    if (!DirectoryExists(dirPath)) return -1;
+
+    return 0;
+}
+
+// Change working directory, returns true on success
+int ChangeDirectory(const char *dirPath)
+{
+    // NOTE: On success, CHDIR() return 0; on error, returns -1 and errno is set to indicate the error,
+    // depending on the filesystem, other errors can be returned
+    int result = CHDIR(dirPath);
+
+    if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dirPath);
+    else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dirPath);
+
+    return result;
+}
+
+// Check if provided path point to a file
+bool IsPathFile(const char *path)
+{
+    bool result = false;
+
+    struct stat info = { 0 };
+    stat(path, &info);
+
+    if (S_ISREG(info.st_mode)) result = true;
+
+    return result;
+}
+
+// Check if provided path point to a directory
+bool IsPathDirectory(const char *path)
+{
+    bool result = false;
+
+    if (!IsPathFile(path)) result = true;
+
+    return result;
+}
+
+// Check if provided path is an absolute path
+bool IsPathAbsolute(const char *path)
+{
+    int result = false;
+
+    if ((path != NULL) && (path[0] != '\0'))
+    {
+#if defined(_WIN32)
+        // Check UNC path (\\server\share)
+        if ((path[0] == '\\') && (path[1] == '\\')) 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
+        // Check POSIX path, 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)
+{
+    bool valid = true;
+
+    if ((fileName != NULL) && (fileName[0] != '\0'))
+    {
+        int fileNameLength = (int)strlen(fileName);
+        bool allPeriods = true;
+
+        for (int i = 0; i < fileNameLength; i++)
+        {
+            // Check invalid characters
+            if ((fileName[i] == '<') ||
+                (fileName[i] == '>') ||
+                (fileName[i] == ':') ||
+                (fileName[i] == '\"') ||
+                (fileName[i] == '/') ||
+                (fileName[i] == '\\') ||
+                (fileName[i] == '|') ||
+                (fileName[i] == '?') ||
+                (fileName[i] == '*')) { valid = false; break; }
+
+            // Check non-glyph characters
+            if ((unsigned char)fileName[i] < 32) { valid = false; break; }
+
+            // Check if filename is not all periods
+            if (fileName[i] != '.') allPeriods = false;
+        }
+
+        if (allPeriods) valid = false;
+
+/*
+        if (valid)
+        {
+            // Check invalid DOS names
+            if (fileNameLength >= 3)
+            {
+                if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'N')) ||   // CON
+                    ((fileName[0] == 'P') && (fileName[1] == 'R') && (fileName[2] == 'N')) ||   // PRN
+                    ((fileName[0] == 'A') && (fileName[1] == 'U') && (fileName[2] == 'X')) ||   // AUX
+                    ((fileName[0] == 'N') && (fileName[1] == 'U') && (fileName[2] == 'L'))) valid = false; // NUL
+            }
+
+            if (fileNameLength >= 4)
+            {
+                if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'M') && ((fileName[3] >= '0') && (fileName[3] <= '9'))) ||  // COM0-9
+                    ((fileName[0] == 'L') && (fileName[1] == 'P') && (fileName[2] == 'T') && ((fileName[3] >= '0') && (fileName[3] <= '9')))) valid = false; // LPT0-9
+            }
+        }
+*/
+    }
+
+    return valid;
+}
+
+// Check if file has been dropped into window
+bool IsFileDropped(void)
+{
+    bool result = false;
+
+    if (CORE.Window.dropFileCount > 0) result = true;
+
+    return result;
+}
+
+// Load dropped filepaths
+FilePathList LoadDroppedFiles(void)
+{
+    FilePathList files = { 0 };
+
+    files.count = CORE.Window.dropFileCount;
+    files.paths = CORE.Window.dropFilepaths;
+
+    return files;
+}
+
+// Unload dropped filepaths
+void UnloadDroppedFiles(FilePathList files)
+{
+    // WARNING: files pointers are the same as internal ones
+
+    if (files.count > 0)
+    {
+        for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]);
+
+        RL_FREE(files.paths);
+
+        CORE.Window.dropFileCount = 0;
+        CORE.Window.dropFilepaths = NULL;
+    }
+}
+
+// Get the file count in a directory
+unsigned int GetDirectoryFileCount(const char *dirPath)
+{
+    return GetDirectoryFileCountEx(dirPath, FILE_FILTER_TAG_ALL, false);
+}
+
+// Get the file count in a directory with extension filtering and recursive directory scan. Use 'FILE_FILTER_TAG_DIR_ONLY' in the filter string to include directories in the result
+unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs)
+{
+    unsigned int fileCounter = 0;
+
+    // WARNING: Path can not be static or it will be reused between recursive function calls!
+    char path[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(path, 0, MAX_FILEPATH_LENGTH);
+
+    struct dirent *entity;
+    DIR *dir = opendir(basePath);
+
+    if (dir != NULL) // It's a directory
+    {
+        while ((entity = readdir(dir)) != NULL)
+        {
+            // NOTE: Skipping '.' (current dir) and '..' (parent dir) filepaths
+            if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0))
+            {
+                // Construct new path from our base path
+                #if defined(_WIN32)
+                    int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s\\%s", basePath, entity->d_name);
+                #else
+                    int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s/%s", basePath, entity->d_name);
+                #endif
+                // Don't add to count if path too long
+                if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
+                {
+                    TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
+                }
+                else if (IsPathFile(path))
+                {
+                    if ((filter == NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL) ||
+                        (strstr(filter, FILE_FILTER_TAG_FILE_ONLY) != NULL) || IsFileExtension(path, filter)) fileCounter++;
+                }
+                else
+                {
+                    if ((filter != NULL) && ((strstr(filter, FILE_FILTER_TAG_ALL) != NULL) || (strstr(filter, FILE_FILTER_TAG_DIR_ONLY) != NULL))) fileCounter++;
+                    if (scanSubdirs) fileCounter += GetDirectoryFileCountEx(path, filter, scanSubdirs);
+                }
+            }
+        }
+        closedir(dir);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);  // Maybe it's a file...
+    return fileCounter;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Compression and Encoding
+//----------------------------------------------------------------------------------
+
+// Compress data (DEFLATE algorithm)
+unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize)
+{
+    #define COMPRESSION_QUALITY_DEFLATE  8
+
+    unsigned char *compData = NULL;
+
+#if SUPPORT_COMPRESSION_API
+    // Compress data and generate a valid DEFLATE stream
+    struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl));   // WARNING: Possible stack overflow, struct sdefl is almost 1MB
+    int bounds = sdefl_bound(dataSize);
+    compData = (unsigned char *)RL_CALLOC(bounds, 1);
+
+    *compDataSize = sdeflate(sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE);   // Compression level 8, same as stbiw
+    RL_FREE(sdefl);
+
+    TRACELOG(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize);
+#endif
+
+    return compData;
+}
+
+// Decompress data (DEFLATE algorithm)
+unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize)
+{
+    unsigned char *data = NULL;
+
+#if SUPPORT_COMPRESSION_API
+    // Decompress data from a valid DEFLATE stream
+    unsigned char *data0 = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
+    int size = sinflate(data0, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
+
+    // WARNING: RL_REALLOC can make (and leave) data copies in memory,
+    // that can be a security concern in case of compression of sensitive data
+    // So, using a second buffer to copy data manually, wiping original buffer memory
+    data = (unsigned char *)RL_CALLOC(size, 1);
+    memcpy(data, data0, size);
+    memset(data0, 0, MAX_DECOMPRESSION_SIZE*1024*1024); // Wipe memory, is memset() safe?
+    RL_FREE(data0);
+
+    TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, size);
+
+    *dataSize = size;
+#endif
+
+    return data;
+}
+
+// Encode data to Base64 string
+// NOTE: Returned string includes NULL terminator, considered on outputSize
+char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
+{
+    // Base64 conversion table from RFC 4648 [0..63]
+    // NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sextets" (6bit characters)
+    static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+    // Compute expected size and padding
+    int paddedSize = dataSize;
+    while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
+    int estimatedOutputSize = 4*(paddedSize/3);
+    int padding = paddedSize - dataSize;
+
+    // Adding null terminator to string
+    estimatedOutputSize += 1;
+
+    // Load some memory to store encoded string
+    char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
+    if (encodedData == NULL) return NULL;
+
+    int outputCount = 0;
+    for (int i = 0; i < dataSize;)
+    {
+        unsigned int octetA = 0;
+        unsigned int octetB = 0;
+        unsigned int octetC = 0;
+        unsigned int octetPack = 0;
+
+        octetA = data[i]; // Generates 2 sextets
+        octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
+        octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
+
+        octetPack = (octetA << 16) | (octetB << 8) | octetC;
+
+        encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
+        encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
+        encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
+        encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
+        outputCount += 4;
+        i += 3;
+    }
+
+    // Add required padding bytes
+    for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
+
+    // Add null terminator to string
+    encodedData[outputCount] = '\0';
+    outputCount++;
+
+    if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
+
+    *outputSize = estimatedOutputSize;
+    return encodedData;
+}
+
+// Decode Base64 string (expected NULL terminated)
+unsigned char *DecodeDataBase64(const char *text, int *outputSize)
+{
+    // Base64 decode table
+    // NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
+    // every character in the corresponding ASCII position
+    static const unsigned char base64DecodeTable[256] = {
+        ['A'] =  0, ['B'] =  1, ['C'] =  2, ['D'] =  3, ['E'] =  4, ['F'] =  5, ['G'] =  6, ['H'] =  7,
+        ['I'] =  8, ['J'] =  9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
+        ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
+        ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
+        ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
+        ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
+        ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
+        ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
+    };
+
+    *outputSize = 0;
+    if (text == NULL) return NULL;
+
+    // Compute expected size and padding
+    int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
+    int ending = dataSize - 1;
+    int padding = 0;
+    while (text[ending] == '=') { padding++; ending--; }
+    int estimatedOutputSize = 3*(dataSize/4) - padding;
+    int maxOutputSize = 3*(dataSize/4);
+
+    // Load some memory to store decoded data
+    // NOTE: Allocated enough size to include padding
+    unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
+    if (decodedData == NULL) return NULL;
+
+    int outputCount = 0;
+    for (int i = 0; i < dataSize;)
+    {
+        // Every 4 sextets must generate 3 octets
+        if ((i + 2) >= dataSize)
+        {
+            TRACELOG(LOG_WARNING, "BASE64: Decoding error: Input data size is not valid");
+            break;
+        }
+
+        unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
+        unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
+        unsigned int sixtetC = (((i + 2) < dataSize) && (unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
+        unsigned int sixtetD = (((i + 3) < dataSize) && (unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
+
+        unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12)  | (sixtetC << 6) | sixtetD;
+
+        if ((outputCount + 3) > maxOutputSize)
+        {
+            TRACELOG(LOG_WARNING, "BASE64: Decoding error: Output data size is too small");
+            break;
+        }
+
+        decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
+        decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
+        decodedData[outputCount + 2] = octetPack & 0xff;
+        outputCount += 3;
+        i += 4;
+    }
+
+    if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
+
+    *outputSize = estimatedOutputSize;
+    return decodedData;
+}
+
+// Compute CRC32 hash code
+unsigned int ComputeCRC32(const unsigned char *data, int dataSize)
+{
+    static unsigned int crcTable[256] = {
+        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+        0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+        0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+        0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+        0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+        0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+        0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+        0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+        0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+        0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+        0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+        0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+        0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+        0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+        0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+    };
+
+    unsigned int crc = ~0u;
+
+    for (int i = 0; i < dataSize; i++) crc = (crc >> 8) ^ crcTable[data[i] ^ (crc & 0xff)];
+
+    return ~crc;
+}
+
+// Compute MD5 hash code
+// NOTE: Returns a static int[4] array (16 bytes)
+unsigned int *ComputeMD5(const unsigned char *data, int dataSize)
+{
+    #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+    static unsigned int hash[4] = { 0 };  // Hash to be returned
+
+    // WARNING: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
+
+    // NOTE: r specifies the per-round shift amounts
+    unsigned int r[] = {
+        7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+        5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
+        4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+        6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+    };
+
+    // Using binary integer part of the sines of integers (in radians) as constants
+    unsigned int k[] = {
+        0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+        0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+        0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+        0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+        0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+        0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+        0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+        0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+        0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+        0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+        0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+        0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+        0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+        0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+        0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+        0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+    };
+
+    hash[0] = 0x67452301;
+    hash[1] = 0xefcdab89;
+    hash[2] = 0x98badcfe;
+    hash[3] = 0x10325476;
+
+    // Pre-processing: adding a single 1 bit
+    // Append '1' bit to message
+    // NOTE: The input bytes are considered as bits strings,
+    // where the first bit is the most significant bit of the byte
+
+    // Pre-processing: padding with zeros
+    // Append '0' bit until message length in bit 448 (mod 512)
+    // Append length mod (2 pow 64) to message
+
+    int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
+
+    unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
+    memcpy(msg, data, dataSize);
+    msg[dataSize] = 128; // Write the '1' bit
+
+    unsigned int bitsLen = 8*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 += 64)  // 512/8
+    {
+        // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
+        unsigned int *w = (unsigned int *)(msg + offset);
+
+        // Initialize hash value for this chunk
+        unsigned int a = hash[0];
+        unsigned int b = hash[1];
+        unsigned int c = hash[2];
+        unsigned int d = hash[3];
+
+        for (int i = 0; i < 64; i++)
+        {
+            unsigned int f = 0;
+            unsigned int g = 0;
+
+            if (i < 16)
+            {
+                f = (b & c) | ((~b) & d);
+                g = i;
+            }
+            else if (i < 32)
+            {
+                f = (d & b) | ((~d) & c);
+                g = (5*i + 1)%16;
+            }
+            else if (i < 48)
+            {
+                f = b ^ c ^ d;
+                g = (3*i + 5)%16;
+            }
+            else
+            {
+                f = c ^ (b | (~d));
+                g = (7*i)%16;
+            }
+
+            unsigned int temp = d;
+            d = c;
+            c = b;
+            b = b + ROTATE_LEFT((a + f + k[i] + w[g]), r[i]);
+            a = temp;
+        }
+
+        // Add chunk's hash to result so far
+        hash[0] += a;
+        hash[1] += b;
+        hash[2] += c;
+        hash[3] += d;
+    }
+
+    RL_FREE(msg);
+
+    return hash;
+}
+
+// Compute SHA-1 hash code
+// NOTE: Returns a static int[5] array (20 bytes)
+unsigned int *ComputeSHA1(const unsigned char *data, int dataSize)
+{
+    #define SHA1_ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+    static unsigned int hash[5] = { 0 };  // Hash to be returned
+
+    // Initialize hash values
+    hash[0] = 0x67452301;
+    hash[1] = 0xEFCDAB89;
+    hash[2] = 0x98BADCFE;
+    hash[3] = 0x10325476;
+    hash[4] = 0xC3D2E1F0;
+
+    // Pre-processing: adding a single 1 bit
+    // Append '1' bit to message
+    // NOTE: The input bytes are considered as bits strings,
+    // where the first bit is the most significant bit of the byte
+
+    // Pre-processing: padding with zeros
+    // Append '0' bit until message length in bit 448 (mod 512)
+    // Append length mod (2 pow 64) to message
+
+    int newDataSize = ((((dataSize + 8)/64) + 1)*64);
+
+    unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
+    memcpy(msg, data, dataSize);
+    msg[dataSize] = 128; // Write the '1' bit
+
+    unsigned long long bitsLen = 8ULL*dataSize;
+    msg[newDataSize - 1] = (unsigned char)(bitsLen);
+    msg[newDataSize - 2] = (unsigned char)(bitsLen >> 8);
+    msg[newDataSize - 3] = (unsigned char)(bitsLen >> 16);
+    msg[newDataSize - 4] = (unsigned char)(bitsLen >> 24);
+    msg[newDataSize - 5] = (unsigned char)(bitsLen >> 32);
+    msg[newDataSize - 6] = (unsigned char)(bitsLen >> 40);
+    msg[newDataSize - 7] = (unsigned char)(bitsLen >> 48);
+    msg[newDataSize - 8] = (unsigned char)(bitsLen >> 56);
+
+    // Process the message in successive 512-bit chunks
+    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 };
+        for (int i = 0; i < 16; i++)
+        {
+            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:
+        for (int i = 16; i < 80; i++) w[i] = SHA1_ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
+
+        // Initialize hash value for this chunk
+        unsigned int a = hash[0];
+        unsigned int b = hash[1];
+        unsigned int c = hash[2];
+        unsigned int d = hash[3];
+        unsigned int e = hash[4];
+
+        for (int i = 0; i < 80; i++)
+        {
+            unsigned int f = 0;
+            unsigned int k = 0;
+
+            if (i < 20)
+            {
+                f = (b & c) | ((~b) & d);
+                k = 0x5A827999;
+            }
+            else if (i < 40)
+            {
+                f = b ^ c ^ d;
+                k = 0x6ED9EBA1;
+            }
+            else if (i < 60)
+            {
+                f = (b & c) | (b & d) | (c & d);
+                k = 0x8F1BBCDC;
+            }
+            else
+            {
+                f = b ^ c ^ d;
+                k = 0xCA62C1D6;
+            }
+
+            unsigned int temp = SHA1_ROTATE_LEFT(a, 5) + f + e + k + w[i];
+            e = d;
+            d = c;
+            c = SHA1_ROTATE_LEFT(b, 30);
+            b = a;
+            a = temp;
+        }
+
+        // Add this chunk's hash to result so far
+        hash[0] += a;
+        hash[1] += b;
+        hash[2] += c;
+        hash[3] += d;
+        hash[4] += e;
+    }
+
+    RL_FREE(msg);
+
+    return hash;
+}
+
+// Compute SHA-256 hash code
+// NOTE: Returns a static int[8] array (32 bytes)
+unsigned int *ComputeSHA256(const unsigned char *data, int dataSize)
+{
+    #define SHA256_ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int)*8) - c)))
+    #define SHA256_A0(x) (SHA256_ROTATE_RIGHT(x, 7) ^ SHA256_ROTATE_RIGHT(x, 18) ^ (x >> 3))
+    #define SHA256_A1(x) (SHA256_ROTATE_RIGHT(x, 17) ^ SHA256_ROTATE_RIGHT(x, 19) ^ (x >> 10))
+
+    static const unsigned int k[64] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+
+    static unsigned int hash[8] = { 0 };
+    hash[0] = 0x6A09e667;
+    hash[1] = 0xbb67ae85;
+    hash[2] = 0x3c6ef372;
+    hash[3] = 0xa54ff53a;
+    hash[4] = 0x510e527f;
+    hash[5] = 0x9b05688c;
+    hash[6] = 0x1f83d9ab;
+    hash[7] = 0x5be0cd19;
+
+    const unsigned long long bitLen = 8ULL*dataSize;
+    unsigned long long paddedSize = dataSize + sizeof(dataSize);
+    paddedSize += (64 - (paddedSize%64));
+    unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char));
+
+    memcpy(buffer, data, dataSize);
+    buffer[dataSize] = 0x80;
+    for (int i = 1; i <= sizeof(bitLen); i++)
+    {
+        buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF;
+    }
+
+    for (unsigned long long blockN = 0; blockN < paddedSize/64; blockN++)
+    {
+        unsigned int a = hash[0];
+        unsigned int b = hash[1];
+        unsigned int c = hash[2];
+        unsigned int d = hash[3];
+        unsigned int e = hash[4];
+        unsigned int f = hash[5];
+        unsigned int g = hash[6];
+        unsigned int h = hash[7];
+
+        unsigned char *block = buffer + (blockN*64);
+        unsigned int w[64] = { 0 };
+        for (int i = 0; i < 16; i++)
+        {
+            w[i] = ((unsigned int)block[i*4 + 0] << 24) |
+                   ((unsigned int)block[i*4 + 1] << 16) |
+                   ((unsigned int)block[i*4 + 2] << 8)  |
+                   ((unsigned int)block[i*4 + 3]);
+        }
+        for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16];
+
+        for (int t = 0; t < 64; t++)
+        {
+            unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25));
+            unsigned int ch = ((e & f) ^ (~e & g));
+            unsigned int t1 = (h + e1 + ch + k[t] + w[t]);
+            unsigned int e0 = (SHA256_ROTATE_RIGHT(a, 2) ^ SHA256_ROTATE_RIGHT(a, 13) ^ SHA256_ROTATE_RIGHT(a, 22));
+            unsigned int maj = ((a & b) ^ (a & c) ^ (b & c));
+            unsigned int t2 = e0 + maj;
+
+            h = g;
+            g = f;
+            f = e;
+            e = d + t1;
+            d = c;
+            c = b;
+            b = a;
+            a = t1 + t2;
+        }
+
+        hash[0] += a;
+        hash[1] += b;
+        hash[2] += c;
+        hash[3] += d;
+        hash[4] += e;
+        hash[5] += f;
+        hash[6] += g;
+        hash[7] += h;
+    }
+
+    RL_FREE(buffer);
+
+    return hash;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Automation Events Recording and Playing
+//----------------------------------------------------------------------------------
+
+// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
+AutomationEventList LoadAutomationEventList(const char *fileName)
+{
+    AutomationEventList list = { 0 };
+
+#if SUPPORT_AUTOMATION_EVENTS
+    // Allocate and empty automation event list, ready to record new events
+    list.events = (AutomationEvent *)RL_CALLOC(MAX_AUTOMATION_EVENTS, sizeof(AutomationEvent));
+    list.capacity = MAX_AUTOMATION_EVENTS;
+
+    if (fileName == NULL) TRACELOG(LOG_INFO, "AUTOMATION: New empty events list loaded successfully");
+    else
+    {
+        // Load automation events file (binary)
+        /*
+        //int dataSize = 0;
+        //unsigned char *data = LoadFileData(fileName, &dataSize);
+
+        FILE *raeFile = fopen(fileName, "rb");
+        unsigned char fileId[4] = { 0 };
+
+        fread(fileId, 1, 4, raeFile);
+
+        if ((fileId[0] == 'r') && (fileId[1] == 'A') && (fileId[2] == 'E') && (fileId[1] == ' '))
+        {
+            fread(&eventCount, sizeof(int), 1, raeFile);
+            TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount);
+            fread(events, sizeof(AutomationEvent), eventCount, raeFile);
+        }
+
+        fclose(raeFile);
+        */
+
+        // Load events file (text)
+        //unsigned char *buffer = LoadFileText(fileName);
+        FILE *raeFile = fopen(fileName, "rt");
+
+        if (raeFile != NULL)
+        {
+            unsigned int counter = 0;
+            char buffer[256] = { 0 };
+            char eventDesc[64] = { 0 };
+
+            char *result = fgets(buffer, 256, raeFile);
+            if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName);
+
+            while (!feof(raeFile))
+            {
+                switch (buffer[0])
+                {
+                    case 'c': sscanf(buffer, "c %i", &list.count); break;
+                    case 'e':
+                    {
+                        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++;
+                        }
+                        else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %u): %s", list.capacity, buffer);
+                    } break;
+                    default: break;
+                }
+
+                result = fgets(buffer, 256, raeFile);
+                if (result != buffer) TRACELOG(LOG_WARNING, "AUTOMATION: [%s] Issue reading line to buffer", fileName);
+            }
+
+            if (counter != list.count)
+            {
+                TRACELOG(LOG_WARNING, "AUTOMATION: Events read from file [%i] do not mach event count specified [%i]", counter, list.count);
+                list.count = counter;
+            }
+
+            fclose(raeFile);
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Events file loaded successfully");
+        }
+
+        TRACELOG(LOG_INFO, "AUTOMATION: Events loaded from file: %i", list.count);
+    }
+#endif
+    return list;
+}
+
+// Unload automation events list from file
+void UnloadAutomationEventList(AutomationEventList list)
+{
+#if SUPPORT_AUTOMATION_EVENTS
+    RL_FREE(list.events);
+#endif
+}
+
+// Export automation events list as text file
+bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
+{
+    bool result = false;
+
+#if SUPPORT_AUTOMATION_EVENTS
+    // Export events as binary file
+    // NOTE: Code not used, only for reference if required in the future
+    /*
+    if (list.count > 0)
+    {
+        int binarySize = 4 + sizeof(int) + sizeof(AutomationEvent)*list.count;
+        unsigned char *binBuffer = (unsigned char *)RL_CALLOC(binarySize, 1);
+        int offset = 0;
+        memcpy(binBuffer + offset, "rAE ", 4);
+        offset += 4;
+        memcpy(binBuffer + offset, &list.count, sizeof(int));
+        offset += sizeof(int);
+        memcpy(binBuffer + offset, list.events, sizeof(AutomationEvent)*list.count);
+        offset += sizeof(AutomationEvent)*list.count;
+
+        result = SaveFileData(TextFormat("%s.rae",fileName), binBuffer, binarySize);
+        RL_FREE(binBuffer);
+    }
+    */
+
+    // Export events as text
+    // NOTE: Save to memory buffer and SaveFileText()
+    char *txtData = (char *)RL_CALLOC(256*list.count + 2048, sizeof(char)); // 256 characters per line plus some header
+
+    int byteCount = 0;
+    byteCount += sprintf(txtData + byteCount, "#\n");
+    byteCount += sprintf(txtData + byteCount, "# Automation events exporter v1.0 - raylib automation events list\n");
+    byteCount += sprintf(txtData + byteCount, "#\n");
+    byteCount += sprintf(txtData + byteCount, "#    c <events_count>\n");
+    byteCount += sprintf(txtData + byteCount, "#    e <frame> <event_type> <param0> <param1> <param2> <param3> // <event_type_name>\n");
+    byteCount += sprintf(txtData + byteCount, "#\n");
+    byteCount += sprintf(txtData + byteCount, "# more info and bugs-report:  github.com/raysan5/raylib\n");
+    byteCount += sprintf(txtData + byteCount, "# feedback and support:       ray[at]raylib.com\n");
+    byteCount += sprintf(txtData + byteCount, "#\n");
+    byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2026 Ramon Santamaria (@raysan5)\n");
+    byteCount += sprintf(txtData + byteCount, "#\n\n");
+
+    // Add events data
+    byteCount += sprintf(txtData + byteCount, "c %i\n", list.count);
+    for (unsigned int i = 0; i < list.count; i++)
+    {
+        byteCount += snprintf(txtData + byteCount, 256, "e %i %i %i %i %i %i // Event: %s\n", list.events[i].frame, list.events[i].type,
+            list.events[i].params[0], list.events[i].params[1], list.events[i].params[2], list.events[i].params[3], autoEventTypeName[list.events[i].type]);
+    }
+
+    // NOTE: Text data size exported is determined by '\0' (NULL) character
+    result = SaveFileText(fileName, txtData);
+
+    RL_FREE(txtData);
+#endif
+
+    return result;
+}
+
+// Setup automation event list to record to
+void SetAutomationEventList(AutomationEventList *list)
+{
+#if SUPPORT_AUTOMATION_EVENTS
+    currentEventList = list;
+#endif
+}
+
+// Set automation event internal base frame to start recording
+void SetAutomationEventBaseFrame(int frame)
+{
+    CORE.Time.frameCounter = frame;
+}
+
+// Start recording automation events (AutomationEventList must be set)
+void StartAutomationEventRecording(void)
+{
+#if SUPPORT_AUTOMATION_EVENTS
+    automationEventRecording = true;
+#endif
+}
+
+// Stop recording automation events
+void StopAutomationEventRecording(void)
+{
+#if SUPPORT_AUTOMATION_EVENTS
+    automationEventRecording = false;
+#endif
+}
+
+// Play a recorded automation event
+void PlayAutomationEvent(AutomationEvent event)
+{
+#if SUPPORT_AUTOMATION_EVENTS
+    // WARNING: When should event be played? After/before/replace PollInputEvents()? -> Up to the user!
+
+    if (!automationEventRecording)
+    {
+        switch (event.type)
+        {
+            // Input event
+            case INPUT_KEY_UP: CORE.Input.Keyboard.currentKeyState[event.params[0]] = false; break;             // param[0]: key
+            case INPUT_KEY_DOWN: {                                                                              // param[0]: key
+                CORE.Input.Keyboard.currentKeyState[event.params[0]] = true;
+
+                if (CORE.Input.Keyboard.previousKeyState[event.params[0]] == false)
+                {
+                    if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)
+                    {
+                        // Add character to the queue
+                        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = event.params[0];
+                        CORE.Input.Keyboard.keyPressedQueueCount++;
+                    }
+                }
+            } break;
+            case INPUT_MOUSE_BUTTON_UP: CORE.Input.Mouse.currentButtonState[event.params[0]] = false; break;    // param[0]: key
+            case INPUT_MOUSE_BUTTON_DOWN: CORE.Input.Mouse.currentButtonState[event.params[0]] = true; break;   // param[0]: key
+            case INPUT_MOUSE_POSITION:      // param[0]: x, param[1]: y
+            {
+                CORE.Input.Mouse.currentPosition.x = (float)event.params[0];
+                CORE.Input.Mouse.currentPosition.y = (float)event.params[1];
+            } break;
+            case INPUT_MOUSE_WHEEL_MOTION:  // param[0]: x delta, param[1]: y delta
+            {
+                CORE.Input.Mouse.currentWheelMove.x = (float)event.params[0];
+                CORE.Input.Mouse.currentWheelMove.y = (float)event.params[1];
+            } break;
+            case INPUT_TOUCH_UP: CORE.Input.Touch.currentTouchState[event.params[0]] = false; break;            // param[0]: id
+            case INPUT_TOUCH_DOWN: CORE.Input.Touch.currentTouchState[event.params[0]] = true; break;           // param[0]: id
+            case INPUT_TOUCH_POSITION:      // param[0]: id, param[1]: x, param[2]: y
+            {
+                CORE.Input.Touch.position[event.params[0]].x = (float)event.params[1];
+                CORE.Input.Touch.position[event.params[0]].y = (float)event.params[2];
+            } break;
+            case INPUT_GAMEPAD_CONNECT: CORE.Input.Gamepad.ready[event.params[0]] = true; break;                // param[0]: gamepad
+            case INPUT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[event.params[0]] = false; break;            // param[0]: gamepad
+            case INPUT_GAMEPAD_BUTTON_UP: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = false; break;    // param[0]: gamepad, param[1]: button
+            case INPUT_GAMEPAD_BUTTON_DOWN: CORE.Input.Gamepad.currentButtonState[event.params[0]][event.params[1]] = true; break;   // param[0]: gamepad, param[1]: button
+            case INPUT_GAMEPAD_AXIS_MOTION: // param[0]: gamepad, param[1]: axis, param[2]: delta
+            {
+                CORE.Input.Gamepad.axisState[event.params[0]][event.params[1]] = ((float)event.params[2]/32768.0f);
+            } break;
+    #if SUPPORT_GESTURES_SYSTEM
+            case INPUT_GESTURE: GESTURES.current = event.params[0]; break;     // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
+    #endif
+            // Window event
+            case WINDOW_CLOSE: CORE.Window.shouldClose = true; break;
+            case WINDOW_MAXIMIZE: MaximizeWindow(); break;
+            case WINDOW_MINIMIZE: MinimizeWindow(); break;
+            case WINDOW_RESIZE: SetWindowSize(event.params[0], event.params[1]); break;
+            // Custom event
+    #if SUPPORT_SCREEN_CAPTURE
+            case ACTION_TAKE_SCREENSHOT:
+            {
+                TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
+                screenshotCounter++;
+            } break;
+    #endif
+            case ACTION_SETTARGETFPS: SetTargetFPS(event.params[0]); break;
+            default: break;
+        }
+
+        TRACELOG(LOG_INFO, "AUTOMATION PLAY: Frame: %i | Event type: %i | Event parameters: %i, %i, %i", event.frame, event.type, event.params[0], event.params[1], event.params[2]);
+    }
+#endif
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Input Handling: Keyboard
+//----------------------------------------------------------------------------------
+
+// Check if key has been pressed once
+bool IsKeyPressed(int key)
+{
+    bool pressed = false;
+
+    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
+    {
+        if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true;
+    }
+
+    return pressed;
+}
+
+// Check if key has been pressed again
+bool IsKeyPressedRepeat(int key)
+{
+    bool repeat = false;
+
+    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
+    {
+        if (CORE.Input.Keyboard.keyRepeatInFrame[key] == 1) repeat = true;
+    }
+
+    return repeat;
+}
+
+// Check if key is being pressed (key held down)
+bool IsKeyDown(int key)
+{
+    bool down = false;
+
+    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
+    {
+        if (CORE.Input.Keyboard.currentKeyState[key] == 1) down = true;
+    }
+
+    return down;
+}
+
+// Check if key has been released once
+bool IsKeyReleased(int key)
+{
+    bool released = false;
+
+    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
+    {
+        if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true;
+    }
+
+    return released;
+}
+
+// Check if key is NOT being pressed (key not held down)
+bool IsKeyUp(int key)
+{
+    bool up = false;
+
+    if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
+    {
+        if (CORE.Input.Keyboard.currentKeyState[key] == 0) up = true;
+    }
+
+    return up;
+}
+
+// Get the last key pressed
+int GetKeyPressed(void)
+{
+    int value = 0;
+
+    if (CORE.Input.Keyboard.keyPressedQueueCount > 0)
+    {
+        // Get character from the queue head
+        value = CORE.Input.Keyboard.keyPressedQueue[0];
+
+        // Shift elements 1 step toward the head
+        for (int i = 0; i < (CORE.Input.Keyboard.keyPressedQueueCount - 1); i++)
+            CORE.Input.Keyboard.keyPressedQueue[i] = CORE.Input.Keyboard.keyPressedQueue[i + 1];
+
+        // Reset last character in the queue
+        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount - 1] = 0;
+        CORE.Input.Keyboard.keyPressedQueueCount--;
+    }
+
+    return value;
+}
+
+// Get the last char pressed
+int GetCharPressed(void)
+{
+    int value = 0;
+
+    if (CORE.Input.Keyboard.charPressedQueueCount > 0)
+    {
+        // Get character from the queue head
+        value = CORE.Input.Keyboard.charPressedQueue[0];
+
+        // Shift elements 1 step toward the head
+        for (int i = 0; i < (CORE.Input.Keyboard.charPressedQueueCount - 1); i++)
+            CORE.Input.Keyboard.charPressedQueue[i] = CORE.Input.Keyboard.charPressedQueue[i + 1];
+
+        // Reset last character in the queue
+        CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount - 1] = 0;
+        CORE.Input.Keyboard.charPressedQueueCount--;
+    }
+
+    return value;
+}
+
+// Set a custom key to exit program
+// NOTE: default exitKey is set to ESCAPE
+void SetExitKey(int key)
+{
+    CORE.Input.Keyboard.exitKey = key;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Input Handling: Gamepad
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//int SetGamepadMappings(const char *mappings)
+
+// Check if gamepad is available
+bool IsGamepadAvailable(int gamepad)
+{
+    bool result = false;
+
+    if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
+
+    return result;
+}
+
+// Get gamepad internal name id
+const char *GetGamepadName(int 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
+bool IsGamepadButtonPressed(int gamepad, int button)
+{
+    bool pressed = false;
+
+    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;
+    }
+
+    return pressed;
+}
+
+// Check if gamepad button is being pressed
+bool IsGamepadButtonDown(int gamepad, int button)
+{
+    bool down = false;
+
+    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;
+    }
+
+    return down;
+}
+
+// Check if gamepad button has NOT been pressed once
+bool IsGamepadButtonReleased(int gamepad, int button)
+{
+    bool released = false;
+
+    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;
+    }
+
+    return released;
+}
+
+// Check if gamepad button is NOT being pressed
+bool IsGamepadButtonUp(int gamepad, int button)
+{
+    bool up = false;
+
+    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;
+    }
+
+    return up;
+}
+
+// Get the last gamepad button pressed
+// NOTE: Returns last gamepad button down, down->up change not considered
+int GetGamepadButtonPressed(void)
+{
+    return CORE.Input.Gamepad.lastButtonPressed;
+}
+
+// Get gamepad axis count
+int GetGamepadAxisCount(int 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
+float GetGamepadAxisMovement(int gamepad, int axis)
+{
+    float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
+
+    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]);
+
+        if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
+    }
+
+    return value;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Input Handling: Mouse
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//void SetMousePosition(int x, int y)
+//void SetMouseCursor(int cursor)
+
+// Check if mouse button has been pressed once
+bool IsMouseButtonPressed(int button)
+{
+    bool pressed = false;
+
+    if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
+    {
+        if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true;
+
+        // Map touches to mouse buttons checking
+        if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true;
+    }
+
+    return pressed;
+}
+
+// Check if mouse button is being pressed
+bool IsMouseButtonDown(int button)
+{
+    bool down = false;
+
+    if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
+    {
+        if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true;
+
+        // NOTE: Touches are considered like mouse buttons
+        if (CORE.Input.Touch.currentTouchState[button] == 1) down = true;
+    }
+
+    return down;
+}
+
+// Check if mouse button has been released once
+bool IsMouseButtonReleased(int button)
+{
+    bool released = false;
+
+    if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
+    {
+        if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true;
+
+        // Map touches to mouse buttons checking
+        if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true;
+    }
+
+    return released;
+}
+
+// Check if mouse button is NOT being pressed
+bool IsMouseButtonUp(int button)
+{
+    bool up = false;
+
+    if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
+    {
+        if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true;
+
+        // NOTE: Touches are considered like mouse buttons
+        if (CORE.Input.Touch.currentTouchState[button] == 0) up = true;
+    }
+
+    return up;
+}
+
+// Get mouse position X
+int GetMouseX(void)
+{
+    int mouseX = (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
+
+    return mouseX;
+}
+
+// Get mouse position Y
+int GetMouseY(void)
+{
+    int mouseY = (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
+
+    return mouseY;
+}
+
+// Get mouse position XY
+Vector2 GetMousePosition(void)
+{
+    Vector2 position = { 0 };
+
+    position.x = (CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x;
+    position.y = (CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y;
+
+    return position;
+}
+
+// Get mouse delta between frames
+Vector2 GetMouseDelta(void)
+{
+    Vector2 delta = { 0 };
+
+    delta.x = (CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x)*CORE.Input.Mouse.scale.x;
+    delta.y = (CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y)*CORE.Input.Mouse.scale.y;
+
+    return delta;
+}
+
+// Set mouse offset
+// NOTE: Useful when rendering to different size targets
+void SetMouseOffset(int offsetX, int offsetY)
+{
+    CORE.Input.Mouse.offset = (Vector2){ (float)offsetX, (float)offsetY };
+}
+
+// Set mouse scaling
+// NOTE: Useful when rendering to different size targets
+void SetMouseScale(float scaleX, float scaleY)
+{
+    CORE.Input.Mouse.scale = (Vector2){ scaleX, scaleY };
+}
+
+// Get mouse wheel movement Y
+float GetMouseWheelMove(void)
+{
+    float result = 0.0f;
+
+    if (fabsf(CORE.Input.Mouse.currentWheelMove.x) > fabsf(CORE.Input.Mouse.currentWheelMove.y)) result = (float)CORE.Input.Mouse.currentWheelMove.x;
+    else result = (float)CORE.Input.Mouse.currentWheelMove.y;
+
+    return result;
+}
+
+// Get mouse wheel movement X/Y as a vector
+Vector2 GetMouseWheelMoveV(void)
+{
+    Vector2 result = { 0 };
+
+    result = CORE.Input.Mouse.currentWheelMove;
+
+    return result;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Input Handling: Touch
+//----------------------------------------------------------------------------------
+
+// Get touch position X for touch point 0 (relative to screen size)
+int GetTouchX(void)
+{
+    int touchX = (int)CORE.Input.Touch.position[0].x;
+    return touchX;
+}
+
+// Get touch position Y for touch point 0 (relative to screen size)
+int GetTouchY(void)
+{
+    int touchY = (int)CORE.Input.Touch.position[0].y;
+    return touchY;
+}
+
+// Get touch position XY for a touch point index (relative to screen size)
+Vector2 GetTouchPosition(int index)
+{
+    Vector2 position = { -1.0f, -1.0f };
+
+    if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index];
+    else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS);
+
+    return position;
+}
+
+// Get touch point identifier for provided index
+int GetTouchPointId(int index)
+{
+    int id = -1;
+
+    if (index < MAX_TOUCH_POINTS) id = CORE.Input.Touch.pointId[index];
+
+    return id;
+}
+
+// Get number of touch points
+int GetTouchPointCount(void)
+{
+    return CORE.Input.Touch.pointCount;
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
+//int InitPlatform(void)
+//void ClosePlatform(void)
+
+// Initialize hi-resolution timer
+void InitTimer(void)
+{
+    // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
+    // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
+    // High resolutions can also prevent the CPU power management system from entering power-saving modes
+    // Setting a higher resolution does not improve the accuracy of the high-resolution performance counter
+#if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP && !defined(PLATFORM_DESKTOP_SDL)
+    timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
+    struct timespec now = { 0 };
+
+    if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
+    {
+        CORE.Time.base = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
+    }
+    else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
+#endif
+
+    CORE.Time.previous = GetTime(); // Get time as double
+}
+
+// Set viewport for a provided width and height
+void SetupViewport(int width, int height)
+{
+    CORE.Window.render.width = width;
+    CORE.Window.render.height = height;
+
+    // Set viewport width and height
+    rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width, CORE.Window.render.height);
+
+    rlMatrixMode(RL_PROJECTION);        // Switch to projection matrix
+    rlLoadIdentity();                   // Reset current matrix (projection)
+
+    // Set orthographic projection to current framebuffer size
+    // NOTE: Configured top-left corner as (0, 0)
+    rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f);
+
+    rlMatrixMode(RL_MODELVIEW);         // Switch back to modelview matrix
+    rlLoadIdentity();                   // Reset current matrix (modelview)
+}
+
+// Scan all files and directories in a base path
+// WARNING: files.paths[] must be previously allocated and
+// contain enough space to store all required paths
+static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter, unsigned int expectedFileCount, bool scanSubdirs)
+{
+    // WARNING: Path can not be static or it will be reused between recursive function calls!
+    char path[MAX_FILEPATH_LENGTH] = { 0 };
+    memset(path, 0, MAX_FILEPATH_LENGTH);
+
+    struct dirent *dp = NULL;
+    DIR *dir = opendir(basePath);
+
+    if (dir != NULL)
+    {
+        while (((dp = readdir(dir)) != NULL) && (files->count < expectedFileCount))
+        {
+            if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
+            {
+                // Construct new path from our base path
+            #if defined(_WIN32)
+                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s\\%s", basePath, dp->d_name);
+            #else
+                int pathLength = snprintf(path, MAX_FILEPATH_LENGTH, "%s/%s", basePath, dp->d_name);
+            #endif
+
+                if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
+                {
+                    TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
+                }
+                else if (IsPathFile(path))
+                {
+                    if ((filter == NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL) ||
+                        (strstr(filter, FILE_FILTER_TAG_FILE_ONLY) != NULL) || IsFileExtension(path, filter))
+                    {
+                        memcpy(files->paths[files->count], path, pathLength);
+                        files->count++;
+                    }
+                }
+                else
+                {
+                    if ((filter != NULL) && ((strstr(filter, FILE_FILTER_TAG_DIR_ONLY) != NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL)))
+                    {
+                        memcpy(files->paths[files->count], path, pathLength);
+                        files->count++;
+                    }
+
+                    if (scanSubdirs) ScanDirectoryFiles(path, files, filter, expectedFileCount, scanSubdirs);
+                }
+            }
+        }
+
+        closedir(dir);
+    }
+    else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);  // Maybe it's a file...
+}
+
+#if SUPPORT_AUTOMATION_EVENTS
+// Automation event recording
+// Checking events in current frame and save them into currentEventList
+// NOTE: Recording is by default done at EndDrawing(), before PollInputEvents()
+static void RecordAutomationEvent(void)
+{
+    if (currentEventList->count == currentEventList->capacity) return;
+
+    // Keyboard input events recording
+    //-------------------------------------------------------------------------------------
+    for (int key = 0; key < MAX_KEYBOARD_KEYS; key++)
+    {
+        // Event type: INPUT_KEY_UP (only saved once)
+        if (CORE.Input.Keyboard.previousKeyState[key] && !CORE.Input.Keyboard.currentKeyState[key])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_KEY_UP;
+            currentEventList->events[currentEventList->count].params[0] = key;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+
+        // Event type: INPUT_KEY_DOWN
+        if (CORE.Input.Keyboard.currentKeyState[key])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_KEY_DOWN;
+            currentEventList->events[currentEventList->count].params[0] = key;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_KEY_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+    //-------------------------------------------------------------------------------------
+
+    // Mouse input currentEventList->events recording
+    //-------------------------------------------------------------------------------------
+    for (int button = 0; button < MAX_MOUSE_BUTTONS; button++)
+    {
+        // Event type: INPUT_MOUSE_BUTTON_UP
+        if (CORE.Input.Mouse.previousButtonState[button] && !CORE.Input.Mouse.currentButtonState[button])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_UP;
+            currentEventList->events[currentEventList->count].params[0] = button;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+
+        // Event type: INPUT_MOUSE_BUTTON_DOWN
+        if (CORE.Input.Mouse.currentButtonState[button])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_MOUSE_BUTTON_DOWN;
+            currentEventList->events[currentEventList->count].params[0] = button;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+
+    // Event type: INPUT_MOUSE_POSITION (only saved if changed)
+    if (((int)CORE.Input.Mouse.currentPosition.x != (int)CORE.Input.Mouse.previousPosition.x) ||
+        ((int)CORE.Input.Mouse.currentPosition.y != (int)CORE.Input.Mouse.previousPosition.y))
+    {
+        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+        currentEventList->events[currentEventList->count].type = INPUT_MOUSE_POSITION;
+        currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentPosition.x;
+        currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentPosition.y;
+        currentEventList->events[currentEventList->count].params[2] = 0;
+
+        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+        currentEventList->count++;
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+
+    // Event type: INPUT_MOUSE_WHEEL_MOTION
+    if (((int)CORE.Input.Mouse.currentWheelMove.x != (int)CORE.Input.Mouse.previousWheelMove.x) ||
+        ((int)CORE.Input.Mouse.currentWheelMove.y != (int)CORE.Input.Mouse.previousWheelMove.y))
+    {
+        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+        currentEventList->events[currentEventList->count].type = INPUT_MOUSE_WHEEL_MOTION;
+        currentEventList->events[currentEventList->count].params[0] = (int)CORE.Input.Mouse.currentWheelMove.x;
+        currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Mouse.currentWheelMove.y;
+        currentEventList->events[currentEventList->count].params[2] = 0;
+
+        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_MOUSE_WHEEL_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+        currentEventList->count++;
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+    //-------------------------------------------------------------------------------------
+
+    // Touch input currentEventList->events recording
+    //-------------------------------------------------------------------------------------
+    for (int id = 0; id < MAX_TOUCH_POINTS; id++)
+    {
+        // Event type: INPUT_TOUCH_UP
+        if (CORE.Input.Touch.previousTouchState[id] && !CORE.Input.Touch.currentTouchState[id])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_UP;
+            currentEventList->events[currentEventList->count].params[0] = id;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+
+        // Event type: INPUT_TOUCH_DOWN
+        if (CORE.Input.Touch.currentTouchState[id])
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_DOWN;
+            currentEventList->events[currentEventList->count].params[0] = id;
+            currentEventList->events[currentEventList->count].params[1] = 0;
+            currentEventList->events[currentEventList->count].params[2] = 0;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+
+        // Event type: INPUT_TOUCH_POSITION
+        if (((int)CORE.Input.Touch.position[id].x != (int)CORE.Input.Touch.previousPosition[id].x) ||
+            ((int)CORE.Input.Touch.position[id].y != (int)CORE.Input.Touch.previousPosition[id].y))
+        {
+            currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+            currentEventList->events[currentEventList->count].type = INPUT_TOUCH_POSITION;
+            currentEventList->events[currentEventList->count].params[0] = id;
+            currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.position[id].x;
+            currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.position[id].y;
+
+            TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+            currentEventList->count++;
+        }
+
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+    //-------------------------------------------------------------------------------------
+
+    // Gamepad input currentEventList->events recording
+    //-------------------------------------------------------------------------------------
+    for (int gamepad = 0; gamepad < MAX_GAMEPADS; gamepad++)
+    {
+        // Event type: INPUT_GAMEPAD_CONNECT
+        /*
+        if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
+            (CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to ready
+        {
+            // TODO: Save gamepad connect event
+        }
+        */
+
+        // Event type: INPUT_GAMEPAD_DISCONNECT
+        /*
+        if ((CORE.Input.Gamepad.currentState[gamepad] != CORE.Input.Gamepad.previousState[gamepad]) &&
+            (!CORE.Input.Gamepad.currentState[gamepad])) // Check if changed to not-ready
+        {
+            // TODO: Save gamepad disconnect event
+        }
+        */
+
+        for (int button = 0; button < MAX_GAMEPAD_BUTTONS; button++)
+        {
+            // Event type: INPUT_GAMEPAD_BUTTON_UP
+            if (CORE.Input.Gamepad.previousButtonState[gamepad][button] && !CORE.Input.Gamepad.currentButtonState[gamepad][button])
+            {
+                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_UP;
+                currentEventList->events[currentEventList->count].params[0] = gamepad;
+                currentEventList->events[currentEventList->count].params[1] = button;
+                currentEventList->events[currentEventList->count].params[2] = 0;
+
+                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_UP | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+                currentEventList->count++;
+            }
+
+            if (currentEventList->count == currentEventList->capacity) return;    // Security check
+
+            // Event type: INPUT_GAMEPAD_BUTTON_DOWN
+            if (CORE.Input.Gamepad.currentButtonState[gamepad][button])
+            {
+                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_BUTTON_DOWN;
+                currentEventList->events[currentEventList->count].params[0] = gamepad;
+                currentEventList->events[currentEventList->count].params[1] = button;
+                currentEventList->events[currentEventList->count].params[2] = 0;
+
+                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_BUTTON_DOWN | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+                currentEventList->count++;
+            }
+
+            if (currentEventList->count == currentEventList->capacity) return;    // Security check
+        }
+
+        for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
+        {
+            // Event type: INPUT_GAMEPAD_AXIS_MOTION
+            float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
+            if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
+            {
+                currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+                currentEventList->events[currentEventList->count].type = INPUT_GAMEPAD_AXIS_MOTION;
+                currentEventList->events[currentEventList->count].params[0] = gamepad;
+                currentEventList->events[currentEventList->count].params[1] = axis;
+                currentEventList->events[currentEventList->count].params[2] = (int)(CORE.Input.Gamepad.axisState[gamepad][axis]*32768.0f);
+
+                TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GAMEPAD_AXIS_MOTION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+                currentEventList->count++;
+            }
+
+            if (currentEventList->count == currentEventList->capacity) return;    // Security check
+        }
+    }
+    //-------------------------------------------------------------------------------------
+
+#if SUPPORT_GESTURES_SYSTEM
+    // Gestures input currentEventList->events recording
+    //-------------------------------------------------------------------------------------
+    if (GESTURES.current != GESTURE_NONE)
+    {
+        // Event type: INPUT_GESTURE
+        currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
+        currentEventList->events[currentEventList->count].type = INPUT_GESTURE;
+        currentEventList->events[currentEventList->count].params[0] = GESTURES.current;
+        currentEventList->events[currentEventList->count].params[1] = 0;
+        currentEventList->events[currentEventList->count].params[2] = 0;
+
+        TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_GESTURE | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
+        currentEventList->count++;
+
+        if (currentEventList->count == currentEventList->capacity) return;    // Security check
+    }
+    //-------------------------------------------------------------------------------------
+#endif
+}
+#endif
+
+#if !SUPPORT_MODULE_RTEXT
+// Formatting of text with variables to 'embed'
+// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
+const char *TextFormat(const char *text, ...)
+{
+#ifndef MAX_TEXTFORMAT_BUFFERS
+    #define MAX_TEXTFORMAT_BUFFERS      4        // Maximum number of static buffers for text formatting
+#endif
+#ifndef MAX_TEXT_BUFFER_LENGTH
+    #define MAX_TEXT_BUFFER_LENGTH   1024        // Maximum size of static text buffer
+#endif
+
+    // Define an array of buffers, so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
+    static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
+    static int index = 0;
+
+    char *currentBuffer = buffers[index];
+    memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
+
+    if (text != NULL)
+    {
+        va_list args;
+        va_start(args, text);
+        int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
+        va_end(args);
+
+        // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred
+        if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
+        {
+            // Inserting "..." at the end of the string to mark as truncated
+            char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
+            snprintf(truncBuffer, 4, "...");
+        }
+
+        index += 1; // Move to next buffer for next function call
+        if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
+    }
+
+    return currentBuffer;
+}
+#endif
diff --git a/raylib/src/rgestures.h b/raylib/src/rgestures.h
--- a/raylib/src/rgestures.h
+++ b/raylib/src/rgestures.h
@@ -59,11 +59,14 @@
 // NOTE: Below types are required for standalone usage
 //----------------------------------------------------------------------------------
 // Boolean type
+#if !defined(__cplusplus)
 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
     #include <stdbool.h>
-#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
+#elif !defined(bool)
     typedef enum bool { false = 0, true = !false } bool;
+    #define RL_BOOL_TYPE
 #endif
+#endif
 
 #if !defined(RL_VECTOR2_TYPE)
 // Vector2 type
@@ -124,7 +127,7 @@
 
 #if defined(RGESTURES_STANDALONE)
 void SetGesturesEnabled(unsigned int flags);            // Enable a set of gestures using flags
-bool IsGestureDetected(int gesture);                    // Check if a gesture have been detected
+bool IsGestureDetected(int gesture);                    // Check if gesture has been detected
 int GetGestureDetected(void);                           // Get latest detected gesture
 
 float GetGestureHoldDuration(void);                     // Get gesture hold time in seconds
@@ -154,8 +157,8 @@
     extern "C" {        // Prevents name mangling of functions
     #endif
     // Functions required to query time on Windows
-    int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
-    int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
+    int __stdcall QueryPerformanceCounter(unsigned long long *lpPerformanceCount);
+    int __stdcall QueryPerformanceFrequency(unsigned long long *lpFrequency);
     #if defined(__cplusplus)
     }
     #endif
@@ -254,7 +257,7 @@
     GESTURES.enabledFlags = flags;
 }
 
-// Check if a gesture have been detected
+// Check if gesture have been detected
 bool IsGestureDetected(unsigned int gesture)
 {
     if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true;
@@ -297,10 +300,10 @@
         }
         else if (event.touchAction == TOUCH_ACTION_UP)
         {
-            // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
+            // A swipe can happen while the current gesture is drag, but (especially for web) also hold, so set upPosition for both cases
             if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0];
 
-            // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
+            // NOTE: GESTURES.Drag.intensity is dependent on the resolution of the screen
             GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
             GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime));
 
@@ -350,7 +353,7 @@
             GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
         }
     }
-    else if (GESTURES.Touch.pointCount == 2)    // Two touch points
+    else if (GESTURES.Touch.pointCount == 2)
     {
         if (event.touchAction == TOUCH_ACTION_DOWN)
         {
@@ -515,37 +518,36 @@
     time = GetTime();
 #else
 #if defined(_WIN32)
-    unsigned long long int clockFrequency, currentTime;
+    unsigned long long clockFrequency = 0;
+    unsigned long long currentClockTicks = 0;
 
     QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
-    QueryPerformanceCounter(&currentTime);
+    QueryPerformanceCounter(&currentClockTicks);
 
-    time = (double)currentTime/clockFrequency;  // Time in seconds
+    time = (double)currentClockTicks/clockFrequency; // Time in seconds
 #endif
-
 #if defined(__linux__)
     // NOTE: Only for Linux-based systems
-    struct timespec now;
+    struct timespec now = { 0 };
     clock_gettime(CLOCK_MONOTONIC, &now);
-    unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds
+    unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
 
-    time = ((double)nowTime*1e-9);     // Time in seconds
+    time = ((double)nanoSeconds*1e-9); // Time in seconds
 #endif
-
 #if defined(__APPLE__)
     //#define CLOCK_REALTIME  CALENDAR_CLOCK    // returns UTC time since 1970-01-01
     //#define CLOCK_MONOTONIC SYSTEM_CLOCK      // returns the time since boot time
 
-    clock_serv_t cclock;
-    mach_timespec_t now;
+    clock_serv_t cclock = { 0 };
+    mach_timespec_t now = { 0 };
     host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
 
     // NOTE: OS X does not have clock_gettime(), using clock_get_time()
     clock_get_time(cclock, &now);
     mach_port_deallocate(mach_task_self(), cclock);
-    unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds
+    unsigned long long nanoSeconds = (unsigned long long)now.tv_sec*1000000000LLU + (unsigned long long)now.tv_nsec;
 
-    time = ((double)nowTime*1e-9);     // Time in seconds
+    time = ((double)nanoSeconds*1e-9); // Time in seconds
 #endif
 #endif
 
diff --git a/raylib/src/rglfw.c b/raylib/src/rglfw.c
--- a/raylib/src/rglfw.c
+++ b/raylib/src/rglfw.c
@@ -77,7 +77,16 @@
 #include "external/glfw/src/window.c"
 #include "external/glfw/src/input.c"
 #include "external/glfw/src/vulkan.c"
+#include "external/glfw/src/egl_context.c"
+#include "external/glfw/src/osmesa_context.c"
 
+//We need to define this function because GLFW calls it even though raylib does
+//not use GLFW's Null platform
+GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform)
+{
+    return GLFW_FALSE;
+}
+
 #if defined(_WIN32) || defined(__CYGWIN__)
     #include "external/glfw/src/win32_init.c"
     #include "external/glfw/src/win32_module.c"
@@ -87,9 +96,6 @@
     #include "external/glfw/src/win32_time.c"
     #include "external/glfw/src/win32_thread.c"
     #include "external/glfw/src/wgl_context.c"
-
-    #include "external/glfw/src/egl_context.c"
-    #include "external/glfw/src/osmesa_context.c"
 #endif
 
 #if defined(__linux__)
@@ -100,19 +106,42 @@
     #include "external/glfw/src/linux_joystick.c"
     #include "external/glfw/src/xkb_unicode.c"
 
-    #include "external/glfw/src/egl_context.c"
-    #include "external/glfw/src/osmesa_context.c"
-
     #if defined(_GLFW_WAYLAND)
+        //These functions need to be temporarily renamed because including
+        //source files for both Wayland and X11 results in pairs of functions
+        //with the same name and thus a build error
+        #define  createKeyTables createKeyTablesWayland
+        #define  translateKey    translateKeyWayland
+        #define  acquireMonitor  acquireMonitorWayland
+        #define  releaseMonitor  releaseMonitorWayland
+
         #include "external/glfw/src/wl_init.c"
         #include "external/glfw/src/wl_monitor.c"
         #include "external/glfw/src/wl_window.c"
+
+        #undef   createKeyTables
+        #undef   translateKey
+        #undef   acquireMonitor
+        #undef   releaseMonitor
     #endif
     #if defined(_GLFW_X11)
+        //These functions need to be temporarily renamed because including
+        //source files for both Wayland and X11 results in pairs of functions
+        //with the same name and thus a build error
+        #define  createKeyTables createKeyTablesX11
+        #define  translateKey    translateKeyX11
+        #define  acquireMonitor  acquireMonitorX11
+        #define  releaseMonitor  releaseMonitorX11
+
         #include "external/glfw/src/x11_init.c"
         #include "external/glfw/src/x11_monitor.c"
         #include "external/glfw/src/x11_window.c"
         #include "external/glfw/src/glx_context.c"
+
+        #undef   createKeyTables
+        #undef   translateKey
+        #undef   acquireMonitor
+        #undef   releaseMonitor
     #endif
 #endif
 
@@ -128,9 +157,6 @@
     #include "external/glfw/src/x11_monitor.c"
     #include "external/glfw/src/x11_window.c"
     #include "external/glfw/src/glx_context.c"
-
-    #include "external/glfw/src/egl_context.c"
-    #include "external/glfw/src/osmesa_context.c"
 #endif
 
 #if defined(__APPLE__)
@@ -140,9 +166,6 @@
     #include "external/glfw/src/cocoa_joystick.m"
     #include "external/glfw/src/cocoa_monitor.m"
     #include "external/glfw/src/cocoa_window.m"
-    #include "external/glfw/src/cocoa_time.c"
+    #include "external/glfw/src/macos_time.c"
     #include "external/glfw/src/nsgl_context.m"
-
-    #include "external/glfw/src/egl_context.c"
-    #include "external/glfw/src/osmesa_context.c"
 #endif
diff --git a/raylib/src/rlgl.h b/raylib/src/rlgl.h
--- a/raylib/src/rlgl.h
+++ b/raylib/src/rlgl.h
@@ -1,16 +1,16 @@
 /**********************************************************************************************
 *
-*   rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
+*   rlgl v6.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
 *
 *   DESCRIPTION:
 *       An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0)
 *       that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
 *
 *   ADDITIONAL NOTES:
-*       When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
+*       When choosing an OpenGL backend different than OpenGL 1.1, some internal buffers are
 *       initialized on rlglInit() to accumulate vertex data
 *
-*       When an internal state change is required all the stored vertex data is rendered in batch,
+*       When an internal state change is required all the stored vertex data is rendered in a batch,
 *       additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch
 *
 *       Some resources are also loaded for convenience, here the complete list:
@@ -21,7 +21,7 @@
 *       Internal buffer (and resources) must be manually unloaded calling rlglClose()
 *
 *   CONFIGURATION:
-*       #define GRAPHICS_API_OPENGL_11_SOFTWARE
+*       #define GRAPHICS_API_OPENGL_SOFTWARE
 *       #define GRAPHICS_API_OPENGL_11
 *       #define GRAPHICS_API_OPENGL_21
 *       #define GRAPHICS_API_OPENGL_33
@@ -29,7 +29,7 @@
 *       #define GRAPHICS_API_OPENGL_ES2
 *       #define GRAPHICS_API_OPENGL_ES3
 *           Use selected OpenGL graphics backend, should be supported by platform
-*           Those preprocessor defines are only used on rlgl module, if OpenGL version is
+*           Those preprocessor defines are only used on the rlgl module, if OpenGL version is
 *           required by any other module, use rlGetVersion() to check it
 *
 *       #define RLGL_IMPLEMENTATION
@@ -37,27 +37,27 @@
 *           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 RLGL_SHOW_GL_DETAILS_INFO
+*       #if RLGL_SHOW_GL_DETAILS_INFO
 *           Show OpenGL extensions and capabilities detailed logs on init
 *
-*       #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
+*       #if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
 *           Enable debug context (only available on OpenGL 4.3)
 *
-*       rlgl capabilities could be customized just defining some internal
+*       rlgl capabilities could be customized defining some internal
 *       values before library inclusion (default values listed):
 *
 *       #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS   8192    // Default internal render batch elements limits
 *       #define RL_DEFAULT_BATCH_BUFFERS              1    // Default number of batch buffers (multi-buffering)
 *       #define RL_DEFAULT_BATCH_DRAWCALLS          256    // Default number of batch draw calls (by state changes: mode, texture)
-*       #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS    4    // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
+*       #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS    4    // Maximum number of texture units that can be activated on batch drawing (SetShaderValueTexture())
 *
 *       #define RL_MAX_MATRIX_STACK_SIZE             32    // Maximum size of internal Matrix stack
 *       #define RL_MAX_SHADER_LOCATIONS              32    // Maximum number of shader locations supported
 *       #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
@@ -65,15 +65,18 @@
 *       #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_BONEIDS      "vertexBoneIds"     // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS
+*       #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
 *       #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_BONE_MATRICES  "boneMatrices"   // bone matrices
+*       #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)
@@ -107,17 +110,17 @@
 #ifndef RLGL_H
 #define RLGL_H
 
-#define RLGL_VERSION  "5.0"
+#define RLGL_VERSION  "6.0"
 
 // Function specifiers in case library is build/used as a shared library
 // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
 // NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden
 #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
-    #define RLAPI __declspec(dllexport)     // We are building the library as a Win32 shared library (.dll)
+    #define RLAPI __declspec(dllexport)     // Building the library as a Win32 shared library (.dll)
 #elif defined(BUILD_LIBTYPE_SHARED)
-    #define RLAPI __attribute__((visibility("default"))) // We are building the library as a Unix shared library (.so/.dylib)
+    #define RLAPI __attribute__((visibility("default"))) // Building the library as a Unix shared library (.so/.dylib)
 #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
-    #define RLAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll)
+    #define RLAPI __declspec(dllimport)     // Using the library as a Win32 shared library (.dll)
 #endif
 
 // Function specifiers definition
@@ -145,7 +148,7 @@
 #endif
 
 // Security check in case no GRAPHICS_API_OPENGL_* defined
-#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \
+#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) && \
     !defined(GRAPHICS_API_OPENGL_11) && \
     !defined(GRAPHICS_API_OPENGL_21) && \
     !defined(GRAPHICS_API_OPENGL_33) && \
@@ -156,7 +159,7 @@
 #endif
 
 // Security check in case multiple GRAPHICS_API_OPENGL_* defined
-#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE)
     #if defined(GRAPHICS_API_OPENGL_21)
         #undef GRAPHICS_API_OPENGL_21
     #endif
@@ -172,7 +175,7 @@
 #endif
 
 // Software implementation uses OpenGL 1.1 functionality
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     #define GRAPHICS_API_OPENGL_11
 #endif
 
@@ -204,9 +207,9 @@
         #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS  8192
     #endif
     #if defined(GRAPHICS_API_OPENGL_ES2)
-        // We reduce memory sizes for embedded systems (RPI and HTML5)
+        // Reducing memory sizes for embedded systems (RPI and HTML5)
         // NOTE: On HTML5 (emscripten) this is allocated on heap,
-        // by default it's only 16MB!...just take care...
+        // by default heap is only 16MB!...just take care...
         #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS  2048
     #endif
 #endif
@@ -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
@@ -345,27 +349,27 @@
 #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES
     #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES     6
 #endif
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS
-    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS     7
+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
+    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7
 #endif
 #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
     #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
 #endif
-#endif
-#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX
-    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9
+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
+    #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM 9
 #endif
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
+#if !defined(__cplusplus)
 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
     #include <stdbool.h>
-#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
-    // Boolean type
-typedef enum bool { false = 0, true = !false } bool;
+#elif !defined(bool)
+    typedef enum bool { false = 0, true = !false } bool;
+    #define RL_BOOL_TYPE
 #endif
+#endif
 
 #if !defined(RL_MATRIX_TYPE)
 // Matrix, 4x4 components, column major, OpenGL style, right handed
@@ -398,7 +402,7 @@
 
 // Draw call type
 // NOTE: Only texture changes register a new draw, other state-change-related elements are not
-// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
+// used at this moment (vaoId, shaderId, matrices), raylib forces a batch draw call if any
 // of those state-change happens (this is done in core module)
 typedef struct rlDrawCall {
     int mode;                   // Drawing mode: LINES, TRIANGLES, QUADS
@@ -425,7 +429,7 @@
 
 // OpenGL version
 typedef enum {
-    RL_OPENGL_11_SOFTWARE = 0,  // Software rendering
+    RL_OPENGL_SOFTWARE = 0,  // Software rendering
     RL_OPENGL_11,               // OpenGL 1.1
     RL_OPENGL_21,               // OpenGL 2.1 (GLSL 120)
     RL_OPENGL_33,               // OpenGL 3.3 (GLSL 330)
@@ -480,7 +484,7 @@
 // NOTE 1: Filtering considers mipmaps if available in the texture
 // NOTE 2: Filter is accordingly set for minification and magnification
 typedef enum {
-    RL_TEXTURE_FILTER_POINT = 0,        // No filter, just pixel approximation
+    RL_TEXTURE_FILTER_POINT = 0,        // No filter, pixel approximation
     RL_TEXTURE_FILTER_BILINEAR,         // Linear filtering
     RL_TEXTURE_FILTER_TRILINEAR,        // Trilinear filtering (linear with mipmaps)
     RL_TEXTURE_FILTER_ANISOTROPIC_4X,   // Anisotropic filtering 4x
@@ -764,7 +768,7 @@
 
 // Framebuffer management (fbo)
 RLAPI unsigned int rlLoadFramebuffer(void);                               // Load an empty framebuffer
-RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
+RLAPI void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
 RLAPI bool rlFramebufferComplete(unsigned int id);                        // Verify framebuffer is complete
 RLAPI void rlUnloadFramebuffer(unsigned int id);                          // Delete framebuffer from GPU
 // WARNING: Copy and resize framebuffer functionality only defined for software backend
@@ -772,12 +776,14 @@
 RLAPI void rlResizeFramebuffer(int width, int height);                    // Resize internal framebuffer
 
 // Shaders management
-RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode);    // Load shader from code strings
-RLAPI unsigned int rlCompileShader(const char *shaderCode, int type);           // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER)
-RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program
+RLAPI unsigned int rlLoadShader(const char *code, int type);                    // Load (compile) shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER)
+RLAPI unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode); // Load shader from code strings
+RLAPI unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId); // Load shader program, using already loaded shader ids
+RLAPI unsigned int rlLoadShaderProgramCompute(unsigned int csId);               // Load compute shader program
+RLAPI void rlUnloadShader(unsigned int id);                                     // Unload shader, loaded with rlLoadShader()
 RLAPI void rlUnloadShaderProgram(unsigned int id);                              // Unload shader program
-RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform, requires shader program id
-RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName);   // Get shader location attribute, requires shader program id
+RLAPI int rlGetLocationUniform(unsigned int id, const char *uniformName);       // Get shader location uniform, requires shader program id
+RLAPI int rlGetLocationAttrib(unsigned int id, const char *attribName);         // Get shader location attribute, requires shader program id
 RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform
 RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat);                        // Set shader value matrix
 RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count);    // Set shader value matrices
@@ -785,7 +791,6 @@
 RLAPI void rlSetShader(unsigned int id, int *locs);                             // Set shader currently active (id and locations)
 
 // Compute shader management
-RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId);           // Load compute shader program
 RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
 
 // Shader buffer storage object management (ssbo)
@@ -836,16 +841,17 @@
 #endif
 
 #if defined(GRAPHICS_API_OPENGL_11)
-    #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+    #if defined(GRAPHICS_API_OPENGL_SOFTWARE)
         #define RLSW_IMPLEMENTATION
         #define SW_MALLOC(sz) RL_MALLOC(sz)
+        #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/gl.h>          // OpenGL 1.1 library for OSX
-            #include <OpenGL/glext.h>       // OpenGL extensions library
+            #include <OpenGL/gl.h>      // OpenGL 1.1 library for OSX
+            #include <OpenGL/glext.h>   // OpenGL extensions library
         #else
             // APIENTRY for OpenGL function pointer declarations is required
             #if !defined(APIENTRY)
@@ -860,7 +866,7 @@
                 #define WINGDIAPI __declspec(dllimport)
             #endif
 
-            #include <GL/gl.h>              // OpenGL 1.1 library
+            #include <GL/gl.h>          // OpenGL 1.1 library
         #endif
     #endif
 #endif
@@ -880,7 +886,7 @@
 #elif defined(GRAPHICS_API_OPENGL_ES2)
     // NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms,
     // in that case, functions are loaded from a custom glad for OpenGL ES 2.0
-    // TODO: OpenGL ES 2.0 support shouldn't be platform-dependant, neither require GLAD
+    // TODO: OpenGL ES 2.0 support shouldn't be platform-dependent, neither require GLAD
     #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL)
         #define GLAD_GLES2_IMPLEMENTATION
         #include "external/glad_gles2.h"
@@ -893,17 +899,18 @@
 
     // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
     // provided headers (despite being defined in official Khronos GLES2 headers)
-    // TODO: Avoid raylib platform-dependant code on rlgl, it should be a completely portable library
-    #if defined(PLATFORM_DRM)
+    // TODO: Avoid raylib platform-dependent code on rlgl, it should be a completely portable library
+    #if defined(PLATFORM_DRM)           // Use CONFIG_DRM?
     typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
     typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
     typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
     #endif
 #endif
 
-#include <stdlib.h>                     // Required for: calloc(), free()
-#include <string.h>                     // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
-#include <math.h>                       // Required for: sqrtf(), sinf(), cosf(), floor(), log()
+#include <stdlib.h>             // Required for: calloc(), free()
+#include <string.h>             // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
+#include <math.h>               // Required for: sqrtf(), sinf(), cosf(), floor(), log()
+#include <limits.h>             // Required for: INT_MAX
 
 //----------------------------------------------------------------------------------
 // Defines and Macros
@@ -987,69 +994,34 @@
     #if !defined(GRAPHICS_API_OPENGL_ES3)
         #define GL_READ_FRAMEBUFFER         GL_FRAMEBUFFER
         #define GL_DRAW_FRAMEBUFFER         GL_FRAMEBUFFER
+        #define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING
     #endif
 #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_NAME_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_NAME_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_NAME_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_NAME_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_NAME_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_NAME_TEXCOORD2
-#endif
-#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS
-    #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS      "vertexBoneIds"     // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS
-#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_NAME_BONEWEIGHTS
-#endif
-#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX
-    #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX  "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX
-#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_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_UNIFORM_NAME_BONE_MATRICES
-    #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES  "boneMatrices"   // bone matrices
-#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
+#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)
 
+#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
 //----------------------------------------------------------------------------------
@@ -1133,26 +1105,28 @@
     } ExtSupported;     // Extensions supported flags
 } rlglData;
 
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
 
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
+static bool isGpuReady = false;
 static double rlCullDistanceNear = RL_CULL_DISTANCE_NEAR;
 static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 static rlglData RLGL = { 0 };
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
-static bool isGpuReady = false;
+#endif
 
 #if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3)
+// VAO functions entry points
 // NOTE: VAO functionality is exposed through extensions (OES)
 static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
 static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
 static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
 
-// NOTE: Instancing functionality could also be available through extension
+// Instancing functionality entry points
+// NOTE: Instancing functionality could be available through extensions
 static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL;
 static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL;
 static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL;
@@ -1164,10 +1138,10 @@
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 static void rlLoadShaderDefault(void);      // Load default shader
 static void rlUnloadShaderDefault(void);    // Unload default shader
-#if defined(RLGL_SHOW_GL_DETAILS_INFO)
+#if RLGL_SHOW_GL_DETAILS_INFO
 static const char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name
-#endif  // RLGL_SHOW_GL_DETAILS_INFO
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#endif
+#endif
 
 static int rlGetPixelDataSize(int width, int height, int format);   // Get pixel data size in bytes (image or texture)
 
@@ -1232,7 +1206,11 @@
 // 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)
     {
@@ -1270,14 +1248,14 @@
 // Multiply the current matrix by a translation matrix
 void rlTranslatef(float x, float y, float z)
 {
-    Matrix matTranslation = {
-        1.0f, 0.0f, 0.0f, x,
-        0.0f, 1.0f, 0.0f, y,
-        0.0f, 0.0f, 1.0f, z,
-        0.0f, 0.0f, 0.0f, 1.0f
-    };
+    Matrix matTranslation = rlMatrixIdentity();
 
-    // NOTE: We transpose matrix with multiplication order
+    // Set translation component of matrix
+    matTranslation.m12 = x;
+    matTranslation.m13 = y;
+    matTranslation.m14 = z;
+
+    // NOTE: Transposing matrix by multiplication order
     *RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix);
 }
 
@@ -1322,21 +1300,21 @@
     matRotation.m14 = 0.0f;
     matRotation.m15 = 1.0f;
 
-    // NOTE: We transpose matrix with multiplication order
+    // NOTE: Transposing matrix by multiplication order
     *RLGL.State.currentMatrix = rlMatrixMultiply(matRotation, *RLGL.State.currentMatrix);
 }
 
 // Multiply the current matrix by a scaling matrix
 void rlScalef(float x, float y, float z)
 {
-    Matrix matScale = {
-        x, 0.0f, 0.0f, 0.0f,
-        0.0f, y, 0.0f, 0.0f,
-        0.0f, 0.0f, z, 0.0f,
-        0.0f, 0.0f, 0.0f, 1.0f
-    };
+    Matrix matScale = rlMatrixIdentity();
 
-    // NOTE: We transpose matrix with multiplication order
+    // Set scale component of matrix
+    matScale.m0 = x;
+    matScale.m5 = y;
+    matScale.m10 = z;
+
+    // NOTE: Transposing matrix by multiplication order
     *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix);
 }
 
@@ -1344,6 +1322,7 @@
 void rlMultMatrixf(const float *matf)
 {
     // Matrix creation from array
+    // Conversion from column-major to row-major memory order
     Matrix mat = { matf[0], matf[4], matf[8], matf[12],
                    matf[1], matf[5], matf[9], matf[13],
                    matf[2], matf[6], matf[10], matf[14],
@@ -1388,7 +1367,7 @@
 void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar)
 {
     // NOTE: If left-right and top-botton values are equal it could create a division by zero,
-    // response to it is platform/compiler dependant
+    // response to it is platform/compiler dependent
     Matrix matOrtho = { 0 };
 
     float rl = (float)(right - left);
@@ -1417,7 +1396,6 @@
 #endif
 
 // Set the viewport area (transformation from normalized device coordinates to window coordinates)
-// NOTE: We store current viewport dimensions
 void rlViewport(int x, int y, int width, int height)
 {
     glViewport(x, y, width, height);
@@ -1506,7 +1484,7 @@
 // Finish vertex providing
 void rlEnd(void)
 {
-    // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
+    // NOTE: Depth increment is dependent on rlOrtho(): z-near and z-far values,
     // as well as depth buffer bit-depth (16bit or 24bit or 32bit)
     // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
     RLGL.currentBatch->currentDepth += (1.0f/20000.0f);
@@ -1528,9 +1506,9 @@
         tz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z + RLGL.State.transform.m14;
     }
 
-    // WARNING: We can't break primitives when launching a new batch
+    // WARNING: Be careful with primitives breaking when launching a new batch!
     // RL_LINES comes in pairs, RL_TRIANGLES come in groups of 3 vertices and RL_QUADS come in groups of 4 vertices
-    // We must check current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4
+    // Checking current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4
     if (RLGL.State.vertexCounter > (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4))
     {
         if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) &&
@@ -1538,7 +1516,7 @@
         {
             // Reached the maximum number of vertices for RL_LINES drawing
             // Launch a draw call but keep current state for next vertices comming
-            // NOTE: We add +1 vertex to the check for security
+            // NOTE: Adding +1 vertex to the check for some safety
             rlCheckRenderBatchLimit(2 + 1);
         }
         else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) &&
@@ -1610,6 +1588,11 @@
         normaly = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z;
         normalz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z;
     }
+
+    // NOTE: Default behavior assumes the normal vector is in the correct space for what the shader expects,
+    // it could be not normalized to 0.0f..1.0f, magnitud can be useed for some effects
+    /*
+    // WARNING: Vector normalization if required
     float length = sqrtf(normalx*normalx + normaly*normaly + normalz*normalz);
     if (length != 0.0f)
     {
@@ -1618,6 +1601,7 @@
         normaly *= ilength;
         normalz *= ilength;
     }
+    */
     RLGL.State.normalx = normalx;
     RLGL.State.normaly = normaly;
     RLGL.State.normalz = normalz;
@@ -1658,7 +1642,7 @@
 #if defined(GRAPHICS_API_OPENGL_11)
         rlDisableTexture();
 #else
-        // NOTE: If quads batch limit is reached, we force a draw call and next batch starts
+        // NOTE: If quads batch limit is reached, force a draw call and next batch starts
         if (RLGL.State.vertexCounter >=
             RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4)
         {
@@ -1855,7 +1839,7 @@
 // Enable rendering to texture (fbo)
 void rlEnableFramebuffer(unsigned int id)
 {
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     glBindFramebuffer(GL_FRAMEBUFFER, id);
 #endif
 }
@@ -1864,7 +1848,7 @@
 unsigned int rlGetActiveFramebuffer(void)
 {
     GLint fboId = 0;
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId);
 #endif
     return fboId;
@@ -1873,7 +1857,7 @@
 // Disable rendering to texture
 void rlDisableFramebuffer(void)
 {
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 #endif
 }
@@ -1889,7 +1873,7 @@
 // Bind framebuffer object (fbo)
 void rlBindFramebuffer(unsigned int target, unsigned int framebuffer)
 {
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     glBindFramebuffer(target, framebuffer);
 #endif
 }
@@ -1899,7 +1883,7 @@
 void rlActiveDrawBuffers(int count)
 {
 #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
-    // NOTE: Maximum number of draw buffers supported is implementation dependant,
+    // NOTE: Maximum number of draw buffers supported is implementation dependent,
     // it can be queried with glGet*() but it must be at least 8
     //GLint maxDrawBuffers = 0;
     //glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
@@ -2209,7 +2193,7 @@
 //----------------------------------------------------------------------------------
 // Module Functions Definition - OpenGL Debug
 //----------------------------------------------------------------------------------
-#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
+#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
 static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
 {
     // Ignore non-significant error/warning codes (NVidia drivers)
@@ -2275,8 +2259,8 @@
 {
     isGpuReady = true;
 
-    // Enable OpenGL debug context if required
-#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
+    // Enable OpenGL debug context if requested (and supported)
+#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
     if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL))
     {
         glDebugMessageCallback(rlDebugMessageCallback, 0);
@@ -2320,9 +2304,9 @@
     RLGL.State.projection = rlMatrixIdentity();
     RLGL.State.modelview = rlMatrixIdentity();
     RLGL.State.currentMatrix = &RLGL.State.modelview;
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
 
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     // Initialize software renderer backend
     int result = swInit(width, height);
     if (result == 0)
@@ -2384,7 +2368,7 @@
     TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
 #endif
 
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     swClose(); // Unload sofware renderer resources
 #endif
     isGpuReady = false;
@@ -2394,7 +2378,7 @@
 // NOTE: External loader function must be provided
 void rlLoadExtensions(void *loader)
 {
-#if defined(GRAPHICS_API_OPENGL_33)     // Also defined for GRAPHICS_API_OPENGL_21
+#if defined(GRAPHICS_API_OPENGL_33) // Also defined for GRAPHICS_API_OPENGL_21
     // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions)
     if (gladLoadGL((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
     else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
@@ -2404,7 +2388,7 @@
     glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
     TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt);
 
-#if defined(RLGL_SHOW_GL_DETAILS_INFO)
+#if RLGL_SHOW_GL_DETAILS_INFO
     // Get supported extensions list
     // WARNING: glGetStringi() not available on OpenGL 2.1
     TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:");
@@ -2446,7 +2430,7 @@
     RLGL.ExtSupported.ssbo = GLAD_GL_ARB_shader_storage_buffer_object;
     #endif
 
-#endif  // GRAPHICS_API_OPENGL_33
+#endif // GRAPHICS_API_OPENGL_33
 
 #if defined(GRAPHICS_API_OPENGL_ES3)
     // Register supported extensions flags
@@ -2484,10 +2468,10 @@
     const char **extList = (const char **)RL_CALLOC(512, sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
     const char *extensions = (const char *)glGetString(GL_EXTENSIONS);  // One big const string
 
-    // NOTE: We have to duplicate string because glGetString() returns a const string
+    // 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++)
@@ -2502,7 +2486,7 @@
 
     TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt);
 
-#if defined(RLGL_SHOW_GL_DETAILS_INFO)
+#if RLGL_SHOW_GL_DETAILS_INFO
     TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:");
     for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, "    %s", extList[i]);
 #endif
@@ -2525,7 +2509,7 @@
         }
 
         // Check instanced rendering support
-        if (strstr(extList[i], (const char *)"instanced_arrays") != NULL)   // Broad check for instanced_arrays
+        if (strstr(extList[i], (const char *)"instanced_arrays") != NULL) // Broad check for instanced_arrays
         {
             // Specific check
             if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0)      // ANGLE
@@ -2612,7 +2596,7 @@
     // Free extensions pointers
     RL_FREE(extList);
     RL_FREE(extensionsDup);    // Duplicated string must be deallocated
-#endif  // GRAPHICS_API_OPENGL_ES2
+#endif // GRAPHICS_API_OPENGL_ES2
 
     // Check OpenGL information and capabilities
     //------------------------------------------------------------------------------
@@ -2632,7 +2616,7 @@
     #endif
     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel);
 
-#if defined(RLGL_SHOW_GL_DETAILS_INFO)
+#if RLGL_SHOW_GL_DETAILS_INFO
     // Show some OpenGL GPU capabilities
     TRACELOG(RL_LOG_INFO, "GL: OpenGL capabilities:");
     GLint capability = 0;
@@ -2663,9 +2647,10 @@
     TRACELOG(RL_LOG_INFO, "    GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability);
     glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability);
     TRACELOG(RL_LOG_INFO, "    GL_MAX_UNIFORM_LOCATIONS: %i", capability);
-#endif  // GRAPHICS_API_OPENGL_43
-#else   // RLGL_SHOW_GL_DETAILS_INFO
+#endif
 
+#else   // !RLGL_SHOW_GL_DETAILS_INFO
+
     // Show some basic info about GL supported features
     if (RLGL.ExtSupported.vao) TRACELOG(RL_LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully");
     else TRACELOG(RL_LOG_WARNING, "GL: VAO extension not found, VAO not supported");
@@ -2678,9 +2663,9 @@
     if (RLGL.ExtSupported.texCompASTC) TRACELOG(RL_LOG_INFO, "GL: ASTC compressed textures supported");
     if (RLGL.ExtSupported.computeShader) TRACELOG(RL_LOG_INFO, "GL: Compute shaders supported");
     if (RLGL.ExtSupported.ssbo) TRACELOG(RL_LOG_INFO, "GL: Shader storage buffer objects supported");
-#endif  // RLGL_SHOW_GL_DETAILS_INFO
+#endif
 
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
 }
 
 // Get OpenGL procedure address
@@ -2698,8 +2683,8 @@
 {
     int glVersion = 0;
 
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
-    glVersion = RL_OPENGL_11_SOFTWARE;
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    glVersion = RL_OPENGL_SOFTWARE;
 #elif defined(GRAPHICS_API_OPENGL_11)
     glVersion = RL_OPENGL_11;
 #endif
@@ -2969,20 +2954,21 @@
 }
 
 // Draw render batch
-// NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer)
+// NOTE: Batch is reseted and current buffer is updated (for multi-buffer config)
 void rlDrawRenderBatch(rlRenderBatch *batch)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     // Update batch vertex buffers
     //------------------------------------------------------------------------------------------------------------
     // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
-    // TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU,
-    // a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it?
     if (RLGL.State.vertexCounter > 0)
     {
         // Activate elements VAO
         if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId);
 
+        // TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU,
+        // a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it?
+
         // Vertex positions buffer
         glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]);
         glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices);
@@ -3005,18 +2991,17 @@
 
         // 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), you can call first glBufferData() with NULL pointer before glMapBuffer()
-        // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new
+        // 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
 
         // Another option: map the buffer object into client's memory
-        // Probably this code could be moved somewhere else...
-        // batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
-        // if (batch->vertexBuffer[batch->currentBuffer].vertices)
-        // {
-            // Update vertex data
-        // }
-        // glUnmapBuffer(GL_ARRAY_BUFFER);
+        //batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+        //if (batch->vertexBuffer[batch->currentBuffer].vertices)
+        //{
+        //    Update vertex data
+        //}
+        //glUnmapBuffer(GL_ARRAY_BUFFER);
 
         // Unbind the current VAO
         if (RLGL.ExtSupported.vao) glBindVertexArray(0);
@@ -3131,7 +3116,7 @@
                 else
                 {
     #if defined(GRAPHICS_API_OPENGL_33)
-                    // We need to define the number of indices to be processed: elementCount*6
+                    // The number of indices to be processed needs to be defined: elementCount*6
                     // NOTE: The final parameter tells the GPU the offset in bytes from the
                     // start of the index buffer to the location of the first index to process
                     glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint)));
@@ -3232,7 +3217,7 @@
 
         rlDrawRenderBatch(RLGL.currentBatch);    // NOTE: Stereo rendering is checked inside
 
-        // Restore state of last batch so we can continue adding vertices
+        // Restore state of last batch so new vertices can be added
         RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = currentMode;
         RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = currentTexture;
     }
@@ -3255,6 +3240,7 @@
 #if defined(GRAPHICS_API_OPENGL_11)
     if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)
     {
+        // TODO: Support texture data decompression
         TRACELOG(RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats");
         return id;
     }
@@ -3290,7 +3276,7 @@
         return id;
     }
 #endif
-#endif  // GRAPHICS_API_OPENGL_11
+#endif // GRAPHICS_API_OPENGL_11
 
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
@@ -3353,10 +3339,17 @@
     }
 
     // Texture parameters configuration
-    // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
+    // NOTE: glTexParameteri does NOT affect texture uploading
 #if defined(GRAPHICS_API_OPENGL_ES2)
+
+    // Check if texture is power-of-two (POT)
+    bool texIsPOT = false;
+
+    if (((width > 0) && ((width & (width - 1)) == 0)) &&
+        ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true;
+
     // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used
-    if (RLGL.ExtSupported.texNPOT)
+    if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
     {
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);       // Set texture to repeat on x-axis
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);       // Set texture to repeat on y-axis
@@ -3394,7 +3387,7 @@
     }
 #endif
 
-    // At this point we have the texture loaded in GPU and texture parameters configured
+    // At this point texture is loaded in GPU and texture parameters configured
 
     // NOTE: If mipmaps were not in data, they are not generated automatically
 
@@ -3415,14 +3408,14 @@
     if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    // In case depth textures not supported, we force renderbuffer usage
+    // In case depth textures were not supported, force renderbuffer usage
     if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true;
 
-    // NOTE: We let the implementation to choose the best bit-depth
+    // NOTE: Letting the implementation to choose the best bit-depth
     // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F
     unsigned int glInternalFormat = GL_DEPTH_COMPONENT;
 
-#if (defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_ES3))
+#if defined(GRAPHICS_API_OPENGL_ES2)
     // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT)
     // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities
     if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer)
@@ -3432,6 +3425,13 @@
         else glInternalFormat = GL_DEPTH_COMPONENT16;
     }
 #endif
+#if defined(GRAPHICS_API_OPENGL_ES3)
+    // NOTE: This sized internal format should also work for WebGL 2.0
+    // WARNING: Specification only allows GL_DEPTH_COMPONENT32F for GL_FLOAT type
+    // REF: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
+    if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24;
+    else glInternalFormat = GL_DEPTH_COMPONENT16;
+#endif
 
     if (!useRenderBuffer && RLGL.ExtSupported.texDepth)
     {
@@ -3460,6 +3460,13 @@
 
         TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16);
     }
+#elif defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    // NOTE: Renderbuffers are the same type of object as textures in rlsw
+    // WARNING: Ensure that the depth format is the one specified at rlsw compilation
+    glGenRenderbuffers(1, &id);
+    glBindRenderbuffer(GL_RENDERBUFFER, id);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height);
+    glBindRenderbuffer(GL_RENDERBUFFER, 0);
 #endif
 
     return id;
@@ -3564,7 +3571,7 @@
 }
 
 // Update already loaded texture in GPU with new data
-// NOTE: We don't know safely if internal texture format is the expected one...
+// WARNING: Not possible to know safely if internal texture format is the expected one...
 void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data)
 {
     glBindTexture(GL_TEXTURE_2D, id);
@@ -3613,7 +3620,7 @@
         case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break;
         case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break;
         case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break;
-        #else // defined(GRAPHICS_API_OPENGL_ES2)
+        #else // GRAPHICS_API_OPENGL_ES2
         case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break;   // NOTE: Requires extension OES_texture_half_float
         case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break;         // NOTE: Requires extension OES_texture_half_float
         case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break;    // NOTE: Requires extension OES_texture_half_float
@@ -3662,6 +3669,8 @@
 // NOTE: Only supports GPU mipmap generation
 void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps)
 {
+    if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return; }
+
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     glBindTexture(GL_TEXTURE_2D, id);
 
@@ -3698,7 +3707,7 @@
 #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
     glBindTexture(GL_TEXTURE_2D, id);
 
-    // NOTE: Using texture id, we can retrieve some texture info (but not on OpenGL ES 2.0)
+    // NOTE: Using texture id, some texture info can be retrieved (but not on OpenGL ES 2.0)
     // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
     //int width, height, format;
     //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
@@ -3731,7 +3740,7 @@
     // Two possible Options:
     // 1 - Bind texture to color fbo attachment and glReadPixels()
     // 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
-    // We are using Option 1, just need to care for texture format on retrieval
+    // Using Option 1, care for texture format on retrieval
     // NOTE: This behaviour could be conditioned by graphic driver...
     unsigned int fboId = rlLoadFramebuffer();
 
@@ -3741,9 +3750,17 @@
     // Attach our texture to FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0);
 
-    // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format
+#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(rlGetPixelDataSize(width, height, format));
+    unsigned int glInternalFormat = 0, glFormat = 0, glType = 0;
+    rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
+    glReadPixels(0, 0, width, height, glFormat, glType, pixels);
+#endif
 
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
@@ -3757,18 +3774,18 @@
 // Copy framebuffer pixel data to internal buffer
 void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels)
 {
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
     unsigned int glInternalFormat, glFormat, glType;
     rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format
-    swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels);
+    swReadPixels(x, y, width, height, glFormat, glType, pixels);
 #endif
 }
 
 // Resize internal framebuffer
 void rlResizeFramebuffer(int width, int height)
 {
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
-    swResizeFramebuffer(width, height);
+#if defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    swResize(width, height);
 #endif
 }
 
@@ -3777,12 +3794,16 @@
 {
     unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
 
-    // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
-    // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly!
+    // 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);
 
-    // Flip image vertically!
-    // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
+    // Flip image vertically
+    // NOTE: Alpha value has already been applied to RGB in framebuffer, not needed anymore
     for (int y = height - 1; y >= height/2; y--)
     {
         for (int x = 0; x < (width*4); x += 4)
@@ -3818,20 +3839,20 @@
     unsigned int fboId = 0;
     if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; }
 
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
-    glGenFramebuffers(1, &fboId);       // Create the framebuffer object
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);   // Unbind any framebuffer
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
+    glGenFramebuffers(1, &fboId);         // Create the framebuffer object
+    glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer
 #endif
 
     return fboId;
 }
 
-// Attach color buffer texture to an fbo (unloads previous attachment)
+// Attach color buffer texture to a framebuffer object (unloads previous attachment)
 // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture
-void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel)
+void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel)
 {
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
-    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
+    glBindFramebuffer(GL_FRAMEBUFFER, id);
 
     switch (attachType)
     {
@@ -3870,7 +3891,7 @@
 {
     bool result = false;
 
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     glBindFramebuffer(GL_FRAMEBUFFER, id);
 
     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -3901,15 +3922,15 @@
 // NOTE: All attached textures/cubemaps/renderbuffers are also deleted
 void rlUnloadFramebuffer(unsigned int id)
 {
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE))
     // Query depth attachment to automatically delete texture/renderbuffer
-    int depthType = 0, depthId = 0;
+    int depthType = 0;
     glBindFramebuffer(GL_FRAMEBUFFER, id);   // Bind framebuffer to query depth texture type
     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType);
 
-    // TODO: Review warning retrieving object name in WebGL
     // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name
     // REF: https://registry.khronos.org/webgl/specs/latest/1.0/
+    int depthId = 0;
     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId);
 
     unsigned int depthIdU = (unsigned int)depthId;
@@ -4168,11 +4189,76 @@
 
 // Shaders management
 //-----------------------------------------------------------------------------------------------
-// Load shader from code strings
+// Load (compile) shader and return shader id
+unsigned int rlLoadShader(const char *code, int type)
+{
+    unsigned int shaderId = 0;
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    shaderId = glCreateShader(type);
+    glShaderSource(shaderId, 1, &code, NULL);
+
+    GLint success = 0;
+    glCompileShader(shaderId);
+    glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success);
+
+    if (success == GL_FALSE)
+    {
+        switch (type)
+        {
+            case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shaderId); break;
+            case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shaderId); break;
+            //case GL_GEOMETRY_SHADER:
+        #if defined(GRAPHICS_API_OPENGL_43)
+            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shaderId); break;
+        #elif defined(GRAPHICS_API_OPENGL_33)
+            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break;
+        #endif
+            default: break;
+        }
+
+        int maxLength = 0;
+        glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength);
+
+        if (maxLength > 0)
+        {
+            int length = 0;
+            char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
+            glGetShaderInfoLog(shaderId, maxLength, &length, log);
+            TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shaderId, log);
+            RL_FREE(log);
+        }
+
+        // Unload object allocated by glCreateShader(),
+        // despite failing in the compilation process
+        glDeleteShader(shaderId);
+        shaderId = 0;
+    }
+    else
+    {
+        switch (type)
+        {
+            case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shaderId); break;
+            case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shaderId); break;
+            //case GL_GEOMETRY_SHADER:
+        #if defined(GRAPHICS_API_OPENGL_43)
+            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shaderId); break;
+        #elif defined(GRAPHICS_API_OPENGL_33)
+            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break;
+        #endif
+            default: break;
+        }
+    }
+#endif
+
+    return shaderId;
+}
+
+// Load shader program from code strings
 // NOTE: If shader string is NULL, using default vertex/fragment shaders
-unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
+unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode)
 {
-    unsigned int id = 0;
+    unsigned int id = 0; // Shader program id
     if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
@@ -4181,23 +4267,23 @@
 
     // Compile vertex shader (if provided)
     // NOTE: If not vertex shader is provided, use default one
-    if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);
+    if (vsCode != NULL) vertexShaderId = rlLoadShader(vsCode, GL_VERTEX_SHADER);
     else vertexShaderId = RLGL.State.defaultVShaderId;
 
     // Compile fragment shader (if provided)
     // NOTE: If not vertex shader is provided, use default one
-    if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER);
+    if (fsCode != NULL) fragmentShaderId = rlLoadShader(fsCode, GL_FRAGMENT_SHADER);
     else fragmentShaderId = RLGL.State.defaultFShaderId;
 
-    // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id
+    // In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id
     if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId;
     else if ((vertexShaderId > 0) && (fragmentShaderId > 0))
     {
-        // One of or both shader are new, we need to compile a new shader program
-        id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId);
+        // One of or both shader are new, a new shader program needs to be compiled
+        id = rlLoadShaderProgramEx(vertexShaderId, fragmentShaderId);
 
-        // We can detach and delete vertex/fragment shaders (if not default ones)
-        // NOTE: We detach shader before deletion to make sure memory is freed
+        // Detaching and deleting vertex/fragment shaders (if not default ones)
+        // WARNING: Detach shader before deletion to make sure memory is freed
         if (vertexShaderId != RLGL.State.defaultVShaderId)
         {
             // WARNING: Shader program linkage could fail and returned id is 0
@@ -4211,10 +4297,10 @@
             glDeleteShader(fragmentShaderId);
         }
 
-        // In case shader program loading failed, we assign default shader
+        // In case shader program loading failed, assign default shader
         if (id == 0)
         {
-            // In case shader loading fails, we return the default shader
+            // In case shader loading fails, reassigning default shader
             TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader");
             id = RLGL.State.defaultShaderId;
         }
@@ -4247,99 +4333,81 @@
     return id;
 }
 
-// Compile custom shader and return shader id
-unsigned int rlCompileShader(const char *shaderCode, int type)
+// Load shader program from already loaded shader ids
+unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId)
 {
-    unsigned int shaderId = 0;
+    unsigned int programId = 0;
+    if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; }
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    shaderId = glCreateShader(type);
-    glShaderSource(shaderId, 1, &shaderCode, NULL);
-
     GLint success = 0;
-    glCompileShader(shaderId);
-    glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success);
+    programId = glCreateProgram();
 
+    glAttachShader(programId, vsId);
+    glAttachShader(programId, fsId);
+
+    // Default attribute shader locations must be bound before linking
+    // NOTE: There is no problem with binding a generic attribute index to an attribute variable name
+    // that is never used; if some attrib name is no found on the shader, it locations becomes -1
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES);
+    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
+
+    glLinkProgram(programId);
+
+    // NOTE: All uniform variables are intitialised to 0 when a program links
+
+    glGetProgramiv(programId, GL_LINK_STATUS, &success);
+
     if (success == GL_FALSE)
     {
-        switch (type)
-        {
-            case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shaderId); break;
-            case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shaderId); break;
-            //case GL_GEOMETRY_SHADER:
-        #if defined(GRAPHICS_API_OPENGL_43)
-            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shaderId); break;
-        #elif defined(GRAPHICS_API_OPENGL_33)
-            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break;
-        #endif
-            default: break;
-        }
+        TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", programId);
 
         int maxLength = 0;
-        glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength);
+        glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength);
 
         if (maxLength > 0)
         {
             int length = 0;
             char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
-            glGetShaderInfoLog(shaderId, maxLength, &length, log);
-            TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shaderId, log);
+            glGetProgramInfoLog(programId, maxLength, &length, log);
+            TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log);
             RL_FREE(log);
         }
 
-        // Unload object allocated by glCreateShader(),
-        // despite failing in the compilation process
-        glDeleteShader(shaderId);
-        shaderId = 0;
+        glDeleteProgram(programId);
+
+        programId = 0;
     }
     else
     {
-        switch (type)
-        {
-            case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shaderId); break;
-            case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shaderId); break;
-            //case GL_GEOMETRY_SHADER:
-        #if defined(GRAPHICS_API_OPENGL_43)
-            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shaderId); break;
-        #elif defined(GRAPHICS_API_OPENGL_33)
-            case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break;
-        #endif
-            default: break;
-        }
+        // Get the size of compiled shader program (not available on OpenGL ES 2.0)
+        // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero
+        //GLint binarySize = 0;
+        //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize);
+
+        TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", programId);
     }
 #endif
-
-    return shaderId;
+    return programId;
 }
 
-// Load custom shader strings and return program id
-unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
+// Load compute shader program
+unsigned int rlLoadShaderProgramCompute(unsigned int csId)
 {
     unsigned int programId = 0;
-    if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; }
 
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_43)
     GLint success = 0;
     programId = glCreateProgram();
 
-    glAttachShader(programId, vShaderId);
-    glAttachShader(programId, fShaderId);
-
-    // NOTE: Default attribute shader locations must be Bound before linking
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX);
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);
-    glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
-#endif
-
-    // NOTE: If some attrib name is no found on the shader, it locations becomes -1
+    glAttachShader(programId, csId);
 
     glLinkProgram(programId);
 
@@ -4349,7 +4417,7 @@
 
     if (success == GL_FALSE)
     {
-        TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", programId);
+        TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId);
 
         int maxLength = 0;
         glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength);
@@ -4374,12 +4442,25 @@
         //GLint binarySize = 0;
         //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize);
 
-        TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", programId);
+        TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId);
     }
+#else
+    TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not supported, enable GRAPHICS_API_OPENGL_43");
 #endif
+
     return programId;
 }
 
+// Delete shader
+void rlUnloadShader(unsigned int id)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    glDeleteShader(id);
+
+    TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader data from VRAM (GPU)", id);
+#endif
+}
+
 // Unload shader program
 void rlUnloadShaderProgram(unsigned int id)
 {
@@ -4392,11 +4473,11 @@
 
 // Get shader location uniform
 // NOTE: First parameter refers to shader program id
-int rlGetLocationUniform(unsigned int shaderId, const char *uniformName)
+int rlGetLocationUniform(unsigned int id, const char *uniformName)
 {
     int location = -1;
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    location = glGetUniformLocation(shaderId, uniformName);
+    location = glGetUniformLocation(id, uniformName);
 
     //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName);
     //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location);
@@ -4406,11 +4487,11 @@
 
 // Get shader location attribute
 // NOTE: First parameter refers to shader program id
-int rlGetLocationAttrib(unsigned int shaderId, const char *attribName)
+int rlGetLocationAttrib(unsigned int id, const char *attribName)
 {
     int location = -1;
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    location = glGetAttribLocation(shaderId, attribName);
+    location = glGetAttribLocation(id, attribName);
 
     //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName);
     //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location);
@@ -4463,13 +4544,7 @@
 void rlSetUniformMatrix(int locIndex, Matrix mat)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    float matfloat[16] = {
-        mat.m0, mat.m1, mat.m2, mat.m3,
-        mat.m4, mat.m5, mat.m6, mat.m7,
-        mat.m8, mat.m9, mat.m10, mat.m11,
-        mat.m12, mat.m13, mat.m14, mat.m15
-    };
-    glUniformMatrix4fv(locIndex, 1, false, matfloat);
+    glUniformMatrix4fv(locIndex, 1, false, rlMatrixToFloat(mat));
 #endif
 }
 
@@ -4526,57 +4601,6 @@
 #endif
 }
 
-// Load compute shader program
-unsigned int rlLoadComputeShaderProgram(unsigned int shaderId)
-{
-    unsigned int programId = 0;
-
-#if defined(GRAPHICS_API_OPENGL_43)
-    GLint success = 0;
-    programId = glCreateProgram();
-    glAttachShader(programId, shaderId);
-    glLinkProgram(programId);
-
-    // NOTE: All uniform variables are intitialised to 0 when a program links
-
-    glGetProgramiv(programId, GL_LINK_STATUS, &success);
-
-    if (success == GL_FALSE)
-    {
-        TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId);
-
-        int maxLength = 0;
-        glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength);
-
-        if (maxLength > 0)
-        {
-            int length = 0;
-            char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
-            glGetProgramInfoLog(programId, maxLength, &length, log);
-            TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log);
-            RL_FREE(log);
-        }
-
-        glDeleteProgram(programId);
-
-        programId = 0;
-    }
-    else
-    {
-        // Get the size of compiled shader program (not available on OpenGL ES 2.0)
-        // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero
-        //GLint binarySize = 0;
-        //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize);
-
-        TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId);
-    }
-#else
-    TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43");
-#endif
-
-    return programId;
-}
-
 // Dispatch compute shader (equivalent to *draw* for graphics pilepine)
 void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ)
 {
@@ -4611,7 +4635,6 @@
 #else
     TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43");
 #endif
-
 }
 
 // Update SSBO buffer data
@@ -4626,14 +4649,14 @@
 // Get SSBO buffer size
 unsigned int rlGetShaderBufferSize(unsigned int id)
 {
+    unsigned int result = 0;
 #if defined(GRAPHICS_API_OPENGL_43)
     GLint64 size = 0;
     glBindBuffer(GL_SHADER_STORAGE_BUFFER, id);
     glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size);
-    return (size > 0)? (unsigned int)size : 0;
-#else
-    return 0;
+    if (size > 0) result = (unsigned int)size;
 #endif
+    return result;
 }
 
 // Read SSBO buffer data (GPU->CPU)
@@ -4742,9 +4765,9 @@
     Matrix mat = rlMatrixIdentity();
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     // TODO: Consider possible transform matrices in the RLGL.State.stack
-    // Is this the right order? or should we start with the first stored matrix instead of the last one?
     //Matrix matStackTransform = rlMatrixIdentity();
     //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = rlMatrixMultiply(RLGL.State.stack[i], matStackTransform);
+
     mat = RLGL.State.transform;
 #endif
     return mat;
@@ -5070,10 +5093,10 @@
 
     // NOTE: Compiled vertex/fragment shaders are not deleted,
     // they are kept for re-use as default shaders in case some shader loading fails
-    RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER);     // Compile default vertex shader
-    RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER);   // Compile default fragment shader
+    RLGL.State.defaultVShaderId = rlLoadShader(defaultVShaderCode, GL_VERTEX_SHADER);     // Compile default vertex shader
+    RLGL.State.defaultFShaderId = rlLoadShader(defaultFShaderCode, GL_FRAGMENT_SHADER);   // Compile default fragment shader
 
-    RLGL.State.defaultShaderId = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId);
+    RLGL.State.defaultShaderId = rlLoadShaderProgramEx(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId);
 
     if (RLGL.State.defaultShaderId > 0)
     {
@@ -5110,7 +5133,7 @@
     TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId);
 }
 
-#if defined(RLGL_SHOW_GL_DETAILS_INFO)
+#if RLGL_SHOW_GL_DETAILS_INFO
 // Get compressed format official GL identifier name
 static const char *rlGetCompressedFormatName(int format)
 {
@@ -5184,9 +5207,9 @@
         default: return "GL_COMPRESSED_UNKNOWN"; break;
     }
 }
-#endif  // RLGL_SHOW_GL_DETAILS_INFO
+#endif
 
-#endif  // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
 
 // Get pixel data size in bytes (image or texture)
 // NOTE: Size depends on pixel format
@@ -5219,7 +5242,9 @@
         {
             int blockWidth = (width + 3)/4;
             int blockHeight = (height + 3)/4;
-            dataSize = blockWidth*blockHeight*8;
+            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:
@@ -5228,13 +5253,17 @@
         {
             int blockWidth = (width + 3)/4;
             int blockHeight = (height + 3)/4;
-            dataSize = blockWidth*blockHeight*16;
+            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
         {
             int blockWidth = (width + 3)/4;
             int blockHeight = (height + 3)/4;
-            dataSize = blockWidth*blockHeight*4;
+            unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*4;
+            if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
+
         } break;
         default: break;
     }
@@ -5243,10 +5272,12 @@
     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 = ((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;
 }
 
@@ -5255,17 +5286,17 @@
 // Get identity matrix
 static Matrix rlMatrixIdentity(void)
 {
-    Matrix result = {
-        1.0f, 0.0f, 0.0f, 0.0f,
-        0.0f, 1.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 1.0f, 0.0f,
-        0.0f, 0.0f, 0.0f, 1.0f
-    };
+    Matrix matIdentity = { 0 };
+    matIdentity.m0 = 1.0f;
+    matIdentity.m5 = 1.0f;
+    matIdentity.m10 = 1.0f;
+    matIdentity.m15 = 1.0f;
 
-    return result;
+    return matIdentity;
 }
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 // Get float array of matrix data
+// Explicit conversion to column-major memory layout
 static rl_float16 rlMatrixToFloatV(Matrix mat)
 {
     rl_float16 result = { 0 };
@@ -5389,4 +5420,4 @@
 }
 #endif
 
-#endif  // RLGL_IMPLEMENTATION
+#endif // RLGL_IMPLEMENTATION
diff --git a/raylib/src/rmodels.c b/raylib/src/rmodels.c
--- a/raylib/src/rmodels.c
+++ b/raylib/src/rmodels.c
@@ -3,7127 +3,7357 @@
 *   rmodels - Basic functions to draw 3d shapes and load and draw 3d models
 *
 *   CONFIGURATION:
-*       #define SUPPORT_MODULE_RMODELS
-*           rmodels module is included in the build
-*
-*       #define SUPPORT_FILEFORMAT_OBJ
-*       #define SUPPORT_FILEFORMAT_MTL
-*       #define SUPPORT_FILEFORMAT_IQM
-*       #define SUPPORT_FILEFORMAT_GLTF
-*       #define SUPPORT_FILEFORMAT_VOX
-*       #define SUPPORT_FILEFORMAT_M3D
-*           Selected desired fileformats to be supported for model data loading
-*
-*       #define SUPPORT_MESH_GENERATION
-*           Support procedural mesh generation functions, uses external par_shapes.h library
-*           NOTE: Some generated meshes DO NOT include generated texture coordinates
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   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.
-*
-**********************************************************************************************/
-
-#include "raylib.h"         // Declares module functions
-
-#include "config.h"         // Defines module configuration flags
-
-#if defined(SUPPORT_MODULE_RMODELS)
-
-#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 <stdio.h>          // Required for: sprintf()
-#include <stdlib.h>         // Required for: malloc(), calloc(), free()
-#include <string.h>         // Required for: memcmp(), strlen(), strncpy()
-#include <math.h>           // Required for: sinf(), cosf(), sqrtf(), fabsf()
-
-#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
-    #define TINYOBJ_MALLOC RL_MALLOC
-    #define TINYOBJ_CALLOC RL_CALLOC
-    #define TINYOBJ_REALLOC RL_REALLOC
-    #define TINYOBJ_FREE RL_FREE
-
-    #define TINYOBJ_LOADER_C_IMPLEMENTATION
-    #include "external/tinyobj_loader_c.h"      // OBJ/MTL file formats loading
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_GLTF)
-    #define CGLTF_MALLOC RL_MALLOC
-    #define CGLTF_FREE RL_FREE
-
-    #define CGLTF_IMPLEMENTATION
-    #include "external/cgltf.h"         // glTF file format loading
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_VOX)
-    #define VOX_MALLOC RL_MALLOC
-    #define VOX_CALLOC RL_CALLOC
-    #define VOX_REALLOC RL_REALLOC
-    #define VOX_FREE RL_FREE
-
-    #define VOX_LOADER_IMPLEMENTATION
-    #include "external/vox_loader.h"    // VOX file format loading (MagikaVoxel)
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_M3D)
-    #define M3D_MALLOC RL_MALLOC
-    #define M3D_REALLOC RL_REALLOC
-    #define M3D_FREE RL_FREE
-
-    #define M3D_IMPLEMENTATION
-    #include "external/m3d.h"           // Model3D file format loading
-#endif
-
-#if defined(SUPPORT_MESH_GENERATION)
-    #define PAR_MALLOC(T, N) ((T *)RL_MALLOC(N*sizeof(T)))
-    #define PAR_CALLOC(T, N) ((T *)RL_CALLOC(N*sizeof(T), 1))
-    #define PAR_REALLOC(T, BUF, N) ((T *)RL_REALLOC(BUF, sizeof(T)*(N)))
-    #define PAR_FREE RL_FREE
-
-    #if defined(_MSC_VER)           // Disable some MSVC warning
-        #pragma warning(push)
-        #pragma warning(disable : 4244)
-        #pragma warning(disable : 4305)
-    #endif
-
-    #define PAR_SHAPES_IMPLEMENTATION
-    #include "external/par_shapes.h"    // Shapes 3d parametric generation
-
-    #if defined(_MSC_VER)
-        #pragma warning(pop)        // Disable MSVC warning suppression
-    #endif
-#endif
-
-#if defined(_WIN32)
-    #include <direct.h>     // Required for: _chdir() [Used in LoadOBJ()]
-    #define CHDIR _chdir
-#else
-    #include <unistd.h>     // Required for: chdir() (POSIX) [Used in LoadOBJ()]
-    #define CHDIR chdir
-#endif
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#ifndef MAX_MATERIAL_MAPS
-    #define MAX_MATERIAL_MAPS       12      // Maximum number of maps supported
-#endif
-#ifndef MAX_MESH_VERTEX_BUFFERS
-    #define MAX_MESH_VERTEX_BUFFERS  9      // Maximum vertex buffers (VBO) per mesh
-#endif
-#ifndef MAX_FILEPATH_LENGTH
-    #define MAX_FILEPATH_LENGTH   4096      // Maximum length for filepaths (Linux PATH_MAX default value)
-#endif
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-#if defined(SUPPORT_FILEFORMAT_OBJ)
-static Model LoadOBJ(const char *fileName);     // Load OBJ mesh data
-#endif
-#if defined(SUPPORT_FILEFORMAT_IQM)
-static Model LoadIQM(const char *fileName);     // Load IQM mesh data
-static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount);   // Load IQM animation data
-#endif
-#if defined(SUPPORT_FILEFORMAT_GLTF)
-static Model LoadGLTF(const char *fileName);    // Load GLTF mesh data
-static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount);  // Load GLTF animation data
-#endif
-#if defined(SUPPORT_FILEFORMAT_VOX)
-static Model LoadVOX(const char *filename);     // Load VOX mesh data
-#endif
-#if defined(SUPPORT_FILEFORMAT_M3D)
-static Model LoadM3D(const char *filename);     // Load M3D mesh data
-static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount);   // Load M3D animation data
-#endif
-#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
-static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount);  // Process obj materials
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-// Draw a line in 3D world space
-void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
-{
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex3f(startPos.x, startPos.y, startPos.z);
-        rlVertex3f(endPos.x, endPos.y, endPos.z);
-    rlEnd();
-}
-
-// Draw a point in 3D space, actually a small line
-// WARNING: OpenGL ES 2.0 does not support point mode drawing
-void DrawPoint3D(Vector3 position, Color color)
-{
-    rlPushMatrix();
-        rlTranslatef(position.x, position.y, position.z);
-        rlBegin(RL_LINES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex3f(0.0f, 0.0f, 0.0f);
-            rlVertex3f(0.0f, 0.0f, 0.1f);
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a circle in 3D world space
-void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
-{
-    rlPushMatrix();
-        rlTranslatef(center.x, center.y, center.z);
-        rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
-
-        rlBegin(RL_LINES);
-            for (int i = 0; i < 360; i += 10)
-            {
-                rlColor4ub(color.r, color.g, color.b, color.a);
-
-                rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f);
-                rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f);
-            }
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a color-filled triangle (vertex in counter-clockwise order!)
-void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
-{
-    rlBegin(RL_TRIANGLES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex3f(v1.x, v1.y, v1.z);
-        rlVertex3f(v2.x, v2.y, v2.z);
-        rlVertex3f(v3.x, v3.y, v3.z);
-    rlEnd();
-}
-
-// Draw a triangle strip defined by points
-void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color)
-{
-    if (pointCount < 3) return; // Security check
-
-    rlBegin(RL_TRIANGLES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        for (int i = 2; i < pointCount; i++)
-        {
-            if ((i%2) == 0)
-            {
-                rlVertex3f(points[i].x, points[i].y, points[i].z);
-                rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
-                rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
-            }
-            else
-            {
-                rlVertex3f(points[i].x, points[i].y, points[i].z);
-                rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
-                rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
-            }
-        }
-    rlEnd();
-}
-
-// Draw cube
-// NOTE: Cube position is the center position
-void DrawCube(Vector3 position, float width, float height, float length, Color color)
-{
-    float x = 0.0f;
-    float y = 0.0f;
-    float z = 0.0f;
-
-    rlPushMatrix();
-        // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
-        rlTranslatef(position.x, position.y, position.z);
-        //rlRotatef(45, 0, 1, 0);
-        //rlScalef(1.0f, 1.0f, 1.0f);   // NOTE: Vertices are directly scaled on definition
-
-        rlBegin(RL_TRIANGLES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            // Front face
-            rlNormal3f(0.0f, 0.0f, 1.0f);
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
-
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Right
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
-
-            // Back face
-            rlNormal3f(0.0f, 0.0f, -1.0f);
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Left
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
-
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
-
-            // Top face
-            rlNormal3f(0.0f, 1.0f, 0.0f);
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Bottom Left
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
-
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
-
-            // Bottom face
-            rlNormal3f(0.0f, -1.0f, 0.0f);
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
-
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top Right
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
-
-            // Right face
-            rlNormal3f(1.0f, 0.0f, 0.0f);
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
-
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Left
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
-
-            // Left face
-            rlNormal3f(-1.0f, 0.0f, 0.0f);
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Right
-
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw cube (Vector version)
-void DrawCubeV(Vector3 position, Vector3 size, Color color)
-{
-    DrawCube(position, size.x, size.y, size.z, color);
-}
-
-// Draw cube wires
-void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
-{
-    float x = 0.0f;
-    float y = 0.0f;
-    float z = 0.0f;
-
-    rlPushMatrix();
-        rlTranslatef(position.x, position.y, position.z);
-
-        rlBegin(RL_LINES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            // Front face
-            //------------------------------------------------------------------
-            // Bottom line
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
-
-            // Left line
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
-
-            // Top line
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
-
-            // Right line
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
-
-            // Back face
-            //------------------------------------------------------------------
-            // Bottom line
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
-
-            // Left line
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
-
-            // Top line
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
-
-            // Right line
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
-
-            // Top face
-            //------------------------------------------------------------------
-            // Left line
-            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left front
-            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left back
-
-            // Right line
-            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right front
-            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right back
-
-            // Bottom face
-            //------------------------------------------------------------------
-            // Left line
-            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Top left front
-            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top left back
-
-            // Right line
-            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Top right front
-            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top right back
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw cube wires (vector version)
-void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
-{
-    DrawCubeWires(position, size.x, size.y, size.z, color);
-}
-
-// Draw sphere
-void DrawSphere(Vector3 centerPos, float radius, Color color)
-{
-    DrawSphereEx(centerPos, radius, 16, 16, color);
-}
-
-// Draw sphere with extended parameters
-void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
-{
-#if 0
-    // Basic implementation, do not use it!
-    // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls!
-    // New optimized version below only requires 4 cos()/sin() calls
-
-    rlPushMatrix();
-        // NOTE: Transformation is applied in inverse order (scale -> translate)
-        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        rlScalef(radius, radius, radius);
-
-        rlBegin(RL_TRIANGLES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            for (int i = 0; i < (rings + 2); 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)));
-                    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)));
-                    rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
-                               sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))),
-                               cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/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)));
-                }
-            }
-        rlEnd();
-    rlPopMatrix();
-#endif
-
-    rlPushMatrix();
-        // NOTE: Transformation is applied in inverse order (scale -> translate)
-        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        rlScalef(radius, radius, radius);
-
-        rlBegin(RL_TRIANGLES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            float ringangle = DEG2RAD*(180.0f/(rings + 1)); // 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 + 1; i++)
-            {
-                for (int j = 0; j < slices; j++)
-                {
-                    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 };
-
-                    rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
-                    rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
-                    rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
-                    rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
-                    rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z);
-                    rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
-
-                    rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
-                    rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
-                    rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z);
-                    rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
-                    rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].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();
-}
-
-// Draw sphere wires
-void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
-{
-    rlPushMatrix();
-        // NOTE: Transformation is applied in inverse order (scale -> translate)
-        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        rlScalef(radius, radius, radius);
-
-        rlBegin(RL_LINES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            for (int i = 0; i < (rings + 2); 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)));
-
-                    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)));
-
-                    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)));
-                }
-            }
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a cylinder
-// NOTE: It could be also used for pyramid and cone
-void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
-{
-    if (sides < 3) sides = 3;
-
-    const float angleStep = 360.0f/sides;
-
-    rlPushMatrix();
-        rlTranslatef(position.x, position.y, position.z);
-
-        rlBegin(RL_TRIANGLES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            if (radiusTop > 0)
-            {
-                // Draw Body -------------------------------------------------------------------------------------
-                for (int i = 0; i < sides; i++)
-                {
-                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
-                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); //Bottom Right
-                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
-
-                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); //Top Left
-                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
-                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
-                }
-
-                // Draw Cap --------------------------------------------------------------------------------------
-                for (int i = 0; i < sides; i++)
-                {
-                    rlVertex3f(0, height, 0);
-                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
-                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
-                }
-            }
-            else
-            {
-                // Draw Cone -------------------------------------------------------------------------------------
-                for (int i = 0; i < sides; i++)
-                {
-                    rlVertex3f(0, height, 0);
-                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
-                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
-                }
-            }
-
-            // Draw Base -----------------------------------------------------------------------------------------
-            for (int i = 0; i < sides; i++)
-            {
-                rlVertex3f(0, 0, 0);
-                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
-                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
-            }
-
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a cylinder with base at startPos and top at endPos
-// NOTE: It could be also used for pyramid and cone
-void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
-{
-    if (sides < 3) sides = 3;
-
-    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
-    if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
-
-    // Construct a basis of the base and the top face:
-    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
-    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
-
-    float baseAngle = (2.0f*PI)/sides;
-
-    rlBegin(RL_TRIANGLES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        for (int i = 0; i < sides; i++)
-        {
-            // Compute the four vertices
-            float s1 = sinf(baseAngle*(i + 0))*startRadius;
-            float c1 = cosf(baseAngle*(i + 0))*startRadius;
-            Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
-            float s2 = sinf(baseAngle*(i + 1))*startRadius;
-            float c2 = cosf(baseAngle*(i + 1))*startRadius;
-            Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
-            float s3 = sinf(baseAngle*(i + 0))*endRadius;
-            float c3 = cosf(baseAngle*(i + 0))*endRadius;
-            Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
-            float s4 = sinf(baseAngle*(i + 1))*endRadius;
-            float c4 = cosf(baseAngle*(i + 1))*endRadius;
-            Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
-
-            if (startRadius > 0)
-            {
-                rlVertex3f(startPos.x, startPos.y, startPos.z); // |
-                rlVertex3f(w2.x, w2.y, w2.z);                   // T0
-                rlVertex3f(w1.x, w1.y, w1.z);                   // |
-            }
-                                                                //          w2 x.-----------x startPos
-            rlVertex3f(w1.x, w1.y, w1.z);                       // |           |\'.  T0    /
-            rlVertex3f(w2.x, w2.y, w2.z);                       // T1          | \ '.     /
-            rlVertex3f(w3.x, w3.y, w3.z);                       // |           |T \  '.  /
-                                                                //             | 2 \ T 'x w1
-            rlVertex3f(w2.x, w2.y, w2.z);                       // |        w4 x.---\-1-|---x endPos
-            rlVertex3f(w4.x, w4.y, w4.z);                       // T2            '.  \  |T3/
-            rlVertex3f(w3.x, w3.y, w3.z);                       // |               '. \ | /
-                                                                //                   '.\|/
-            if (endRadius > 0)                                  //                     'x w3
-            {
-                rlVertex3f(endPos.x, endPos.y, endPos.z);       // |
-                rlVertex3f(w3.x, w3.y, w3.z);                   // T3
-                rlVertex3f(w4.x, w4.y, w4.z);                   // |
-            }                                                   //
-        }
-    rlEnd();
-}
-
-// Draw a wired cylinder
-// NOTE: It could be also used for pyramid and cone
-void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
-{
-    if (sides < 3) sides = 3;
-
-    const float angleStep = 360.0f/sides;
-
-    rlPushMatrix();
-        rlTranslatef(position.x, position.y, position.z);
-
-        rlBegin(RL_LINES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            for (int i = 0; i < sides; i++)
-            {
-                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
-                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
-
-                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
-                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
-
-                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
-                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
-
-                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
-                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
-            }
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a wired cylinder with base at startPos and top at endPos
-// NOTE: It could be also used for pyramid and cone
-void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
-{
-    if (sides < 3) sides = 3;
-
-    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
-    if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
-
-    // Construct a basis of the base and the top face:
-    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
-    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
-
-    float baseAngle = (2.0f*PI)/sides;
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        for (int i = 0; i < sides; i++)
-        {
-            // Compute the four vertices
-            float s1 = sinf(baseAngle*(i + 0))*startRadius;
-            float c1 = cosf(baseAngle*(i + 0))*startRadius;
-            Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
-            float s2 = sinf(baseAngle*(i + 1))*startRadius;
-            float c2 = cosf(baseAngle*(i + 1))*startRadius;
-            Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
-            float s3 = sinf(baseAngle*(i + 0))*endRadius;
-            float c3 = cosf(baseAngle*(i + 0))*endRadius;
-            Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
-            float s4 = sinf(baseAngle*(i + 1))*endRadius;
-            float c4 = cosf(baseAngle*(i + 1))*endRadius;
-            Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
-
-            rlVertex3f(w1.x, w1.y, w1.z);
-            rlVertex3f(w2.x, w2.y, w2.z);
-
-            rlVertex3f(w1.x, w1.y, w1.z);
-            rlVertex3f(w3.x, w3.y, w3.z);
-
-            rlVertex3f(w3.x, w3.y, w3.z);
-            rlVertex3f(w4.x, w4.y, w4.z);
-        }
-    rlEnd();
-}
-
-// Draw a capsule with the center of its sphere caps at startPos and endPos
-void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
-{
-    if (slices < 3) slices = 3;
-
-    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
-
-    // draw a sphere if start and end points are the same
-    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
-    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
-
-    // Construct a basis of the base and the caps:
-    Vector3 b0 = Vector3Normalize(direction);
-    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
-    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
-    Vector3 capCenter = endPos;
-
-    float baseSliceAngle = (2.0f*PI)/slices;
-    float baseRingAngle  = PI*0.5f/rings;
-
-    rlBegin(RL_TRIANGLES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        // render both caps
-        for (int c = 0; c < 2; c++)
-        {
-            for (int i = 0; i < rings; i++)
-            {
-                for (int j = 0; j < slices; j++)
-                {
-
-                    // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
-
-                    // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
-                    // as we iterate through the rings they must get smaller by the cos(angle(i))
-
-                    // compute the four vertices
-                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
-                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
-                    Vector3 w1 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
-                    };
-                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
-                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
-                    Vector3 w2 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
-                    };
-
-                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
-                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
-                    Vector3 w3 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
-                    };
-                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
-                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
-                    Vector3 w4 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
-                    };
-
-                    // Make sure cap triangle normals are facing outwards
-                    if (c == 0)
-                    {
-                        rlVertex3f(w1.x, w1.y, w1.z);
-                        rlVertex3f(w2.x, w2.y, w2.z);
-                        rlVertex3f(w3.x, w3.y, w3.z);
-
-                        rlVertex3f(w2.x, w2.y, w2.z);
-                        rlVertex3f(w4.x, w4.y, w4.z);
-                        rlVertex3f(w3.x, w3.y, w3.z);
-                    }
-                    else
-                    {
-                        rlVertex3f(w1.x, w1.y, w1.z);
-                        rlVertex3f(w3.x, w3.y, w3.z);
-                        rlVertex3f(w2.x, w2.y, w2.z);
-
-                        rlVertex3f(w2.x, w2.y, w2.z);
-                        rlVertex3f(w3.x, w3.y, w3.z);
-                        rlVertex3f(w4.x, w4.y, w4.z);
-                    }
-                }
-            }
-            capCenter = startPos;
-            b0 = Vector3Scale(b0, -1.0f);
-        }
-        // render middle
-        if (!sphereCase)
-        {
-            for (int j = 0; j < slices; j++)
-            {
-                // compute the four vertices
-                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
-                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
-                Vector3 w1 = {
-                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
-                    startPos.y + ringSin1*b1.y + ringCos1*b2.y,
-                    startPos.z + ringSin1*b1.z + ringCos1*b2.z
-                };
-                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
-                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
-                Vector3 w2 = {
-                    startPos.x + ringSin2*b1.x + ringCos2*b2.x,
-                    startPos.y + ringSin2*b1.y + ringCos2*b2.y,
-                    startPos.z + ringSin2*b1.z + ringCos2*b2.z
-                };
-
-                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
-                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
-                Vector3 w3 = {
-                    endPos.x + ringSin3*b1.x + ringCos3*b2.x,
-                    endPos.y + ringSin3*b1.y + ringCos3*b2.y,
-                    endPos.z + ringSin3*b1.z + ringCos3*b2.z
-                };
-                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
-                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
-                Vector3 w4 = {
-                    endPos.x + ringSin4*b1.x + ringCos4*b2.x,
-                    endPos.y + ringSin4*b1.y + ringCos4*b2.y,
-                    endPos.z + ringSin4*b1.z + ringCos4*b2.z
-                };
-                                                                        //          w2 x.-----------x startPos
-                rlVertex3f(w1.x, w1.y, w1.z);                         // |           |\'.  T0    /
-                rlVertex3f(w2.x, w2.y, w2.z);                         // T1          | \ '.     /
-                rlVertex3f(w3.x, w3.y, w3.z);                         // |           |T \  '.  /
-                                                                        //             | 2 \ T 'x w1
-                rlVertex3f(w2.x, w2.y, w2.z);                         // |        w4 x.---\-1-|---x endPos
-                rlVertex3f(w4.x, w4.y, w4.z);                         // T2            '.  \  |T3/
-                rlVertex3f(w3.x, w3.y, w3.z);                         // |               '. \ | /
-                                                                        //                   '.\|/
-                                                                        //                   'x w3
-            }
-        }
-    rlEnd();
-}
-
-// Draw capsule wires with the center of its sphere caps at startPos and endPos
-void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
-{
-    if (slices < 3) slices = 3;
-
-    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
-
-    // draw a sphere if start and end points are the same
-    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
-    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
-
-    // Construct a basis of the base and the caps:
-    Vector3 b0 = Vector3Normalize(direction);
-    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
-    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
-    Vector3 capCenter = endPos;
-
-    float baseSliceAngle = (2.0f*PI)/slices;
-    float baseRingAngle  = PI*0.5f/rings;
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        // render both caps
-        for (int c = 0; c < 2; c++)
-        {
-            for (int i = 0; i < rings; i++)
-            {
-                for (int j = 0; j < slices; j++)
-                {
-
-                    // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
-
-                    // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
-                    // as we iterate through the rings they must get smaller by the cos(angle(i))
-
-                    // compute the four vertices
-                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
-                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
-                    Vector3 w1 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
-                    };
-                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
-                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
-                    Vector3 w2 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
-                    };
-
-                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
-                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
-                    Vector3 w3 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
-                    };
-                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
-                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
-                    Vector3 w4 = (Vector3){
-                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
-                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
-                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
-                    };
-
-                    rlVertex3f(w1.x, w1.y, w1.z);
-                    rlVertex3f(w2.x, w2.y, w2.z);
-
-                    rlVertex3f(w2.x, w2.y, w2.z);
-                    rlVertex3f(w3.x, w3.y, w3.z);
-
-                    rlVertex3f(w1.x, w1.y, w1.z);
-                    rlVertex3f(w3.x, w3.y, w3.z);
-
-                    rlVertex3f(w2.x, w2.y, w2.z);
-                    rlVertex3f(w4.x, w4.y, w4.z);
-
-                    rlVertex3f(w3.x, w3.y, w3.z);
-                    rlVertex3f(w4.x, w4.y, w4.z);
-                }
-            }
-            capCenter = startPos;
-            b0 = Vector3Scale(b0, -1.0f);
-        }
-        // render middle
-        if (!sphereCase)
-        {
-            for (int j = 0; j < slices; j++)
-            {
-                // compute the four vertices
-                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
-                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
-                Vector3 w1 = {
-                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
-                    startPos.y + ringSin1*b1.y + ringCos1*b2.y,
-                    startPos.z + ringSin1*b1.z + ringCos1*b2.z
-                };
-                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
-                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
-                Vector3 w2 = {
-                    startPos.x + ringSin2*b1.x + ringCos2*b2.x,
-                    startPos.y + ringSin2*b1.y + ringCos2*b2.y,
-                    startPos.z + ringSin2*b1.z + ringCos2*b2.z
-                };
-
-                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
-                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
-                Vector3 w3 = {
-                    endPos.x + ringSin3*b1.x + ringCos3*b2.x,
-                    endPos.y + ringSin3*b1.y + ringCos3*b2.y,
-                    endPos.z + ringSin3*b1.z + ringCos3*b2.z
-                };
-                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
-                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
-                Vector3 w4 = {
-                    endPos.x + ringSin4*b1.x + ringCos4*b2.x,
-                    endPos.y + ringSin4*b1.y + ringCos4*b2.y,
-                    endPos.z + ringSin4*b1.z + ringCos4*b2.z
-                };
-
-                rlVertex3f(w1.x, w1.y, w1.z);
-                rlVertex3f(w3.x, w3.y, w3.z);
-
-                rlVertex3f(w2.x, w2.y, w2.z);
-                rlVertex3f(w4.x, w4.y, w4.z);
-
-                rlVertex3f(w2.x, w2.y, w2.z);
-                rlVertex3f(w3.x, w3.y, w3.z);
-            }
-        }
-    rlEnd();
-}
-
-// Draw a plane
-void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
-{
-    // NOTE: Plane is always created on XZ ground
-    rlPushMatrix();
-        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        rlScalef(size.x, 1.0f, size.y);
-
-        rlBegin(RL_QUADS);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlNormal3f(0.0f, 1.0f, 0.0f);
-
-            rlVertex3f(-0.5f, 0.0f, -0.5f);
-            rlVertex3f(-0.5f, 0.0f, 0.5f);
-            rlVertex3f(0.5f, 0.0f, 0.5f);
-            rlVertex3f(0.5f, 0.0f, -0.5f);
-        rlEnd();
-    rlPopMatrix();
-}
-
-// Draw a ray line
-void DrawRay(Ray ray, Color color)
-{
-    float scale = 10000;
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlVertex3f(ray.position.x, ray.position.y, ray.position.z);
-        rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale);
-    rlEnd();
-}
-
-// Draw a grid centered at (0, 0, 0)
-void DrawGrid(int slices, float spacing)
-{
-    int halfSlices = slices/2;
-
-    rlBegin(RL_LINES);
-        for (int i = -halfSlices; i <= halfSlices; i++)
-        {
-            if (i == 0)
-            {
-                rlColor3f(0.5f, 0.5f, 0.5f);
-            }
-            else
-            {
-                rlColor3f(0.75f, 0.75f, 0.75f);
-            }
-
-            rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
-            rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
-
-            rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
-            rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
-        }
-    rlEnd();
-}
-
-// Load model from files (mesh and material)
-Model LoadModel(const char *fileName)
-{
-    Model model = { 0 };
-
-#if defined(SUPPORT_FILEFORMAT_OBJ)
-    if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName);
-#endif
-#if defined(SUPPORT_FILEFORMAT_IQM)
-    if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
-#endif
-#if defined(SUPPORT_FILEFORMAT_GLTF)
-    if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName);
-#endif
-#if defined(SUPPORT_FILEFORMAT_VOX)
-    if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
-#endif
-#if defined(SUPPORT_FILEFORMAT_M3D)
-    if (IsFileExtension(fileName, ".m3d")) model = LoadM3D(fileName);
-#endif
-
-    // Make sure model transform is set to identity matrix!
-    model.transform = MatrixIdentity();
-
-    if ((model.meshCount != 0) && (model.meshes != NULL))
-    {
-        // Upload vertex data to GPU (static meshes)
-        for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load model mesh(es) data", fileName);
-
-    if (model.materialCount == 0)
-    {
-        TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load model material data, default to white material", fileName);
-
-        model.materialCount = 1;
-        model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
-        model.materials[0] = LoadMaterialDefault();
-
-        if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-    }
-
-    return model;
-}
-
-// Load model from generated mesh
-// WARNING: A shallow copy of mesh is generated, passed by value,
-// as long as struct contains pointers to data and some values, we get a copy
-// of mesh pointing to same data as original version... be careful!
-Model LoadModelFromMesh(Mesh mesh)
-{
-    Model model = { 0 };
-
-    model.transform = MatrixIdentity();
-
-    model.meshCount = 1;
-    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-    model.meshes[0] = mesh;
-
-    model.materialCount = 1;
-    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
-    model.materials[0] = LoadMaterialDefault();
-
-    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-    model.meshMaterial[0] = 0;  // First material index
-
-    return model;
-}
-
-// Check if a model is valid (loaded in GPU, VAO/VBOs)
-bool IsModelValid(Model model)
-{
-    bool result = false;
-
-    if ((model.meshes != NULL) &&           // Validate model contains some mesh
-        (model.materials != NULL) &&        // Validate model contains some material (at least default one)
-        (model.meshMaterial != NULL) &&     // Validate mesh-material linkage
-        (model.meshCount > 0) &&            // Validate mesh count
-        (model.materialCount > 0)) result = true; // Validate material count
-
-    // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs
-    // but some VBOs could not be used, it depends on Mesh vertex data
-    for (int i = 0; i < model.meshCount; i++)
-    {
-        if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; }  // Vertex position buffer not uploaded to GPU
-        if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; }  // Vertex textcoords buffer not uploaded to GPU
-        if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; }  // Vertex normals buffer not uploaded to GPU
-        if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; }  // Vertex colors buffer not uploaded to GPU
-        if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; }  // Vertex tangents buffer not uploaded to GPU
-        if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; }  // Vertex texcoords2 buffer not uploaded to GPU
-        if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; }  // Vertex indices buffer not uploaded to GPU
-        if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; }  // Vertex boneIds buffer not uploaded to GPU
-        if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; }  // Vertex boneWeights buffer not uploaded to GPU
-
-        // NOTE: Some OpenGL versions do not support VAO, so we don't check it
-        //if (model.meshes[i].vaoId == 0) { result = false; break }
-    }
-
-    return result;
-}
-
-// Unload model (meshes/materials) from memory (RAM and/or VRAM)
-// NOTE: This function takes care of all model elements, for a detailed control
-// over them, use UnloadMesh() and UnloadMaterial()
-void UnloadModel(Model model)
-{
-    // Unload meshes
-    for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]);
-
-    // Unload materials maps
-    // NOTE: As the user could be sharing shaders and textures between models,
-    // we don't unload the material but just free its maps,
-    // the user is responsible for freeing models shaders and textures
-    for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
-
-    // Unload arrays
-    RL_FREE(model.meshes);
-    RL_FREE(model.materials);
-    RL_FREE(model.meshMaterial);
-
-    // Unload animation data
-    RL_FREE(model.bones);
-    RL_FREE(model.bindPose);
-
-    TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
-}
-
-// Compute model bounding box limits (considers all meshes)
-BoundingBox GetModelBoundingBox(Model model)
-{
-    BoundingBox bounds = { 0 };
-
-    if (model.meshCount > 0)
-    {
-        Vector3 temp = { 0 };
-        bounds = GetMeshBoundingBox(model.meshes[0]);
-
-        for (int i = 1; i < model.meshCount; i++)
-        {
-            BoundingBox tempBounds = GetMeshBoundingBox(model.meshes[i]);
-
-            temp.x = (bounds.min.x < tempBounds.min.x)? bounds.min.x : tempBounds.min.x;
-            temp.y = (bounds.min.y < tempBounds.min.y)? bounds.min.y : tempBounds.min.y;
-            temp.z = (bounds.min.z < tempBounds.min.z)? bounds.min.z : tempBounds.min.z;
-            bounds.min = temp;
-
-            temp.x = (bounds.max.x > tempBounds.max.x)? bounds.max.x : tempBounds.max.x;
-            temp.y = (bounds.max.y > tempBounds.max.y)? bounds.max.y : tempBounds.max.y;
-            temp.z = (bounds.max.z > tempBounds.max.z)? bounds.max.z : tempBounds.max.z;
-            bounds.max = temp;
-        }
-    }
-
-    // Apply model.transform to bounding box
-    // WARNING: Current BoundingBox structure design does not support rotation transformations,
-    // in those cases is up to the user to calculate the proper box bounds (8 vertices transformed)
-    bounds.min = Vector3Transform(bounds.min, model.transform);
-    bounds.max = Vector3Transform(bounds.max, model.transform);
-
-    return bounds;
-}
-
-// Upload vertex data into a VAO (if supported) and VBO
-void UploadMesh(Mesh *mesh, bool dynamic)
-{
-    if (mesh->vaoId > 0)
-    {
-        // Check if mesh has already been loaded in GPU
-        TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
-        return;
-    }
-
-    mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
-
-    mesh->vaoId = 0;        // Vertex Array Object
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0;     // Vertex buffer: positions
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0;     // Vertex buffer: texcoords
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0;       // Vertex buffer: normals
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0;        // Vertex buffer: colors
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0;      // Vertex buffer: tangents
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0;    // Vertex buffer: texcoords2
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0;      // Vertex buffer: indices
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0;      // Vertex buffer: boneIds
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0;  // Vertex buffer: boneWeights
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    mesh->vaoId = rlLoadVertexArray();
-    if (mesh->vaoId == 0) return;
-
-    rlEnableVertexArray(mesh->vaoId);
-
-    // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
-
-    // Enable vertex attributes: position (shader-location = 0)
-    void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices;
-    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
-    rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0);
-    rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
-
-    // Enable vertex attributes: texcoords (shader-location = 1)
-
-    if (mesh->texcoords != NULL)
-    {
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
-    }
-    else
-    {
-        float value[2] = { 0.0f, 0.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, value, SHADER_ATTRIB_VEC2, 2);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
-    }
-    // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
-    // is part of current state, and it is maintained even if a different program object is used
-
-    if (mesh->normals != NULL)
-    {
-        // Enable vertex attributes: normals (shader-location = 2)
-        void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals;
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
-    }
-    else
-    {
-        // Default vertex attribute: normal
-        // WARNING: Default value provided to shader if location available
-        float value[3] = { 0.0f, 0.0f, 1.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, value, SHADER_ATTRIB_VEC3, 3);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
-    }
-
-    if (mesh->colors != NULL)
-    {
-        // Enable vertex attribute: color (shader-location = 3)
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
-    }
-    else
-    {
-        // Default vertex attribute: color
-        // WARNING: Default value provided to shader if location available
-        float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };    // WHITE
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, value, SHADER_ATTRIB_VEC4, 4);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
-    }
-
-    if (mesh->tangents != NULL)
-    {
-        // Enable vertex attribute: tangent (shader-location = 4)
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
-    }
-    else
-    {
-        // Default vertex attribute: tangent
-        // WARNING: Default value provided to shader if location available
-        float value[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, value, SHADER_ATTRIB_VEC4, 4);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
-    }
-
-    if (mesh->texcoords2 != NULL)
-    {
-        // Enable vertex attribute: texcoord2 (shader-location = 5)
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
-    }
-    else
-    {
-        // Default vertex attribute: texcoord2
-        // WARNING: Default value provided to shader if location available
-        float value[2] = { 0.0f, 0.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
-    }
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-    if (mesh->boneIds != NULL)
-    {
-        // Enable vertex attribute: boneIds (shader-location = 7)
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
-    }
-    else
-    {
-        // Default vertex attribute: boneIds
-        // WARNING: Default value provided to shader if location available
-        float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
-    }
-
-    if (mesh->boneWeights != NULL)
-    {
-        // Enable vertex attribute: boneWeights (shader-location = 8)
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
-    }
-    else
-    {
-        // Default vertex attribute: boneWeights
-        // WARNING: Default value provided to shader if location available
-        float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
-        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);
-        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
-    }
-#endif
-
-    if (mesh->indices != NULL)
-    {
-        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
-    }
-
-    if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
-    else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
-
-    rlDisableVertexArray();
-#endif
-}
-
-// Update mesh vertex data in GPU for a specific buffer index
-void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
-{
-    rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
-}
-
-// Draw a 3d mesh with material and transform
-void DrawMesh(Mesh mesh, Material material, Matrix transform)
-{
-#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
-    #define GL_VERTEX_ARRAY         0x8074
-    #define GL_NORMAL_ARRAY         0x8075
-    #define GL_COLOR_ARRAY          0x8076
-    #define GL_TEXTURE_COORD_ARRAY  0x8078
-
-    if (mesh.texcoords && material.maps[MATERIAL_MAP_DIFFUSE].texture.id > 0) rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
-
-    if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
-    else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
-
-    if (mesh.texcoords) rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
-
-    if (mesh.animNormals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals);
-    else if (mesh.normals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
-
-    if (mesh.colors) rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
-
-    rlPushMatrix();
-        rlMultMatrixf(MatrixToFloat(transform));
-        rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
-                   material.maps[MATERIAL_MAP_DIFFUSE].color.g,
-                   material.maps[MATERIAL_MAP_DIFFUSE].color.b,
-                   material.maps[MATERIAL_MAP_DIFFUSE].color.a);
-
-        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
-        else rlDrawVertexArray(0, mesh.vertexCount);
-    rlPopMatrix();
-
-    rlDisableStatePointer(GL_VERTEX_ARRAY);
-    rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
-    rlDisableStatePointer(GL_NORMAL_ARRAY);
-    rlDisableStatePointer(GL_COLOR_ARRAY);
-
-    rlDisableTexture();
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    // Bind shader program
-    rlEnableShader(material.shader.id);
-
-    if (material.shader.locs == NULL) return;
-
-    // Send required data to shader (matrices, values)
-    //-----------------------------------------------------
-    // Upload to shader material.colDiffuse
-    if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
-    {
-        float values[4] = {
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
-        };
-
-        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
-    }
-
-    // Upload to shader material.colSpecular (if location available)
-    if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
-    {
-        float values[4] = {
-            (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
-            (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
-            (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
-            (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f
-        };
-
-        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
-    }
-
-    // Get a copy of current matrices to work with,
-    // just in case stereo render is required, and we need to modify them
-    // NOTE: At this point the modelview matrix just contains the view matrix (camera)
-    // That's because BeginMode3D() sets it and there is no model-drawing function
-    // that modifies it, all use rlPushMatrix() and rlPopMatrix()
-    Matrix matModel = MatrixIdentity();
-    Matrix matView = rlGetMatrixModelview();
-    Matrix matModelView = MatrixIdentity();
-    Matrix matProjection = rlGetMatrixProjection();
-
-    // Upload view and projection matrices (if locations available)
-    if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
-    if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
-
-    // Accumulate several model transformations:
-    //    transform: model transformation provided (includes DrawModel() params combined with model.transform)
-    //    rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
-    matModel = MatrixMultiply(transform, rlGetMatrixTransform());
-
-    // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
-    if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], matModel);
-
-    // Get model-view matrix
-    matModelView = MatrixMultiply(matModel, matView);
-
-    // Upload model normal matrix (if locations available)
-    if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-    // Upload Bone Transforms
-    if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
-    {
-        rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
-    }
-#endif
-    //-----------------------------------------------------
-
-    // Bind active texture maps (if available)
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-    {
-        if (material.maps[i].texture.id > 0)
-        {
-            // Select current shader texture slot
-            rlActiveTextureSlot(i);
-
-            // Enable texture for active slot
-            if ((i == MATERIAL_MAP_IRRADIANCE) ||
-                (i == MATERIAL_MAP_PREFILTER) ||
-                (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
-            else rlEnableTexture(material.maps[i].texture.id);
-
-            rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
-        }
-    }
-
-    // Try binding vertex array objects (VAO) or use VBOs if not possible
-    // WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values
-    // for shader expected vertex attributes that are not provided by the mesh (i.e. colors)
-    // This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes
-    if (!rlEnableVertexArray(mesh.vaoId))
-    {
-        // Bind mesh VBO data: vertex position (shader-location = 0)
-        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
-        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
-
-        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
-        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
-        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
-
-        if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
-        {
-            // Bind mesh VBO data: vertex normals (shader-location = 2)
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
-        }
-
-        // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
-        {
-            if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
-            {
-                rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
-                rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
-                rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
-            }
-            else
-            {
-                // Set default value for defined vertex attribute in shader but not provided by mesh
-                // WARNING: It could result in GPU undefined behaviour
-                float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
-                rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
-                rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
-            }
-        }
-
-        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
-        }
-
-        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
-        }
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-        // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
-        }
-
-        // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
-        }
-#endif
-
-        if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
-    }
-
-    int eyeCount = 1;
-    if (rlIsStereoRenderEnabled()) eyeCount = 2;
-
-    for (int eye = 0; eye < eyeCount; eye++)
-    {
-        // Calculate model-view-projection matrix (MVP)
-        Matrix matModelViewProjection = MatrixIdentity();
-        if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
-        else
-        {
-            // Setup current eye viewport (half screen width)
-            rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
-            matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
-        }
-
-        // Send combined model-view-projection matrix to shader
-        rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
-
-        // Draw mesh
-        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
-        else rlDrawVertexArray(0, mesh.vertexCount);
-    }
-
-    // Unbind all bound texture maps
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-    {
-        if (material.maps[i].texture.id > 0)
-        {
-            // Select current shader texture slot
-            rlActiveTextureSlot(i);
-
-            // Disable texture for active slot
-            if ((i == MATERIAL_MAP_IRRADIANCE) ||
-                (i == MATERIAL_MAP_PREFILTER) ||
-                (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
-            else rlDisableTexture();
-        }
-    }
-
-    // Disable all possible vertex array objects (or VBOs)
-    rlDisableVertexArray();
-    rlDisableVertexBuffer();
-    rlDisableVertexBufferElement();
-
-    // Disable shader program
-    rlDisableShader();
-
-    // Restore rlgl internal modelview and projection matrices
-    rlSetMatrixModelview(matView);
-    rlSetMatrixProjection(matProjection);
-#endif
-}
-
-// Draw multiple mesh instances with material and different transforms
-void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
-{
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    // Instancing required variables
-    float16 *instanceTransforms = NULL;
-    unsigned int instancesVboId = 0;
-
-    // Bind shader program
-    rlEnableShader(material.shader.id);
-
-    // Send required data to shader (matrices, values)
-    //-----------------------------------------------------
-    // Upload to shader material.colDiffuse
-    if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
-    {
-        float values[4] = {
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
-            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
-        };
-
-        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
-    }
-
-    // Upload to shader material.colSpecular (if location available)
-    if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
-    {
-        float values[4] = {
-            (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.r/255.0f,
-            (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.g/255.0f,
-            (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.b/255.0f,
-            (float)material.maps[SHADER_LOC_COLOR_SPECULAR].color.a/255.0f
-        };
-
-        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
-    }
-
-    // Get a copy of current matrices to work with,
-    // just in case stereo render is required, and we need to modify them
-    // NOTE: At this point the modelview matrix just contains the view matrix (camera)
-    // That's because BeginMode3D() sets it and there is no model-drawing function
-    // that modifies it, all use rlPushMatrix() and rlPopMatrix()
-    Matrix matModel = MatrixIdentity();
-    Matrix matView = rlGetMatrixModelview();
-    Matrix matModelView = MatrixIdentity();
-    Matrix matProjection = rlGetMatrixProjection();
-
-    // Upload view and projection matrices (if locations available)
-    if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
-    if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
-
-    // Create instances buffer
-    instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
-
-    // Fill buffer with instances transformations as float16 arrays
-    for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
-
-    // Enable mesh VAO to attach new buffer
-    rlEnableVertexArray(mesh.vaoId);
-
-    // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData()
-    // It isn't clear which would be reliably faster in all cases and on all platforms,
-    // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
-    // no faster, since we're transferring all the transform matrices anyway
-    instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
-
-    // Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCE_TX
-    if (material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] != -1)
-    {
-        for (unsigned int i = 0; i < 4; i++)
-        {
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4));
-            rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 1);
-        }
-    }
-
-    rlDisableVertexBuffer();
-    rlDisableVertexArray();
-
-    // Accumulate internal matrix transform (push/pop) and view matrix
-    // NOTE: In this case, model instance transformation must be computed in the shader
-    matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
-
-    // Upload model normal matrix (if locations available)
-    if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-    // Upload Bone Transforms
-    if ((material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1) && mesh.boneMatrices)
-    {
-        rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
-    }
-#endif
-
-    //-----------------------------------------------------
-
-    // Bind active texture maps (if available)
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-    {
-        if (material.maps[i].texture.id > 0)
-        {
-            // Select current shader texture slot
-            rlActiveTextureSlot(i);
-
-            // Enable texture for active slot
-            if ((i == MATERIAL_MAP_IRRADIANCE) ||
-                (i == MATERIAL_MAP_PREFILTER) ||
-                (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
-            else rlEnableTexture(material.maps[i].texture.id);
-
-            rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
-        }
-    }
-
-    // Try binding vertex array objects (VAO)
-    // or use VBOs if not possible
-    if (!rlEnableVertexArray(mesh.vaoId))
-    {
-        // Bind mesh VBO data: vertex position (shader-location = 0)
-        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
-        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
-
-        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
-        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
-        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
-
-        if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
-        {
-            // Bind mesh VBO data: vertex normals (shader-location = 2)
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
-        }
-
-        // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
-        {
-            if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
-            {
-                rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
-                rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
-                rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
-            }
-            else
-            {
-                // Set default value for unused attribute
-                // NOTE: Required when using default shader and no VAO support
-                float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
-                rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
-                rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
-            }
-        }
-
-        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
-        }
-
-        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
-        }
-
-#ifdef RL_SUPPORT_MESH_GPU_SKINNING
-        // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
-        }
-
-        // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
-        if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
-        {
-            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
-            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
-            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
-        }
-#endif
-
-        if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
-    }
-
-    int eyeCount = 1;
-    if (rlIsStereoRenderEnabled()) eyeCount = 2;
-
-    for (int eye = 0; eye < eyeCount; eye++)
-    {
-        // Calculate model-view-projection matrix (MVP)
-        Matrix matModelViewProjection = MatrixIdentity();
-        if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
-        else
-        {
-            // Setup current eye viewport (half screen width)
-            rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
-            matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
-        }
-
-        // Send combined model-view-projection matrix to shader
-        rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
-
-        // Draw mesh instanced
-        if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
-        else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
-    }
-
-    // Unbind all bound texture maps
-    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-    {
-        if (material.maps[i].texture.id > 0)
-        {
-            // Select current shader texture slot
-            rlActiveTextureSlot(i);
-
-            // Disable texture for active slot
-            if ((i == MATERIAL_MAP_IRRADIANCE) ||
-                (i == MATERIAL_MAP_PREFILTER) ||
-                (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
-            else rlDisableTexture();
-        }
-    }
-
-    // Disable all possible vertex array objects (or VBOs)
-    rlDisableVertexArray();
-    rlDisableVertexBuffer();
-    rlDisableVertexBufferElement();
-
-    // Disable shader program
-    rlDisableShader();
-
-    // Remove instance transforms buffer
-    rlUnloadVertexBuffer(instancesVboId);
-    RL_FREE(instanceTransforms);
-#endif
-}
-
-// Unload mesh from memory (RAM and VRAM)
-void UnloadMesh(Mesh mesh)
-{
-    // Unload rlgl mesh vboId data
-    rlUnloadVertexArray(mesh.vaoId);
-
-    if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
-    RL_FREE(mesh.vboId);
-
-    RL_FREE(mesh.vertices);
-    RL_FREE(mesh.texcoords);
-    RL_FREE(mesh.normals);
-    RL_FREE(mesh.colors);
-    RL_FREE(mesh.tangents);
-    RL_FREE(mesh.texcoords2);
-    RL_FREE(mesh.indices);
-
-    RL_FREE(mesh.animVertices);
-    RL_FREE(mesh.animNormals);
-    RL_FREE(mesh.boneWeights);
-    RL_FREE(mesh.boneIds);
-    RL_FREE(mesh.boneMatrices);
-}
-
-// Export mesh data to file
-bool ExportMesh(Mesh mesh, const char *fileName)
-{
-    bool success = false;
-
-    if (IsFileExtension(fileName, ".obj"))
-    {
-        // Estimated data size, it should be enough...
-        int vc = mesh.vertexCount;
-        int dataSize = vc*(int)strlen("v -0000.000000f -0000.000000f -0000.000000f\n") +
-                       vc*(int)strlen("vt -0.000000f -0.000000f\n") +
-                       vc*(int)strlen("vn -0.0000f -0.0000f -0.0000f\n") +
-                       mesh.triangleCount*snprintf(NULL, 0, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", vc, vc, vc, vc, vc, vc, vc, vc, vc);
-
-        // NOTE: Text data buffer size is estimated considering mesh data size
-        char *txtData = (char *)RL_CALLOC(dataSize + 1000, sizeof(char));
-
-        int byteCount = 0;
-        byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
-        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
-        byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized   //\n");
-        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
-        byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report:  github.com/raysan5/raylib                        //\n");
-        byteCount += sprintf(txtData + byteCount, "# // feedback and support:       ray[at]raylib.com                                //\n");
-        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
-        byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2026 Ramon Santamaria (@raysan5)                          //\n");
-        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
-        byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
-        byteCount += sprintf(txtData + byteCount, "# Vertex Count:     %i\n", mesh.vertexCount);
-        byteCount += sprintf(txtData + byteCount, "# Triangle Count:   %i\n\n", mesh.triangleCount);
-
-        byteCount += sprintf(txtData + byteCount, "g mesh\n");
-
-        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
-        {
-            byteCount += sprintf(txtData + byteCount, "v %.6f %.6f %.6f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
-        }
-
-        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
-        {
-            byteCount += sprintf(txtData + byteCount, "vt %.6f %.6f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
-        }
-
-        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
-        {
-            byteCount += sprintf(txtData + byteCount, "vn %.4f %.4f %.4f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
-        }
-
-        if (mesh.indices != NULL)
-        {
-            for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3)
-            {
-                byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
-                    mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1,
-                    mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1,
-                    mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1);
-            }
-        }
-        else
-        {
-            for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3)
-            {
-                byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2);
-            }
-        }
-
-        // NOTE: Text data length exported is determined by '\0' (NULL) character
-        success = SaveFileText(fileName, txtData);
-
-        RL_FREE(txtData);
-    }
-    else if (IsFileExtension(fileName, ".raw"))
-    {
-        // TODO: Support additional file formats to export mesh vertex data
-    }
-
-    return success;
-}
-
-// Export mesh as code file (.h) defining multiple arrays of vertex attributes
-bool ExportMeshAsCode(Mesh mesh, const char *fileName)
-{
-    bool success = false;
-
-#ifndef TEXT_BYTES_PER_LINE
-    #define TEXT_BYTES_PER_LINE     20
-#endif
-
-    // NOTE: Text data buffer size is fixed to 64MB
-    char *txtData = (char *)RL_CALLOC(64*1024*1024, sizeof(char));  // 64 MB
-
-    int byteCount = 0;
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// MeshAsCode exporter v1.0 - Mesh vertex data exported as arrays                     //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
-    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2023 Ramon Santamaria (@raysan5)                                     //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
-
-    // 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
-    for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
-
-    // Add image information
-    byteCount += sprintf(txtData + byteCount, "// Mesh basic information\n");
-    byteCount += sprintf(txtData + byteCount, "#define %s_VERTEX_COUNT    %i\n", varFileName, mesh.vertexCount);
-    byteCount += sprintf(txtData + byteCount, "#define %s_TRIANGLE_COUNT   %i\n\n", varFileName, mesh.triangleCount);
-
-    // Define vertex attributes data as separate arrays
-    //-----------------------------------------------------------------------------------------
-    if (mesh.vertices != NULL)      // Vertex position (XYZ - 3 components per vertex - float)
-    {
-        byteCount += sprintf(txtData + byteCount, "static float %s_VERTEX_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
-        for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.vertices[i]);
-        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.vertices[mesh.vertexCount*3 - 1]);
-    }
-
-    if (mesh.texcoords != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
-    {
-        byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
-        for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords[i]);
-        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords[mesh.vertexCount*2 - 1]);
-    }
-
-    if (mesh.texcoords2 != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
-    {
-        byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD2_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
-        for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords2[i]);
-        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords2[mesh.vertexCount*2 - 1]);
-    }
-
-    if (mesh.normals != NULL)      // Vertex normals (XYZ - 3 components per vertex - float)
-    {
-        byteCount += sprintf(txtData + byteCount, "static float %s_NORMAL_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
-        for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.normals[i]);
-        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.normals[mesh.vertexCount*3 - 1]);
-    }
-
-    if (mesh.tangents != NULL)      // Vertex tangents (XYZW - 4 components per vertex - float)
-    {
-        byteCount += sprintf(txtData + byteCount, "static float %s_TANGENT_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
-        for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.tangents[i]);
-        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.tangents[mesh.vertexCount*4 - 1]);
-    }
-
-    if (mesh.colors != NULL)        // Vertex colors (RGBA - 4 components per vertex - unsigned char)
-    {
-        byteCount += sprintf(txtData + byteCount, "static unsigned char %s_COLOR_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
-        for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), mesh.colors[i]);
-        byteCount += sprintf(txtData + byteCount, "0x%x };\n\n", mesh.colors[mesh.vertexCount*4 - 1]);
-    }
-
-    if (mesh.indices != NULL)       // Vertex indices (3 index per triangle - unsigned short)
-    {
-        byteCount += sprintf(txtData + byteCount, "static unsigned short %s_INDEX_DATA[%i] = { ", varFileName, mesh.triangleCount*3);
-        for (int i = 0; i < mesh.triangleCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%i,\n" : "%i, "), mesh.indices[i]);
-        byteCount += sprintf(txtData + byteCount, "%i };\n", mesh.indices[mesh.triangleCount*3 - 1]);
-    }
-    //-----------------------------------------------------------------------------------------
-
-    // NOTE: Text data size exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
-
-    RL_FREE(txtData);
-
-    //if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
-    //else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
-
-    return success;
-}
-
-#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
-// Process obj materials
-static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
-{
-    // Init model mats
-    for (int m = 0; m < materialCount; m++)
-    {
-        // Init material to default
-        // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
-        materials[m] = LoadMaterialDefault();
-
-        if (mats == NULL) continue;
-
-        // Get default texture, in case no texture is defined
-        // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
-        materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
-
-        if (mats[m].diffuse_texname != NULL) materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(mats[m].diffuse_texname);  //char *diffuse_texname; // map_Kd
-        else materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(mats[m].diffuse[0]*255.0f), (unsigned char)(mats[m].diffuse[1]*255.0f), (unsigned char)(mats[m].diffuse[2]*255.0f), 255 }; //float diffuse[3];
-        materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
-
-        if (mats[m].specular_texname != NULL) materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(mats[m].specular_texname);  //char *specular_texname; // map_Ks
-        materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(mats[m].specular[0]*255.0f), (unsigned char)(mats[m].specular[1]*255.0f), (unsigned char)(mats[m].specular[2]*255.0f), 255 }; //float specular[3];
-        materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
-
-        if (mats[m].bump_texname != NULL) materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(mats[m].bump_texname);  //char *bump_texname; // map_bump, bump
-        materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
-        materials[m].maps[MATERIAL_MAP_NORMAL].value = mats[m].shininess;
-
-        materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(mats[m].emission[0]*255.0f), (unsigned char)(mats[m].emission[1]*255.0f), (unsigned char)(mats[m].emission[2]*255.0f), 255 }; //float emission[3];
-
-        if (mats[m].displacement_texname != NULL) materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(mats[m].displacement_texname);  //char *displacement_texname; // disp
-    }
-}
-#endif
-
-// Load materials from model file
-Material *LoadMaterials(const char *fileName, int *materialCount)
-{
-    Material *materials = NULL;
-    unsigned int count = 0;
-
-    // TODO: Support IQM and GLTF for materials parsing
-
-#if defined(SUPPORT_FILEFORMAT_MTL)
-    if (IsFileExtension(fileName, ".mtl"))
-    {
-        tinyobj_material_t *mats = NULL;
-
-        int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
-        if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
-
-        materials = (Material *)RL_MALLOC(count*sizeof(Material));
-        ProcessMaterialsOBJ(materials, mats, count);
-
-        tinyobj_materials_free(mats, count);
-    }
-#else
-    TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
-#endif
-
-    *materialCount = count;
-    return materials;
-}
-
-// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
-Material LoadMaterialDefault(void)
-{
-    Material material = { 0 };
-    material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap));
-
-    // Using rlgl default shader
-    material.shader.id = rlGetShaderIdDefault();
-    material.shader.locs = rlGetShaderLocsDefault();
-
-    // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap)
-    material.maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
-    //material.maps[MATERIAL_MAP_NORMAL].texture;         // NOTE: By default, not set
-    //material.maps[MATERIAL_MAP_SPECULAR].texture;       // NOTE: By default, not set
-
-    material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE;    // Diffuse color
-    material.maps[MATERIAL_MAP_SPECULAR].color = WHITE;   // Specular color
-
-    return material;
-}
-
-// Check if a material is valid (map textures loaded in GPU)
-bool IsMaterialValid(Material material)
-{
-    bool result = false;
-
-    if ((material.maps != NULL) &&      // Validate material contain some map
-        (material.shader.id > 0)) result = true; // Validate material shader is valid
-
-    // TODO: Check if available maps contain loaded textures
-
-    return result;
-}
-
-// Unload material from memory
-void UnloadMaterial(Material material)
-{
-    // Unload material shader (avoid unloading default shader, managed by raylib)
-    if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
-
-    // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
-    if (material.maps != NULL)
-    {
-        for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
-        {
-            if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
-        }
-    }
-
-    RL_FREE(material.maps);
-}
-
-// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
-// NOTE: Previous texture should be manually unloaded
-void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
-{
-    material->maps[mapType].texture = texture;
-}
-
-// Set the material for a mesh
-void SetModelMeshMaterial(Model *model, int meshId, int materialId)
-{
-    if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
-    else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
-    else  model->meshMaterial[meshId] = materialId;
-}
-
-// Load model animations from file
-ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
-{
-    ModelAnimation *animations = NULL;
-
-#if defined(SUPPORT_FILEFORMAT_IQM)
-    if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
-#endif
-#if defined(SUPPORT_FILEFORMAT_M3D)
-    if (IsFileExtension(fileName, ".m3d")) animations = LoadModelAnimationsM3D(fileName, animCount);
-#endif
-#if defined(SUPPORT_FILEFORMAT_GLTF)
-    if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationsGLTF(fileName, animCount);
-#endif
-
-    return animations;
-}
-
-// Update model animated bones transform matrices for a given frame
-// NOTE: Updated data is not uploaded to GPU but kept at model.meshes[i].boneMatrices[boneId],
-// to be uploaded to shader at drawing, in case GPU skinning is enabled
-void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
-{
-    if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
-    {
-        if (frame >= anim.frameCount) frame = frame%anim.frameCount;
-
-        // Get first mesh which have bones
-        int firstMeshWithBones = -1;
-
-        for (int i = 0; i < model.meshCount; i++)
-        {
-            if (model.meshes[i].boneMatrices)
-            {
-                if (firstMeshWithBones == -1)
-                {
-                    firstMeshWithBones = i;
-                    break;
-                }
-            }
-        }
-
-        if (firstMeshWithBones != -1)
-        {
-            // Update all bones and boneMatrices of first mesh with bones
-            for (int boneId = 0; boneId < anim.boneCount; boneId++)
-            {
-                Transform *bindTransform = &model.bindPose[boneId];
-                Matrix bindMatrix = MatrixMultiply(MatrixMultiply(
-                    MatrixScale(bindTransform->scale.x, bindTransform->scale.y, bindTransform->scale.z),
-                    QuaternionToMatrix(bindTransform->rotation)),
-                    MatrixTranslate(bindTransform->translation.x, bindTransform->translation.y, bindTransform->translation.z));
-
-                Transform *targetTransform = &anim.framePoses[frame][boneId];
-                Matrix targetMatrix = MatrixMultiply(MatrixMultiply(
-                    MatrixScale(targetTransform->scale.x, targetTransform->scale.y, targetTransform->scale.z),
-                    QuaternionToMatrix(targetTransform->rotation)),
-                    MatrixTranslate(targetTransform->translation.x, targetTransform->translation.y, targetTransform->translation.z));
-
-                model.meshes[firstMeshWithBones].boneMatrices[boneId] = MatrixMultiply(MatrixInvert(bindMatrix), targetMatrix);
-            }
-
-            // Update remaining meshes with bones
-            // NOTE: Using deep copy because shallow copy results in double free with 'UnloadModel()'
-            for (int i = firstMeshWithBones + 1; i < model.meshCount; i++)
-            {
-                if (model.meshes[i].boneMatrices)
-                {
-                    memcpy(model.meshes[i].boneMatrices,
-                        model.meshes[firstMeshWithBones].boneMatrices,
-                        model.meshes[i].boneCount*sizeof(model.meshes[i].boneMatrices[0]));
-                }
-            }
-        }
-    }
-}
-
-// at least 2x speed up vs the old method
-// Update model animated vertex data (positions and normals) for a given frame
-// NOTE: Updated data is uploaded to GPU
-void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
-{
-    UpdateModelAnimationBones(model,anim,frame);
-
-    for (int m = 0; m < model.meshCount; m++)
-    {
-        Mesh mesh = model.meshes[m];
-        Vector3 animVertex = { 0 };
-        Vector3 animNormal = { 0 };
-        int boneId = 0;
-        int boneCounter = 0;
-        float boneWeight = 0.0;
-        bool updated = false; // Flag to check when anim vertex information is updated
-        const int vValues = mesh.vertexCount*3;
-
-        // Skip if missing bone data, causes segfault without on some models
-        if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue;
-
-        for (int vCounter = 0; vCounter < vValues; vCounter += 3)
-        {
-            mesh.animVertices[vCounter] = 0;
-            mesh.animVertices[vCounter + 1] = 0;
-            mesh.animVertices[vCounter + 2] = 0;
-            if (mesh.animNormals != NULL)
-            {
-                mesh.animNormals[vCounter] = 0;
-                mesh.animNormals[vCounter + 1] = 0;
-                mesh.animNormals[vCounter + 2] = 0;
-            }
-
-            // Iterates over 4 bones per vertex
-            for (int j = 0; j < 4; j++, boneCounter++)
-            {
-                boneWeight = mesh.boneWeights[boneCounter];
-                boneId = mesh.boneIds[boneCounter];
-
-                // Early stop when no transformation will be applied
-                if (boneWeight == 0.0f) continue;
-                animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
-                animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
-                mesh.animVertices[vCounter] += animVertex.x*boneWeight;
-                mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
-                mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
-                updated = true;
-
-                // Normals processing
-                // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
-                if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
-                {
-                    animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
-                    animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.meshes[m].boneMatrices[boneId])));
-                    mesh.animNormals[vCounter] += animNormal.x*boneWeight;
-                    mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
-                    mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
-                }
-            }
-        }
-
-        if (updated)
-        {
-            rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
-            if (mesh.normals != NULL) rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals
-        }
-    }
-}
-
-// Unload animation array data
-void UnloadModelAnimations(ModelAnimation *animations, int animCount)
-{
-    for (int i = 0; i < animCount; i++) UnloadModelAnimation(animations[i]);
-    RL_FREE(animations);
-}
-
-// Unload animation data
-void UnloadModelAnimation(ModelAnimation anim)
-{
-    for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]);
-
-    RL_FREE(anim.bones);
-    RL_FREE(anim.framePoses);
-}
-
-// Check model animation skeleton match
-// NOTE: Only number of bones and parent connections are checked
-bool IsModelAnimationValid(Model model, ModelAnimation anim)
-{
-    int result = true;
-
-    if (model.boneCount != anim.boneCount) result = false;
-    else
-    {
-        for (int i = 0; i < model.boneCount; i++)
-        {
-            if (model.bones[i].parent != anim.bones[i].parent) { result = false; break; }
-        }
-    }
-
-    return result;
-}
-
-#if defined(SUPPORT_MESH_GENERATION)
-// Generate polygonal mesh
-Mesh GenMeshPoly(int sides, float radius)
-{
-    Mesh mesh = { 0 };
-
-    if (sides < 3) return mesh; // Security check
-
-    int vertexCount = sides*3;
-
-    // Vertices definition
-    Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
-
-    float d = 0.0f, dStep = 360.0f/sides;
-    for (int v = 0; v < vertexCount - 2; v += 3)
-    {
-        vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
-        vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
-        vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
-        d += dStep;
-    }
-
-    // Normals definition
-    Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
-    for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
-
-    // TexCoords definition
-    Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
-    for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
-
-    mesh.vertexCount = vertexCount;
-    mesh.triangleCount = sides;
-    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-
-    // Mesh vertices position array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.vertices[3*i] = vertices[i].x;
-        mesh.vertices[3*i + 1] = vertices[i].y;
-        mesh.vertices[3*i + 2] = vertices[i].z;
-    }
-
-    // Mesh texcoords array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.texcoords[2*i] = texcoords[i].x;
-        mesh.texcoords[2*i + 1] = texcoords[i].y;
-    }
-
-    // Mesh normals array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.normals[3*i] = normals[i].x;
-        mesh.normals[3*i + 1] = normals[i].y;
-        mesh.normals[3*i + 2] = normals[i].z;
-    }
-
-    RL_FREE(vertices);
-    RL_FREE(normals);
-    RL_FREE(texcoords);
-
-    // Upload vertex data to GPU (static mesh)
-    // NOTE: mesh.vboId array is allocated inside UploadMesh()
-    UploadMesh(&mesh, false);
-
-    return mesh;
-}
-
-// Generate plane mesh (with subdivisions)
-Mesh GenMeshPlane(float width, float length, int resX, int resZ)
-{
-    Mesh mesh = { 0 };
-
-#define CUSTOM_MESH_GEN_PLANE
-#if defined(CUSTOM_MESH_GEN_PLANE)
-    resX++;
-    resZ++;
-
-    // Vertices definition
-    int vertexCount = resX*resZ; // vertices get reused for the faces
-
-    Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
-    for (int z = 0; z < resZ; z++)
-    {
-        // [-length/2, length/2]
-        float zPos = ((float)z/(resZ - 1) - 0.5f)*length;
-        for (int x = 0; x < resX; x++)
-        {
-            // [-width/2, width/2]
-            float xPos = ((float)x/(resX - 1) - 0.5f)*width;
-            vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos };
-        }
-    }
-
-    // Normals definition
-    Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
-    for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
-
-    // TexCoords definition
-    Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
-    for (int v = 0; v < resZ; v++)
-    {
-        for (int u = 0; u < resX; u++)
-        {
-            texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) };
-        }
-    }
-
-    // Triangles definition (indices)
-    int numFaces = (resX - 1)*(resZ - 1);
-    int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int));
-    int t = 0;
-    for (int face = 0; face < numFaces; face++)
-    {
-        // Retrieve lower left corner from face ind
-        int i = face + face/(resX - 1);
-
-        triangles[t++] = i + resX;
-        triangles[t++] = i + 1;
-        triangles[t++] = i;
-
-        triangles[t++] = i + resX;
-        triangles[t++] = i + resX + 1;
-        triangles[t++] = i + 1;
-    }
-
-    mesh.vertexCount = vertexCount;
-    mesh.triangleCount = numFaces*2;
-    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short));
-
-    // Mesh vertices position array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.vertices[3*i] = vertices[i].x;
-        mesh.vertices[3*i + 1] = vertices[i].y;
-        mesh.vertices[3*i + 2] = vertices[i].z;
-    }
-
-    // Mesh texcoords array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.texcoords[2*i] = texcoords[i].x;
-        mesh.texcoords[2*i + 1] = texcoords[i].y;
-    }
-
-    // Mesh normals array
-    for (int i = 0; i < mesh.vertexCount; i++)
-    {
-        mesh.normals[3*i] = normals[i].x;
-        mesh.normals[3*i + 1] = normals[i].y;
-        mesh.normals[3*i + 2] = normals[i].z;
-    }
-
-    // Mesh indices array initialization
-    for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
-
-    RL_FREE(vertices);
-    RL_FREE(normals);
-    RL_FREE(texcoords);
-    RL_FREE(triangles);
-
-#else       // Use par_shapes library to generate plane mesh
-
-    par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ);   // No normals/texcoords generated!!!
-    par_shapes_scale(plane, width, length, 1.0f);
-    par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
-    par_shapes_translate(plane, -width/2, 0.0f, length/2);
-
-    mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
-
-    mesh.vertexCount = plane->ntriangles*3;
-    mesh.triangleCount = plane->ntriangles;
-
-    for (int k = 0; k < mesh.vertexCount; k++)
-    {
-        mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
-        mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
-        mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
-
-        mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
-        mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
-        mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
-
-        mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
-        mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
-    }
-
-    par_shapes_free_mesh(plane);
-#endif
-
-    // Upload vertex data to GPU (static mesh)
-    UploadMesh(&mesh, false);
-
-    return mesh;
-}
-
-// Generated cuboid mesh
-Mesh GenMeshCube(float width, float height, float length)
-{
-    Mesh mesh = { 0 };
-
-#define CUSTOM_MESH_GEN_CUBE
-#if defined(CUSTOM_MESH_GEN_CUBE)
-    float vertices[] = {
-        -width/2, -height/2, length/2,
-        width/2, -height/2, length/2,
-        width/2, height/2, length/2,
-        -width/2, height/2, length/2,
-        -width/2, -height/2, -length/2,
-        -width/2, height/2, -length/2,
-        width/2, height/2, -length/2,
-        width/2, -height/2, -length/2,
-        -width/2, height/2, -length/2,
-        -width/2, height/2, length/2,
-        width/2, height/2, length/2,
-        width/2, height/2, -length/2,
-        -width/2, -height/2, -length/2,
-        width/2, -height/2, -length/2,
-        width/2, -height/2, length/2,
-        -width/2, -height/2, length/2,
-        width/2, -height/2, -length/2,
-        width/2, height/2, -length/2,
-        width/2, height/2, length/2,
-        width/2, -height/2, length/2,
-        -width/2, -height/2, -length/2,
-        -width/2, -height/2, length/2,
-        -width/2, height/2, length/2,
-        -width/2, height/2, -length/2
-    };
-
-    float texcoords[] = {
-        0.0f, 0.0f,
-        1.0f, 0.0f,
-        1.0f, 1.0f,
-        0.0f, 1.0f,
-        1.0f, 0.0f,
-        1.0f, 1.0f,
-        0.0f, 1.0f,
-        0.0f, 0.0f,
-        0.0f, 1.0f,
-        0.0f, 0.0f,
-        1.0f, 0.0f,
-        1.0f, 1.0f,
-        1.0f, 1.0f,
-        0.0f, 1.0f,
-        0.0f, 0.0f,
-        1.0f, 0.0f,
-        1.0f, 0.0f,
-        1.0f, 1.0f,
-        0.0f, 1.0f,
-        0.0f, 0.0f,
-        0.0f, 0.0f,
-        1.0f, 0.0f,
-        1.0f, 1.0f,
-        0.0f, 1.0f
-    };
-
-    float normals[] = {
-        0.0f, 0.0f, 1.0f,
-        0.0f, 0.0f, 1.0f,
-        0.0f, 0.0f, 1.0f,
-        0.0f, 0.0f, 1.0f,
-        0.0f, 0.0f,-1.0f,
-        0.0f, 0.0f,-1.0f,
-        0.0f, 0.0f,-1.0f,
-        0.0f, 0.0f,-1.0f,
-        0.0f, 1.0f, 0.0f,
-        0.0f, 1.0f, 0.0f,
-        0.0f, 1.0f, 0.0f,
-        0.0f, 1.0f, 0.0f,
-        0.0f,-1.0f, 0.0f,
-        0.0f,-1.0f, 0.0f,
-        0.0f,-1.0f, 0.0f,
-        0.0f,-1.0f, 0.0f,
-        1.0f, 0.0f, 0.0f,
-        1.0f, 0.0f, 0.0f,
-        1.0f, 0.0f, 0.0f,
-        1.0f, 0.0f, 0.0f,
-        -1.0f, 0.0f, 0.0f,
-        -1.0f, 0.0f, 0.0f,
-        -1.0f, 0.0f, 0.0f,
-        -1.0f, 0.0f, 0.0f
-    };
-
-    mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float));
-    memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
-
-    mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float));
-    memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
-
-    mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float));
-    memcpy(mesh.normals, normals, 24*3*sizeof(float));
-
-    mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short));
-
-    int k = 0;
-
-    // Indices can be initialized right now
-    for (int i = 0; i < 36; i += 6)
-    {
-        mesh.indices[i] = 4*k;
-        mesh.indices[i + 1] = 4*k + 1;
-        mesh.indices[i + 2] = 4*k + 2;
-        mesh.indices[i + 3] = 4*k;
-        mesh.indices[i + 4] = 4*k + 2;
-        mesh.indices[i + 5] = 4*k + 3;
-
-        k++;
-    }
-
-    mesh.vertexCount = 24;
-    mesh.triangleCount = 12;
-
-#else               // Use par_shapes library to generate cube mesh
-/*
-// Platonic solids:
-par_shapes_mesh *par_shapes_create_tetrahedron();       // 4 sides polyhedron (pyramid)
-par_shapes_mesh *par_shapes_create_cube();              // 6 sides polyhedron (cube)
-par_shapes_mesh *par_shapes_create_octahedron();        // 8 sides polyhedron (diamond)
-par_shapes_mesh *par_shapes_create_dodecahedron();      // 12 sides polyhedron
-par_shapes_mesh *par_shapes_create_icosahedron();       // 20 sides polyhedron
-*/
-    // Platonic solid generation: cube (6 sides)
-    // NOTE: No normals/texcoords generated by default
-    par_shapes_mesh *cube = par_shapes_create_cube();
-    cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
-    for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
-    par_shapes_scale(cube, width, height, length);
-    par_shapes_translate(cube, -width/2, 0.0f, -length/2);
-    par_shapes_compute_normals(cube);
-
-    mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
-
-    mesh.vertexCount = cube->ntriangles*3;
-    mesh.triangleCount = cube->ntriangles;
-
-    for (int k = 0; k < mesh.vertexCount; k++)
-    {
-        mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
-        mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
-        mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
-
-        mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
-        mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
-        mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
-
-        mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
-        mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
-    }
-
-    par_shapes_free_mesh(cube);
-#endif
-
-    // Upload vertex data to GPU (static mesh)
-    UploadMesh(&mesh, false);
-
-    return mesh;
-}
-
-// Generate sphere mesh (standard sphere)
-Mesh GenMeshSphere(float radius, int rings, int slices)
-{
-    Mesh mesh = { 0 };
-
-    if ((rings >= 3) && (slices >= 3))
-    {
-        par_shapes_set_epsilon_degenerate_sphere(0.0);
-        par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings);
-        par_shapes_scale(sphere, radius, radius, radius);
-        // NOTE: Soft normals are computed internally
-
-        mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = sphere->ntriangles*3;
-        mesh.triangleCount = sphere->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
-            mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(sphere);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere");
-
-    return mesh;
-}
-
-// Generate hemisphere mesh (half sphere, no bottom cap)
-Mesh GenMeshHemiSphere(float radius, int rings, int slices)
-{
-    Mesh mesh = { 0 };
-
-    if ((rings >= 3) && (slices >= 3))
-    {
-        if (radius < 0.0f) radius = 0.0f;
-
-        par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
-        par_shapes_scale(sphere, radius, radius, radius);
-        // NOTE: Soft normals are computed internally
-
-        mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = sphere->ntriangles*3;
-        mesh.triangleCount = sphere->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
-            mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(sphere);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere");
-
-    return mesh;
-}
-
-// Generate cylinder mesh
-Mesh GenMeshCylinder(float radius, float height, int slices)
-{
-    Mesh mesh = { 0 };
-
-    if (slices >= 3)
-    {
-        // Instance a cylinder that sits on the Z=0 plane using the given tessellation
-        // levels across the UV domain.  Think of "slices" like a number of pizza
-        // slices, and "stacks" like a number of stacked rings
-        // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
-        par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
-        par_shapes_scale(cylinder, radius, radius, height);
-        par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
-
-        // Generate an orientable disk shape (top cap)
-        par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
-        capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
-        for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
-        par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
-        par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 });
-        par_shapes_translate(capTop, 0, height, 0);
-
-        // Generate an orientable disk shape (bottom cap)
-        par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
-        capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
-        for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
-        par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
-        par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 });
-
-        par_shapes_merge_and_free(cylinder, capTop);
-        par_shapes_merge_and_free(cylinder, capBottom);
-
-        mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = cylinder->ntriangles*3;
-        mesh.triangleCount = cylinder->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
-            mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(cylinder);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder");
-
-    return mesh;
-}
-
-// Generate cone/pyramid mesh
-Mesh GenMeshCone(float radius, float height, int slices)
-{
-    Mesh mesh = { 0 };
-
-    if (slices >= 3)
-    {
-        // Instance a cone that sits on the Z=0 plane using the given tessellation
-        // levels across the UV domain.  Think of "slices" like a number of pizza
-        // slices, and "stacks" like a number of stacked rings
-        // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
-        par_shapes_mesh *cone = par_shapes_create_cone(slices, 8);
-        par_shapes_scale(cone, radius, radius, height);
-        par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 });
-        par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 });
-
-        // Generate an orientable disk shape (bottom cap)
-        par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
-        capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
-        for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
-        par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
-
-        par_shapes_merge_and_free(cone, capBottom);
-
-        mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = cone->ntriangles*3;
-        mesh.triangleCount = cone->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = cone->points[cone->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = cone->normals[cone->triangles[k]*3];
-            mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(cone);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone");
-
-    return mesh;
-}
-
-// Generate torus mesh
-Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
-{
-    Mesh mesh = { 0 };
-
-    if ((sides >= 3) && (radSeg >= 3))
-    {
-        if (radius > 1.0f) radius = 1.0f;
-        else if (radius < 0.1f) radius = 0.1f;
-
-        // Create a donut that sits on the Z=0 plane with the specified inner radius
-        // The outer radius can be controlled with par_shapes_scale
-        par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
-        par_shapes_scale(torus, size/2, size/2, size/2);
-
-        mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = torus->ntriangles*3;
-        mesh.triangleCount = torus->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
-            mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(torus);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus");
-
-    return mesh;
-}
-
-// Generate trefoil knot mesh
-Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
-{
-    Mesh mesh = { 0 };
-
-    if ((sides >= 3) && (radSeg >= 3))
-    {
-        if (radius > 3.0f) radius = 3.0f;
-        else if (radius < 0.5f) radius = 0.5f;
-
-        par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius);
-        par_shapes_scale(knot, size, size, size);
-
-        mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
-        mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float));
-        mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
-
-        mesh.vertexCount = knot->ntriangles*3;
-        mesh.triangleCount = knot->ntriangles;
-
-        for (int k = 0; k < mesh.vertexCount; k++)
-        {
-            mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
-            mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
-            mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
-
-            mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
-            mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
-            mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
-
-            mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
-            mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
-        }
-
-        par_shapes_free_mesh(knot);
-
-        // Upload vertex data to GPU (static mesh)
-        UploadMesh(&mesh, false);
-    }
-    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot");
-
-    return mesh;
-}
-
-// Generate a mesh from heightmap
-// NOTE: Vertex data is uploaded to GPU
-Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
-{
-    #define GRAY_VALUE(c) ((float)(c.r + c.g + c.b)/3.0f)
-
-    Mesh mesh = { 0 };
-
-    int mapX = heightmap.width;
-    int mapZ = heightmap.height;
-
-    Color *pixels = LoadImageColors(heightmap);
-
-    // NOTE: One vertex per pixel
-    mesh.triangleCount = (mapX - 1)*(mapZ - 1)*2;    // One quad every four pixels
-
-    mesh.vertexCount = mesh.triangleCount*3;
-
-    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
-    mesh.colors = NULL;
-
-    int vCounter = 0;       // Used to count vertices float by float
-    int tcCounter = 0;      // Used to count texcoords float by float
-    int nCounter = 0;       // Used to count normals float by float
-
-    Vector3 scaleFactor = { size.x/(mapX - 1), size.y/255.0f, size.z/(mapZ - 1) };
-
-    Vector3 vA = { 0 };
-    Vector3 vB = { 0 };
-    Vector3 vC = { 0 };
-    Vector3 vN = { 0 };
-
-    for (int z = 0; z < mapZ-1; z++)
-    {
-        for (int x = 0; x < mapX-1; x++)
-        {
-            // Fill vertices array with data
-            //----------------------------------------------------------
-
-            // one triangle - 3 vertex
-            mesh.vertices[vCounter] = (float)x*scaleFactor.x;
-            mesh.vertices[vCounter + 1] = GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
-            mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
-
-            mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
-            mesh.vertices[vCounter + 4] = GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
-            mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
-
-            mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
-            mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
-            mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
-
-            // Another triangle - 3 vertex
-            mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
-            mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
-            mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
-
-            mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3];
-            mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
-            mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
-
-            mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
-            mesh.vertices[vCounter + 16] = GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
-            mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
-            vCounter += 18;     // 6 vertex, 18 floats
-
-            // Fill texcoords array with data
-            //--------------------------------------------------------------
-            mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
-            mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
-
-            mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
-            mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
-
-            mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
-            mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
-
-            mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
-            mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
-
-            mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
-            mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
-
-            mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
-            mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
-            tcCounter += 12;    // 6 texcoords, 12 floats
-
-            // Fill normals array with data
-            //--------------------------------------------------------------
-            for (int i = 0; i < 18; i += 9)
-            {
-                vA.x = mesh.vertices[nCounter + i];
-                vA.y = mesh.vertices[nCounter + i + 1];
-                vA.z = mesh.vertices[nCounter + i + 2];
-
-                vB.x = mesh.vertices[nCounter + i + 3];
-                vB.y = mesh.vertices[nCounter + i + 4];
-                vB.z = mesh.vertices[nCounter + i + 5];
-
-                vC.x = mesh.vertices[nCounter + i + 6];
-                vC.y = mesh.vertices[nCounter + i + 7];
-                vC.z = mesh.vertices[nCounter + i + 8];
-
-                vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
-
-                mesh.normals[nCounter + i] = vN.x;
-                mesh.normals[nCounter + i + 1] = vN.y;
-                mesh.normals[nCounter + i + 2] = vN.z;
-
-                mesh.normals[nCounter + i + 3] = vN.x;
-                mesh.normals[nCounter + i + 4] = vN.y;
-                mesh.normals[nCounter + i + 5] = vN.z;
-
-                mesh.normals[nCounter + i + 6] = vN.x;
-                mesh.normals[nCounter + i + 7] = vN.y;
-                mesh.normals[nCounter + i + 8] = vN.z;
-            }
-
-            nCounter += 18;     // 6 vertex, 18 floats
-        }
-    }
-
-    UnloadImageColors(pixels);  // Unload pixels color data
-
-    // Upload vertex data to GPU (static mesh)
-    UploadMesh(&mesh, false);
-
-    return mesh;
-}
-
-// Generate a cubes mesh from pixel data
-// NOTE: Vertex data is uploaded to GPU
-Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
-{
-    #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
-
-    Mesh mesh = { 0 };
-
-    Color *pixels = LoadImageColors(cubicmap);
-
-    // NOTE: Max possible number of triangles numCubes*(12 triangles by cube)
-    int maxTriangles = cubicmap.width*cubicmap.height*12;
-
-    int vCounter = 0;       // Used to count vertices
-    int tcCounter = 0;      // Used to count texcoords
-    int nCounter = 0;       // Used to count normals
-
-    float w = cubeSize.x;
-    float h = cubeSize.z;
-    float h2 = cubeSize.y;
-
-    Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
-    Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
-    Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
-
-    // Define the 6 normals of the cube, we will combine them accordingly later...
-    Vector3 n1 = { 1.0f, 0.0f, 0.0f };
-    Vector3 n2 = { -1.0f, 0.0f, 0.0f };
-    Vector3 n3 = { 0.0f, 1.0f, 0.0f };
-    Vector3 n4 = { 0.0f, -1.0f, 0.0f };
-    Vector3 n5 = { 0.0f, 0.0f, -1.0f };
-    Vector3 n6 = { 0.0f, 0.0f, 1.0f };
-
-    // NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
-    typedef struct RectangleF {
-        float x;
-        float y;
-        float width;
-        float height;
-    } RectangleF;
-
-    RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
-    RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
-    RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
-    RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
-    RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f };
-    RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f };
-
-    for (int z = 0; z < cubicmap.height; ++z)
-    {
-        for (int x = 0; x < cubicmap.width; x++)
-        {
-            // Define the 8 vertex of the cube, we will combine them accordingly later...
-            Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
-            Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
-            Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
-            Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) };
-            Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) };
-            Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) };
-            Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
-            Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
-
-            // We check pixel color to be WHITE -> draw full cube
-            if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
-            {
-                // Define triangles and checking collateral cubes
-                //------------------------------------------------
-
-                // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
-                // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
-                mapVertices[vCounter] = v1;
-                mapVertices[vCounter + 1] = v2;
-                mapVertices[vCounter + 2] = v3;
-                mapVertices[vCounter + 3] = v1;
-                mapVertices[vCounter + 4] = v3;
-                mapVertices[vCounter + 5] = v4;
-                vCounter += 6;
-
-                mapNormals[nCounter] = n3;
-                mapNormals[nCounter + 1] = n3;
-                mapNormals[nCounter + 2] = n3;
-                mapNormals[nCounter + 3] = n3;
-                mapNormals[nCounter + 4] = n3;
-                mapNormals[nCounter + 5] = n3;
-                nCounter += 6;
-
-                mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
-                mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
-                mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
-                mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
-                mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
-                mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
-                tcCounter += 6;
-
-                // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
-                mapVertices[vCounter] = v6;
-                mapVertices[vCounter + 1] = v8;
-                mapVertices[vCounter + 2] = v7;
-                mapVertices[vCounter + 3] = v6;
-                mapVertices[vCounter + 4] = v5;
-                mapVertices[vCounter + 5] = v8;
-                vCounter += 6;
-
-                mapNormals[nCounter] = n4;
-                mapNormals[nCounter + 1] = n4;
-                mapNormals[nCounter + 2] = n4;
-                mapNormals[nCounter + 3] = n4;
-                mapNormals[nCounter + 4] = n4;
-                mapNormals[nCounter + 5] = n4;
-                nCounter += 6;
-
-                mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
-                mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
-                mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
-                mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
-                mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
-                mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
-                tcCounter += 6;
-
-                // Checking cube on bottom of current cube
-                if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
-                {
-                    // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
-                    // NOTE: Collateral occluded faces are not generated
-                    mapVertices[vCounter] = v2;
-                    mapVertices[vCounter + 1] = v7;
-                    mapVertices[vCounter + 2] = v3;
-                    mapVertices[vCounter + 3] = v3;
-                    mapVertices[vCounter + 4] = v7;
-                    mapVertices[vCounter + 5] = v8;
-                    vCounter += 6;
-
-                    mapNormals[nCounter] = n6;
-                    mapNormals[nCounter + 1] = n6;
-                    mapNormals[nCounter + 2] = n6;
-                    mapNormals[nCounter + 3] = n6;
-                    mapNormals[nCounter + 4] = n6;
-                    mapNormals[nCounter + 5] = n6;
-                    nCounter += 6;
-
-                    mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y };
-                    mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
-                    mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
-                    mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
-                    mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
-                    mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height };
-                    tcCounter += 6;
-                }
-
-                // Checking cube on top of current cube
-                if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
-                {
-                    // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
-                    // NOTE: Collateral occluded faces are not generated
-                    mapVertices[vCounter] = v1;
-                    mapVertices[vCounter + 1] = v5;
-                    mapVertices[vCounter + 2] = v6;
-                    mapVertices[vCounter + 3] = v1;
-                    mapVertices[vCounter + 4] = v4;
-                    mapVertices[vCounter + 5] = v5;
-                    vCounter += 6;
-
-                    mapNormals[nCounter] = n5;
-                    mapNormals[nCounter + 1] = n5;
-                    mapNormals[nCounter + 2] = n5;
-                    mapNormals[nCounter + 3] = n5;
-                    mapNormals[nCounter + 4] = n5;
-                    mapNormals[nCounter + 5] = n5;
-                    nCounter += 6;
-
-                    mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
-                    mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
-                    mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height };
-                    mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
-                    mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y };
-                    mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
-                    tcCounter += 6;
-                }
-
-                // Checking cube on right of current cube
-                if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
-                {
-                    // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
-                    // NOTE: Collateral occluded faces are not generated
-                    mapVertices[vCounter] = v3;
-                    mapVertices[vCounter + 1] = v8;
-                    mapVertices[vCounter + 2] = v4;
-                    mapVertices[vCounter + 3] = v4;
-                    mapVertices[vCounter + 4] = v8;
-                    mapVertices[vCounter + 5] = v5;
-                    vCounter += 6;
-
-                    mapNormals[nCounter] = n1;
-                    mapNormals[nCounter + 1] = n1;
-                    mapNormals[nCounter + 2] = n1;
-                    mapNormals[nCounter + 3] = n1;
-                    mapNormals[nCounter + 4] = n1;
-                    mapNormals[nCounter + 5] = n1;
-                    nCounter += 6;
-
-                    mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y };
-                    mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
-                    mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
-                    mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
-                    mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
-                    mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height };
-                    tcCounter += 6;
-                }
-
-                // Checking cube on left of current cube
-                if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
-                {
-                    // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
-                    // NOTE: Collateral occluded faces are not generated
-                    mapVertices[vCounter] = v1;
-                    mapVertices[vCounter + 1] = v7;
-                    mapVertices[vCounter + 2] = v2;
-                    mapVertices[vCounter + 3] = v1;
-                    mapVertices[vCounter + 4] = v6;
-                    mapVertices[vCounter + 5] = v7;
-                    vCounter += 6;
-
-                    mapNormals[nCounter] = n2;
-                    mapNormals[nCounter + 1] = n2;
-                    mapNormals[nCounter + 2] = n2;
-                    mapNormals[nCounter + 3] = n2;
-                    mapNormals[nCounter + 4] = n2;
-                    mapNormals[nCounter + 5] = n2;
-                    nCounter += 6;
-
-                    mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y };
-                    mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
-                    mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y };
-                    mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y };
-                    mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height };
-                    mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
-                    tcCounter += 6;
-                }
-            }
-            // We check pixel color to be BLACK, we will only draw floor and roof
-            else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
-            {
-                // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
-                mapVertices[vCounter] = v1;
-                mapVertices[vCounter + 1] = v3;
-                mapVertices[vCounter + 2] = v2;
-                mapVertices[vCounter + 3] = v1;
-                mapVertices[vCounter + 4] = v4;
-                mapVertices[vCounter + 5] = v3;
-                vCounter += 6;
-
-                mapNormals[nCounter] = n4;
-                mapNormals[nCounter + 1] = n4;
-                mapNormals[nCounter + 2] = n4;
-                mapNormals[nCounter + 3] = n4;
-                mapNormals[nCounter + 4] = n4;
-                mapNormals[nCounter + 5] = n4;
-                nCounter += 6;
-
-                mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
-                mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
-                mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
-                mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
-                mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
-                mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
-                tcCounter += 6;
-
-                // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
-                mapVertices[vCounter] = v6;
-                mapVertices[vCounter + 1] = v7;
-                mapVertices[vCounter + 2] = v8;
-                mapVertices[vCounter + 3] = v6;
-                mapVertices[vCounter + 4] = v8;
-                mapVertices[vCounter + 5] = v5;
-                vCounter += 6;
-
-                mapNormals[nCounter] = n3;
-                mapNormals[nCounter + 1] = n3;
-                mapNormals[nCounter + 2] = n3;
-                mapNormals[nCounter + 3] = n3;
-                mapNormals[nCounter + 4] = n3;
-                mapNormals[nCounter + 5] = n3;
-                nCounter += 6;
-
-                mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
-                mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
-                mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
-                mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
-                mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
-                mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
-                tcCounter += 6;
-            }
-        }
-    }
-
-    // Move data from mapVertices temp arrays to vertices float array
-    mesh.vertexCount = vCounter;
-    mesh.triangleCount = vCounter/3;
-
-    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
-    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
-    mesh.colors = NULL;
-
-    int fCounter = 0;
-
-    // Move vertices data
-    for (int i = 0; i < vCounter; i++)
-    {
-        mesh.vertices[fCounter] = mapVertices[i].x;
-        mesh.vertices[fCounter + 1] = mapVertices[i].y;
-        mesh.vertices[fCounter + 2] = mapVertices[i].z;
-        fCounter += 3;
-    }
-
-    fCounter = 0;
-
-    // Move normals data
-    for (int i = 0; i < nCounter; i++)
-    {
-        mesh.normals[fCounter] = mapNormals[i].x;
-        mesh.normals[fCounter + 1] = mapNormals[i].y;
-        mesh.normals[fCounter + 2] = mapNormals[i].z;
-        fCounter += 3;
-    }
-
-    fCounter = 0;
-
-    // Move texcoords data
-    for (int i = 0; i < tcCounter; i++)
-    {
-        mesh.texcoords[fCounter] = mapTexcoords[i].x;
-        mesh.texcoords[fCounter + 1] = mapTexcoords[i].y;
-        fCounter += 2;
-    }
-
-    RL_FREE(mapVertices);
-    RL_FREE(mapNormals);
-    RL_FREE(mapTexcoords);
-
-    UnloadImageColors(pixels);   // Unload pixels color data
-
-    // Upload vertex data to GPU (static mesh)
-    UploadMesh(&mesh, false);
-
-    return mesh;
-}
-#endif      // SUPPORT_MESH_GENERATION
-
-// Compute mesh bounding box limits
-// NOTE: minVertex and maxVertex should be transformed by model transform matrix
-BoundingBox GetMeshBoundingBox(Mesh mesh)
-{
-    // Get min and max vertex to construct bounds (AABB)
-    Vector3 minVertex = { 0 };
-    Vector3 maxVertex = { 0 };
-
-    if (mesh.vertices != NULL)
-    {
-        minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
-        maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
-
-        for (int i = 1; i < mesh.vertexCount; i++)
-        {
-            minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
-            maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
-        }
-    }
-
-    // Create the bounding box
-    BoundingBox box = { 0 };
-    box.min = minVertex;
-    box.max = maxVertex;
-
-    return box;
-}
-
-// Compute mesh tangents
-void GenMeshTangents(Mesh *mesh)
-{
-    // Check if input mesh data is useful
-    if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
-    {
-        TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
-        return;
-    }
-
-    // Allocate or reallocate tangents data
-    if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
-    else
-    {
-        RL_FREE(mesh->tangents);
-        mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
-    }
-
-    // Allocate temporary arrays for tangents calculation
-    Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
-    Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
-
-    if (tan1 == NULL || tan2 == NULL)
-    {
-        TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
-        if (tan1) RL_FREE(tan1);
-        if (tan2) RL_FREE(tan2);
-        return;
-    }
-
-    // Process all triangles of the mesh
-    // 'triangleCount' must be always valid
-    for (int t = 0; t < mesh->triangleCount; t++)
-    {
-        // Get triangle vertex indices
-        int i0 = 0, i1 = 0, i2 = 0;
-
-        if (mesh->indices != NULL)
-        {
-            // Use indices if available
-            i0 = mesh->indices[t*3 + 0];
-            i1 = mesh->indices[t*3 + 1];
-            i2 = mesh->indices[t*3 + 2];
-        }
-        else
-        {
-            // Sequential access for non-indexed mesh
-            i0 = t*3 + 0;
-            i1 = t*3 + 1;
-            i2 = t*3 + 2;
-        }
-
-        // Get triangle vertices position
-        Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
-        Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
-        Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
-
-        // Get triangle texcoords
-        Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
-        Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
-        Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
-
-        // Calculate triangle edges
-        float x1 = v2.x - v1.x;
-        float y1 = v2.y - v1.y;
-        float z1 = v2.z - v1.z;
-        float x2 = v3.x - v1.x;
-        float y2 = v3.y - v1.y;
-        float z2 = v3.z - v1.z;
-
-        // Calculate texture coordinate differences
-        float s1 = uv2.x - uv1.x;
-        float t1 = uv2.y - uv1.y;
-        float s2 = uv3.x - uv1.x;
-        float t2 = uv3.y - uv1.y;
-
-        // Calculate denominator and check for degenerate UV
-        float div = s1*t2 - s2*t1;
-        float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
-
-        // Calculate tangent and bitangent directions
-        Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
-        Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
-
-        // Accumulate tangents and bitangents for each vertex of the triangle
-        tan1[i0] = Vector3Add(tan1[i0], sdir);
-        tan1[i1] = Vector3Add(tan1[i1], sdir);
-        tan1[i2] = Vector3Add(tan1[i2], sdir);
-
-        tan2[i0] = Vector3Add(tan2[i0], tdir);
-        tan2[i1] = Vector3Add(tan2[i1], tdir);
-        tan2[i2] = Vector3Add(tan2[i2], tdir);
-    }
-
-    // Calculate final tangents for each vertex
-    for (int i = 0; i < mesh->vertexCount; i++)
-    {
-        Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
-        Vector3 tangent = tan1[i];
-
-        // Handle zero tangent (can happen with degenerate UVs)
-        if (Vector3Length(tangent) < 0.0001f)
-        {
-            // Create a tangent perpendicular to the normal
-            if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
-            else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
-
-            mesh->tangents[i*4 + 0] = tangent.x;
-            mesh->tangents[i*4 + 1] = tangent.y;
-            mesh->tangents[i*4 + 2] = tangent.z;
-            mesh->tangents[i*4 + 3] = 1.0f;
-            continue;
-        }
-
-        // Gram-Schmidt orthogonalization to make tangent orthogonal to normal
-        // T_prime = T - N*dot(N, T)
-        Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
-
-        // Handle cases where orthogonalized vector is too small
-        if (Vector3Length(orthogonalized) < 0.0001f)
-        {
-            // Create a tangent perpendicular to the normal
-            if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
-            else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
-        }
-        else
-        {
-            // Normalize the orthogonalized tangent
-            orthogonalized = Vector3Normalize(orthogonalized);
-        }
-
-        // Store the calculated tangent
-        mesh->tangents[i*4 + 0] = orthogonalized.x;
-        mesh->tangents[i*4 + 1] = orthogonalized.y;
-        mesh->tangents[i*4 + 2] = orthogonalized.z;
-
-        // Calculate the handedness (w component)
-        mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
-    }
-
-    // Free temporary arrays
-    RL_FREE(tan1);
-    RL_FREE(tan2);
-
-    // Update vertex buffers if available
-    if (mesh->vboId != NULL)
-    {
-        if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
-        {
-            // Update existing tangent vertex buffer
-            rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
-        }
-        else
-        {
-            // Create new tangent vertex buffer
-            mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
-        }
-
-        // Set up vertex attributes for shader
-        rlEnableVertexArray(mesh->vaoId);
-        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
-        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
-        rlDisableVertexArray();
-    }
-
-    TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
-}
-
-// Draw a model (with texture if set)
-void DrawModel(Model model, Vector3 position, float scale, Color tint)
-{
-    Vector3 vScale = { scale, scale, scale };
-    Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
-
-    DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
-}
-
-// Draw a model with extended parameters
-void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
-{
-    // Calculate transformation matrix from function parameters
-    // Get transform matrix (rotation -> scale -> translation)
-    Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
-    Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
-    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
-
-    Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-
-    // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
-    model.transform = MatrixMultiply(model.transform, matTransform);
-
-    for (int i = 0; i < model.meshCount; i++)
-    {
-        Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
-
-        Color colorTint = WHITE;
-        colorTint.r = (unsigned char)(((int)color.r*(int)tint.r)/255);
-        colorTint.g = (unsigned char)(((int)color.g*(int)tint.g)/255);
-        colorTint.b = (unsigned char)(((int)color.b*(int)tint.b)/255);
-        colorTint.a = (unsigned char)(((int)color.a*(int)tint.a)/255);
-
-        model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
-        DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
-        model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
-    }
-}
-
-// Draw a model wires (with texture if set)
-void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
-{
-    rlEnableWireMode();
-
-    DrawModel(model, position, scale, tint);
-
-    rlDisableWireMode();
-}
-
-// Draw a model wires (with texture if set) with extended parameters
-void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
-{
-    rlEnableWireMode();
-
-    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
-
-    rlDisableWireMode();
-}
-
-// Draw a model points
-// WARNING: OpenGL ES 2.0 does not support point mode drawing
-void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
-{
-    rlEnablePointMode();
-    rlDisableBackfaceCulling();
-
-    DrawModel(model, position, scale, tint);
-
-    rlEnableBackfaceCulling();
-    rlDisablePointMode();
-}
-
-// Draw a model points
-// WARNING: OpenGL ES 2.0 does not support point mode drawing
-void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
-{
-    rlEnablePointMode();
-    rlDisableBackfaceCulling();
-
-    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
-
-    rlEnableBackfaceCulling();
-    rlDisablePointMode();
-}
-
-// Draw a billboard
-void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
-{
-    Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
-
-    DrawBillboardRec(camera, texture, source, position, (Vector2){ scale*fabsf((float)source.width/source.height), scale }, tint);
-}
-
-// Draw a billboard (part of a texture defined by a rectangle)
-void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
-{
-    // NOTE: Billboard locked on axis-Y
-    Vector3 up = { 0.0f, 1.0f, 0.0f };
-
-    DrawBillboardPro(camera, texture, source, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
-}
-
-// Draw a billboard with additional parameters
-void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
-{
-    // Compute the up vector and the right vector
-    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
-    Vector3 right = { matView.m0, matView.m4, matView.m8 };
-    right = Vector3Scale(right, size.x);
-    up = Vector3Scale(up, size.y);
-
-    // Flip the content of the billboard while maintaining the counterclockwise edge rendering order
-    if (size.x < 0.0f)
-    {
-        source.x -= size.x;
-        source.width *= -1.0;
-        right = Vector3Negate(right);
-        origin.x *= -1.0f;
-    }
-    if (size.y < 0.0f)
-    {
-        source.y -= size.y;
-        source.height *= -1.0;
-        up = Vector3Negate(up);
-        origin.y *= -1.0f;
-    }
-
-    // Draw the texture region described by source on the following rectangle in 3D space:
-    //
-    //                size.x          <--.
-    //  3 ^---------------------------+ 2 \ rotation
-    //    |                           |   /
-    //    |                           |
-    //    |   origin.x   position     |
-    // up |..............             | size.y
-    //    |             .             |
-    //    |             . origin.y    |
-    //    |             .             |
-    //  0 +---------------------------> 1
-    //                right
-    Vector3 forward;
-    if (rotation != 0.0) forward = Vector3CrossProduct(right, up);
-
-    Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(right), origin.x), Vector3Scale(Vector3Normalize(up), origin.y));
-
-    Vector3 points[4];
-    points[0] = Vector3Zero();
-    points[1] = right;
-    points[2] = Vector3Add(up, right);
-    points[3] = up;
-
-    for (int i = 0; i < 4; i++)
-    {
-        points[i] = Vector3Subtract(points[i], origin3D);
-        if (rotation != 0.0) points[i] = Vector3RotateByAxisAngle(points[i], forward, rotation*DEG2RAD);
-        points[i] = Vector3Add(points[i], position);
-    }
-
-    Vector2 texcoords[4];
-    texcoords[0] = (Vector2){ (float)source.x/texture.width, (float)(source.y + source.height)/texture.height };
-    texcoords[1] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height };
-    texcoords[2] = (Vector2){ (float)(source.x + source.width)/texture.width, (float)source.y/texture.height };
-    texcoords[3] = (Vector2){ (float)source.x/texture.width, (float)source.y/texture.height };
-
-    rlSetTexture(texture.id);
-    rlBegin(RL_QUADS);
-
-        rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-        for (int i = 0; i < 4; i++)
-        {
-            rlTexCoord2f(texcoords[i].x, texcoords[i].y);
-            rlVertex3f(points[i].x, points[i].y, points[i].z);
-        }
-
-    rlEnd();
-    rlSetTexture(0);
-}
-
-// Draw a bounding box with wires
-void DrawBoundingBox(BoundingBox box, Color color)
-{
-    Vector3 size = { 0 };
-
-    size.x = fabsf(box.max.x - box.min.x);
-    size.y = fabsf(box.max.y - box.min.y);
-    size.z = fabsf(box.max.z - box.min.z);
-
-    Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
-
-    DrawCubeWires(center, size.x, size.y, size.z, color);
-}
-
-// Check collision between two spheres
-bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
-{
-    bool collision = false;
-
-    // Simple way to check for collision, just checking distance between two points
-    // Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution
-    /*
-    float dx = center1.x - center2.x;      // X distance between centers
-    float dy = center1.y - center2.y;      // Y distance between centers
-    float dz = center1.z - center2.z;      // Z distance between centers
-
-    float distance = sqrtf(dx*dx + dy*dy + dz*dz);  // Distance between centers
-
-    if (distance <= (radius1 + radius2)) collision = true;
-    */
-
-    // Check for distances squared to avoid sqrtf()
-    if (Vector3DotProduct(Vector3Subtract(center2, center1), Vector3Subtract(center2, center1)) <= (radius1 + radius2)*(radius1 + radius2)) collision = true;
-
-    return collision;
-}
-
-// Check collision between two boxes
-// NOTE: Boxes are defined by two points minimum and maximum
-bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2)
-{
-    bool collision = true;
-
-    if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x))
-    {
-        if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false;
-        if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false;
-    }
-    else collision = false;
-
-    return collision;
-}
-
-// Check collision between box and sphere
-bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
-{
-    bool collision = false;
-
-    float dmin = 0;
-
-    if (center.x < box.min.x) dmin += powf(center.x - box.min.x, 2);
-    else if (center.x > box.max.x) dmin += powf(center.x - box.max.x, 2);
-
-    if (center.y < box.min.y) dmin += powf(center.y - box.min.y, 2);
-    else if (center.y > box.max.y) dmin += powf(center.y - box.max.y, 2);
-
-    if (center.z < box.min.z) dmin += powf(center.z - box.min.z, 2);
-    else if (center.z > box.max.z) dmin += powf(center.z - box.max.z, 2);
-
-    if (dmin <= (radius*radius)) collision = true;
-
-    return collision;
-}
-
-// Get collision info between ray and sphere
-RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
-{
-    RayCollision collision = { 0 };
-
-    Vector3 raySpherePos = Vector3Subtract(center, ray.position);
-    float vector = Vector3DotProduct(raySpherePos, ray.direction);
-    float distance = Vector3Length(raySpherePos);
-    float d = radius*radius - (distance*distance - vector*vector);
-
-    collision.hit = d >= 0.0f;
-
-    // Check if ray origin is inside the sphere to calculate the correct collision point
-    if (distance < radius)
-    {
-        collision.distance = vector + sqrtf(d);
-
-        // Calculate collision point
-        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
-
-        // Calculate collision normal (pointing outwards)
-        collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center)));
-    }
-    else
-    {
-        collision.distance = vector - sqrtf(d);
-
-        // Calculate collision point
-        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
-
-        // Calculate collision normal (pointing inwards)
-        collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center));
-    }
-
-    return collision;
-}
-
-// Get collision info between ray and box
-RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
-{
-    RayCollision collision = { 0 };
-
-    // Note: If ray.position is inside the box, the distance is negative (as if the ray was reversed)
-    // Reversing ray.direction will give use the correct result
-    bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) &&
-                     (ray.position.y > box.min.y) && (ray.position.y < box.max.y) &&
-                     (ray.position.z > box.min.z) && (ray.position.z < box.max.z);
-
-    if (insideBox) ray.direction = Vector3Negate(ray.direction);
-
-    float t[11] = { 0 };
-
-    t[8] = 1.0f/ray.direction.x;
-    t[9] = 1.0f/ray.direction.y;
-    t[10] = 1.0f/ray.direction.z;
-
-    t[0] = (box.min.x - ray.position.x)*t[8];
-    t[1] = (box.max.x - ray.position.x)*t[8];
-    t[2] = (box.min.y - ray.position.y)*t[9];
-    t[3] = (box.max.y - ray.position.y)*t[9];
-    t[4] = (box.min.z - ray.position.z)*t[10];
-    t[5] = (box.max.z - ray.position.z)*t[10];
-    t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
-    t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
-
-    collision.hit = !((t[7] < 0) || (t[6] > t[7]));
-    collision.distance = t[6];
-    collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
-
-    // Get box center point
-    collision.normal = Vector3Lerp(box.min, box.max, 0.5f);
-    // Get vector center point->hit point
-    collision.normal = Vector3Subtract(collision.point, collision.normal);
-    // Scale vector to unit cube
-    // NOTE: We use an additional .01 to fix numerical errors
-    collision.normal = Vector3Scale(collision.normal, 2.01f);
-    collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
-    // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
-    // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
-    collision.normal.x = (float)((int)collision.normal.x);
-    collision.normal.y = (float)((int)collision.normal.y);
-    collision.normal.z = (float)((int)collision.normal.z);
-
-    collision.normal = Vector3Normalize(collision.normal);
-
-    if (insideBox)
-    {
-        // Reset ray.direction
-        ray.direction = Vector3Negate(ray.direction);
-        // Fix result
-        collision.distance *= -1.0f;
-        collision.normal = Vector3Negate(collision.normal);
-    }
-
-    return collision;
-}
-
-// Get collision info between ray and mesh
-RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
-{
-    RayCollision collision = { 0 };
-
-    // Check if mesh vertex data on CPU for testing
-    if (mesh.vertices != NULL)
-    {
-        int triangleCount = mesh.triangleCount;
-
-        // Test against all triangles in mesh
-        for (int i = 0; i < triangleCount; i++)
-        {
-            Vector3 a = { 0 };
-            Vector3 b = { 0 };
-            Vector3 c = { 0 };
-            Vector3 *vertdata = (Vector3 *)mesh.vertices;
-
-            if (mesh.indices)
-            {
-                a = vertdata[mesh.indices[i*3 + 0]];
-                b = vertdata[mesh.indices[i*3 + 1]];
-                c = vertdata[mesh.indices[i*3 + 2]];
-            }
-            else
-            {
-                a = vertdata[i*3 + 0];
-                b = vertdata[i*3 + 1];
-                c = vertdata[i*3 + 2];
-            }
-
-            a = Vector3Transform(a, transform);
-            b = Vector3Transform(b, transform);
-            c = Vector3Transform(c, transform);
-
-            RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c);
-
-            if (triHitInfo.hit)
-            {
-                // Save the closest hit triangle
-                if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo;
-            }
-        }
-    }
-
-    return collision;
-}
-
-// Get collision info between ray and triangle
-// NOTE: The points are expected to be in counter-clockwise winding
-// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
-RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
-{
-    #define EPSILON 0.000001f        // A small number
-
-    RayCollision collision = { 0 };
-    Vector3 edge1 = { 0 };
-    Vector3 edge2 = { 0 };
-    Vector3 p = { 0 };
-    Vector3 q = { 0 };
-    Vector3 tv = { 0 };
-    float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f;
-
-    // Find vectors for two edges sharing V1
-    edge1 = Vector3Subtract(p2, p1);
-    edge2 = Vector3Subtract(p3, p1);
-
-    // Begin calculating determinant - also used to calculate u parameter
-    p = Vector3CrossProduct(ray.direction, edge2);
-
-    // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
-    det = Vector3DotProduct(edge1, p);
-
-    // Avoid culling!
-    if ((det > -EPSILON) && (det < EPSILON)) return collision;
-
-    invDet = 1.0f/det;
-
-    // Calculate distance from V1 to ray origin
-    tv = Vector3Subtract(ray.position, p1);
-
-    // Calculate u parameter and test bound
-    u = Vector3DotProduct(tv, p)*invDet;
-
-    // The intersection lies outside the triangle
-    if ((u < 0.0f) || (u > 1.0f)) return collision;
-
-    // Prepare to test v parameter
-    q = Vector3CrossProduct(tv, edge1);
-
-    // Calculate V parameter and test bound
-    v = Vector3DotProduct(ray.direction, q)*invDet;
-
-    // The intersection lies outside the triangle
-    if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
-
-    t = Vector3DotProduct(edge2, q)*invDet;
-
-    if (t > EPSILON)
-    {
-        // Ray hit, get hit point and normal
-        collision.hit = true;
-        collision.distance = t;
-        collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
-        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
-    }
-
-    return collision;
-}
-
-// Get collision info between ray and quad
-// NOTE: The points are expected to be in counter-clockwise winding
-RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
-{
-    RayCollision collision = { 0 };
-
-    collision = GetRayCollisionTriangle(ray, p1, p2, p4);
-
-    if (!collision.hit) collision = GetRayCollisionTriangle(ray, p2, p3, p4);
-
-    return collision;
-}
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-#if defined(SUPPORT_FILEFORMAT_IQM) || defined(SUPPORT_FILEFORMAT_GLTF)
-// Build pose from parent joints
-// NOTE: Required for animations loading (required by IQM and GLTF)
-static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms)
-{
-    for (int i = 0; i < boneCount; i++)
-    {
-        if (bones[i].parent >= 0)
-        {
-            if (bones[i].parent > i)
-            {
-                TRACELOG(LOG_WARNING, "Assumes bones are toplogically sorted, but bone %d has parent %d. Skipping.", i, bones[i].parent);
-                continue;
-            }
-            transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation);
-            transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale);
-            transforms[i].translation = Vector3Multiply(transforms[i].translation, transforms[bones[i].parent].scale);
-            transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation);
-            transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation);
-        }
-    }
-}
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_OBJ)
-// Load OBJ mesh data
-//
-// Keep the following information in mind when reading this
-//  - A mesh is created for every material present in the obj file
-//  - the model.meshCount is therefore the materialCount returned from tinyobj
-//  - the mesh is automatically triangulated by tinyobj
-static Model LoadOBJ(const char *fileName)
-{
-    tinyobj_attrib_t objAttributes = { 0 };
-    tinyobj_shape_t *objShapes = NULL;
-    unsigned int objShapeCount = 0;
-
-    tinyobj_material_t *objMaterials = NULL;
-    unsigned int objMaterialCount = 0;
-
-    Model model = { 0 };
-    model.transform = MatrixIdentity();
-
-    char *fileText = LoadFileText(fileName);
-
-    if (fileText == NULL)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] Unable to read obj file", fileName);
-        return model;
-    }
-
-    char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
-    strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // 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);
-
-    unsigned int dataSize = (unsigned int)strlen(fileText);
-
-    unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
-    int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags);
-
-    if (ret != TINYOBJ_SUCCESS)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: Unable to read obj data %s", fileName);
-        return model;
-    }
-
-    UnloadFileText(fileText);
-
-    unsigned int faceVertIndex = 0;
-    unsigned int nextShape = 1;
-    int lastMaterial = -1;
-    unsigned int meshIndex = 0;
-
-    // Count meshes
-    unsigned int nextShapeEnd = objAttributes.num_face_num_verts;
-
-    // See how many verts till the next shape
-    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
-
-    // Walk all the faces
-    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
-    {
-        if (faceId >= nextShapeEnd)
-        {
-            // Try to find the last vert in the next shape
-            nextShape++;
-            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
-            else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces
-            meshIndex++;
-        }
-        else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial))
-        {
-            meshIndex++; // If this is a new material, we need to allocate a new mesh
-        }
-
-        lastMaterial = objAttributes.material_ids[faceId];
-        faceVertIndex += objAttributes.face_num_verts[faceId];
-    }
-
-    // Allocate the base meshes and materials
-    model.meshCount = meshIndex + 1;
-    model.meshes = (Mesh *)MemAlloc(sizeof(Mesh)*model.meshCount);
-
-    if (objMaterialCount > 0)
-    {
-        model.materialCount = objMaterialCount;
-        model.materials = (Material *)MemAlloc(sizeof(Material)*objMaterialCount);
-    }
-    else // We must allocate at least one material
-    {
-        model.materialCount = 1;
-        model.materials = (Material *)MemAlloc(sizeof(Material)*1);
-    }
-
-    model.meshMaterial = (int *)MemAlloc(sizeof(int)*model.meshCount);
-
-    // See how many verts are in each mesh
-    unsigned int *localMeshVertexCounts = (unsigned int *)MemAlloc(sizeof(unsigned int)*model.meshCount);
-
-    faceVertIndex = 0;
-    nextShapeEnd = objAttributes.num_face_num_verts;
-    lastMaterial = -1;
-    meshIndex = 0;
-    unsigned int localMeshVertexCount = 0;
-
-    nextShape = 1;
-    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
-
-    // Walk all the faces
-    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
-    {
-        bool newMesh = false; // Do we need a new mesh?
-        if (faceId >= nextShapeEnd)
-        {
-            // Try to find the last vert in the next shape
-            nextShape++;
-            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
-            else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
-
-            newMesh = true;
-        }
-        else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial))
-        {
-            newMesh = true;
-        }
-
-        lastMaterial = objAttributes.material_ids[faceId];
-
-        if (newMesh)
-        {
-            localMeshVertexCounts[meshIndex] = localMeshVertexCount;
-
-            localMeshVertexCount = 0;
-            meshIndex++;
-        }
-
-        faceVertIndex += objAttributes.face_num_verts[faceId];
-        localMeshVertexCount += objAttributes.face_num_verts[faceId];
-    }
-
-    localMeshVertexCounts[meshIndex] = localMeshVertexCount;
-
-    for (int i = 0; i < model.meshCount; i++)
-    {
-        // Allocate the buffers for each mesh
-        unsigned int vertexCount = localMeshVertexCounts[i];
-
-        model.meshes[i].vertexCount = vertexCount;
-        model.meshes[i].triangleCount = vertexCount/3;
-
-        model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3);
-        model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3);
-    #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-        model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
-        model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4);
-    #else
-        if (objAttributes.texcoords != NULL && objAttributes.num_texcoords > 0) model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
-        else model.meshes[i].texcoords = NULL;
-        model.meshes[i].colors = NULL;
-    #endif
-    }
-
-    MemFree(localMeshVertexCounts);
-    localMeshVertexCounts = NULL;
-
-    // Fill meshes
-    faceVertIndex = 0;
-
-    nextShapeEnd = objAttributes.num_face_num_verts;
-
-    // See how many verts till the next shape
-    nextShape = 1;
-    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
-    lastMaterial = -1;
-    meshIndex = 0;
-    localMeshVertexCount = 0;
-
-    // Walk all the faces
-    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
-    {
-        bool newMesh = false; // Do we need a new mesh?
-        if (faceId >= nextShapeEnd)
-        {
-            // Try to find the last vert in the next shape
-            nextShape++;
-            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
-            else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces
-            newMesh = true;
-        }
-
-        // If this is a new material, we need to allocate a new mesh
-        if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;
-        lastMaterial = objAttributes.material_ids[faceId];
-
-        if (newMesh)
-        {
-            localMeshVertexCount = 0;
-            meshIndex++;
-        }
-
-        int matId = 0;
-        if ((lastMaterial >= 0) && (lastMaterial < (int)objMaterialCount)) matId = lastMaterial;
-
-        model.meshMaterial[meshIndex] = matId;
-
-        for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++)
-        {
-            int vertIndex = objAttributes.faces[faceVertIndex].v_idx;
-            int normalIndex = objAttributes.faces[faceVertIndex].vn_idx;
-            int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx;
-
-            for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i];
-
-            if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0) && (model.meshes[meshIndex].texcoords))
-            {
-                for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
-                model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
-            }
-
-            if ((objAttributes.normals != NULL) && (normalIndex != TINYOBJ_INVALID_INDEX) && (normalIndex >= 0))
-            {
-                for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i];
-            }
-            else
-            {
-                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 0] = 0.0f;
-                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 1] = 1.0f;
-                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 2] = 0.0f;
-            }
-        #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-            for (int i = 0; i < 4; i++) model.meshes[meshIndex].colors[localMeshVertexCount*4 + i] = 255;
-        #endif
-            faceVertIndex++;
-            localMeshVertexCount++;
-        }
-    }
-
-    if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount);
-    else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
-
-    tinyobj_attrib_free(&objAttributes);
-    tinyobj_shapes_free(objShapes, objShapeCount);
-    tinyobj_materials_free(objMaterials, objMaterialCount);
-
-    // Restore current working directory
-    if (CHDIR(currentDir) != 0)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
-    }
-
-    return model;
-}
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_IQM)
-// Load IQM mesh data
-static Model LoadIQM(const char *fileName)
-{
-    #define IQM_MAGIC     "INTERQUAKEMODEL" // IQM file magic number
-    #define IQM_VERSION          2          // only IQM version 2 supported
-
-    #define BONE_NAME_LENGTH    32          // BoneInfo name string length
-    #define MESH_NAME_LENGTH    32          // Mesh name string length
-    #define MATERIAL_NAME_LENGTH 32         // Material name string length
-
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-    unsigned char *fileDataPtr = fileData;
-
-    // IQM file structs
-    //-----------------------------------------------------------------------------------
-    typedef struct IQMHeader {
-        char magic[16];
-        unsigned int version;
-        unsigned int dataSize;
-        unsigned int flags;
-        unsigned int num_text, ofs_text;
-        unsigned int num_meshes, ofs_meshes;
-        unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
-        unsigned int num_triangles, ofs_triangles, ofs_adjacency;
-        unsigned int num_joints, ofs_joints;
-        unsigned int num_poses, ofs_poses;
-        unsigned int num_anims, ofs_anims;
-        unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
-        unsigned int num_comment, ofs_comment;
-        unsigned int num_extensions, ofs_extensions;
-    } IQMHeader;
-
-    typedef struct IQMMesh {
-        unsigned int name;
-        unsigned int material;
-        unsigned int first_vertex, num_vertexes;
-        unsigned int first_triangle, num_triangles;
-    } IQMMesh;
-
-    typedef struct IQMTriangle {
-        unsigned int vertex[3];
-    } IQMTriangle;
-
-    typedef struct IQMJoint {
-        unsigned int name;
-        int parent;
-        float translate[3], rotate[4], scale[3];
-    } IQMJoint;
-
-    typedef struct IQMVertexArray {
-        unsigned int type;
-        unsigned int flags;
-        unsigned int format;
-        unsigned int size;
-        unsigned int offset;
-    } IQMVertexArray;
-
-    // NOTE: Below IQM structures are not used but listed for reference
-    /*
-    typedef struct IQMAdjacency {
-        unsigned int triangle[3];
-    } IQMAdjacency;
-
-    typedef struct IQMPose {
-        int parent;
-        unsigned int mask;
-        float channeloffset[10];
-        float channelscale[10];
-    } IQMPose;
-
-    typedef struct IQMAnim {
-        unsigned int name;
-        unsigned int first_frame, num_frames;
-        float framerate;
-        unsigned int flags;
-    } IQMAnim;
-
-    typedef struct IQMBounds {
-        float bbmin[3], bbmax[3];
-        float xyradius, radius;
-    } IQMBounds;
-    */
-    //-----------------------------------------------------------------------------------
-
-    // IQM vertex data types
-    enum {
-        IQM_POSITION     = 0,
-        IQM_TEXCOORD     = 1,
-        IQM_NORMAL       = 2,
-        IQM_TANGENT      = 3,       // NOTE: Tangents unused by default
-        IQM_BLENDINDEXES = 4,
-        IQM_BLENDWEIGHTS = 5,
-        IQM_COLOR        = 6,
-        IQM_CUSTOM       = 0x10     // NOTE: Custom vertex values unused by default
-    };
-
-    Model model = { 0 };
-
-    IQMMesh *imesh = NULL;
-    IQMTriangle *tri = NULL;
-    IQMVertexArray *va = NULL;
-    IQMJoint *ijoint = NULL;
-
-    float *vertex = NULL;
-    float *normal = NULL;
-    float *text = NULL;
-    char *blendi = NULL;
-    unsigned char *blendw = NULL;
-    unsigned char *color = NULL;
-
-    // In case file can not be read, return an empty model
-    if (fileDataPtr == NULL) return model;
-
-    const char *basePath = GetDirectoryPath(fileName);
-
-    // Read IQM header
-    IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
-
-    if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
-        UnloadFileData(fileData);
-        return model;
-    }
-
-    if (iqmHeader->version != IQM_VERSION)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
-        UnloadFileData(fileData);
-        return model;
-    }
-
-    //fileDataPtr += sizeof(IQMHeader);       // Move file data pointer
-
-    // Meshes data processing
-    imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
-    //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
-    //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
-    memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
-
-    model.meshCount = iqmHeader->num_meshes;
-    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-
-    model.materialCount = model.meshCount;
-    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
-    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-
-    char name[MESH_NAME_LENGTH] = { 0 };
-    char material[MATERIAL_NAME_LENGTH] = { 0 };
-
-    for (int i = 0; i < model.meshCount; i++)
-    {
-        //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].name, SEEK_SET);
-        //fread(name, sizeof(char), MESH_NAME_LENGTH, iqmFile);
-        memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
-
-        //fseek(iqmFile, iqmHeader->ofs_text + imesh[i].material, SEEK_SET);
-        //fread(material, sizeof(char), MATERIAL_NAME_LENGTH, iqmFile);
-        memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
-
-        model.materials[i] = LoadMaterialDefault();
-        model.materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture(TextFormat("%s/%s", basePath, material));
-
-        model.meshMaterial[i] = i;
-
-        TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
-
-        model.meshes[i].vertexCount = imesh[i].num_vertexes;
-
-        model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));       // Default vertex positions
-        model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));        // Default vertex normals
-        model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));      // Default vertex texcoords
-
-        model.meshes[i].boneIds = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char));  // Up-to 4 bones supported!
-        model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float));      // Up-to 4 bones supported!
-
-        model.meshes[i].triangleCount = imesh[i].num_triangles;
-        model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
-
-        // Animated vertex data, what we actually process for rendering
-        // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
-        model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
-        model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
-    }
-
-    // Triangles data processing
-    tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
-    //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
-    //fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
-    memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
-
-    for (int m = 0; m < model.meshCount; m++)
-    {
-        int tcounter = 0;
-
-        for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
-        {
-            // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
-            // expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes
-            // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
-            model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
-            model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
-            model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
-            tcounter += 3;
-        }
-    }
-
-    // Vertex arrays data processing
-    va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
-    //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
-    //fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
-    memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
-
-    for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
-    {
-        switch (va[i].type)
-        {
-            case IQM_POSITION:
-            {
-                vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
-                memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    int vCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
-                    {
-                        model.meshes[m].vertices[vCounter] = vertex[i];
-                        model.meshes[m].animVertices[vCounter] = vertex[i];
-                        vCounter++;
-                    }
-                }
-            } break;
-            case IQM_NORMAL:
-            {
-                normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
-                memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    int vCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
-                    {
-                        model.meshes[m].normals[vCounter] = normal[i];
-                        model.meshes[m].animNormals[vCounter] = normal[i];
-                        vCounter++;
-                    }
-                }
-            } break;
-            case IQM_TEXCOORD:
-            {
-                text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
-                memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    int vCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
-                    {
-                        model.meshes[m].texcoords[vCounter] = text[i];
-                        vCounter++;
-                    }
-                }
-            } break;
-            case IQM_BLENDINDEXES:
-            {
-                blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
-                memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    int boneCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
-                    {
-                        model.meshes[m].boneIds[boneCounter] = blendi[i];
-                        boneCounter++;
-                    }
-                }
-            } break;
-            case IQM_BLENDWEIGHTS:
-            {
-                blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
-                memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    int boneCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
-                    {
-                        model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
-                        boneCounter++;
-                    }
-                }
-            } break;
-            case IQM_COLOR:
-            {
-                color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
-                //fseek(iqmFile, va[i].offset, SEEK_SET);
-                //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
-                memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
-
-                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
-                {
-                    model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
-
-                    int vCounter = 0;
-                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
-                    {
-                        model.meshes[m].colors[vCounter] = color[i];
-                        vCounter++;
-                    }
-                }
-            } break;
-        }
-    }
-
-    // Bones (joints) data processing
-    ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
-    //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
-    //fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
-    memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
-
-    model.boneCount = iqmHeader->num_joints;
-    model.bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
-    model.bindPose = (Transform *)RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
-
-    for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
-    {
-        // Bones
-        model.bones[i].parent = ijoint[i].parent;
-        //fseek(iqmFile, iqmHeader->ofs_text + ijoint[i].name, SEEK_SET);
-        //fread(model.bones[i].name, sizeof(char), BONE_NAME_LENGTH, iqmFile);
-        memcpy(model.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
-
-        // Bind pose (base pose)
-        model.bindPose[i].translation.x = ijoint[i].translate[0];
-        model.bindPose[i].translation.y = ijoint[i].translate[1];
-        model.bindPose[i].translation.z = ijoint[i].translate[2];
-
-        model.bindPose[i].rotation.x = ijoint[i].rotate[0];
-        model.bindPose[i].rotation.y = ijoint[i].rotate[1];
-        model.bindPose[i].rotation.z = ijoint[i].rotate[2];
-        model.bindPose[i].rotation.w = ijoint[i].rotate[3];
-
-        model.bindPose[i].scale.x = ijoint[i].scale[0];
-        model.bindPose[i].scale.y = ijoint[i].scale[1];
-        model.bindPose[i].scale.z = ijoint[i].scale[2];
-    }
-
-    BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
-
-    for (int i = 0; i < model.meshCount; i++)
-    {
-        model.meshes[i].boneCount = model.boneCount;
-        model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
-
-        for (int j = 0; j < model.meshes[i].boneCount; j++)
-        {
-            model.meshes[i].boneMatrices[j] = MatrixIdentity();
-        }
-    }
-
-    UnloadFileData(fileData);
-
-    RL_FREE(imesh);
-    RL_FREE(tri);
-    RL_FREE(va);
-    RL_FREE(vertex);
-    RL_FREE(normal);
-    RL_FREE(text);
-    RL_FREE(blendi);
-    RL_FREE(blendw);
-    RL_FREE(ijoint);
-    RL_FREE(color);
-
-    return model;
-}
-
-// Load IQM animation data
-static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount)
-{
-    #define IQM_MAGIC       "INTERQUAKEMODEL"   // IQM file magic number
-    #define IQM_VERSION     2                   // only IQM version 2 supported
-
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-    unsigned char *fileDataPtr = fileData;
-
-    typedef struct IQMHeader {
-        char magic[16];
-        unsigned int version;
-        unsigned int dataSize;
-        unsigned int flags;
-        unsigned int num_text, ofs_text;
-        unsigned int num_meshes, ofs_meshes;
-        unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
-        unsigned int num_triangles, ofs_triangles, ofs_adjacency;
-        unsigned int num_joints, ofs_joints;
-        unsigned int num_poses, ofs_poses;
-        unsigned int num_anims, ofs_anims;
-        unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
-        unsigned int num_comment, ofs_comment;
-        unsigned int num_extensions, ofs_extensions;
-    } IQMHeader;
-
-    typedef struct IQMJoint {
-        unsigned int name;
-        int parent;
-        float translate[3], rotate[4], scale[3];
-    } IQMJoint;
-
-    typedef struct IQMPose {
-        int parent;
-        unsigned int mask;
-        float channeloffset[10];
-        float channelscale[10];
-    } IQMPose;
-
-    typedef struct IQMAnim {
-        unsigned int name;
-        unsigned int first_frame, num_frames;
-        float framerate;
-        unsigned int flags;
-    } IQMAnim;
-
-    // In case file can not be read, return an empty model
-    if (fileDataPtr == NULL) return NULL;
-
-    // Read IQM header
-    IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
-
-    if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
-        UnloadFileData(fileData);
-        return NULL;
-    }
-
-    if (iqmHeader->version != IQM_VERSION)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
-        UnloadFileData(fileData);
-        return NULL;
-    }
-
-    // Get bones data
-    IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
-    //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
-    //fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
-    memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
-
-    // Get animations data
-    *animCount = iqmHeader->num_anims;
-    IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
-    //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
-    //fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
-    memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
-
-    ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
-
-    // frameposes
-    unsigned short *framedata = (unsigned short *)RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
-    //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
-    //fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
-    memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
-
-    // joints
-    IQMJoint *joints = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
-    memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
-
-    for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
-    {
-        animations[a].frameCount = anim[a].num_frames;
-        animations[a].boneCount = iqmHeader->num_poses;
-        animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
-        animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
-        memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32);
-        TRACELOG(LOG_INFO, "IQM Anim %s", animations[a].name);
-        //animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
-
-        for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
-        {
-            // If animations and skeleton are in the same file, copy bone names to anim
-            if (iqmHeader->num_joints > 0) memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
-            else memcpy(animations[a].bones[j].name, "ANIMJOINTNAME", 13); // Default bone name otherwise
-            animations[a].bones[j].parent = poses[j].parent;
-        }
-
-        for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
-
-        int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
-
-        for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
-        {
-            for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
-            {
-                animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0];
-
-                if (poses[i].mask & 0x01)
-                {
-                    animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1];
-
-                if (poses[i].mask & 0x02)
-                {
-                    animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2];
-
-                if (poses[i].mask & 0x04)
-                {
-                    animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3];
-
-                if (poses[i].mask & 0x08)
-                {
-                    animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4];
-
-                if (poses[i].mask & 0x10)
-                {
-                    animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5];
-
-                if (poses[i].mask & 0x20)
-                {
-                    animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6];
-
-                if (poses[i].mask & 0x40)
-                {
-                    animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7];
-
-                if (poses[i].mask & 0x80)
-                {
-                    animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8];
-
-                if (poses[i].mask & 0x100)
-                {
-                    animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9];
-
-                if (poses[i].mask & 0x200)
-                {
-                    animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
-                    dcounter++;
-                }
-
-                animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation);
-            }
-        }
-
-        // Build frameposes
-        for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
-        {
-            for (int i = 0; i < animations[a].boneCount; i++)
-            {
-                if (animations[a].bones[i].parent >= 0)
-                {
-                    animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
-                    animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
-                    animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
-                    animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
-                }
-            }
-        }
-    }
-
-    UnloadFileData(fileData);
-
-    RL_FREE(joints);
-    RL_FREE(framedata);
-    RL_FREE(poses);
-    RL_FREE(anim);
-
-    return animations;
-}
-
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_GLTF)
-// Load file data callback for cgltf
-static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, const char *path, cgltf_size *size, void **data)
-{
-    int filesize;
-    unsigned char *filedata = LoadFileData(path, &filesize);
-
-    if (filedata == NULL) return cgltf_result_io_error;
-
-    *size = filesize;
-    *data = filedata;
-
-    return cgltf_result_success;
-}
-
-// Release file data callback for cgltf
-static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data)
-{
-    UnloadFileData((unsigned char *)data);
-}
-
-// Load image from different glTF provided methods (uri, path, buffer_view)
-static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPath)
-{
-    Image image = { 0 };
-
-    if (cgltfImage == NULL) return image;
-
-    if (cgltfImage->uri != NULL)     // Check if image data is provided as an uri (base64 or path)
-    {
-        if ((strlen(cgltfImage->uri) > 5) &&
-            (cgltfImage->uri[0] == 'd') &&
-            (cgltfImage->uri[1] == 'a') &&
-            (cgltfImage->uri[2] == 't') &&
-            (cgltfImage->uri[3] == 'a') &&
-            (cgltfImage->uri[4] == ':'))     // Check if image is provided as base64 text data
-        {
-            // Data URI Format: data:<mediatype>;base64,<data>
-
-            // Find the comma
-            int i = 0;
-            while ((cgltfImage->uri[i] != ',') && (cgltfImage->uri[i] != 0)) i++;
-
-            if (cgltfImage->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
-            else
-            {
-                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
-                void *data = NULL;
-
-                cgltf_options options = { 0 };
-                options.file.read = LoadFileGLTFCallback;
-                options.file.release = ReleaseFileGLTFCallback;
-                cgltf_result result = cgltf_load_buffer_base64(&options, outSize, cgltfImage->uri + i + 1, &data);
-
-                if (result == cgltf_result_success)
-                {
-                    image = LoadImageFromMemory(".png", (unsigned char *)data, outSize);
-                    RL_FREE(data);
-                }
-            }
-        }
-        else     // Check if image is provided as image path
-        {
-            image = LoadImage(TextFormat("%s/%s", texPath, cgltfImage->uri));
-        }
-    }
-    else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL))    // Check if image is provided as data buffer
-    {
-        unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size);
-        int offset = (int)cgltfImage->buffer_view->offset;
-        int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
-
-        // Copy buffer data to memory for loading
-        for (unsigned int i = 0; i < cgltfImage->buffer_view->size; i++)
-        {
-            data[i] = ((unsigned char *)cgltfImage->buffer_view->buffer->data)[offset];
-            offset += stride;
-        }
-
-        // Check mime_type for image: (cgltfImage->mime_type == "image/png")
-        // NOTE: Detected that some models define mime_type as "image\\/png"
-        if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) || (strcmp(cgltfImage->mime_type, "image/png") == 0))
-        {
-            image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size);
-        }
-        else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) || (strcmp(cgltfImage->mime_type, "image/jpeg") == 0))
-        {
-            image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size);
-        }
-        else TRACELOG(LOG_WARNING, "MODEL: glTF image data MIME type not recognized", TextFormat("%s/%s", texPath, cgltfImage->uri));
-
-        RL_FREE(data);
-    }
-
-    return image;
-}
-
-// Load bone info from GLTF skin data
-static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
-{
-    *boneCount = (int)skin.joints_count;
-    BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
-
-    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);
-
-        // Find parent bone index
-        int parentIndex = -1;
-
-        for (unsigned int j = 0; j < skin.joints_count; j++)
-        {
-            if (skin.joints[j] == node.parent)
-            {
-                parentIndex = (int)j;
-                break;
-            }
-        }
-
-        bones[i].parent = parentIndex;
-    }
-
-    return bones;
-}
-
-// Load glTF file into model struct, .gltf and .glb supported
-static Model LoadGLTF(const char *fileName)
-{
-    /*********************************************************************************************
-
-        Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
-        Transform handling implemented by Paul Melis (@paulmelis)
-        Reviewed by Ramon Santamaria (@raysan5)
-
-        FEATURES:
-          - Supports .gltf and .glb files
-          - Supports embedded (base64) or external textures
-          - Supports PBR metallic/roughness flow, loads material textures, values and colors
-                     PBR specular/glossiness flow and extended texture flows not supported
-          - Supports multiple meshes per model (every primitives is loaded as a separate mesh)
-          - Supports basic animations
-          - Transforms, including parent-child relations, are applied on the mesh data,
-            but the hierarchy is not kept (as it can't be represented)
-          - Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
-            are turned into separate raylib Meshes
-
-        RESTRICTIONS:
-          - Only triangle meshes supported
-          - Vertex attribute types and formats supported:
-              > Vertices (position): vec3: float
-              > Normals: vec3: float
-              > Texcoords: vec2: float
-              > Colors: vec4: u8, u16, f32 (normalized)
-              > Indices: u16, u32 (truncated to u16)
-          - Scenes defined in the glTF file are ignored. All nodes in the file are used
-
-    ***********************************************************************************************/
-
-    // Macro to simplify attributes loading code
-    #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType)
-
-    #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
-    { \
-        int n = 0; \
-        srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
-        for (unsigned int k = 0; k < accesor->count; k++) \
-        {\
-            for (int l = 0; l < numComp; l++) \
-            {\
-                dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
-            }\
-            n += (int)(accesor->stride/sizeof(srcType));\
-        }\
-    }
-
-    Model model = { 0 };
-
-    // glTF file loading
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    if (fileData == NULL) return model;
-
-    // glTF data loading
-    cgltf_options options = { 0 };
-    options.file.read = LoadFileGLTFCallback;
-    options.file.release = ReleaseFileGLTFCallback;
-    cgltf_data *data = NULL;
-    cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
-
-    if (result == cgltf_result_success)
-    {
-        if (data->file_type == cgltf_file_type_glb) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glb) loaded successfully", fileName);
-        else if (data->file_type == cgltf_file_type_gltf) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glTF) loaded successfully", fileName);
-        else TRACELOG(LOG_WARNING, "MODEL: [%s] Model format not recognized", fileName);
-
-        TRACELOG(LOG_INFO, "    > Meshes count: %i", data->meshes_count);
-        TRACELOG(LOG_INFO, "    > Materials count: %i (+1 default)", data->materials_count);
-        TRACELOG(LOG_DEBUG, "    > Buffers count: %i", data->buffers_count);
-        TRACELOG(LOG_DEBUG, "    > Images count: %i", data->images_count);
-        TRACELOG(LOG_DEBUG, "    > Textures count: %i", data->textures_count);
-
-        // Force reading data buffers (fills buffer_view->buffer->data)
-        // NOTE: If an uri is defined to base64 data or external path, it's automatically loaded
-        result = cgltf_load_buffers(&options, data, fileName);
-        if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
-
-        int primitivesCount = 0;
-
-        // NOTE: We will load every primitive in the glTF as a separate raylib Mesh
-        // Determine total number of meshes needed from the node hierarchy
-        for (unsigned int i = 0; i < data->nodes_count; i++)
-        {
-            cgltf_node *node = &(data->nodes[i]);
-            cgltf_mesh *mesh = node->mesh;
-            if (!mesh) continue;
-
-            for (unsigned int p = 0; p < mesh->primitives_count; p++)
-            {
-                if (mesh->primitives[p].type == cgltf_primitive_type_triangles) primitivesCount++;
-            }
-        }
-        TRACELOG(LOG_DEBUG, "    > Primitives (triangles only) count based on hierarchy : %i", primitivesCount);
-
-        // Load our model data: meshes and materials
-        model.meshCount = primitivesCount;
-        model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-
-        // NOTE: We keep an extra slot for default material, in case some mesh requires it
-        model.materialCount = (int)data->materials_count + 1;
-        model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
-        model.materials[0] = LoadMaterialDefault();     // Load default material (index: 0)
-
-        // Load mesh-material indices, by default all meshes are mapped to material index: 0
-        model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-
-        // Load materials data
-        //----------------------------------------------------------------------------------------------------
-        for (unsigned int i = 0, j = 1; i < data->materials_count; i++, j++)
-        {
-            model.materials[j] = LoadMaterialDefault();
-            const char *texPath = GetDirectoryPath(fileName);
-
-            // Check glTF material flow: PBR metallic/roughness flow
-            // NOTE: Alternatively, materials can follow PBR specular/glossiness flow
-            if (data->materials[i].has_pbr_metallic_roughness)
-            {
-                // Load base color texture (albedo)
-                if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
-                {
-                    Image imAlbedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath);
-                    if (imAlbedo.data != NULL)
-                    {
-                        model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo);
-                        UnloadImage(imAlbedo);
-                    }
-                }
-                // Load base color factor (tint)
-                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
-                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
-                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
-                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
-
-                // Load metallic/roughness texture
-                if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
-                {
-                    Image imMetallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath);
-                    if (imMetallicRoughness.data != NULL)
-                    {
-                        Image imMetallic = { 0 };
-                        Image imRoughness = { 0 };
-
-                        imMetallic.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height);
-                        imRoughness.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height);
-
-                        imMetallic.width = imRoughness.width = imMetallicRoughness.width;
-                        imMetallic.height = imRoughness.height = imMetallicRoughness.height;
-
-                        imMetallic.format = imRoughness.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-                        imMetallic.mipmaps = imRoughness.mipmaps = 1;
-
-                        for (int x = 0; x < imRoughness.width; x++)
-                        {
-                            for (int y = 0; y < imRoughness.height; y++)
-                            {
-                                Color color = GetImageColor(imMetallicRoughness, x, y);
-
-                                ((unsigned char *)imRoughness.data)[y*imRoughness.width + x] = color.g; // Roughness color channel
-                                ((unsigned char *)imMetallic.data)[y*imMetallic.width + x] = color.b; // Metallic color channel
-                            }
-                        }
-
-                        model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imRoughness);
-                        model.materials[j].maps[MATERIAL_MAP_METALNESS].texture = LoadTextureFromImage(imMetallic);
-
-                        UnloadImage(imRoughness);
-                        UnloadImage(imMetallic);
-                        UnloadImage(imMetallicRoughness);
-                    }
-
-                    // Load metallic/roughness material properties
-                    float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
-                    model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
-
-                    float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
-                    model.materials[j].maps[MATERIAL_MAP_METALNESS].value = metallic;
-                }
-
-                // Load normal texture
-                if (data->materials[i].normal_texture.texture)
-                {
-                    Image imNormal = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath);
-                    if (imNormal.data != NULL)
-                    {
-                        model.materials[j].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(imNormal);
-                        UnloadImage(imNormal);
-                    }
-                }
-
-                // Load ambient occlusion texture
-                if (data->materials[i].occlusion_texture.texture)
-                {
-                    Image imOcclusion = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath);
-                    if (imOcclusion.data != NULL)
-                    {
-                        model.materials[j].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(imOcclusion);
-                        UnloadImage(imOcclusion);
-                    }
-                }
-
-                // Load emissive texture
-                if (data->materials[i].emissive_texture.texture)
-                {
-                    Image imEmissive = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath);
-                    if (imEmissive.data != NULL)
-                    {
-                        model.materials[j].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(imEmissive);
-                        UnloadImage(imEmissive);
-                    }
-
-                    // Load emissive color factor
-                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
-                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
-                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
-                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.a = 255;
-                }
-            }
-
-            // Other possible materials not supported by raylib pipeline:
-            // has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen
-        }
-        //----------------------------------------------------------------------------------------------------
-
-        // Load meshes data
-        //
-        // NOTE: Visit each node in the hierarchy and process any mesh linked from it
-        //  - Each primitive within a glTF node becomes a raylib Mesh
-        //  - The local-to-world transform of each node is used to transform the points/normals/tangents of the created Mesh(es)
-        //  - Any glTF mesh linked from more than one Node (i.e. instancing) is turned into multiple Mesh's, as each Node will have its own transform applied
-        //
-        // WARNING: The code below disregards the scenes defined in the file, all nodes are used
-        //----------------------------------------------------------------------------------------------------
-        int meshIndex = 0;
-        for (unsigned int i = 0; i < data->nodes_count; i++)
-        {
-            cgltf_node *node = &(data->nodes[i]);
-
-            cgltf_mesh *mesh = node->mesh;
-            if (!mesh) continue;
-
-            cgltf_float worldTransform[16];
-            cgltf_node_transform_world(node, worldTransform);
-
-            Matrix worldMatrix = {
-                worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
-                worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
-                worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
-                worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
-            };
-
-            Matrix worldMatrixNormals = MatrixTranspose(MatrixInvert(worldMatrix));
-
-            for (unsigned int p = 0; p < mesh->primitives_count; p++)
-            {
-                // NOTE: We only support primitives defined by triangles
-                // Other alternatives: points, lines, line_strip, triangle_strip
-                if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
-
-                // NOTE: Attributes data could be provided in several data formats (8, 8u, 16u, 32...),
-                // Only some formats for each attribute type are supported, read info at the top of this function!
-
-                for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
-                {
-                    // Check the different attributes for every primitive
-                    if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_position)      // POSITION, vec3, float
-                    {
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined
-
-                        if (model.meshes[meshIndex].vertices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data already loaded", fileName);
-                        else
-                        {
-                            if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
-                            {
-                                // Init raylib mesh vertices to copy glTF attribute data
-                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
-                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load 3 components of float data type into mesh.vertices
-                                LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
-
-                                // Transform the vertices
-                                float *vertices = model.meshes[meshIndex].vertices;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k+1], vertices[3*k+2] }, worldMatrix);
-                                    vertices[3*k] = vt.x;
-                                    vertices[3*k+1] = vt.y;
-                                    vertices[3*k+2] = vt.z;
-                                }
-                            }
-                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16u))
-                            {
-                                // Init raylib mesh vertices to copy glTF attribute data
-                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
-                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
-                                LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
-
-                                // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
-                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
-
-                                RL_FREE(temp);
-
-                                // Transform the vertices
-                                float *vertices = model.meshes[meshIndex].vertices;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
-                                    vertices[3*k] = vt.x;
-                                    vertices[3*k + 1] = vt.y;
-                                    vertices[3*k + 2] = vt.z;
-                                }
-                            }
-                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
-                            {
-                                // Init raylib mesh vertices to copy glTF attribute data
-                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
-                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
-                                LOAD_ATTRIBUTE(attribute, 3, short, temp);
-
-                                // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
-                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
-
-                                RL_FREE(temp);
-
-                                // Transform the vertices
-                                float *vertices = model.meshes[meshIndex].vertices;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
-                                    vertices[3*k] = vt.x;
-                                    vertices[3*k + 1] = vt.y;
-                                    vertices[3*k + 2] = vt.z;
-                                }
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName);
-                        }
-                    }
-                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_normal)   // NORMAL, vec3, float
-                    {
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        if (model.meshes[meshIndex].normals != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data already loaded", fileName);
-                        else
-                        {
-                            if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
-                            {
-                                // Init raylib mesh normals to copy glTF attribute data
-                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load 3 components of float data type into mesh.normals
-                                LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
-
-                                // Transform the normals
-                                float *normals = model.meshes[meshIndex].normals;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 nt = Vector3Transform((Vector3){ normals[3*k], normals[3*k+1], normals[3*k+2] }, worldMatrixNormals);
-                                    normals[3*k] = nt.x;
-                                    normals[3*k+1] = nt.y;
-                                    normals[3*k+2] = nt.z;
-                                }
-                            }
-                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
-                            {
-                                // Init raylib mesh normals to copy glTF attribute data
-                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
-                                LOAD_ATTRIBUTE(attribute, 3, short, temp);
-
-                                // Convert data to raylib normal data type (float)
-                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
-
-                                RL_FREE(temp);
-
-                                // Transform the normals
-                                float *normals = model.meshes[meshIndex].normals;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
-                                    normals[3*k] = nt.x;
-                                    normals[3*k + 1] = nt.y;
-                                    normals[3*k + 2] = nt.z;
-                                }
-                            }
-                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8u))
-                            {
-                                // Init raylib mesh normals to copy glTF attribute data
-                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
-                                LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
-
-                                // Convert data to raylib normal data type (float)
-                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
-
-                                RL_FREE(temp);
-
-                                // Transform the normals
-                                float *normals = model.meshes[meshIndex].normals;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
-                                    normals[3*k] = nt.x;
-                                    normals[3*k + 1] = nt.y;
-                                    normals[3*k + 2] = nt.z;
-                                }
-                            }
-                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8))
-                            {
-                                // Init raylib mesh normals to copy glTF attribute data
-                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                char *temp = (char *)RL_MALLOC(attribute->count*3*sizeof(char));
-                                LOAD_ATTRIBUTE(attribute, 3, char, temp);
-
-                                // Convert data to raylib normal data type (float)
-                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
-
-                                RL_FREE(temp);
-
-                                // Transform the normals
-                                float *normals = model.meshes[meshIndex].normals;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
-                                    normals[3*k] = nt.x;
-                                    normals[3*k + 1] = nt.y;
-                                    normals[3*k + 2] = nt.z;
-                                }
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data format not supported, use vec3 float", fileName);
-                        }
-                    }
-                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent)   // TANGENT, vec4, float, w is tangent basis sign
-                    {
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        if (model.meshes[meshIndex].tangents != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Tangents attribute data already loaded", fileName);
-                        else
-                        {
-                            if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
-                            {
-                                // Init raylib mesh tangent to copy glTF attribute data
-                                model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
-
-                                // Load 4 components of float data type into mesh.tangents
-                                LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
-
-                                // Transform the tangents
-                                float *tangents = model.meshes[meshIndex].tangents;
-                                for (unsigned int k = 0; k < attribute->count; k++)
-                                {
-                                    Vector3 tt = Vector3Transform((Vector3){ tangents[4*k], tangents[4*k+1], tangents[4*k+2] }, worldMatrix);
-                                    tangents[4*k] = tt.x;
-                                    tangents[4*k+1] = tt.y;
-                                    tangents[4*k+2] = tt.z;
-                                }
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangents attribute data format not supported, use vec4 float", fileName);
-                        }
-                    }
-                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) // TEXCOORD_n, vec2, float/u8n/u16n
-                    {
-                        // Support up to 2 texture coordinates attributes
-                        float *texcoordPtr = NULL;
-
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        if (attribute->type == cgltf_type_vec2)
-                        {
-                            if (attribute->component_type == cgltf_component_type_r_32f)  // vec2, float
-                            {
-                                // Init raylib mesh texcoords to copy glTF attribute data
-                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
-
-                                // Load 3 components of float data type into mesh.texcoords
-                                LOAD_ATTRIBUTE(attribute, 2, float, texcoordPtr)
-                            }
-                            else if (attribute->component_type == cgltf_component_type_r_8u) // vec2, u8n
-                            {
-                                // Init raylib mesh texcoords to copy glTF attribute data
-                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*2*sizeof(unsigned char));
-                                LOAD_ATTRIBUTE(attribute, 2, unsigned char, temp);
-
-                                // Convert data to raylib texcoord data type (float)
-                                for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/255.0f;
-
-                                RL_FREE(temp);
-                            }
-                            else if (attribute->component_type == cgltf_component_type_r_16u) // vec2, u16n
-                            {
-                                // Init raylib mesh texcoords to copy glTF attribute data
-                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*2*sizeof(unsigned short));
-                                LOAD_ATTRIBUTE(attribute, 2, unsigned short, temp);
-
-                                // Convert data to raylib texcoord data type (float)
-                                for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/65535.0f;
-
-                                RL_FREE(temp);
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported", fileName);
-                        }
-                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported, use vec2 float", fileName);
-
-                        int index = mesh->primitives[p].attributes[j].index;
-                        if (index == 0) model.meshes[meshIndex].texcoords = texcoordPtr;
-                        else if (index == 1) model.meshes[meshIndex].texcoords2 = texcoordPtr;
-                        else
-                        {
-                            TRACELOG(LOG_WARNING, "MODEL: [%s] No more than 2 texture coordinates attributes supported", fileName);
-                            if (texcoordPtr != NULL) RL_FREE(texcoordPtr);
-                        }
-                    }
-                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_color)    // COLOR_n, vec3/vec4, float/u8n/u16n
-                    {
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        // WARNING: SPECS: All components of each COLOR_n accessor element MUST be clamped to [0.0, 1.0] range
-
-                        if (model.meshes[meshIndex].colors != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Colors attribute data already loaded", fileName);
-                        else
-                        {
-                            if (attribute->type == cgltf_type_vec3)  // RGB
-                            {
-                                if (attribute->component_type == cgltf_component_type_r_8u)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load data into a temp buffer to be converted to raylib data type
-                                    unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
-                                    LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
-
-                                    // Convert data to raylib color data type (4 bytes)
-                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
-                                    {
-                                        model.meshes[meshIndex].colors[c] = temp[k];
-                                        model.meshes[meshIndex].colors[c + 1] = temp[k + 1];
-                                        model.meshes[meshIndex].colors[c + 2] = temp[k + 2];
-                                        model.meshes[meshIndex].colors[c + 3] = 255;
-                                    }
-
-                                    RL_FREE(temp);
-                                }
-                                else if (attribute->component_type == cgltf_component_type_r_16u)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load data into a temp buffer to be converted to raylib data type
-                                    unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
-                                    LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
-
-                                    // Convert data to raylib color data type (4 bytes)
-                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
-                                    {
-                                        model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[k]/65535.0f)*255.0f);
-                                        model.meshes[meshIndex].colors[c + 1] = (unsigned char)(((float)temp[k + 1]/65535.0f)*255.0f);
-                                        model.meshes[meshIndex].colors[c + 2] = (unsigned char)(((float)temp[k + 2]/65535.0f)*255.0f);
-                                        model.meshes[meshIndex].colors[c + 3] = 255;
-                                    }
-
-                                    RL_FREE(temp);
-                                }
-                                else if (attribute->component_type == cgltf_component_type_r_32f)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load data into a temp buffer to be converted to raylib data type
-                                    float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
-                                    LOAD_ATTRIBUTE(attribute, 3, float, temp);
-
-                                    // Convert data to raylib color data type (4 bytes)
-                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
-                                    {
-                                        model.meshes[meshIndex].colors[c] = (unsigned char)(temp[k]*255.0f);
-                                        model.meshes[meshIndex].colors[c + 1] = (unsigned char)(temp[k + 1]*255.0f);
-                                        model.meshes[meshIndex].colors[c + 2] = (unsigned char)(temp[k + 2]*255.0f);
-                                        model.meshes[meshIndex].colors[c + 3] = 255;
-                                    }
-
-                                    RL_FREE(temp);
-                                }
-                                else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
-                            }
-                            else if (attribute->type == cgltf_type_vec4) // RGBA
-                            {
-                                if (attribute->component_type == cgltf_component_type_r_8u)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load 4 components of unsigned char data type into mesh.colors
-                                    LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
-                                }
-                                else if (attribute->component_type == cgltf_component_type_r_16u)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load data into a temp buffer to be converted to raylib data type
-                                    unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
-                                    LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
-
-                                    // Convert data to raylib color data type (4 bytes)
-                                    for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
-
-                                    RL_FREE(temp);
-                                }
-                                else if (attribute->component_type == cgltf_component_type_r_32f)
-                                {
-                                    // Init raylib mesh color to copy glTF attribute data
-                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-
-                                    // Load data into a temp buffer to be converted to raylib data type
-                                    float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
-                                    LOAD_ATTRIBUTE(attribute, 4, float, temp);
-
-                                    // Convert data to raylib color data type (4 bytes), we expect the color data normalized
-                                    for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
-
-                                    RL_FREE(temp);
-                                }
-                                else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
-                        }
-                    }
-
-                    // NOTE: Attributes related to animations data are processed after mesh data loading
-                }
-
-                // Load primitive indices data (if provided)
-                if ((mesh->primitives[p].indices != NULL) && (mesh->primitives[p].indices->buffer_view != NULL))
-                {
-                    cgltf_accessor *attribute = mesh->primitives[p].indices;
-
-                    model.meshes[meshIndex].triangleCount = (int)attribute->count/3;
-
-                    if (model.meshes[meshIndex].indices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Indices attribute data already loaded", fileName);
-                    else
-                    {
-                        if (attribute->component_type == cgltf_component_type_r_16u)
-                        {
-                            // Init raylib mesh indices to copy glTF attribute data
-                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
-
-                            // Load unsigned short data type into mesh.indices
-                            LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
-                        }
-                        else if (attribute->component_type == cgltf_component_type_r_8u)
-                        {
-                            // Init raylib mesh indices to copy glTF attribute data
-                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
-                            LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
-
-                        }
-                        else if (attribute->component_type == cgltf_component_type_r_32u)
-                        {
-                            // Init raylib mesh indices to copy glTF attribute data
-                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
-                            LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
-
-                            TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
-                        }
-                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
-                    }
-                }
-                else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3;    // Unindexed mesh
-
-                // Assign to the primitive mesh the corresponding material index
-                // NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
-                for (unsigned int m = 0; m < data->materials_count; m++)
-                {
-                    // The primitive actually keeps the pointer to the corresponding material,
-                    // raylib instead assigns to the mesh the by its index, as loaded in model.materials array
-                    // To get the index, we check if material pointers match, and we assign the corresponding index,
-                    // skipping index 0, the default material
-                    if (&data->materials[m] == mesh->primitives[p].material)
-                    {
-                        model.meshMaterial[meshIndex] = m + 1;
-                        break;
-                    }
-                }
-
-                meshIndex++;       // Move to next mesh
-            }
-        }
-        //----------------------------------------------------------------------------------------------------
-
-        // Load animation data
-        // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
-        // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
-        //
-        // LIMITATIONS:
-        //  - Only supports 1 armature per file, and skips loading it if there are multiple armatures
-        //  - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file)
-        //  - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets)
-        //----------------------------------------------------------------------------------------------------
-        if (data->skins_count > 0)
-        {
-            cgltf_skin skin = data->skins[0];
-            model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
-            model.bindPose = (Transform *)RL_MALLOC(model.boneCount*sizeof(Transform));
-
-            for (int i = 0; i < model.boneCount; i++)
-            {
-                cgltf_node *node = skin.joints[i];
-                cgltf_float worldTransform[16];
-                cgltf_node_transform_world(node, worldTransform);
-                Matrix worldMatrix = {
-                    worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
-                    worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
-                    worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
-                    worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
-                };
-                MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale));
-            }
-
-            if (data->skins_count > 1) TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
-        }
-
-        meshIndex = 0;
-        for (unsigned int i = 0; i < data->nodes_count; i++)
-        {
-            cgltf_node *node = &(data->nodes[i]);
-
-            cgltf_mesh *mesh = node->mesh;
-            if (!mesh) continue;
-
-            for (unsigned int p = 0; p < mesh->primitives_count; p++)
-            {
-                bool hasJoints = false;
-
-                // NOTE: We only support primitives defined by triangles
-                if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
-
-                for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
-                {
-                    // NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
-                    if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
-                    {
-                        hasJoints = true;
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        // NOTE: JOINTS_n can only be vec4 and u8/u16
-                        // SPECS: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview
-
-                        // WARNING: raylib only supports model.meshes[].boneIds as u8 (unsigned char),
-                        // if data is provided in any other format, it is converted to supported format but
-                        // it could imply data loss (a warning message is issued in that case)
-
-                        if (attribute->type == cgltf_type_vec4)
-                        {
-                            if (attribute->component_type == cgltf_component_type_r_8u)
-                            {
-                                // Init raylib mesh boneIds to copy glTF attribute data
-                                model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
-
-                                // Load attribute: vec4, u8 (unsigned char)
-                                LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
-                            }
-                            else if (attribute->component_type == cgltf_component_type_r_16u)
-                            {
-                                // Init raylib mesh boneIds to copy glTF attribute data
-                                model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
-                                LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
-
-                                // Convert data to raylib color data type (4 bytes)
-                                bool boneIdOverflowWarning = false;
-                                for (int b = 0; b < model.meshes[meshIndex].vertexCount*4; b++)
-                                {
-                                    if ((temp[b] > 255) && !boneIdOverflowWarning)
-                                    {
-                                        TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format (u16) overflow", fileName);
-                                        boneIdOverflowWarning = true;
-                                    }
-
-                                    // Despite the possible overflow, we convert data to unsigned char
-                                    model.meshes[meshIndex].boneIds[b] = (unsigned char)temp[b];
-                                }
-
-                                RL_FREE(temp);
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
-                        }
-                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
-                    }
-                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_weights)  // WEIGHTS_n (vec4, u8n/u16n/f32)
-                    {
-                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
-
-                        if (attribute->type == cgltf_type_vec4)
-                        {
-                            if (attribute->component_type == cgltf_component_type_r_8u)
-                            {
-                                // Init raylib mesh bone weight to copy glTF attribute data
-                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
-                                LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
-
-                                // Convert data to raylib bone weight data type (4 bytes)
-                                for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/255.0f;
-
-                                RL_FREE(temp);
-                            }
-                            else if (attribute->component_type == cgltf_component_type_r_16u)
-                            {
-                                // Init raylib mesh bone weight to copy glTF attribute data
-                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
-
-                                // Load data into a temp buffer to be converted to raylib data type
-                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
-                                LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
-
-                                // Convert data to raylib bone weight data type
-                                for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/65535.0f;
-
-                                RL_FREE(temp);
-                            }
-                            else if (attribute->component_type == cgltf_component_type_r_32f)
-                            {
-                                // Init raylib mesh bone weight to copy glTF attribute data
-                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
-
-                                // Load 4 components of float data type into mesh.boneWeights
-                                // for cgltf_attribute_type_weights we have:
-
-                                //   - data.meshes[0] (256 vertices)
-                                //   - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
-                                LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
-                            }
-                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
-                        }
-                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
-                    }
-                }
-
-                // Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node
-                // in this case we need to fully attach all the verts to the parent bone so it will animate with the bone
-                if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL)
-                {
-                    int parentBoneId = -1;
-                    for (int joint = 0; joint < model.boneCount; joint++)
-                    {
-                        if (data->skins[0].joints[joint] == node->parent)
-                        {
-                            parentBoneId = joint;
-                            break;
-                        }
-                    }
-
-                    if (parentBoneId >= 0)
-                    {
-                        model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
-                        model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
-
-                        for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
-                        {
-                            model.meshes[meshIndex].boneIds[vertexIndex] = (unsigned char)parentBoneId;
-                            model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f;
-                        }
-                    }
-                }
-
-                // Animated vertex data
-                model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
-                memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
-                model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
-                if (model.meshes[meshIndex].normals != NULL)
-                {
-                    memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
-                }
-
-                // Bone Transform Matrices
-                model.meshes[meshIndex].boneCount = model.boneCount;
-                model.meshes[meshIndex].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
-
-                for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
-                {
-                    model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
-                }
-
-                meshIndex++; // Move to next mesh
-            }
-        }
-        //----------------------------------------------------------------------------------------------------
-
-        // Free all cgltf loaded data
-        cgltf_free(data);
-    }
-    else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
-
-    // WARNING: cgltf requires the file pointer available while reading data
-    UnloadFileData(fileData);
-
-    return model;
-}
-
-// Get interpolated pose for bone sampler at a specific time. Returns true on success
-static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_accessor *input, cgltf_accessor *output, float time, void *data)
-{
-    if (interpolationType >= cgltf_interpolation_type_max_enum) return false;
-
-    // Input and output should have the same count
-    float tstart = 0.0f;
-    float tend = 0.0f;
-    int keyframe = 0;       // Defaults to first pose
-
-    for (int i = 0; i < (int)input->count - 1; i++)
-    {
-        cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1);
-        if (!r1) return false;
-
-        cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1);
-        if (!r2) return false;
-
-        if ((tstart <= time) && (time < tend))
-        {
-            keyframe = i;
-            break;
-        }
-    }
-
-    // Constant animation, no need to interpolate
-    if (FloatEquals(tend, tstart)) return true;
-
-    float duration = fmaxf((tend - tstart), EPSILON);
-    float t = (time - tstart)/duration;
-    t = (t < 0.0f)? 0.0f : t;
-    t = (t > 1.0f)? 1.0f : t;
-
-    if (output->component_type != cgltf_component_type_r_32f) return false;
-
-    if (output->type == cgltf_type_vec3)
-    {
-        switch (interpolationType)
-        {
-            case cgltf_interpolation_type_step:
-            {
-                float tmp[3] = { 0.0f };
-                cgltf_accessor_read_float(output, keyframe, tmp, 3);
-                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
-                Vector3 *r = (Vector3 *)data;
-
-                *r = v1;
-            } break;
-            case cgltf_interpolation_type_linear:
-            {
-                float tmp[3] = { 0.0f };
-                cgltf_accessor_read_float(output, keyframe, tmp, 3);
-                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
-                cgltf_accessor_read_float(output, keyframe+1, tmp, 3);
-                Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
-                Vector3 *r = (Vector3 *)data;
-
-                *r = Vector3Lerp(v1, v2, t);
-            } break;
-            case cgltf_interpolation_type_cubic_spline:
-            {
-                float tmp[3] = { 0.0f };
-                cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 3);
-                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
-                cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 3);
-                Vector3 tangent1 = {tmp[0], tmp[1], tmp[2]};
-                cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 3);
-                Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
-                cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 3);
-                Vector3 tangent2 = {tmp[0], tmp[1], tmp[2]};
-                Vector3 *r = (Vector3 *)data;
-
-                *r = Vector3CubicHermite(v1, tangent1, v2, tangent2, t);
-            } break;
-            default: break;
-        }
-    }
-    else if (output->type == cgltf_type_vec4)
-    {
-        // Only v4 is for rotations, so we know it's a quaternion
-        switch (interpolationType)
-        {
-            case cgltf_interpolation_type_step:
-            {
-                float tmp[4] = { 0.0f };
-                cgltf_accessor_read_float(output, keyframe, tmp, 4);
-                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
-                Vector4 *r = (Vector4 *)data;
-
-                *r = v1;
-            } break;
-            case cgltf_interpolation_type_linear:
-            {
-                float tmp[4] = { 0.0f };
-                cgltf_accessor_read_float(output, keyframe, tmp, 4);
-                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
-                cgltf_accessor_read_float(output, keyframe+1, tmp, 4);
-                Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
-                Vector4 *r = (Vector4 *)data;
-
-                *r = QuaternionSlerp(v1, v2, t);
-            } break;
-            case cgltf_interpolation_type_cubic_spline:
-            {
-                float tmp[4] = { 0.0f };
-                cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 4);
-                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
-                cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 4);
-                Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2], 0.0f};
-                cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 4);
-                Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
-                cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4);
-                Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f};
-                Vector4 *r = (Vector4 *)data;
-
-                v1 = QuaternionNormalize(v1);
-                v2 = QuaternionNormalize(v2);
-
-                if (Vector4DotProduct(v1, v2) < 0.0f)
-                {
-                    v2 = Vector4Negate(v2);
-                }
-
-                outTangent1 = Vector4Scale(outTangent1, duration);
-                inTangent2 = Vector4Scale(inTangent2, duration);
-
-                *r = QuaternionCubicHermiteSpline(v1, outTangent1, v2, inTangent2, t);
-            } break;
-            default: break;
-        }
-    }
-
-    return true;
-}
-
-#define GLTF_FRAMERATE 60.0f    // glTF animation framerate (frames per second)
-
-static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount)
-{
-    // glTF file loading
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    ModelAnimation *animations = NULL;
-
-    // glTF data loading
-    cgltf_options options = { 0 };
-    options.file.read = LoadFileGLTFCallback;
-    options.file.release = ReleaseFileGLTFCallback;
-    cgltf_data *data = NULL;
-    cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
-
-    if (result != cgltf_result_success)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
-        *animCount = 0;
-        return NULL;
-    }
-
-    result = cgltf_load_buffers(&options, data, fileName);
-    if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName);
-
-    if (result == cgltf_result_success)
-    {
-        if (data->skins_count > 0)
-        {
-            cgltf_skin skin = data->skins[0];
-            *animCount = (int)data->animations_count;
-            animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
-
-            Transform worldTransform = { 0 };
-            cgltf_float cgltf_worldTransform[16] = { 0 };
-            cgltf_node *node = skin.joints[0];
-            cgltf_node_transform_world(node->parent, cgltf_worldTransform);
-            Matrix worldMatrix = {
-                cgltf_worldTransform[0], cgltf_worldTransform[4], cgltf_worldTransform[8], cgltf_worldTransform[12],
-                cgltf_worldTransform[1], cgltf_worldTransform[5], cgltf_worldTransform[9], cgltf_worldTransform[13],
-                cgltf_worldTransform[2], cgltf_worldTransform[6], cgltf_worldTransform[10], cgltf_worldTransform[14],
-                cgltf_worldTransform[3], cgltf_worldTransform[7], cgltf_worldTransform[11], cgltf_worldTransform[15]
-            };
-            MatrixDecompose(worldMatrix, &worldTransform.translation, &worldTransform.rotation, &worldTransform.scale);
-
-            for (unsigned int i = 0; i < data->animations_count; i++)
-            {
-                animations[i].bones = LoadBoneInfoGLTF(skin, &animations[i].boneCount);
-
-                cgltf_animation animData = data->animations[i];
-
-                struct Channels {
-                    cgltf_animation_channel *translate;
-                    cgltf_animation_channel *rotate;
-                    cgltf_animation_channel *scale;
-                    cgltf_interpolation_type interpolationType;
-                };
-
-                struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
-                float animDuration = 0.0f;
-
-                for (unsigned int j = 0; j < animData.channels_count; j++)
-                {
-                    cgltf_animation_channel channel = animData.channels[j];
-                    int boneIndex = -1;
-
-                    for (unsigned int k = 0; k < skin.joints_count; k++)
-                    {
-                        if (animData.channels[j].target_node == skin.joints[k])
-                        {
-                            boneIndex = k;
-                            break;
-                        }
-                    }
-
-                    if (boneIndex == -1)
-                    {
-                        // Animation channel for a node not in the armature
-                        continue;
-                    }
-
-                    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)
-                        {
-                            boneChannels[boneIndex].translate = &animData.channels[j];
-                        }
-                        else if (channel.target_path == cgltf_animation_path_type_rotation)
-                        {
-                            boneChannels[boneIndex].rotate = &animData.channels[j];
-                        }
-                        else if (channel.target_path == cgltf_animation_path_type_scale)
-                        {
-                            boneChannels[boneIndex].scale = &animData.channels[j];
-                        }
-                        else
-                        {
-                            TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i);
-                        }
-                    }
-                    else TRACELOG(LOG_WARNING, "MODEL: [%s] Invalid interpolation curve encountered for GLTF animation.", fileName);
-
-                    float t = 0.0f;
-                    cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1);
-
-                    if (!r)
-                    {
-                        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName);
-                        continue;
-                    }
-
-                    animDuration = (t > animDuration)? t : animDuration;
-                }
-
-                if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1);
-
-                animations[i].frameCount = (int)(animDuration*GLTF_FRAMERATE) + 1;
-                animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
-
-                for (int j = 0; j < animations[i].frameCount; j++)
-                {
-                    animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform));
-                    float time = (float)j / GLTF_FRAMERATE;
-
-                    for (int k = 0; k < animations[i].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]};
-                        Vector3 scale = {skin.joints[k]->scale[0], skin.joints[k]->scale[1], skin.joints[k]->scale[2]};
-
-                        if (boneChannels[k].translate)
-                        {
-                            if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, 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, animations[i].bones[k].name);
-                            }
-                        }
-
-                        if (boneChannels[k].rotate)
-                        {
-                            if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, 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, animations[i].bones[k].name);
-                            }
-                        }
-
-                        if (boneChannels[k].scale)
-                        {
-                            if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, 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, animations[i].bones[k].name);
-                            }
-                        }
-
-                        animations[i].framePoses[j][k] = (Transform){
-                            .translation = translation,
-                            .rotation = rotation,
-                            .scale = scale
-                        };
-                    }
-
-                    Transform* root = &animations[i].framePoses[j][0];
-                    root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation);
-                    root->scale = Vector3Multiply(root->scale, worldTransform.scale);
-                    root->translation = Vector3Multiply(root->translation, worldTransform.scale);
-                    root->translation = Vector3RotateByQuaternion(root->translation, worldTransform.rotation);
-                    root->translation = Vector3Add(root->translation, worldTransform.translation);
-
-                    BuildPoseFromParentJoints(animations[i].bones, animations[i].boneCount, animations[i].framePoses[j]);
-                }
-
-                TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s (%d frames, %fs)", fileName, (animData.name != NULL)? animData.name : "NULL", animations[i].frameCount, animDuration);
-                RL_FREE(boneChannels);
-            }
-        }
-
-        if (data->skins_count > 1)
-        {
-            TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
-        }
-
-        cgltf_free(data);
-    }
-    UnloadFileData(fileData);
-    return animations;
-}
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_VOX)
-// Load VOX (MagicaVoxel) mesh data
-static Model LoadVOX(const char *fileName)
-{
-    Model model = { 0 };
-
-    int nbvertices = 0;
-    int meshescount = 0;
-
-    // Read vox file into buffer
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    if (fileData == 0)
-    {
-        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName);
-        return model;
-    }
-
-    // Read and build voxarray description
-    VoxArray3D voxarray = { 0 };
-    int ret = Vox_LoadFromMemory(fileData, dataSize, &voxarray);
-
-    if (ret != VOX_SUCCESS)
-    {
-        // Error
-        UnloadFileData(fileData);
-
-        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName);
-        return model;
-    }
-    else
-    {
-        // Success: Compute meshes count
-        nbvertices = voxarray.vertices.used;
-        meshescount = 1 + (nbvertices/65536);
-
-        TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount);
-    }
-
-    // Build models from meshes
-    model.transform = MatrixIdentity();
-
-    model.meshCount = meshescount;
-    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-
-    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-
-    model.materialCount = 1;
-    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
-    model.materials[0] = LoadMaterialDefault();
-
-    // Init model meshes
-    int verticesRemain = voxarray.vertices.used;
-    int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536)
-
-    // 6*4 = 12 vertices per voxel
-    Vector3 *pvertices = (Vector3 *)voxarray.vertices.array;
-    Vector3 *pnormals = (Vector3 *)voxarray.normals.array;
-    Color *pcolors = (Color *)voxarray.colors.array;
-
-    unsigned short *pindices = voxarray.indices.array;    // 5461*6*6 = 196596 indices max per mesh
-
-    int size = 0;
-
-    for (int i = 0; i < meshescount; i++)
-    {
-        Mesh *pmesh = &model.meshes[i];
-        memset(pmesh, 0, sizeof(Mesh));
-
-        // Copy vertices
-        pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain);
-
-        size = pmesh->vertexCount*sizeof(float)*3;
-        pmesh->vertices = (float *)RL_MALLOC(size);
-        memcpy(pmesh->vertices, pvertices, size);
-
-        // Copy normals
-        pmesh->normals = (float *)RL_MALLOC(size);
-        memcpy(pmesh->normals, pnormals, size);
-
-        // Copy indices
-        size = voxarray.indices.used*sizeof(unsigned short);
-        pmesh->indices = (unsigned short *)RL_MALLOC(size);
-        memcpy(pmesh->indices, pindices, size);
-
-        pmesh->triangleCount = (pmesh->vertexCount/4)*2;
-
-        // Copy colors
-        size = pmesh->vertexCount*sizeof(Color);
-        pmesh->colors = (unsigned char *)RL_MALLOC(size);
-        memcpy(pmesh->colors, pcolors, size);
-
-        // First material index
-        model.meshMaterial[i] = 0;
-
-        verticesRemain -= verticesMax;
-        pvertices += verticesMax;
-        pnormals += verticesMax;
-        pcolors += verticesMax;
-    }
-
-    // Free buffers
-    Vox_FreeArrays(&voxarray);
-    UnloadFileData(fileData);
-
-    return model;
-}
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_M3D)
-// Hook LoadFileData()/UnloadFileData() calls to M3D loaders
-unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, (int *)len); }
-void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); }
-
-// Load M3D mesh data
-static Model LoadM3D(const char *fileName)
-{
-    Model model = { 0 };
-
-    m3d_t *m3d = NULL;
-    m3dp_t *prop = NULL;
-    int i, j, k, l, n, mi = -2, vcolor = 0;
-
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    if (fileData != NULL)
-    {
-        m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
-
-        if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
-        {
-            TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
-            if (m3d) m3d_free(m3d);
-            UnloadFileData(fileData);
-            return model;
-        }
-        else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial);
-
-        // no face? this is probably just a material library
-        if (!m3d->numface)
-        {
-            m3d_free(m3d);
-            UnloadFileData(fileData);
-            return model;
-        }
-
-        if (m3d->nummaterial > 0)
-        {
-            model.meshCount = model.materialCount = m3d->nummaterial;
-            TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount);
-        }
-        else
-        {
-            model.meshCount = 1; model.materialCount = 0;
-            TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
-        }
-
-        // We always need a default material, so we add +1
-        model.materialCount++;
-
-        // Faces must be in non-decreasing materialid order. Verify that quickly, sorting them otherwise
-        // WARNING: Sorting is not needed, valid M3D model files should already be sorted
-        // Just keeping the sorting function for reference (Check PR #3363 #3385)
-        /*
-        for (i = 1; i < m3d->numface; i++)
-        {
-            if (m3d->face[i-1].materialid <= m3d->face[i].materialid) continue;
-
-            // face[i-1] > face[i].  slide face[i] lower
-            m3df_t slider = m3d->face[i];
-            j = i-1;
-
-            do
-            {   // face[j] > slider, face[j+1] is svailable vacant gap
-                m3d->face[j+1] = m3d->face[j];
-                j = j-1;
-            }
-            while (j >= 0 && m3d->face[j].materialid > slider.materialid);
-
-            m3d->face[j+1] = slider;
-        }
-        */
-
-        model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-        model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-        model.materials = (Material *)RL_CALLOC(model.materialCount + 1, sizeof(Material));
-
-        // Map no material to index 0 with default shader, everything else materialid + 1
-        model.materials[0] = LoadMaterialDefault();
-
-        for (i = l = 0, k = -1; i < (int)m3d->numface; i++, l++)
-        {
-            // Materials are grouped together
-            if (mi != m3d->face[i].materialid)
-            {
-                // There should be only one material switch per material kind,
-                // but be bulletproof for non-optimal model files
-                if (k + 1 >= model.meshCount)
-                {
-                    model.meshCount++;
-
-                    // Create a second buffer for mesh re-allocation
-                    Mesh *tempMeshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
-                    memcpy(tempMeshes, model.meshes, (model.meshCount - 1)*sizeof(Mesh));
-                    RL_FREE(model.meshes);
-                    model.meshes = tempMeshes;
-
-                    // Create a second buffer for material re-allocation
-                    int *tempMeshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
-                    memcpy(tempMeshMaterial, model.meshMaterial, (model.meshCount - 1)*sizeof(int));
-                    RL_FREE(model.meshMaterial);
-                    model.meshMaterial = tempMeshMaterial;
-                }
-
-                k++;
-                mi = m3d->face[i].materialid;
-
-                // Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch
-                // if all colors are fully transparent black for all verteces of this materal, then we assume no vertex colors
-                for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++)
-                {
-                    if (!m3d->vertex[m3d->face[j].vertex[0]].color ||
-                        !m3d->vertex[m3d->face[j].vertex[1]].color ||
-                        !m3d->vertex[m3d->face[j].vertex[2]].color) vcolor = 1;
-                }
-
-                model.meshes[k].vertexCount = l*3;
-                model.meshes[k].triangleCount = l;
-                model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
-                model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
-                model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
-
-                // If no map is provided, or we have colors defined, we allocate storage for vertex colors
-                // M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
-                if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
-
-                // If no map is provided and we allocated vertex colors, set them to white
-                if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
-                {
-                    for (int c = 0; c < model.meshes[k].vertexCount*4; c++) model.meshes[k].colors[c] = 255;
-                }
-
-                if (m3d->numbone && m3d->numskin)
-                {
-                    model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
-                    model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float));
-                    model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
-                    model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
-                }
-
-                model.meshMaterial[k] = mi + 1;
-                l = 0;
-            }
-
-            // Process meshes per material, add triangles
-            model.meshes[k].vertices[l*9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale;
-            model.meshes[k].vertices[l*9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale;
-            model.meshes[k].vertices[l*9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale;
-            model.meshes[k].vertices[l*9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale;
-            model.meshes[k].vertices[l*9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale;
-            model.meshes[k].vertices[l*9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale;
-            model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale;
-            model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale;
-            model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale;
-
-            // Without vertex color (full transparency), we use the default color
-            if (model.meshes[k].colors != NULL)
-            {
-                if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
-                    memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
-                if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000)
-                    memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
-                if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000)
-                    memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
-            }
-
-            if (m3d->face[i].texcoord[0] != M3D_UNDEF)
-            {
-                model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u;
-                model.meshes[k].texcoords[l*6 + 1] = 1.0f - m3d->tmap[m3d->face[i].texcoord[0]].v;
-                model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u;
-                model.meshes[k].texcoords[l*6 + 3] = 1.0f - m3d->tmap[m3d->face[i].texcoord[1]].v;
-                model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u;
-                model.meshes[k].texcoords[l*6 + 5] = 1.0f - m3d->tmap[m3d->face[i].texcoord[2]].v;
-            }
-
-            if (m3d->face[i].normal[0] != M3D_UNDEF)
-            {
-                model.meshes[k].normals[l*9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x;
-                model.meshes[k].normals[l*9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y;
-                model.meshes[k].normals[l*9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z;
-                model.meshes[k].normals[l*9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x;
-                model.meshes[k].normals[l*9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y;
-                model.meshes[k].normals[l*9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z;
-                model.meshes[k].normals[l*9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x;
-                model.meshes[k].normals[l*9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y;
-                model.meshes[k].normals[l*9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z;
-            }
-
-            // Add skin (vertex / bone weight pairs)
-            if (m3d->numbone && m3d->numskin)
-            {
-                for (n = 0; n < 3; n++)
-                {
-                    int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
-
-                    // Check if there is a skin for this mesh, should be, just failsafe
-                    if ((skinid != M3D_UNDEF) && (skinid < (int)m3d->numskin))
-                    {
-                        for (j = 0; j < 4; j++)
-                        {
-                            model.meshes[k].boneIds[l*12 + n*4 + j] = m3d->skin[skinid].boneid[j];
-                            model.meshes[k].boneWeights[l*12 + n*4 + j] = m3d->skin[skinid].weight[j];
-                        }
-                    }
-                    else
-                    {
-                        // raylib does not handle boneless meshes with skeletal animations, so
-                        // we put all vertices without a bone into a special "no bone" bone
-                        model.meshes[k].boneIds[l*12 + n*4] = m3d->numbone;
-                        model.meshes[k].boneWeights[l*12 + n*4] = 1.0f;
-                    }
-                }
-            }
-        }
-
-        // Load materials
-        for (i = 0; i < (int)m3d->nummaterial; i++)
-        {
-            model.materials[i + 1] = LoadMaterialDefault();
-
-            for (j = 0; j < m3d->material[i].numprop; j++)
-            {
-                prop = &m3d->material[i].prop[j];
-
-                switch (prop->type)
-                {
-                    case m3dp_Kd:
-                    {
-                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4);
-                        model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
-                    } break;
-                    case m3dp_Ks:
-                    {
-                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4);
-                    } break;
-                    case m3dp_Ns:
-                    {
-                        model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = prop->value.fnum;
-                    } break;
-                    case m3dp_Ke:
-                    {
-                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4);
-                        model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f;
-                    } break;
-                    case m3dp_Pm:
-                    {
-                        model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum;
-                    } break;
-                    case m3dp_Pr:
-                    {
-                        model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum;
-                    } break;
-                    case m3dp_Ps:
-                    {
-                        model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE;
-                        model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum;
-                    } break;
-                    default:
-                    {
-                        if (prop->type >= 128)
-                        {
-                            Image image = { 0 };
-                            image.data = m3d->texture[prop->value.textureid].d;
-                            image.width = m3d->texture[prop->value.textureid].w;
-                            image.height = m3d->texture[prop->value.textureid].h;
-                            image.mipmaps = 1;
-                            image.format = (m3d->texture[prop->value.textureid].f == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 :
-                                           ((m3d->texture[prop->value.textureid].f == 3)? PIXELFORMAT_UNCOMPRESSED_R8G8B8 :
-                                           ((m3d->texture[prop->value.textureid].f == 2)? PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : PIXELFORMAT_UNCOMPRESSED_GRAYSCALE));
-
-                            switch (prop->type)
-                            {
-                                case m3dp_map_Kd: model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTextureFromImage(image); break;
-                                case m3dp_map_Ks: model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].texture = LoadTextureFromImage(image); break;
-                                case m3dp_map_Ke: model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(image); break;
-                                case m3dp_map_Km: model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(image); break;
-                                case m3dp_map_Ka: model.materials[i + 1].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(image); break;
-                                case m3dp_map_Pm: model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(image); break;
-                                default: break;
-                            }
-                        }
-                    } break;
-                }
-            }
-        }
-
-        // Load bones
-        if (m3d->numbone)
-        {
-            model.boneCount = m3d->numbone + 1;
-            model.bones = (BoneInfo *)RL_CALLOC(model.boneCount, sizeof(BoneInfo));
-            model.bindPose = (Transform *)RL_CALLOC(model.boneCount, sizeof(Transform));
-
-            for (i = 0; i < (int)m3d->numbone; i++)
-            {
-                model.bones[i].parent = m3d->bone[i].parent;
-                strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name) - 1);
-                model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
-                model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
-                model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
-                model.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x;
-                model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y;
-                model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z;
-                model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w;
-
-                // TODO: If the orientation quaternion is not normalized, then that's encoding scaling
-                model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation);
-                model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
-
-                // Child bones are stored in parent bone relative space, convert that into model space
-                if (model.bones[i].parent >= 0)
-                {
-                    model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
-                    model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
-                    model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
-                    model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
-                }
-            }
-
-            // Add a special "no bone" bone
-            model.bones[i].parent = -1;
-            memcpy(model.bones[i].name, "NO BONE", 7);
-            model.bindPose[i].translation.x = 0.0f;
-            model.bindPose[i].translation.y = 0.0f;
-            model.bindPose[i].translation.z = 0.0f;
-            model.bindPose[i].rotation.x = 0.0f;
-            model.bindPose[i].rotation.y = 0.0f;
-            model.bindPose[i].rotation.z = 0.0f;
-            model.bindPose[i].rotation.w = 1.0f;
-            model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
-        }
-
-        // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
-        // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty)
-        if (m3d->numbone && m3d->numskin)
-        {
-            for (i = 0; i < model.meshCount; i++)
-            {
-                memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
-                memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
-
-                model.meshes[i].boneCount = model.boneCount;
-                model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
-                for (j = 0; j < model.meshes[i].boneCount; j++)
-                {
-                    model.meshes[i].boneMatrices[j] = MatrixIdentity();
-                }
-            }
-        }
-
-        m3d_free(m3d);
-        UnloadFileData(fileData);
-    }
-
-    return model;
-}
-
-#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)
-{
-    ModelAnimation *animations = NULL;
-
-    m3d_t *m3d = NULL;
-    int i = 0, j = 0;
-    *animCount = 0;
-
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    if (fileData != NULL)
-    {
-        m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
-
-        if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
-        {
-            TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
-            UnloadFileData(fileData);
-            return NULL;
-        }
-        else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName,
-            m3d->numaction, m3d->numbone, m3d->numskin);
-
-        // No animation or bones, exit out. skins are not required because some people use one animation for N models
-        if (!m3d->numaction || !m3d->numbone)
-        {
-            m3d_free(m3d);
-            UnloadFileData(fileData);
-            return NULL;
-        }
-
-        animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation));
-        *animCount = m3d->numaction;
-
-        for (unsigned int a = 0; a < m3d->numaction; a++)
-        {
-            animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
-            animations[a].boneCount = m3d->numbone + 1;
-            animations[a].bones = (BoneInfo *)RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
-            animations[a].framePoses = (Transform **)RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
-            strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
-
-            TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
-
-            for (i = 0; i < (int)m3d->numbone; i++)
-            {
-                animations[a].bones[i].parent = m3d->bone[i].parent;
-                strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name) - 1);
-            }
-
-            // A special, never transformed "no bone" bone, used for boneless vertices
-            animations[a].bones[i].parent = -1;
-            memcpy(animations[a].bones[i].name, "NO BONE", 7);
-
-            // M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
-            // regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
-            for (i = 0; i < animations[a].frameCount; i++)
-            {
-                animations[a].framePoses[i] = (Transform *)RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
-
-                m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
-
-                if (pose != NULL)
-                {
-                    for (j = 0; j < (int)m3d->numbone; j++)
-                    {
-                        animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale;
-                        animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale;
-                        animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z*m3d->scale;
-                        animations[a].framePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x;
-                        animations[a].framePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y;
-                        animations[a].framePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z;
-                        animations[a].framePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w;
-                        animations[a].framePoses[i][j].rotation = QuaternionNormalize(animations[a].framePoses[i][j].rotation);
-                        animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
-
-                        // Child bones are stored in parent bone relative space, convert that into model space
-                        if (animations[a].bones[j].parent >= 0)
-                        {
-                            animations[a].framePoses[i][j].rotation = QuaternionMultiply(animations[a].framePoses[i][animations[a].bones[j].parent].rotation, animations[a].framePoses[i][j].rotation);
-                            animations[a].framePoses[i][j].translation = Vector3RotateByQuaternion(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].rotation);
-                            animations[a].framePoses[i][j].translation = Vector3Add(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].translation);
-                            animations[a].framePoses[i][j].scale = Vector3Multiply(animations[a].framePoses[i][j].scale, animations[a].framePoses[i][animations[a].bones[j].parent].scale);
-                        }
-                    }
-
-                    // Default transform for the "no bone" bone
-                    animations[a].framePoses[i][j].translation.x = 0.0f;
-                    animations[a].framePoses[i][j].translation.y = 0.0f;
-                    animations[a].framePoses[i][j].translation.z = 0.0f;
-                    animations[a].framePoses[i][j].rotation.x = 0.0f;
-                    animations[a].framePoses[i][j].rotation.y = 0.0f;
-                    animations[a].framePoses[i][j].rotation.z = 0.0f;
-                    animations[a].framePoses[i][j].rotation.w = 1.0f;
-                    animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
-                    RL_FREE(pose);
-                }
-            }
-        }
-
-        m3d_free(m3d);
-        UnloadFileData(fileData);
-    }
-
-    return animations;
-}
-#endif
-
-#endif      // SUPPORT_MODULE_RMODELS
+*       #define SUPPORT_MODULE_RMODELS      1
+*           rmodels module is included in the build
+*
+*       #define SUPPORT_FILEFORMAT_OBJ      1
+*       #define SUPPORT_FILEFORMAT_MTL      1
+*       #define SUPPORT_FILEFORMAT_IQM      1
+*       #define SUPPORT_FILEFORMAT_GLTF     1
+*       #define SUPPORT_FILEFORMAT_GLTF_WRITE   0
+*       #define SUPPORT_FILEFORMAT_VOX      1
+*       #define SUPPORT_FILEFORMAT_M3D      1
+*           Selected desired fileformats to be supported for model data loading
+*
+*       #define SUPPORT_MESH_GENERATION     1
+*           Support procedural mesh generation functions, uses external par_shapes.h library
+*           NOTE: Some generated meshes DO NOT include generated texture coordinates
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   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.
+*
+**********************************************************************************************/
+
+#include "raylib.h"         // Declares module functions
+
+#include "config.h"         // Defines module configuration flags
+
+#if SUPPORT_MODULE_RMODELS
+
+#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 <stdio.h>          // Required for: sprintf(), snprintf()
+#include <stdlib.h>         // Required for: malloc(), calloc(), free()
+#include <string.h>         // Required for: strlen(), memcmp()
+#include <math.h>           // Required for: sinf(), cosf(), sqrtf(), fabsf()
+
+#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
+    #define TINYOBJ_MALLOC RL_MALLOC
+    #define TINYOBJ_CALLOC RL_CALLOC
+    #define TINYOBJ_REALLOC RL_REALLOC
+    #define TINYOBJ_FREE RL_FREE
+
+    #define TINYOBJ_LOADER_C_IMPLEMENTATION
+    #include "external/tinyobj_loader_c.h"      // OBJ/MTL file formats loading
+#endif
+
+#if SUPPORT_FILEFORMAT_GLTF
+    #define CGLTF_MALLOC RL_MALLOC
+    #define CGLTF_FREE RL_FREE
+
+    #define CGLTF_IMPLEMENTATION
+    #include "external/cgltf.h"         // glTF file format loading
+#endif
+#if SUPPORT_FILEFORMAT_GLTF_WRITE
+    // NOTE: No need for custom allocators, memory buffer provided
+    #define CGLTF_WRITE_IMPLEMENTATION
+    #include "external/cgltf_write.h"   // glTF file format writing
+#endif
+
+#if SUPPORT_FILEFORMAT_VOX
+    #define VOX_MALLOC RL_MALLOC
+    #define VOX_CALLOC RL_CALLOC
+    #define VOX_REALLOC RL_REALLOC
+    #define VOX_FREE RL_FREE
+
+    #define VOX_LOADER_IMPLEMENTATION
+    #include "external/vox_loader.h"    // VOX file format loading (MagicaVoxel)
+#endif
+
+#if SUPPORT_FILEFORMAT_M3D
+    #define M3D_MALLOC RL_MALLOC
+    #define M3D_REALLOC RL_REALLOC
+    #define M3D_FREE RL_FREE
+
+    #define M3D_IMPLEMENTATION
+    #include "external/m3d.h"           // Model3D file format loading
+#endif
+
+#if SUPPORT_MESH_GENERATION
+    #define PAR_MALLOC(T, N) ((T *)RL_MALLOC(N*sizeof(T)))
+    #define PAR_CALLOC(T, N) ((T *)RL_CALLOC(N*sizeof(T), 1))
+    #define PAR_REALLOC(T, BUF, N) ((T *)RL_REALLOC(BUF, sizeof(T)*(N)))
+    #define PAR_FREE RL_FREE
+
+    #if defined(_MSC_VER)           // Disable some MSVC warning
+        #pragma warning(push)
+        #pragma warning(disable : 4244)
+        #pragma warning(disable : 4305)
+    #endif
+
+    #define PAR_SHAPES_IMPLEMENTATION
+    #include "external/par_shapes.h"    // Shapes 3d parametric generation
+
+    #if defined(_MSC_VER)
+        #pragma warning(pop)        // Disable MSVC warning suppression
+    #endif
+#endif
+
+#if defined(_WIN32)
+    #include <direct.h>     // Required for: _chdir() [Used in LoadOBJ()]
+    #define CHDIR _chdir
+#else
+    #include <unistd.h>     // Required for: chdir() (POSIX) [Used in LoadOBJ()]
+    #define CHDIR chdir
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef MAX_MATERIAL_MAPS
+    #define MAX_MATERIAL_MAPS       12      // Maximum number of maps supported
+#endif
+#ifndef MAX_MESH_VERTEX_BUFFERS
+#if SUPPORT_GPU_SKINNING
+    // NOTE: Two additional vertex buffers required to store bone indices and bone weights
+    // WARNING: Some GPUs could not support more than 8 VBOs
+    #define MAX_MESH_VERTEX_BUFFERS  9      // Maximum vertex buffers (VBO) per mesh
+#else
+    #define MAX_MESH_VERTEX_BUFFERS  7      // Maximum vertex buffers (VBO) per mesh
+#endif
+#endif
+#ifndef MAX_FILEPATH_LENGTH
+    #define MAX_FILEPATH_LENGTH   4096      // Maximum length for filepaths (Linux PATH_MAX default value)
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+#if SUPPORT_FILEFORMAT_OBJ
+static Model LoadOBJ(const char *fileName);     // Load OBJ mesh data
+#endif
+#if SUPPORT_FILEFORMAT_IQM
+static Model LoadIQM(const char *fileName);     // Load IQM mesh data
+static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount);   // Load IQM animation data
+#endif
+#if SUPPORT_FILEFORMAT_GLTF
+static Model LoadGLTF(const char *fileName);    // Load GLTF mesh data
+static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount);  // Load GLTF animation data
+#endif
+#if SUPPORT_FILEFORMAT_VOX
+static Model LoadVOX(const char *filename);     // Load VOX mesh data
+#endif
+#if SUPPORT_FILEFORMAT_M3D
+static Model LoadM3D(const char *filename);     // Load M3D mesh data
+static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount);   // Load M3D animation data
+#endif
+#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
+static void ProcessMaterialsOBJ(Material *rayMaterials, tinyobj_material_t *materials, int materialCount);  // Process obj materials
+#endif
+
+// Update model vertex data (positions and normals)
+static void UpdateModelAnimationVertexBuffers(Model model);
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Draw a line in 3D world space
+void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex3f(startPos.x, startPos.y, startPos.z);
+        rlVertex3f(endPos.x, endPos.y, endPos.z);
+    rlEnd();
+}
+
+// Draw a point in 3D space, actually a small line
+// WARNING: OpenGL ES 2.0 does not support point mode drawing
+void DrawPoint3D(Vector3 position, Color color)
+{
+    rlPushMatrix();
+        rlTranslatef(position.x, position.y, position.z);
+        rlBegin(RL_LINES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlVertex3f(0.0f, 0.0f, 0.0f);
+            rlVertex3f(0.0f, 0.0f, 0.1f);
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a circle in 3D world space
+void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
+{
+    rlPushMatrix();
+        rlTranslatef(center.x, center.y, center.z);
+        rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
+
+        rlBegin(RL_LINES);
+            for (int i = 0; i < 360; i += 10)
+            {
+                rlColor4ub(color.r, color.g, color.b, color.a);
+
+                rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f);
+                rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f);
+            }
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a color-filled triangle (vertex in counter-clockwise order!)
+void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
+{
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex3f(v1.x, v1.y, v1.z);
+        rlVertex3f(v2.x, v2.y, v2.z);
+        rlVertex3f(v3.x, v3.y, v3.z);
+    rlEnd();
+}
+
+// Draw a triangle strip defined by points
+void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color)
+{
+    if (pointCount < 3) return; // Security check
+
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 2; i < pointCount; i++)
+        {
+            if ((i%2) == 0)
+            {
+                rlVertex3f(points[i].x, points[i].y, points[i].z);
+                rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
+                rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
+            }
+            else
+            {
+                rlVertex3f(points[i].x, points[i].y, points[i].z);
+                rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
+                rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
+            }
+        }
+    rlEnd();
+}
+
+// Draw cube
+// NOTE: Cube position is the center position
+void DrawCube(Vector3 position, float width, float height, float length, Color color)
+{
+    float x = 0.0f;
+    float y = 0.0f;
+    float z = 0.0f;
+
+    rlPushMatrix();
+        // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
+        rlTranslatef(position.x, position.y, position.z);
+        //rlRotatef(45, 0, 1, 0);
+        //rlScalef(1.0f, 1.0f, 1.0f);   // NOTE: Vertices are directly scaled on definition
+
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            // Front face
+            rlNormal3f(0.0f, 0.0f, 1.0f);
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
+
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Right
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
+
+            // Back face
+            rlNormal3f(0.0f, 0.0f, -1.0f);
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Left
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
+
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
+
+            // Top face
+            rlNormal3f(0.0f, 1.0f, 0.0f);
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Bottom Left
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
+
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Left
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Bottom Right
+
+            // Bottom face
+            rlNormal3f(0.0f, -1.0f, 0.0f);
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
+
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top Right
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Right
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top Left
+
+            // Right face
+            rlNormal3f(1.0f, 0.0f, 0.0f);
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top Right
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
+
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom Left
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom Right
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top Left
+
+            // Left face
+            rlNormal3f(-1.0f, 0.0f, 0.0f);
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top Right
+
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom Left
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top Left
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom Right
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw cube (Vector version)
+void DrawCubeV(Vector3 position, Vector3 size, Color color)
+{
+    DrawCube(position, size.x, size.y, size.z, color);
+}
+
+// Draw cube wires
+void DrawCubeWires(Vector3 position, float width, float height, float length, Color color)
+{
+    float x = 0.0f;
+    float y = 0.0f;
+    float z = 0.0f;
+
+    rlPushMatrix();
+        rlTranslatef(position.x, position.y, position.z);
+
+        rlBegin(RL_LINES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            // Front face
+            //------------------------------------------------------------------
+            // Bottom line
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
+
+            // Left line
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Bottom right
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
+
+            // Top line
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
+
+            // Right line
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Bottom left
+
+            // Back face
+            //------------------------------------------------------------------
+            // Bottom line
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
+
+            // Left line
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Bottom right
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
+
+            // Top line
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
+
+            // Right line
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Bottom left
+
+            // Top face
+            //------------------------------------------------------------------
+            // Left line
+            rlVertex3f(x - width/2, y + height/2, z + length/2);  // Top left front
+            rlVertex3f(x - width/2, y + height/2, z - length/2);  // Top left back
+
+            // Right line
+            rlVertex3f(x + width/2, y + height/2, z + length/2);  // Top right front
+            rlVertex3f(x + width/2, y + height/2, z - length/2);  // Top right back
+
+            // Bottom face
+            //------------------------------------------------------------------
+            // Left line
+            rlVertex3f(x - width/2, y - height/2, z + length/2);  // Top left front
+            rlVertex3f(x - width/2, y - height/2, z - length/2);  // Top left back
+
+            // Right line
+            rlVertex3f(x + width/2, y - height/2, z + length/2);  // Top right front
+            rlVertex3f(x + width/2, y - height/2, z - length/2);  // Top right back
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw cube wires (vector version)
+void DrawCubeWiresV(Vector3 position, Vector3 size, Color color)
+{
+    DrawCubeWires(position, size.x, size.y, size.z, color);
+}
+
+// Draw sphere
+void DrawSphere(Vector3 centerPos, float radius, Color color)
+{
+    DrawSphereEx(centerPos, radius, 16, 16, color);
+}
+
+// Draw sphere with defined rings and slices
+void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
+{
+#if 0
+    // Basic implementation, do not use it!
+    // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls!
+    // New optimized version below only requires 4 cos()/sin() calls
+
+    rlPushMatrix();
+        // NOTE: Transformation is applied in inverse order (scale -> translate)
+        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+        rlScalef(radius, radius, radius);
+
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            for (int i = 0; i < (rings + 2); 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)));
+                    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)));
+                    rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
+                               sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i))),
+                               cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*(360.0f*(j + 1)/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)));
+                }
+            }
+        rlEnd();
+    rlPopMatrix();
+#endif
+
+    rlPushMatrix();
+        // NOTE: Transformation is applied in inverse order (scale -> translate)
+        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+        rlScalef(radius, radius, radius);
+
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            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++)
+                {
+                    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 };
+
+                    rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
+                    rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
+                    rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
+                    rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
+                    rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z);
+                    rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
+
+                    rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
+                    rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
+                    rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z);
+                    rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
+                    rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].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();
+}
+
+// Draw sphere wires
+void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
+{
+    rlPushMatrix();
+        // NOTE: Transformation is applied in inverse order (scale -> translate)
+        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+        rlScalef(radius, radius, radius);
+
+        rlBegin(RL_LINES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            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++)
+                {
+                    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 };
+
+                    // Longitude Lines
+                    rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
+                    rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
+
+                    // 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();
+}
+
+// Draw a cylinder
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
+{
+    if (sides < 3) sides = 3;
+
+    const float angleStep = 360.0f/sides;
+
+    rlPushMatrix();
+        rlTranslatef(position.x, position.y, position.z);
+
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            if (radiusTop > 0)
+            {
+                // Draw Body -------------------------------------------------------------------------------------
+                for (int i = 0; i < sides; i++)
+                {
+                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
+                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom); //Bottom Right
+                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
+
+                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop); //Top Left
+                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom); //Bottom Left
+                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop); //Top Right
+                }
+
+                // Draw Cap --------------------------------------------------------------------------------------
+                for (int i = 0; i < sides; i++)
+                {
+                    rlVertex3f(0, height, 0);
+                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
+                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
+                }
+            }
+            else
+            {
+                // Draw Cone -------------------------------------------------------------------------------------
+                for (int i = 0; i < sides; i++)
+                {
+                    rlVertex3f(0, height, 0);
+                    rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
+                    rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
+                }
+            }
+
+            // Draw Base -----------------------------------------------------------------------------------------
+            for (int i = 0; i < sides; i++)
+            {
+                rlVertex3f(0, 0, 0);
+                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
+                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
+            }
+
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a cylinder with base at startPos and top at endPos
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
+{
+    if (sides < 3) sides = 3;
+
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+    if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
+
+    // Construct a basis of the base and the top face:
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+
+    float baseAngle = (2.0f*PI)/sides;
+
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < sides; i++)
+        {
+            // Compute the four vertices
+            float s1 = sinf(baseAngle*(i + 0))*startRadius;
+            float c1 = cosf(baseAngle*(i + 0))*startRadius;
+            Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
+            float s2 = sinf(baseAngle*(i + 1))*startRadius;
+            float c2 = cosf(baseAngle*(i + 1))*startRadius;
+            Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
+            float s3 = sinf(baseAngle*(i + 0))*endRadius;
+            float c3 = cosf(baseAngle*(i + 0))*endRadius;
+            Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
+            float s4 = sinf(baseAngle*(i + 1))*endRadius;
+            float c4 = cosf(baseAngle*(i + 1))*endRadius;
+            Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
+
+            if (startRadius > 0)
+            {
+                rlVertex3f(startPos.x, startPos.y, startPos.z); // |
+                rlVertex3f(w2.x, w2.y, w2.z);                   // T0
+                rlVertex3f(w1.x, w1.y, w1.z);                   // |
+            }
+                                                                //          w2 x.-----------x startPos
+            rlVertex3f(w1.x, w1.y, w1.z);                       // |           |\'.  T0    /
+            rlVertex3f(w2.x, w2.y, w2.z);                       // T1          | \ '.     /
+            rlVertex3f(w3.x, w3.y, w3.z);                       // |           |T \  '.  /
+                                                                //             | 2 \ T 'x w1
+            rlVertex3f(w2.x, w2.y, w2.z);                       // |        w4 x.---\-1-|---x endPos
+            rlVertex3f(w4.x, w4.y, w4.z);                       // T2            '.  \  |T3/
+            rlVertex3f(w3.x, w3.y, w3.z);                       // |               '. \ | /
+                                                                //                   '.\|/
+            if (endRadius > 0)                                  //                     'x w3
+            {
+                rlVertex3f(endPos.x, endPos.y, endPos.z);       // |
+                rlVertex3f(w3.x, w3.y, w3.z);                   // T3
+                rlVertex3f(w4.x, w4.y, w4.z);                   // |
+            }                                                   //
+        }
+    rlEnd();
+}
+
+// Draw a wired cylinder
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
+{
+    if (sides < 3) sides = 3;
+
+    const float angleStep = 360.0f/sides;
+
+    rlPushMatrix();
+        rlTranslatef(position.x, position.y, position.z);
+
+        rlBegin(RL_LINES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            for (int i = 0; i < sides; i++)
+            {
+                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
+                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
+
+                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusBottom, 0, cosf(DEG2RAD*(i+1)*angleStep)*radiusBottom);
+                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
+
+                rlVertex3f(sinf(DEG2RAD*(i+1)*angleStep)*radiusTop, height, cosf(DEG2RAD*(i+1)*angleStep)*radiusTop);
+                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
+
+                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusTop, height, cosf(DEG2RAD*i*angleStep)*radiusTop);
+                rlVertex3f(sinf(DEG2RAD*i*angleStep)*radiusBottom, 0, cosf(DEG2RAD*i*angleStep)*radiusBottom);
+            }
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a wired cylinder with base at startPos and top at endPos
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int slices, Color color)
+{
+    if (slices < 3) slices = 3;
+
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+    if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return; // Security check
+
+    // Construct a basis of the base and the top face:
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+
+    float baseAngle = (2.0f*PI)/slices;
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < slices; i++)
+        {
+            // Compute the four vertices
+            float s1 = sinf(baseAngle*(i + 0))*startRadius;
+            float c1 = cosf(baseAngle*(i + 0))*startRadius;
+            Vector3 w1 = { startPos.x + s1*b1.x + c1*b2.x, startPos.y + s1*b1.y + c1*b2.y, startPos.z + s1*b1.z + c1*b2.z };
+            float s2 = sinf(baseAngle*(i + 1))*startRadius;
+            float c2 = cosf(baseAngle*(i + 1))*startRadius;
+            Vector3 w2 = { startPos.x + s2*b1.x + c2*b2.x, startPos.y + s2*b1.y + c2*b2.y, startPos.z + s2*b1.z + c2*b2.z };
+            float s3 = sinf(baseAngle*(i + 0))*endRadius;
+            float c3 = cosf(baseAngle*(i + 0))*endRadius;
+            Vector3 w3 = { endPos.x + s3*b1.x + c3*b2.x, endPos.y + s3*b1.y + c3*b2.y, endPos.z + s3*b1.z + c3*b2.z };
+            float s4 = sinf(baseAngle*(i + 1))*endRadius;
+            float c4 = cosf(baseAngle*(i + 1))*endRadius;
+            Vector3 w4 = { endPos.x + s4*b1.x + c4*b2.x, endPos.y + s4*b1.y + c4*b2.y, endPos.z + s4*b1.z + c4*b2.z };
+
+            rlVertex3f(w1.x, w1.y, w1.z);
+            rlVertex3f(w2.x, w2.y, w2.z);
+
+            rlVertex3f(w1.x, w1.y, w1.z);
+            rlVertex3f(w3.x, w3.y, w3.z);
+
+            rlVertex3f(w3.x, w3.y, w3.z);
+            rlVertex3f(w4.x, w4.y, w4.z);
+        }
+    rlEnd();
+}
+
+// Draw a capsule with the center of its sphere caps at startPos and endPos
+void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color)
+{
+    if (slices < 3) slices = 3;
+    if (rings  < 1) rings  = 1;
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+
+    // draw a sphere if start and end points are the same
+    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
+    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
+
+    // Construct a basis of the base and the caps:
+    Vector3 b0 = Vector3Normalize(direction);
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+    Vector3 capCenter = endPos;
+
+    float baseSliceAngle = (2.0f*PI)/slices;
+    float baseRingAngle  = PI*0.5f/rings;
+
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // render both caps
+        for (int c = 0; c < 2; c++)
+        {
+            for (int i = 0; i < rings; i++)
+            {
+                for (int j = 0; j < slices; j++)
+                {
+                    // Building up the rings from capCenter in the direction of the 'direction' vector computed earlier
+
+                    // Compute the four vertices
+                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
+                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
+                    Vector3 w1 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
+                    };
+                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
+                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
+                    Vector3 w2 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
+                    };
+
+                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
+                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
+                    Vector3 w3 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
+                    };
+                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
+                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
+                    Vector3 w4 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
+                    };
+
+                    // Make sure cap triangle normals are facing outwards
+                    if (c == 0)
+                    {
+                        rlVertex3f(w1.x, w1.y, w1.z);
+                        rlVertex3f(w2.x, w2.y, w2.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+
+                        rlVertex3f(w2.x, w2.y, w2.z);
+                        rlVertex3f(w4.x, w4.y, w4.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+                    }
+                    else
+                    {
+                        rlVertex3f(w1.x, w1.y, w1.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+                        rlVertex3f(w2.x, w2.y, w2.z);
+
+                        rlVertex3f(w2.x, w2.y, w2.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+                        rlVertex3f(w4.x, w4.y, w4.z);
+                    }
+                }
+            }
+            capCenter = startPos;
+            b0 = Vector3Scale(b0, -1.0f);
+        }
+        // render middle
+        if (!sphereCase)
+        {
+            for (int j = 0; j < slices; j++)
+            {
+                // compute the four vertices
+                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w1 = {
+                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
+                    startPos.y + ringSin1*b1.y + ringCos1*b2.y,
+                    startPos.z + ringSin1*b1.z + ringCos1*b2.z
+                };
+                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w2 = {
+                    startPos.x + ringSin2*b1.x + ringCos2*b2.x,
+                    startPos.y + ringSin2*b1.y + ringCos2*b2.y,
+                    startPos.z + ringSin2*b1.z + ringCos2*b2.z
+                };
+
+                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w3 = {
+                    endPos.x + ringSin3*b1.x + ringCos3*b2.x,
+                    endPos.y + ringSin3*b1.y + ringCos3*b2.y,
+                    endPos.z + ringSin3*b1.z + ringCos3*b2.z
+                };
+                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w4 = {
+                    endPos.x + ringSin4*b1.x + ringCos4*b2.x,
+                    endPos.y + ringSin4*b1.y + ringCos4*b2.y,
+                    endPos.z + ringSin4*b1.z + ringCos4*b2.z
+                };
+                                                                        //          w2 x.-----------x startPos
+                rlVertex3f(w1.x, w1.y, w1.z);                         // |           |\'.  T0    /
+                rlVertex3f(w2.x, w2.y, w2.z);                         // T1          | \ '.     /
+                rlVertex3f(w3.x, w3.y, w3.z);                         // |           |T \  '.  /
+                                                                        //             | 2 \ T 'x w1
+                rlVertex3f(w2.x, w2.y, w2.z);                         // |        w4 x.---\-1-|---x endPos
+                rlVertex3f(w4.x, w4.y, w4.z);                         // T2            '.  \  |T3/
+                rlVertex3f(w3.x, w3.y, w3.z);                         // |               '. \ | /
+                                                                        //                   '.\|/
+                                                                        //                   'x w3
+            }
+        }
+    rlEnd();
+}
+
+// Draw capsule wires with the center of its sphere caps at startPos and endPos
+void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int rings, int slices, Color color)
+{
+    if (slices < 3) slices = 3;
+    if (rings  < 1) rings = 1;
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+
+    // draw a sphere if start and end points are the same
+    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
+    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
+
+    // Construct a basis of the base and the caps:
+    Vector3 b0 = Vector3Normalize(direction);
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+    Vector3 capCenter = endPos;
+
+    float baseSliceAngle = (2.0f*PI)/slices;
+    float baseRingAngle  = PI*0.5f/rings;
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // render both caps
+        for (int c = 0; c < 2; c++)
+        {
+            for (int i = 0; i < rings; i++)
+            {
+                for (int j = 0; j < slices; j++)
+                {
+                    // Building up the rings from capCenter in the direction of the 'direction' vector computed earlier
+
+                    // Compute the four vertices
+                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
+                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
+                    Vector3 w1 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z)*radius
+                    };
+                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
+                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 0 ));
+                    Vector3 w2 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z)*radius
+                    };
+
+                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
+                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 1 ));
+                    Vector3 w3 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z)*radius
+                    };
+                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
+                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle*( i + 1 ));
+                    Vector3 w4 = (Vector3){
+                        capCenter.x + (sinf(baseRingAngle*( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x)*radius,
+                        capCenter.y + (sinf(baseRingAngle*( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y)*radius,
+                        capCenter.z + (sinf(baseRingAngle*( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z)*radius
+                    };
+
+                    rlVertex3f(w1.x, w1.y, w1.z);
+                    rlVertex3f(w2.x, w2.y, w2.z);
+
+                    rlVertex3f(w2.x, w2.y, w2.z);
+                    rlVertex3f(w3.x, w3.y, w3.z);
+
+                    rlVertex3f(w1.x, w1.y, w1.z);
+                    rlVertex3f(w3.x, w3.y, w3.z);
+
+                    rlVertex3f(w2.x, w2.y, w2.z);
+                    rlVertex3f(w4.x, w4.y, w4.z);
+
+                    rlVertex3f(w3.x, w3.y, w3.z);
+                    rlVertex3f(w4.x, w4.y, w4.z);
+                }
+            }
+            capCenter = startPos;
+            b0 = Vector3Scale(b0, -1.0f);
+        }
+        // render middle
+        if (!sphereCase)
+        {
+            for (int j = 0; j < slices; j++)
+            {
+                // compute the four vertices
+                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w1 = {
+                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
+                    startPos.y + ringSin1*b1.y + ringCos1*b2.y,
+                    startPos.z + ringSin1*b1.z + ringCos1*b2.z
+                };
+                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w2 = {
+                    startPos.x + ringSin2*b1.x + ringCos2*b2.x,
+                    startPos.y + ringSin2*b1.y + ringCos2*b2.y,
+                    startPos.z + ringSin2*b1.z + ringCos2*b2.z
+                };
+
+                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w3 = {
+                    endPos.x + ringSin3*b1.x + ringCos3*b2.x,
+                    endPos.y + ringSin3*b1.y + ringCos3*b2.y,
+                    endPos.z + ringSin3*b1.z + ringCos3*b2.z
+                };
+                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w4 = {
+                    endPos.x + ringSin4*b1.x + ringCos4*b2.x,
+                    endPos.y + ringSin4*b1.y + ringCos4*b2.y,
+                    endPos.z + ringSin4*b1.z + ringCos4*b2.z
+                };
+
+                rlVertex3f(w1.x, w1.y, w1.z);
+                rlVertex3f(w3.x, w3.y, w3.z);
+
+                rlVertex3f(w2.x, w2.y, w2.z);
+                rlVertex3f(w4.x, w4.y, w4.z);
+
+                rlVertex3f(w2.x, w2.y, w2.z);
+                rlVertex3f(w3.x, w3.y, w3.z);
+            }
+        }
+    rlEnd();
+}
+
+// Draw a plane
+void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
+{
+    // NOTE: Plane is always created on XZ ground
+    rlPushMatrix();
+        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+        rlScalef(size.x, 1.0f, size.y);
+
+        rlBegin(RL_QUADS);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlNormal3f(0.0f, 1.0f, 0.0f);
+
+            rlVertex3f(-0.5f, 0.0f, -0.5f);
+            rlVertex3f(-0.5f, 0.0f, 0.5f);
+            rlVertex3f(0.5f, 0.0f, 0.5f);
+            rlVertex3f(0.5f, 0.0f, -0.5f);
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a ray line
+void DrawRay(Ray ray, Color color)
+{
+    float scale = 10000;
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlVertex3f(ray.position.x, ray.position.y, ray.position.z);
+        rlVertex3f(ray.position.x + ray.direction.x*scale, ray.position.y + ray.direction.y*scale, ray.position.z + ray.direction.z*scale);
+    rlEnd();
+}
+
+// Draw a grid centered at (0, 0, 0)
+void DrawGrid(int slices, float spacing)
+{
+    int halfSlices = slices/2;
+
+    rlBegin(RL_LINES);
+        for (int i = -halfSlices; i <= halfSlices; i++)
+        {
+            if (i == 0)
+            {
+                rlColor3f(0.5f, 0.5f, 0.5f);
+            }
+            else
+            {
+                rlColor3f(0.75f, 0.75f, 0.75f);
+            }
+
+            rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
+            rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
+
+            rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
+            rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
+        }
+    rlEnd();
+}
+
+// Load model from files (mesh and material)
+Model LoadModel(const char *fileName)
+{
+    Model model = { 0 };
+
+#if SUPPORT_FILEFORMAT_OBJ
+    if (IsFileExtension(fileName, ".obj")) model = LoadOBJ(fileName);
+#endif
+#if SUPPORT_FILEFORMAT_IQM
+    if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
+#endif
+#if SUPPORT_FILEFORMAT_GLTF
+    if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName);
+#endif
+#if SUPPORT_FILEFORMAT_VOX
+    if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
+#endif
+#if SUPPORT_FILEFORMAT_M3D
+    if (IsFileExtension(fileName, ".m3d")) model = LoadM3D(fileName);
+#endif
+
+    // Make sure model transform is set to identity matrix!
+    model.transform = MatrixIdentity();
+
+    if ((model.meshCount != 0) && (model.meshes != NULL))
+    {
+        // Upload vertex data to GPU (static meshes)
+        for (int i = 0; i < model.meshCount; i++) UploadMesh(&model.meshes[i], false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load model mesh(es) data", fileName);
+
+    if (model.materialCount == 0)
+    {
+        TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load model material data, default to white material", fileName);
+
+        model.materialCount = 1;
+        model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+        model.materials[0] = LoadMaterialDefault();
+
+        if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+    }
+
+    return model;
+}
+
+// Load model from generated mesh
+// WARNING: A shallow copy of mesh is generated, passed by value,
+// as long as struct contains pointers to data and some values, get a copy
+// of mesh pointing to same data as original version... be careful!
+Model LoadModelFromMesh(Mesh mesh)
+{
+    Model model = { 0 };
+
+    model.transform = MatrixIdentity();
+
+    model.meshCount = 1;
+    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+    model.meshes[0] = mesh;
+
+    model.materialCount = 1;
+    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+    model.materials[0] = LoadMaterialDefault();
+
+    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+    model.meshMaterial[0] = 0;  // First material index
+
+    return model;
+}
+
+// Check if model is valid (loaded in GPU, VAO/VBOs)
+bool IsModelValid(Model model)
+{
+    bool result = false;
+
+    if ((model.meshes != NULL) &&           // Validate model contains some mesh
+        (model.materials != NULL) &&        // Validate model contains some material (at least default one)
+        (model.meshMaterial != NULL) &&     // Validate mesh-material linkage
+        (model.meshCount > 0) &&            // Validate mesh count
+        (model.materialCount > 0)) result = true; // Validate material count
+
+    // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs
+    // but some VBOs could not be used, it depends on Mesh vertex data
+    for (int i = 0; i < model.meshCount; i++)
+    {
+        if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; }   // Vertex position buffer not uploaded to GPU
+        if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; }  // Vertex textcoords buffer not uploaded to GPU
+        if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; }    // Vertex normals buffer not uploaded to GPU
+        if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; }     // Vertex colors buffer not uploaded to GPU
+        if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; }   // Vertex tangents buffer not uploaded to GPU
+        if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU
+        if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; }    // Vertex indices buffer not uploaded to GPU
+#if SUPPORT_GPU_SKINNING
+        if ((model.meshes[i].boneIndices != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIndices buffer not uploaded to GPU
+        if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU
+#endif
+        // NOTE: Some OpenGL versions do not support VAO, so avoid below check
+        //if (model.meshes[i].vaoId == 0) { result = false; break }
+    }
+
+    return result;
+}
+
+// Unload model (meshes/materials) from memory (RAM and/or VRAM)
+// NOTE: This function takes care of all model elements, for a detailed control
+// over them, use UnloadMesh() and UnloadMaterial()
+void UnloadModel(Model model)
+{
+    // Unload meshes
+    for (int i = 0; i < model.meshCount; i++) UnloadMesh(model.meshes[i]);
+
+    // Unload materials maps
+    // NOTE: As the user could be sharing shaders and textures between models,
+    // don't unload the material but free its maps,
+    // the user is responsible for freeing models shaders and textures
+    for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
+
+    // Unload arrays
+    RL_FREE(model.meshes);
+    RL_FREE(model.materials);
+    RL_FREE(model.meshMaterial);
+
+    // Unload animation data
+    RL_FREE(model.skeleton.bones);
+    RL_FREE(model.skeleton.bindPose);
+    RL_FREE(model.currentPose);
+    RL_FREE(model.boneMatrices);
+
+    TRACELOG(LOG_INFO, "MODEL: Unloaded model (and meshes) from RAM and VRAM");
+}
+
+// Compute model bounding box limits (considers all meshes)
+BoundingBox GetModelBoundingBox(Model model)
+{
+    BoundingBox bounds = { 0 };
+
+    if (model.meshCount > 0)
+    {
+        Vector3 temp = { 0 };
+        bounds = GetMeshBoundingBox(model.meshes[0]);
+
+        for (int i = 1; i < model.meshCount; i++)
+        {
+            BoundingBox tempBounds = GetMeshBoundingBox(model.meshes[i]);
+
+            temp.x = (bounds.min.x < tempBounds.min.x)? bounds.min.x : tempBounds.min.x;
+            temp.y = (bounds.min.y < tempBounds.min.y)? bounds.min.y : tempBounds.min.y;
+            temp.z = (bounds.min.z < tempBounds.min.z)? bounds.min.z : tempBounds.min.z;
+            bounds.min = temp;
+
+            temp.x = (bounds.max.x > tempBounds.max.x)? bounds.max.x : tempBounds.max.x;
+            temp.y = (bounds.max.y > tempBounds.max.y)? bounds.max.y : tempBounds.max.y;
+            temp.z = (bounds.max.z > tempBounds.max.z)? bounds.max.z : tempBounds.max.z;
+            bounds.max = temp;
+        }
+    }
+
+    // Apply model.transform to bounding box
+    // WARNING: Current BoundingBox structure design does not support rotation transformations,
+    // in those cases is up to the user to calculate the proper box bounds (8 vertices transformed)
+    bounds.min = Vector3Transform(bounds.min, model.transform);
+    bounds.max = Vector3Transform(bounds.max, model.transform);
+
+    return bounds;
+}
+
+// Upload vertex data into a VAO (if supported) and VBO
+void UploadMesh(Mesh *mesh, bool dynamic)
+{
+    if (mesh->vaoId > 0)
+    {
+        // Check if mesh has already been loaded in GPU
+        TRACELOG(LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded mesh", mesh->vaoId);
+        return;
+    }
+
+    mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
+
+    mesh->vaoId = 0;        // Vertex Array Object
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0;     // Vertex buffer: positions
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0;     // Vertex buffer: texcoords
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0;       // Vertex buffer: normals
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0;        // Vertex buffer: colors
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0;      // Vertex buffer: tangents
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0;    // Vertex buffer: texcoords2
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0;      // Vertex buffer: indices
+#if SUPPORT_GPU_SKINNING
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES] = 0;  // Vertex buffer: boneIndices
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0;  // Vertex buffer: boneWeights
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    mesh->vaoId = rlLoadVertexArray();
+
+    rlEnableVertexArray(mesh->vaoId);
+
+    // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
+
+    // Enable vertex attributes: position (shader-location = 0)
+    void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices;
+    mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
+    rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0);
+    rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
+
+    // Enable vertex attributes: texcoords (shader-location = 1)
+
+    if (mesh->texcoords != NULL)
+    {
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
+    }
+    else
+    {
+        float value[2] = { 0.0f, 0.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, value, SHADER_ATTRIB_VEC2, 2);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
+    }
+    // WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
+    // is part of current state, and it is maintained even if a different program object is used
+
+    if (mesh->normals != NULL)
+    {
+        // Enable vertex attributes: normals (shader-location = 2)
+        void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals;
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
+    }
+    else
+    {
+        // Default vertex attribute: normal
+        // WARNING: Default value provided to shader if location available
+        float value[3] = { 0.0f, 0.0f, 1.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, value, SHADER_ATTRIB_VEC3, 3);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
+    }
+
+    if (mesh->colors != NULL)
+    {
+        // Enable vertex attribute: color (shader-location = 3)
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
+    }
+    else
+    {
+        // Default vertex attribute: color
+        // WARNING: Default value provided to shader if location available
+        float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };    // WHITE
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, value, SHADER_ATTRIB_VEC4, 4);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
+    }
+
+    if (mesh->tangents != NULL)
+    {
+        // Enable vertex attribute: tangent (shader-location = 4)
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
+    }
+    else
+    {
+        // Default vertex attribute: tangent
+        // WARNING: Default value provided to shader if location available
+        float value[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, value, SHADER_ATTRIB_VEC4, 4);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
+    }
+
+    if (mesh->texcoords2 != NULL)
+    {
+        // Enable vertex attribute: texcoord2 (shader-location = 5)
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
+    }
+    else
+    {
+        // Default vertex attribute: texcoord2
+        // WARNING: Default value provided to shader if location available
+        float value[2] = { 0.0f, 0.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
+    }
+
+#if SUPPORT_GPU_SKINNING
+    if (mesh->boneIndices != NULL)
+    {
+        // Enable vertex attribute: boneIndices (shader-location = 7)
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES] = rlLoadVertexBuffer(mesh->boneIndices, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES, 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES);
+    }
+    else
+    {
+        // Default vertex attribute: boneIndices
+        // WARNING: Default value provided to shader if location available
+        float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES, value, SHADER_ATTRIB_VEC4, 4);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES);
+    }
+
+    if (mesh->boneWeights != NULL)
+    {
+        // Enable vertex attribute: boneWeights (shader-location = 8)
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
+    }
+    else
+    {
+        // Default vertex attribute: boneWeights
+        // WARNING: Default value provided to shader if location available
+        float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+        rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);
+        rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
+    }
+#endif
+
+    if (mesh->indices != NULL)
+    {
+        mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
+    }
+
+    if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
+    else TRACELOG(LOG_INFO, "VBO: Mesh uploaded successfully to VRAM (GPU)");
+
+    rlDisableVertexArray();
+#endif
+}
+
+// Update mesh vertex data in GPU for a specific buffer index
+void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
+{
+    rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
+}
+
+// Draw a 3d mesh with material and transform
+void DrawMesh(Mesh mesh, Material material, Matrix transform)
+{
+#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE)
+    #define GL_VERTEX_ARRAY         0x8074
+    #define GL_NORMAL_ARRAY         0x8075
+    #define GL_COLOR_ARRAY          0x8076
+    #define GL_TEXTURE_COORD_ARRAY  0x8078
+
+    if ((mesh.texcoords != NULL) && (material.maps[MATERIAL_MAP_DIFFUSE].texture.id > 0)) rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
+
+    if (mesh.animVertices != NULL) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
+    else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
+
+    if (mesh.texcoords) rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
+
+    if (mesh.animNormals != NULL) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals);
+    else if (mesh.normals != NULL) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
+
+    if (mesh.colors != NULL) rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
+
+    rlPushMatrix();
+        rlMultMatrixf(MatrixToFloat(transform));
+        rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
+                   material.maps[MATERIAL_MAP_DIFFUSE].color.g,
+                   material.maps[MATERIAL_MAP_DIFFUSE].color.b,
+                   material.maps[MATERIAL_MAP_DIFFUSE].color.a);
+
+        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
+        else rlDrawVertexArray(0, mesh.vertexCount);
+    rlPopMatrix();
+
+    rlDisableStatePointer(GL_VERTEX_ARRAY);
+    rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
+    rlDisableStatePointer(GL_NORMAL_ARRAY);
+    rlDisableStatePointer(GL_COLOR_ARRAY);
+
+    rlDisableTexture();
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    // Bind shader program
+    rlEnableShader(material.shader.id);
+
+    if (material.shader.locs == NULL) return;
+
+    // Send required data to shader (matrices, values)
+    //-----------------------------------------------------
+    // Upload to shader material.colDiffuse
+    if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
+    {
+        float values[4] = {
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
+        };
+
+        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
+    }
+
+    // Upload to shader material.colSpecular (if location available)
+    if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
+    {
+        float values[4] = {
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f
+        };
+
+        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
+    }
+
+    // Get a copy of current matrices to work with,
+    // in case stereo render is required, and they need to be modified
+    // NOTE: At this point the modelview matrix contains the view matrix (camera)
+    // That's because BeginMode3D() sets it and there is no model-drawing function
+    // that modifies it, all use rlPushMatrix() and rlPopMatrix()
+    Matrix matModel = MatrixIdentity();
+    Matrix matView = rlGetMatrixModelview();
+    Matrix matModelView = MatrixIdentity();
+    Matrix matProjection = rlGetMatrixProjection();
+
+    // Upload view and projection matrices (if locations available)
+    if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
+    if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
+
+    // Accumulate several model transformations:
+    //    transform: model transformation provided (includes DrawModel() params combined with model.transform)
+    //    rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
+    matModel = MatrixMultiply(transform, rlGetMatrixTransform());
+
+    // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
+    if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], matModel);
+
+    // Get model-view matrix
+    matModelView = MatrixMultiply(matModel, matView);
+
+    // Upload model normal matrix (if locations available)
+    if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
+    //-----------------------------------------------------
+
+    // Bind active texture maps (if available)
+    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+    {
+        if (material.maps[i].texture.id > 0)
+        {
+            // Select current shader texture slot
+            rlActiveTextureSlot(i);
+
+            // Enable texture for active slot
+            if ((i == MATERIAL_MAP_IRRADIANCE) ||
+                (i == MATERIAL_MAP_PREFILTER) ||
+                (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
+            else rlEnableTexture(material.maps[i].texture.id);
+
+            rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
+        }
+    }
+
+    // Try binding vertex array objects (VAO) or use VBOs if not possible
+    // WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values
+    // for shader expected vertex attributes that are not provided by the mesh (i.e. colors)
+    // This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes
+    if (!rlEnableVertexArray(mesh.vaoId))
+    {
+        // Bind mesh VBO data: vertex position (shader-location = 0)
+        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
+        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
+
+        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
+        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
+        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
+
+        if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
+        {
+            // Bind mesh VBO data: vertex normals (shader-location = 2)
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
+        }
+
+        // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
+        {
+            if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
+            {
+                rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
+                rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
+                rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+            }
+            else
+            {
+                // Set default value for defined vertex attribute in shader but not provided by mesh
+                // WARNING: It could result in GPU undefined behaviour
+                float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+                rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
+                rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+            }
+        }
+
+        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
+        }
+
+        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
+        }
+
+#if SUPPORT_GPU_SKINNING
+        // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
+        }
+
+        // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
+        }
+#endif
+
+        if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
+    }
+
+    int eyeCount = 1;
+    if (rlIsStereoRenderEnabled()) eyeCount = 2;
+
+    for (int eye = 0; eye < eyeCount; eye++)
+    {
+        // Calculate model-view-projection matrix (MVP)
+        Matrix matModelViewProjection = MatrixIdentity();
+        if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
+        else
+        {
+            // Setup current eye viewport (half screen width)
+            rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
+            matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
+        }
+
+        // Send combined model-view-projection matrix to shader
+        rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
+
+        // Draw mesh
+        if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, 0);
+        else rlDrawVertexArray(0, mesh.vertexCount);
+    }
+
+    // Unbind all bound texture maps
+    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+    {
+        if (material.maps[i].texture.id > 0)
+        {
+            // Select current shader texture slot
+            rlActiveTextureSlot(i);
+
+            // Disable texture for active slot
+            if ((i == MATERIAL_MAP_IRRADIANCE) ||
+                (i == MATERIAL_MAP_PREFILTER) ||
+                (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
+            else rlDisableTexture();
+        }
+    }
+
+    // Disable all possible vertex array objects (or VBOs)
+    rlDisableVertexArray();
+    rlDisableVertexBuffer();
+    rlDisableVertexBufferElement();
+
+    // Disable shader program
+    rlDisableShader();
+
+    // Restore rlgl internal modelview and projection matrices
+    rlSetMatrixModelview(matView);
+    rlSetMatrixProjection(matProjection);
+#endif
+}
+
+// Draw multiple mesh instances with material and different transforms
+void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    // Instancing required variables
+    float16 *instanceTransform = NULL;
+    unsigned int instancesVboId = 0;
+
+    // Bind shader program
+    rlEnableShader(material.shader.id);
+
+    // Send required data to shader (matrices, values)
+    //-----------------------------------------------------
+    // Upload to shader material.colDiffuse
+    if (material.shader.locs[SHADER_LOC_COLOR_DIFFUSE] != -1)
+    {
+        float values[4] = {
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
+            (float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
+        };
+
+        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
+    }
+
+    // Upload to shader material.colSpecular (if location available)
+    if (material.shader.locs[SHADER_LOC_COLOR_SPECULAR] != -1)
+    {
+        float values[4] = {
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
+            (float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f
+        };
+
+        rlSetUniform(material.shader.locs[SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
+    }
+
+    // Get a copy of current matrices to work with,
+    // in case stereo render is required, and they need to be modified
+    // NOTE: At this point the modelview matrix contains the view matrix (camera)
+    // That's because BeginMode3D() sets it and there is no model-drawing function
+    // that modifies it, all use rlPushMatrix() and rlPopMatrix()
+    Matrix matModel = MatrixIdentity();
+    Matrix matView = rlGetMatrixModelview();
+    Matrix matModelView = MatrixIdentity();
+    Matrix matProjection = rlGetMatrixProjection();
+
+    // Upload view and projection matrices (if locations available)
+    if (material.shader.locs[SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_VIEW], matView);
+    if (material.shader.locs[SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_PROJECTION], matProjection);
+
+    // Create instances buffer
+    instanceTransform = (float16 *)RL_CALLOC(instances, sizeof(float16));
+
+    // Fill buffer with instances transformations as float16 arrays
+    for (int i = 0; i < instances; i++) instanceTransform[i] = MatrixToFloatV(transforms[i]);
+
+    // Enable mesh VAO to attach new buffer
+    rlEnableVertexArray(mesh.vaoId);
+
+    // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData()
+    // It isn't clear which would be reliably faster in all cases and on all platforms,
+    // anecdotally glMapBuffer() seems quite slow (syncs) while glBufferSubData() seems
+    // no faster, since all the transform matrices are transferred anyway
+    instancesVboId = rlLoadVertexBuffer(instanceTransform, instances*sizeof(float16), false);
+
+    // Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCETRANSFORM
+    if (material.shader.locs[SHADER_LOC_VERTEX_INSTANCETRANSFORM] != -1)
+    {
+        for (unsigned int i = 0; i < 4; i++)
+        {
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCETRANSFORM] + i);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCETRANSFORM] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4));
+            rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_VERTEX_INSTANCETRANSFORM] + i, 1);
+        }
+    }
+
+    rlDisableVertexBuffer();
+    rlDisableVertexArray();
+
+    // Accumulate internal matrix transform (push/pop) and view matrix
+    // NOTE: In this case, model instance transformation must be computed in the shader
+    matModelView = MatrixMultiply(rlGetMatrixTransform(), matView);
+
+    // Upload model normal matrix (if locations available)
+    if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
+    //-----------------------------------------------------
+
+    // Bind active texture maps (if available)
+    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+    {
+        if (material.maps[i].texture.id > 0)
+        {
+            // Select current shader texture slot
+            rlActiveTextureSlot(i);
+
+            // Enable texture for active slot
+            if ((i == MATERIAL_MAP_IRRADIANCE) ||
+                (i == MATERIAL_MAP_PREFILTER) ||
+                (i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
+            else rlEnableTexture(material.maps[i].texture.id);
+
+            rlSetUniform(material.shader.locs[SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
+        }
+    }
+
+    // Try binding vertex array objects (VAO)
+    // or use VBOs if not possible
+    if (!rlEnableVertexArray(mesh.vaoId))
+    {
+        // Bind mesh VBO data: vertex position (shader-location = 0)
+        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
+        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
+
+        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
+        rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
+        rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
+
+        if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
+        {
+            // Bind mesh VBO data: vertex normals (shader-location = 2)
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
+        }
+
+        // Bind mesh VBO data: vertex colors (shader-location = 3, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
+        {
+            if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
+            {
+                rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
+                rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
+                rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+            }
+            else
+            {
+                // Set default value for unused attribute
+                // NOTE: Required when using default shader and no VAO support
+                float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+                rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
+                rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
+            }
+        }
+
+        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
+        }
+
+        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
+        }
+
+#if SUPPORT_GPU_SKINNING
+        // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
+        }
+
+        // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
+        if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
+        {
+            rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
+            rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
+            rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
+        }
+#endif
+
+        if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
+    }
+
+    int eyeCount = 1;
+    if (rlIsStereoRenderEnabled()) eyeCount = 2;
+
+    for (int eye = 0; eye < eyeCount; eye++)
+    {
+        // Calculate model-view-projection matrix (MVP)
+        Matrix matModelViewProjection = MatrixIdentity();
+        if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
+        else
+        {
+            // Setup current eye viewport (half screen width)
+            rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
+            matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
+        }
+
+        // Send combined model-view-projection matrix to shader
+        rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MVP], matModelViewProjection);
+
+        // Draw mesh instanced
+        if (mesh.indices != NULL) rlDrawVertexArrayElementsInstanced(0, mesh.triangleCount*3, 0, instances);
+        else rlDrawVertexArrayInstanced(0, mesh.vertexCount, instances);
+    }
+
+    // Unbind all bound texture maps
+    for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+    {
+        if (material.maps[i].texture.id > 0)
+        {
+            // Select current shader texture slot
+            rlActiveTextureSlot(i);
+
+            // Disable texture for active slot
+            if ((i == MATERIAL_MAP_IRRADIANCE) ||
+                (i == MATERIAL_MAP_PREFILTER) ||
+                (i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
+            else rlDisableTexture();
+        }
+    }
+
+    // Disable all possible vertex array objects (or VBOs)
+    rlDisableVertexArray();
+    rlDisableVertexBuffer();
+    rlDisableVertexBufferElement();
+
+    // Disable shader program
+    rlDisableShader();
+
+    // Remove instance transforms buffer
+    rlUnloadVertexBuffer(instancesVboId);
+    RL_FREE(instanceTransform);
+#endif
+}
+
+// Unload mesh from memory (RAM and VRAM)
+void UnloadMesh(Mesh mesh)
+{
+    // Unload rlgl mesh vboId data
+    rlUnloadVertexArray(mesh.vaoId);
+
+    if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
+    RL_FREE(mesh.vboId);
+
+    // Unload mesh vertex buffers
+    RL_FREE(mesh.vertices);
+    RL_FREE(mesh.texcoords);
+    RL_FREE(mesh.normals);
+    RL_FREE(mesh.colors);
+    RL_FREE(mesh.tangents);
+    RL_FREE(mesh.texcoords2);
+    RL_FREE(mesh.indices);
+
+    // Unload mesh skin animation data
+    RL_FREE(mesh.boneWeights);
+    RL_FREE(mesh.boneIndices);
+
+    // Unload mesh runtime CPU skinning data
+    RL_FREE(mesh.animVertices);
+    RL_FREE(mesh.animNormals);
+}
+
+// Export mesh data to file
+bool ExportMesh(Mesh mesh, const char *fileName)
+{
+    bool result = false;
+
+    if (IsFileExtension(fileName, ".obj"))
+    {
+        // Estimated data size, it should be enough...
+        int vc = mesh.vertexCount;
+        int dataSize = vc*(int)strlen("v -0000.000000f -0000.000000f -0000.000000f\n") +
+                       vc*(int)strlen("vt -0.000000f -0.000000f\n") +
+                       vc*(int)strlen("vn -0.0000f -0.0000f -0.0000f\n") +
+                       mesh.triangleCount*snprintf(NULL, 0, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", vc, vc, vc, vc, vc, vc, vc, vc, vc);
+
+        // NOTE: Text data buffer size is estimated considering mesh data size
+        char *txtData = (char *)RL_CALLOC(dataSize + 1000, sizeof(char));
+
+        int byteCount = 0;
+        byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
+        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
+        byteCount += sprintf(txtData + byteCount, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized   //\n");
+        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
+        byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report:  github.com/raysan5/raylib                        //\n");
+        byteCount += sprintf(txtData + byteCount, "# // feedback and support:       ray[at]raylib.com                                //\n");
+        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
+        byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2026 Ramon Santamaria (@raysan5)                          //\n");
+        byteCount += sprintf(txtData + byteCount, "# //                                                                              //\n");
+        byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
+        byteCount += sprintf(txtData + byteCount, "# Vertex Count:     %i\n", mesh.vertexCount);
+        byteCount += sprintf(txtData + byteCount, "# Triangle Count:   %i\n\n", mesh.triangleCount);
+
+        byteCount += sprintf(txtData + byteCount, "g mesh\n");
+
+        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
+        {
+            byteCount += sprintf(txtData + byteCount, "v %.6f %.6f %.6f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
+        }
+
+        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
+        {
+            byteCount += sprintf(txtData + byteCount, "vt %.6f %.6f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
+        }
+
+        for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
+        {
+            byteCount += sprintf(txtData + byteCount, "vn %.4f %.4f %.4f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
+        }
+
+        if (mesh.indices != NULL)
+        {
+            for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3)
+            {
+                byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
+                    mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1,
+                    mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1,
+                    mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1);
+            }
+        }
+        else
+        {
+            for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3)
+            {
+                byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2);
+            }
+        }
+
+        // NOTE: Text data length exported is determined by '\0' (NULL) character
+        result = SaveFileText(fileName, txtData);
+
+        RL_FREE(txtData);
+    }
+    else if (IsFileExtension(fileName, ".gltf")) // Or .glb
+    {
+        // TODO: Implement gltf/glb support
+        /*
+        cgltf_size expected = cgltf_write(options, NULL, 0, data);
+        char *buffer = (char *)RL_CALLOC(expected, 0);
+        cgltf_size actual = cgltf_write(options, buffer, expected, data);
+
+        // NOTE: cgltf_write() includes a NULL terminator that should be ommited in case of a .glb
+        if (options->type == cgltf_file_type_glb) cgltf_write_glb(file, buffer, actual - 1, data->bin, data->bin_size);
+        else SaveFileText(fileName, buffer); // Write a plain JSON file
+        */
+    }
+    else if (IsFileExtension(fileName, ".raw"))
+    {
+        // TODO: Support additional file formats to export mesh vertex data
+    }
+
+    return result;
+}
+
+// Export mesh as code file (.h) defining multiple arrays of vertex attributes
+bool ExportMeshAsCode(Mesh mesh, const char *fileName)
+{
+    bool result = false;
+
+#ifndef TEXT_BYTES_PER_LINE
+    #define TEXT_BYTES_PER_LINE     20
+#endif
+
+    // NOTE: Text data buffer size is fixed to 64MB
+    char *txtData = (char *)RL_CALLOC(64*1024*1024, sizeof(char));  // 64 MB
+
+    int byteCount = 0;
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// MeshAsCode exporter v1.0 - Mesh vertex data exported as arrays                     //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
+    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2023 Ramon Santamaria (@raysan5)                                     //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
+
+    // Get file name from path and convert variable name to uppercase
+    char varFileName[256] = { 0 };
+    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
+    byteCount += sprintf(txtData + byteCount, "// Mesh basic information\n");
+    byteCount += sprintf(txtData + byteCount, "#define %s_VERTEX_COUNT    %i\n", varFileName, mesh.vertexCount);
+    byteCount += sprintf(txtData + byteCount, "#define %s_TRIANGLE_COUNT   %i\n\n", varFileName, mesh.triangleCount);
+
+    // Define vertex attributes data as separate arrays
+    //-----------------------------------------------------------------------------------------
+    if (mesh.vertices != NULL)      // Vertex position (XYZ - 3 components per vertex - float)
+    {
+        byteCount += sprintf(txtData + byteCount, "static float %s_VERTEX_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
+        for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.vertices[i]);
+        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.vertices[mesh.vertexCount*3 - 1]);
+    }
+
+    if (mesh.texcoords != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
+    {
+        byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
+        for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords[i]);
+        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords[mesh.vertexCount*2 - 1]);
+    }
+
+    if (mesh.texcoords2 != NULL)      // Vertex texture coordinates (UV - 2 components per vertex - float)
+    {
+        byteCount += sprintf(txtData + byteCount, "static float %s_TEXCOORD2_DATA[%i] = { ", varFileName, mesh.vertexCount*2);
+        for (int i = 0; i < mesh.vertexCount*2 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.texcoords2[i]);
+        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.texcoords2[mesh.vertexCount*2 - 1]);
+    }
+
+    if (mesh.normals != NULL)      // Vertex normals (XYZ - 3 components per vertex - float)
+    {
+        byteCount += sprintf(txtData + byteCount, "static float %s_NORMAL_DATA[%i] = { ", varFileName, mesh.vertexCount*3);
+        for (int i = 0; i < mesh.vertexCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.normals[i]);
+        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.normals[mesh.vertexCount*3 - 1]);
+    }
+
+    if (mesh.tangents != NULL)      // Vertex tangents (XYZW - 4 components per vertex - float)
+    {
+        byteCount += sprintf(txtData + byteCount, "static float %s_TANGENT_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
+        for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.3ff,\n" : "%.3ff, "), mesh.tangents[i]);
+        byteCount += sprintf(txtData + byteCount, "%.3ff };\n\n", mesh.tangents[mesh.vertexCount*4 - 1]);
+    }
+
+    if (mesh.colors != NULL)        // Vertex colors (RGBA - 4 components per vertex - unsigned char)
+    {
+        byteCount += sprintf(txtData + byteCount, "static unsigned char %s_COLOR_DATA[%i] = { ", varFileName, mesh.vertexCount*4);
+        for (int i = 0; i < mesh.vertexCount*4 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), mesh.colors[i]);
+        byteCount += sprintf(txtData + byteCount, "0x%x };\n\n", mesh.colors[mesh.vertexCount*4 - 1]);
+    }
+
+    if (mesh.indices != NULL)       // Vertex indices (3 index per triangle - unsigned short)
+    {
+        byteCount += sprintf(txtData + byteCount, "static unsigned short %s_INDEX_DATA[%i] = { ", varFileName, mesh.triangleCount*3);
+        for (int i = 0; i < mesh.triangleCount*3 - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%i,\n" : "%i, "), mesh.indices[i]);
+        byteCount += sprintf(txtData + byteCount, "%i };\n", mesh.indices[mesh.triangleCount*3 - 1]);
+    }
+    //-----------------------------------------------------------------------------------------
+
+    // NOTE: Text data size exported is determined by '\0' (NULL) character
+    result = SaveFileText(fileName, txtData);
+
+    RL_FREE(txtData);
+
+    //if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
+    //else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
+
+    return result;
+}
+
+#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
+// Process obj materials
+static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
+{
+    // Init model mats
+    for (int m = 0; m < materialCount; m++)
+    {
+        // Init material to default
+        // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
+        materials[m] = LoadMaterialDefault();
+
+        if (mats == NULL) continue;
+
+        // Get default texture, in case no texture is defined
+        // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
+        materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
+
+        if (mats[m].diffuse_texname != NULL) materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture(mats[m].diffuse_texname);  //char *diffuse_texname; // map_Kd
+        else materials[m].maps[MATERIAL_MAP_DIFFUSE].color = (Color){ (unsigned char)(mats[m].diffuse[0]*255.0f), (unsigned char)(mats[m].diffuse[1]*255.0f), (unsigned char)(mats[m].diffuse[2]*255.0f), 255 }; //float diffuse[3];
+        materials[m].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
+
+        if (mats[m].specular_texname != NULL) materials[m].maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture(mats[m].specular_texname);  //char *specular_texname; // map_Ks
+        materials[m].maps[MATERIAL_MAP_SPECULAR].color = (Color){ (unsigned char)(mats[m].specular[0]*255.0f), (unsigned char)(mats[m].specular[1]*255.0f), (unsigned char)(mats[m].specular[2]*255.0f), 255 }; //float specular[3];
+        materials[m].maps[MATERIAL_MAP_SPECULAR].value = 0.0f;
+
+        if (mats[m].bump_texname != NULL) materials[m].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture(mats[m].bump_texname);  //char *bump_texname; // map_bump, bump
+        materials[m].maps[MATERIAL_MAP_NORMAL].color = WHITE;
+        materials[m].maps[MATERIAL_MAP_NORMAL].value = mats[m].shininess;
+
+        materials[m].maps[MATERIAL_MAP_EMISSION].color = (Color){ (unsigned char)(mats[m].emission[0]*255.0f), (unsigned char)(mats[m].emission[1]*255.0f), (unsigned char)(mats[m].emission[2]*255.0f), 255 }; //float emission[3];
+
+        if (mats[m].displacement_texname != NULL) materials[m].maps[MATERIAL_MAP_HEIGHT].texture = LoadTexture(mats[m].displacement_texname);  //char *displacement_texname; // disp
+    }
+}
+#endif
+
+// Load materials from model file
+Material *LoadMaterials(const char *fileName, int *materialCount)
+{
+    Material *materials = NULL;
+    unsigned int count = 0;
+
+    // TODO: Support IQM and GLTF for materials parsing
+
+#if SUPPORT_FILEFORMAT_MTL
+    if (IsFileExtension(fileName, ".mtl"))
+    {
+        tinyobj_material_t *mats = NULL;
+
+        int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
+        if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
+
+        materials = (Material *)RL_CALLOC(count, sizeof(Material));
+        ProcessMaterialsOBJ(materials, mats, count);
+
+        tinyobj_materials_free(mats, count);
+    }
+#else
+    TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
+#endif
+
+    *materialCount = count;
+    return materials;
+}
+
+// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
+Material LoadMaterialDefault(void)
+{
+    Material material = { 0 };
+    material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap));
+
+    // Using rlgl default shader
+    material.shader.id = rlGetShaderIdDefault();
+    material.shader.locs = rlGetShaderLocsDefault();
+
+    // Using rlgl default texture (1x1 pixel, UNCOMPRESSED_R8G8B8A8, 1 mipmap)
+    material.maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
+    //material.maps[MATERIAL_MAP_NORMAL].texture;         // NOTE: By default, not set
+    //material.maps[MATERIAL_MAP_SPECULAR].texture;       // NOTE: By default, not set
+
+    material.maps[MATERIAL_MAP_DIFFUSE].color = WHITE;    // Diffuse color
+    material.maps[MATERIAL_MAP_SPECULAR].color = WHITE;   // Specular color
+
+    return material;
+}
+
+// Check if material is valid (map textures loaded in GPU)
+bool IsMaterialValid(Material material)
+{
+    bool result = false;
+
+    if ((material.maps != NULL) && // Validate material contain some map
+        (material.shader.id > 0)) result = true; // Validate material shader is valid
+
+    // NOTE: Checking if available maps contain loaded textures does not determine if
+    // a material is valid, there can be maps without a texture assigned, only properties
+
+    return result;
+}
+
+// Unload material from memory
+void UnloadMaterial(Material material)
+{
+    // Unload material shader (avoid unloading default shader, managed by raylib)
+    if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
+
+    // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
+    if (material.maps != NULL)
+    {
+        for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
+        {
+            if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
+        }
+    }
+
+    RL_FREE(material.maps);
+}
+
+// Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
+// NOTE: Previous texture should be manually unloaded
+void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
+{
+    material->maps[mapType].texture = texture;
+}
+
+// Set the material for a mesh
+void SetModelMeshMaterial(Model *model, int meshId, int materialId)
+{
+    if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
+    else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
+    else  model->meshMaterial[meshId] = materialId;
+}
+
+// Load model animations from file
+ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
+{
+    ModelAnimation *animations = NULL;
+
+#if SUPPORT_FILEFORMAT_IQM
+    if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
+#endif
+#if SUPPORT_FILEFORMAT_M3D
+    if (IsFileExtension(fileName, ".m3d")) animations = LoadModelAnimationsM3D(fileName, animCount);
+#endif
+#if SUPPORT_FILEFORMAT_GLTF
+    if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationsGLTF(fileName, animCount);
+#endif
+
+    return animations;
+}
+
+// Update model animation data (vertex buffers / bone matrices) for a specific pose
+// NOTE 1: Request frame could be fractional, using a lerp interpolation between two frames
+// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning,
+// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
+void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
+{
+    if (model.boneMatrices == NULL) return;
+
+    //UpdateModelAnimationEx(model, anim, frame, anim, frame, 0.0f);
+
+    // Update model animated bones transform matrices for a given frame
+    if ((anim.keyframeCount > 0) && (model.skeleton.bones != NULL) && (anim.keyframePoses != NULL))
+    {
+        // Get frame and blending from frame factor required
+        int currentFrame = (int)frame;
+        int nextFrame = currentFrame + 1;
+        float blend = frame - currentFrame;
+        blend = Clamp(blend, 0.0f, 1.0f);
+        if (currentFrame >= anim.keyframeCount) currentFrame = currentFrame%anim.keyframeCount;
+        if (nextFrame >= anim.keyframeCount) nextFrame = nextFrame%anim.keyframeCount;
+
+        Matrix bindPoseMatrix = { 0 };
+        Matrix currentPoseMatrix = { 0 };
+
+        // Update all bones and bone matrices of model
+        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
+            model.currentPose[boneIndex].translation = Vector3Lerp(
+                anim.keyframePoses[currentFrame][boneIndex].translation,
+                anim.keyframePoses[nextFrame][boneIndex].translation, blend);
+            model.currentPose[boneIndex].rotation = QuaternionSlerp(
+                anim.keyframePoses[currentFrame][boneIndex].rotation,
+                anim.keyframePoses[nextFrame][boneIndex].rotation, blend);
+            model.currentPose[boneIndex].scale = Vector3Lerp(
+                anim.keyframePoses[currentFrame][boneIndex].scale,
+                anim.keyframePoses[nextFrame][boneIndex].scale, blend);
+
+            // Compute runtime bone matrix from model current pose
+            //-----------------------------------------------------------------------------------
+            Transform *bindPoseTransform = &model.skeleton.bindPose[boneIndex];
+            bindPoseMatrix = MatrixMultiply(
+                MatrixMultiply(MatrixScale(bindPoseTransform->scale.x, bindPoseTransform->scale.y, bindPoseTransform->scale.z),
+                    QuaternionToMatrix(bindPoseTransform->rotation)),
+                MatrixTranslate(bindPoseTransform->translation.x, bindPoseTransform->translation.y, bindPoseTransform->translation.z));
+
+            Transform *currentPoseTransform = &model.currentPose[boneIndex];
+            currentPoseMatrix = MatrixMultiply(
+                MatrixMultiply(MatrixScale(currentPoseTransform->scale.x, currentPoseTransform->scale.y, currentPoseTransform->scale.z),
+                    QuaternionToMatrix(currentPoseTransform->rotation)),
+                MatrixTranslate(currentPoseTransform->translation.x, currentPoseTransform->translation.y, currentPoseTransform->translation.z));
+
+            model.boneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindPoseMatrix), currentPoseMatrix);
+            //-----------------------------------------------------------------------------------
+        }
+
+        // CPU skinning, updates CPU buffers and uploads them to GPU
+        // NOTE: On GPU skinning not supported, use CPU skinning
+        UpdateModelAnimationVertexBuffers(model);
+    }
+}
+
+// Update model animation data (vertex buffers / bone matrices) for a specific pose,
+// defined by two different animations at specific frames blended together
+// NOTE 1: Request frames could be fractional, using a lerp interpolation between two frames
+// NOTE 2: Updated vertex animation data is uploaded to GPU in case of CPU skinning,
+// for GPU skinning, bone matrices are uploaded to shader on DrawModelEx()
+void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend)
+{
+    if (model.boneMatrices == NULL) return;
+
+    if ((animA.keyframeCount > 0) && (animA.keyframePoses != NULL) &&
+        (animB.keyframeCount > 0) && (animB.keyframePoses != NULL) &&
+        (blend >= 0.0f) && (blend <= 1.0f))
+    {
+        // Inter-frame interpolation values for first animation
+        int currentFrameA = (int)frameA%animA.keyframeCount;
+        int nextFrameA = currentFrameA + 1;
+        float blendA = frameA - currentFrameA;
+        blendA = Clamp(blendA, 0.0f, 1.0f);
+        if (currentFrameA >= animA.keyframeCount) currentFrameA = currentFrameA%animA.keyframeCount;
+        if (nextFrameA >= animA.keyframeCount) nextFrameA = nextFrameA%animA.keyframeCount;
+
+        // Inter-frame interpolation values for second animation
+        int currentFrameB = (int)frameB%animB.keyframeCount;
+        int nextFrameB = currentFrameB + 1;
+        float blendB = frameB - currentFrameB;
+        blendB = Clamp(blendB, 0.0f, 1.0f);
+        if (currentFrameB >= animB.keyframeCount) currentFrameB = currentFrameB%animB.keyframeCount;
+        if (nextFrameB >= animB.keyframeCount) nextFrameB = nextFrameB%animB.keyframeCount;
+
+        Matrix bindPoseMatrix = { 0 };
+        Matrix currentPoseMatrix = { 0 };
+
+        for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
+        {
+            // Get frame-interpolation for first animation
+            Vector3 frameATranslation = Vector3Lerp(
+                animA.keyframePoses[currentFrameA][boneIndex].translation,
+                animA.keyframePoses[nextFrameA][boneIndex].translation, blendA);
+            Quaternion frameARotation = QuaternionSlerp(
+                animA.keyframePoses[currentFrameA][boneIndex].rotation,
+                animA.keyframePoses[nextFrameA][boneIndex].rotation, blendA);
+            Vector3 frameAScale = Vector3Lerp(
+                animA.keyframePoses[currentFrameA][boneIndex].scale,
+                animA.keyframePoses[nextFrameA][boneIndex].scale, blendA);
+
+            // Get frame-interpolation for second animation
+            Vector3 frameBTranslation = Vector3Lerp(
+                animB.keyframePoses[currentFrameB][boneIndex].translation,
+                animB.keyframePoses[nextFrameB][boneIndex].translation, blendB);
+            Quaternion frameBRotation = QuaternionSlerp(
+                animB.keyframePoses[currentFrameB][boneIndex].rotation,
+                animB.keyframePoses[nextFrameB][boneIndex].rotation, blendB);
+            Vector3 frameBScale = Vector3Lerp(
+                animB.keyframePoses[currentFrameB][boneIndex].scale,
+                animB.keyframePoses[nextFrameB][boneIndex].scale, blendB);
+
+            // Compute interpolated pose between both animations frames
+            // NOTE: Storing animation frame data in model.currentPose
+            model.currentPose[boneIndex].translation = Vector3Lerp(frameATranslation, frameBTranslation, blend);
+            model.currentPose[boneIndex].rotation = QuaternionSlerp(frameARotation, frameBRotation, blend);
+            model.currentPose[boneIndex].scale = Vector3Lerp(frameAScale, frameBScale, blend);
+
+            // Compute runtime bone matrix from model current pose
+            //-----------------------------------------------------------------------------------
+            Transform *bindPoseTransform = &model.skeleton.bindPose[boneIndex];
+            bindPoseMatrix = MatrixMultiply(
+                MatrixMultiply(MatrixScale(bindPoseTransform->scale.x, bindPoseTransform->scale.y, bindPoseTransform->scale.z),
+                    QuaternionToMatrix(bindPoseTransform->rotation)),
+                MatrixTranslate(bindPoseTransform->translation.x, bindPoseTransform->translation.y, bindPoseTransform->translation.z));
+
+            Transform *currentPoseTransform = &model.currentPose[boneIndex];
+            currentPoseMatrix = MatrixMultiply(
+                MatrixMultiply(MatrixScale(currentPoseTransform->scale.x, currentPoseTransform->scale.y, currentPoseTransform->scale.z),
+                    QuaternionToMatrix(currentPoseTransform->rotation)),
+                MatrixTranslate(currentPoseTransform->translation.x, currentPoseTransform->translation.y, currentPoseTransform->translation.z));
+
+            model.boneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindPoseMatrix), currentPoseMatrix);
+            //-----------------------------------------------------------------------------------
+
+            /*
+            Vector3 outATranslation = animA.keyframePoses[currentFrameA][boneIndex].translation;
+            Quaternion outARotation = animA.keyframePoses[currentFrameA][boneIndex].rotation;
+            Vector3 outAScale = animA.keyframePoses[currentFrameA][boneIndex].scale;
+
+            Vector3 outBTranslation = animB.keyframePoses[currentFrameB][boneIndex].translation;
+            Quaternion outBRotation = animB.keyframePoses[currentFrameB][boneIndex].rotation;
+            Vector3 outBScale = animB.keyframePoses[currentFrameB][boneIndex].scale;
+
+            // Invert bind pose transformation
+            Vector3 invBindTranslation = Vector3RotateByQuaternion(
+                Vector3Negate(model.skeleton.bindPose[boneIndex].translation),
+                QuaternionInvert(model.skeleton.bindPose[boneIndex].rotation));
+            Quaternion invBindRotation = QuaternionInvert(model.skeleton.bindPose[boneIndex].rotation);
+            Vector3 invBindScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, model.skeleton.bindPose[boneIndex].scale);
+
+            Vector3 boneTranslation = Vector3Add(Vector3RotateByQuaternion(
+                Vector3Multiply(model.currentPose[boneIndex].scale, invBindTranslation),
+                    model.currentPose[boneIndex].rotation),
+                    model.currentPose[boneIndex].translation);
+            Quaternion boneRotation = QuaternionMultiply(model.currentPose[boneIndex].rotation, invBindRotation);
+            Vector3 boneScale = Vector3Multiply(model.currentPose[boneIndex].scale, invBindScale);
+
+            model.boneMatrices[boneIndex] = MatrixMultiply(
+                MatrixMultiply(QuaternionToMatrix(boneRotation),
+                    MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
+                MatrixScale(boneScale.x, boneScale.y, boneScale.z));
+            */
+        }
+
+        // CPU skinning, updates CPU buffers and uploads them to GPU (if available)
+        // NOTE: Fallback in case GPU skinning is not supported or enabled
+        UpdateModelAnimationVertexBuffers(model);
+    }
+}
+
+// Update model vertex animation buffers (positions and normals)
+// NOTE: Required for CPU skinning, uploads animated vertex buffers to GPU
+static void UpdateModelAnimationVertexBuffers(Model model)
+{
+    for (int m = 0; m < model.meshCount; m++)
+    {
+        Mesh mesh = model.meshes[m];
+        Vector3 animVertex = { 0 };
+        Vector3 animNormal = { 0 };
+        const int vertexValuesCount = mesh.vertexCount*3;
+
+        int boneIndex = 0;
+        int boneCounter = 0;
+        float boneWeight = 0.0f;
+        bool bufferUpdateRequired = false; // Flag to check when anim vertex information is updated
+
+        // Skip if missing bone data or missing anim buffers initialization
+        if ((mesh.boneWeights == NULL) || (mesh.boneIndices == NULL) ||
+            (mesh.animVertices == NULL) || (mesh.animNormals == NULL)) continue;
+
+        for (int vCounter = 0; vCounter < vertexValuesCount; vCounter += 3)
+        {
+            mesh.animVertices[vCounter] = 0;
+            mesh.animVertices[vCounter + 1] = 0;
+            mesh.animVertices[vCounter + 2] = 0;
+            if (mesh.animNormals != NULL)
+            {
+                mesh.animNormals[vCounter] = 0;
+                mesh.animNormals[vCounter + 1] = 0;
+                mesh.animNormals[vCounter + 2] = 0;
+            }
+
+            // Iterates over 4 bones per vertex
+            for (int j = 0; j < 4; j++, boneCounter++)
+            {
+                boneWeight = mesh.boneWeights[boneCounter];
+                boneIndex = mesh.boneIndices[boneCounter];
+
+                // Early stop when no transformation will be applied
+                if (boneWeight == 0.0f) continue;
+                animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
+                animVertex = Vector3Transform(animVertex, model.boneMatrices[boneIndex]);
+                mesh.animVertices[vCounter] += animVertex.x*boneWeight;
+                mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
+                mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
+                bufferUpdateRequired = true;
+
+                // Normals processing
+                // NOTE: Using meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
+                if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
+                {
+                    animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
+                    animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.boneMatrices[boneIndex])));
+                    mesh.animNormals[vCounter] += animNormal.x*boneWeight;
+                    mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
+                    mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
+                }
+            }
+        }
+
+        if (bufferUpdateRequired)
+        {
+            // Update GPU vertex buffers with updated data (position + normals)
+            rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_POSITION], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0);
+            if (mesh.normals != NULL) rlUpdateVertexBuffer(mesh.vboId[SHADER_LOC_VERTEX_NORMAL], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0);
+        }
+    }
+}
+
+// Unload animation array data
+void UnloadModelAnimations(ModelAnimation *animations, int animCount)
+{
+    for (int a = 0; a < animCount; a++)
+    {
+        for (int i = 0; i < animations[a].keyframeCount; i++)
+            RL_FREE(animations[a].keyframePoses[i]);
+
+        RL_FREE(animations[a].keyframePoses);
+    }
+
+    RL_FREE(animations);
+}
+
+// Check model animation skeleton match
+// NOTE: Only number of bones and parent connections are checked
+bool IsModelAnimationValid(Model model, ModelAnimation anim)
+{
+    int result = true;
+
+    if (model.skeleton.boneCount != anim.boneCount) result = false;
+
+    return result;
+}
+
+#if SUPPORT_MESH_GENERATION
+// Generate polygonal mesh
+Mesh GenMeshPoly(int sides, float radius)
+{
+    Mesh mesh = { 0 };
+
+    if (sides < 3) return mesh; // Security check
+
+    int vertexCount = sides*3;
+
+    // Vertices definition
+    Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
+
+    float d = 0.0f, dStep = 360.0f/sides;
+    for (int v = 0; v < vertexCount - 2; v += 3)
+    {
+        vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
+        vertices[v + 1] = (Vector3){ sinf(DEG2RAD*d)*radius, 0.0f, cosf(DEG2RAD*d)*radius };
+        vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(d+dStep))*radius, 0.0f, cosf(DEG2RAD*(d+dStep))*radius };
+        d += dStep;
+    }
+
+    // Normals definition
+    Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
+    for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
+
+    // TexCoords definition
+    Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
+    for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
+
+    mesh.vertexCount = vertexCount;
+    mesh.triangleCount = sides;
+    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+
+    // Mesh vertices position array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.vertices[3*i] = vertices[i].x;
+        mesh.vertices[3*i + 1] = vertices[i].y;
+        mesh.vertices[3*i + 2] = vertices[i].z;
+    }
+
+    // Mesh texcoords array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.texcoords[2*i] = texcoords[i].x;
+        mesh.texcoords[2*i + 1] = texcoords[i].y;
+    }
+
+    // Mesh normals array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.normals[3*i] = normals[i].x;
+        mesh.normals[3*i + 1] = normals[i].y;
+        mesh.normals[3*i + 2] = normals[i].z;
+    }
+
+    RL_FREE(vertices);
+    RL_FREE(normals);
+    RL_FREE(texcoords);
+
+    // Upload vertex data to GPU (static mesh)
+    // NOTE: mesh.vboId array is allocated inside UploadMesh()
+    UploadMesh(&mesh, false);
+
+    return mesh;
+}
+
+// Generate plane mesh (with subdivisions)
+Mesh GenMeshPlane(float width, float length, int resX, int resZ)
+{
+    Mesh mesh = { 0 };
+
+#define CUSTOM_MESH_GEN_PLANE
+#if defined(CUSTOM_MESH_GEN_PLANE)
+    resX++;
+    resZ++;
+
+    // Vertices definition
+    int vertexCount = resX*resZ; // vertices get reused for the faces
+
+    Vector3 *vertices = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
+    for (int z = 0; z < resZ; z++)
+    {
+        // [-length/2, length/2]
+        float zPos = ((float)z/(resZ - 1) - 0.5f)*length;
+        for (int x = 0; x < resX; x++)
+        {
+            // [-width/2, width/2]
+            float xPos = ((float)x/(resX - 1) - 0.5f)*width;
+            vertices[x + z*resX] = (Vector3){ xPos, 0.0f, zPos };
+        }
+    }
+
+    // Normals definition
+    Vector3 *normals = (Vector3 *)RL_MALLOC(vertexCount*sizeof(Vector3));
+    for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f };   // Vector3.up;
+
+    // TexCoords definition
+    Vector2 *texcoords = (Vector2 *)RL_MALLOC(vertexCount*sizeof(Vector2));
+    for (int v = 0; v < resZ; v++)
+    {
+        for (int u = 0; u < resX; u++)
+        {
+            texcoords[u + v*resX] = (Vector2){ (float)u/(resX - 1), (float)v/(resZ - 1) };
+        }
+    }
+
+    // Triangles definition (indices)
+    int numFaces = (resX - 1)*(resZ - 1);
+    int *triangles = (int *)RL_MALLOC(numFaces*6*sizeof(int));
+    int t = 0;
+    for (int face = 0; face < numFaces; face++)
+    {
+        // Retrieve lower left corner from face ind
+        int i = face + face/(resX - 1);
+
+        triangles[t++] = i + resX;
+        triangles[t++] = i + 1;
+        triangles[t++] = i;
+
+        triangles[t++] = i + resX;
+        triangles[t++] = i + resX + 1;
+        triangles[t++] = i + 1;
+    }
+
+    mesh.vertexCount = vertexCount;
+    mesh.triangleCount = numFaces*2;
+    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.indices = (unsigned short *)RL_MALLOC(mesh.triangleCount*3*sizeof(unsigned short));
+
+    // Mesh vertices position array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.vertices[3*i] = vertices[i].x;
+        mesh.vertices[3*i + 1] = vertices[i].y;
+        mesh.vertices[3*i + 2] = vertices[i].z;
+    }
+
+    // Mesh texcoords array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.texcoords[2*i] = texcoords[i].x;
+        mesh.texcoords[2*i + 1] = texcoords[i].y;
+    }
+
+    // Mesh normals array
+    for (int i = 0; i < mesh.vertexCount; i++)
+    {
+        mesh.normals[3*i] = normals[i].x;
+        mesh.normals[3*i + 1] = normals[i].y;
+        mesh.normals[3*i + 2] = normals[i].z;
+    }
+
+    // Mesh indices array initialization
+    for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
+
+    RL_FREE(vertices);
+    RL_FREE(normals);
+    RL_FREE(texcoords);
+    RL_FREE(triangles);
+
+#else       // Use par_shapes library to generate plane mesh
+
+    par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ);   // No normals/texcoords generated!!!
+    par_shapes_scale(plane, width, length, 1.0f);
+    par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
+    par_shapes_translate(plane, -width/2, 0.0f, length/2);
+
+    mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float));
+
+    mesh.vertexCount = plane->ntriangles*3;
+    mesh.triangleCount = plane->ntriangles;
+
+    for (int k = 0; k < mesh.vertexCount; k++)
+    {
+        mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
+        mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
+        mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
+
+        mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
+        mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
+        mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
+
+        mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
+        mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
+    }
+
+    par_shapes_free_mesh(plane);
+#endif
+
+    // Upload vertex data to GPU (static mesh)
+    UploadMesh(&mesh, false);
+
+    return mesh;
+}
+
+// Generated cuboid mesh
+Mesh GenMeshCube(float width, float height, float length)
+{
+    Mesh mesh = { 0 };
+
+#define CUSTOM_MESH_GEN_CUBE
+#if defined(CUSTOM_MESH_GEN_CUBE)
+    float vertices[] = {
+        -width/2, -height/2, length/2,
+        width/2, -height/2, length/2,
+        width/2, height/2, length/2,
+        -width/2, height/2, length/2,
+        -width/2, -height/2, -length/2,
+        -width/2, height/2, -length/2,
+        width/2, height/2, -length/2,
+        width/2, -height/2, -length/2,
+        -width/2, height/2, -length/2,
+        -width/2, height/2, length/2,
+        width/2, height/2, length/2,
+        width/2, height/2, -length/2,
+        -width/2, -height/2, -length/2,
+        width/2, -height/2, -length/2,
+        width/2, -height/2, length/2,
+        -width/2, -height/2, length/2,
+        width/2, -height/2, -length/2,
+        width/2, height/2, -length/2,
+        width/2, height/2, length/2,
+        width/2, -height/2, length/2,
+        -width/2, -height/2, -length/2,
+        -width/2, -height/2, length/2,
+        -width/2, height/2, length/2,
+        -width/2, height/2, -length/2
+    };
+
+    float texcoords[] = {
+        0.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f,
+        0.0f, 1.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f,
+        0.0f, 1.0f,
+        0.0f, 0.0f,
+        0.0f, 1.0f,
+        0.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f,
+        1.0f, 1.0f,
+        0.0f, 1.0f,
+        0.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f,
+        0.0f, 1.0f,
+        0.0f, 0.0f,
+        0.0f, 0.0f,
+        1.0f, 0.0f,
+        1.0f, 1.0f,
+        0.0f, 1.0f
+    };
+
+    float normals[] = {
+        0.0f, 0.0f, 1.0f,
+        0.0f, 0.0f, 1.0f,
+        0.0f, 0.0f, 1.0f,
+        0.0f, 0.0f, 1.0f,
+        0.0f, 0.0f,-1.0f,
+        0.0f, 0.0f,-1.0f,
+        0.0f, 0.0f,-1.0f,
+        0.0f, 0.0f,-1.0f,
+        0.0f, 1.0f, 0.0f,
+        0.0f, 1.0f, 0.0f,
+        0.0f, 1.0f, 0.0f,
+        0.0f, 1.0f, 0.0f,
+        0.0f,-1.0f, 0.0f,
+        0.0f,-1.0f, 0.0f,
+        0.0f,-1.0f, 0.0f,
+        0.0f,-1.0f, 0.0f,
+        1.0f, 0.0f, 0.0f,
+        1.0f, 0.0f, 0.0f,
+        1.0f, 0.0f, 0.0f,
+        1.0f, 0.0f, 0.0f,
+        -1.0f, 0.0f, 0.0f,
+        -1.0f, 0.0f, 0.0f,
+        -1.0f, 0.0f, 0.0f,
+        -1.0f, 0.0f, 0.0f
+    };
+
+    mesh.vertices = (float *)RL_MALLOC(24*3*sizeof(float));
+    memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
+
+    mesh.texcoords = (float *)RL_MALLOC(24*2*sizeof(float));
+    memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
+
+    mesh.normals = (float *)RL_MALLOC(24*3*sizeof(float));
+    memcpy(mesh.normals, normals, 24*3*sizeof(float));
+
+    mesh.indices = (unsigned short *)RL_MALLOC(36*sizeof(unsigned short));
+
+    int k = 0;
+
+    // Indices can be initialized right now
+    for (int i = 0; i < 36; i += 6)
+    {
+        mesh.indices[i] = 4*k;
+        mesh.indices[i + 1] = 4*k + 1;
+        mesh.indices[i + 2] = 4*k + 2;
+        mesh.indices[i + 3] = 4*k;
+        mesh.indices[i + 4] = 4*k + 2;
+        mesh.indices[i + 5] = 4*k + 3;
+
+        k++;
+    }
+
+    mesh.vertexCount = 24;
+    mesh.triangleCount = 12;
+
+#else               // Use par_shapes library to generate cube mesh
+/*
+// Platonic solids:
+par_shapes_mesh *par_shapes_create_tetrahedron();       // 4 sides polyhedron (pyramid)
+par_shapes_mesh *par_shapes_create_cube();              // 6 sides polyhedron (cube)
+par_shapes_mesh *par_shapes_create_octahedron();        // 8 sides polyhedron (diamond)
+par_shapes_mesh *par_shapes_create_dodecahedron();      // 12 sides polyhedron
+par_shapes_mesh *par_shapes_create_icosahedron();       // 20 sides polyhedron
+*/
+    // Platonic solid generation: cube (6 sides)
+    // NOTE: No normals/texcoords generated by default
+    par_shapes_mesh *cube = par_shapes_create_cube();
+    cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
+    for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
+    par_shapes_scale(cube, width, height, length);
+    par_shapes_translate(cube, -width/2, 0.0f, -length/2);
+    par_shapes_compute_normals(cube);
+
+    mesh.vertices = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(cube->ntriangles*3*2*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(cube->ntriangles*3*3*sizeof(float));
+
+    mesh.vertexCount = cube->ntriangles*3;
+    mesh.triangleCount = cube->ntriangles;
+
+    for (int k = 0; k < mesh.vertexCount; k++)
+    {
+        mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
+        mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
+        mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
+
+        mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
+        mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
+        mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
+
+        mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
+        mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
+    }
+
+    par_shapes_free_mesh(cube);
+#endif
+
+    // Upload vertex data to GPU (static mesh)
+    UploadMesh(&mesh, false);
+
+    return mesh;
+}
+
+// Generate sphere mesh (standard sphere)
+Mesh GenMeshSphere(float radius, int rings, int slices)
+{
+    Mesh mesh = { 0 };
+
+    if ((rings >= 3) && (slices >= 3))
+    {
+        par_shapes_set_epsilon_degenerate_sphere(0.0);
+        par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings);
+        par_shapes_scale(sphere, radius, radius, radius);
+        // NOTE: Soft normals are computed internally
+
+        mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = sphere->ntriangles*3;
+        mesh.triangleCount = sphere->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
+            mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(sphere);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: sphere");
+
+    return mesh;
+}
+
+// Generate hemisphere mesh (half sphere, no bottom cap)
+Mesh GenMeshHemiSphere(float radius, int rings, int slices)
+{
+    Mesh mesh = { 0 };
+
+    if ((rings >= 3) && (slices >= 3))
+    {
+        if (radius < 0.0f) radius = 0.0f;
+
+        par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
+        par_shapes_scale(sphere, radius, radius, radius);
+        // NOTE: Soft normals are computed internally
+
+        mesh.vertices = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(sphere->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(sphere->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = sphere->ntriangles*3;
+        mesh.triangleCount = sphere->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
+            mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(sphere);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: hemisphere");
+
+    return mesh;
+}
+
+// Generate cylinder mesh
+Mesh GenMeshCylinder(float radius, float height, int slices)
+{
+    Mesh mesh = { 0 };
+
+    if (slices >= 3)
+    {
+        // Instance a cylinder that sits on the Z=0 plane using the given tessellation
+        // levels across the UV domain.  Think of "slices" like a number of pizza
+        // slices, and "stacks" like a number of stacked rings
+        // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
+        par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
+        par_shapes_scale(cylinder, radius, radius, height);
+        par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
+
+        // Generate an orientable disk shape (top cap)
+        par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
+        capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
+        for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
+        par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
+        par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 });
+        par_shapes_translate(capTop, 0, height, 0);
+
+        // Generate an orientable disk shape (bottom cap)
+        par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
+        capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
+        for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
+        par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
+        par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 });
+
+        par_shapes_merge_and_free(cylinder, capTop);
+        par_shapes_merge_and_free(cylinder, capBottom);
+
+        mesh.vertices = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(cylinder->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(cylinder->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = cylinder->ntriangles*3;
+        mesh.triangleCount = cylinder->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
+            mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(cylinder);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cylinder");
+
+    return mesh;
+}
+
+// Generate cone/pyramid mesh
+Mesh GenMeshCone(float radius, float height, int slices)
+{
+    Mesh mesh = { 0 };
+
+    if (slices >= 3)
+    {
+        // Instance a cone that sits on the Z=0 plane using the given tessellation
+        // levels across the UV domain.  Think of "slices" like a number of pizza
+        // slices, and "stacks" like a number of stacked rings
+        // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
+        par_shapes_mesh *cone = par_shapes_create_cone(slices, 8);
+        par_shapes_scale(cone, radius, radius, height);
+        par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 });
+        par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 });
+
+        // Generate an orientable disk shape (bottom cap)
+        par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
+        capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
+        for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
+        par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
+
+        par_shapes_merge_and_free(cone, capBottom);
+
+        mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = cone->ntriangles*3;
+        mesh.triangleCount = cone->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = cone->points[cone->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = cone->normals[cone->triangles[k]*3];
+            mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(cone);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone");
+
+    return mesh;
+}
+
+// Generate torus mesh
+// 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 };
+
+    if ((sides >= 3) && (radSeg >= 3))
+    {
+        if (radius > 1.0f) radius = 1.0f;
+        else if (radius < 0.1f) radius = 0.1f;
+
+        // Create a donut that sits on the Z=0 plane with the specified inner radius
+        // The outer radius can be controlled with par_shapes_scale
+        par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
+        par_shapes_scale(torus, size/2, size/2, size/2);
+
+        mesh.vertices = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(torus->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(torus->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = torus->ntriangles*3;
+        mesh.triangleCount = torus->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
+            mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(torus);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: torus");
+
+    return mesh;
+}
+
+// Generate trefoil knot mesh
+Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
+{
+    Mesh mesh = { 0 };
+
+    if ((sides >= 3) && (radSeg >= 3))
+    {
+        if (radius > 3.0f) radius = 3.0f;
+        else if (radius < 0.5f) radius = 0.5f;
+
+        par_shapes_mesh *knot = par_shapes_create_trefoil_knot(radSeg, sides, radius);
+        par_shapes_scale(knot, size, size, size);
+
+        mesh.vertices = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
+        mesh.texcoords = (float *)RL_MALLOC(knot->ntriangles*3*2*sizeof(float));
+        mesh.normals = (float *)RL_MALLOC(knot->ntriangles*3*3*sizeof(float));
+
+        mesh.vertexCount = knot->ntriangles*3;
+        mesh.triangleCount = knot->ntriangles;
+
+        for (int k = 0; k < mesh.vertexCount; k++)
+        {
+            mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
+            mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
+            mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
+
+            mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
+            mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
+            mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
+
+            mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
+            mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
+        }
+
+        par_shapes_free_mesh(knot);
+
+        // Upload vertex data to GPU (static mesh)
+        UploadMesh(&mesh, false);
+    }
+    else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: knot");
+
+    return mesh;
+}
+
+// Generate a mesh from heightmap
+// NOTE: Vertex data is uploaded to GPU
+Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
+{
+    #define GRAY_VALUE(c) ((float)(c.r + c.g + c.b)/3.0f)
+
+    Mesh mesh = { 0 };
+
+    int mapX = heightmap.width;
+    int mapZ = heightmap.height;
+
+    Color *pixels = LoadImageColors(heightmap);
+
+    // NOTE: One vertex per pixel
+    mesh.triangleCount = (mapX - 1)*(mapZ - 1)*2;    // One quad every four pixels
+
+    mesh.vertexCount = mesh.triangleCount*3;
+
+    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
+    mesh.colors = NULL;
+
+    int vCounter = 0;       // Used to count vertices float by float
+    int tcCounter = 0;      // Used to count texcoords float by float
+    int nCounter = 0;       // Used to count normals float by float
+
+    Vector3 scaleFactor = { size.x/(mapX - 1), size.y/255.0f, size.z/(mapZ - 1) };
+
+    Vector3 vA = { 0 };
+    Vector3 vB = { 0 };
+    Vector3 vC = { 0 };
+    Vector3 vN = { 0 };
+
+    for (int z = 0; z < mapZ-1; z++)
+    {
+        for (int x = 0; x < mapX-1; x++)
+        {
+            // Fill vertices array with data
+            //----------------------------------------------------------
+
+            // one triangle - 3 vertex
+            mesh.vertices[vCounter] = (float)x*scaleFactor.x;
+            mesh.vertices[vCounter + 1] = GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
+            mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
+
+            mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
+            mesh.vertices[vCounter + 4] = GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
+            mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
+
+            mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
+            mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
+            mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
+
+            // Another triangle - 3 vertex
+            mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
+            mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
+            mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
+
+            mesh.vertices[vCounter + 12] = mesh.vertices[vCounter + 3];
+            mesh.vertices[vCounter + 13] = mesh.vertices[vCounter + 4];
+            mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
+
+            mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
+            mesh.vertices[vCounter + 16] = GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
+            mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
+            vCounter += 18;     // 6 vertex, 18 floats
+
+            // Fill texcoords array with data
+            //--------------------------------------------------------------
+            mesh.texcoords[tcCounter] = (float)x/(mapX - 1);
+            mesh.texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
+
+            mesh.texcoords[tcCounter + 2] = (float)x/(mapX - 1);
+            mesh.texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
+
+            mesh.texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
+            mesh.texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
+
+            mesh.texcoords[tcCounter + 6] = mesh.texcoords[tcCounter + 4];
+            mesh.texcoords[tcCounter + 7] = mesh.texcoords[tcCounter + 5];
+
+            mesh.texcoords[tcCounter + 8] = mesh.texcoords[tcCounter + 2];
+            mesh.texcoords[tcCounter + 9] = mesh.texcoords[tcCounter + 3];
+
+            mesh.texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
+            mesh.texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
+            tcCounter += 12;    // 6 texcoords, 12 floats
+
+            // Fill normals array with data
+            //--------------------------------------------------------------
+            for (int i = 0; i < 18; i += 9)
+            {
+                vA.x = mesh.vertices[nCounter + i];
+                vA.y = mesh.vertices[nCounter + i + 1];
+                vA.z = mesh.vertices[nCounter + i + 2];
+
+                vB.x = mesh.vertices[nCounter + i + 3];
+                vB.y = mesh.vertices[nCounter + i + 4];
+                vB.z = mesh.vertices[nCounter + i + 5];
+
+                vC.x = mesh.vertices[nCounter + i + 6];
+                vC.y = mesh.vertices[nCounter + i + 7];
+                vC.z = mesh.vertices[nCounter + i + 8];
+
+                vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
+
+                mesh.normals[nCounter + i] = vN.x;
+                mesh.normals[nCounter + i + 1] = vN.y;
+                mesh.normals[nCounter + i + 2] = vN.z;
+
+                mesh.normals[nCounter + i + 3] = vN.x;
+                mesh.normals[nCounter + i + 4] = vN.y;
+                mesh.normals[nCounter + i + 5] = vN.z;
+
+                mesh.normals[nCounter + i + 6] = vN.x;
+                mesh.normals[nCounter + i + 7] = vN.y;
+                mesh.normals[nCounter + i + 8] = vN.z;
+            }
+
+            nCounter += 18;     // 6 vertex, 18 floats
+        }
+    }
+
+    UnloadImageColors(pixels);  // Unload pixels color data
+
+    // Upload vertex data to GPU (static mesh)
+    UploadMesh(&mesh, false);
+
+    return mesh;
+}
+
+// Generate a cubes mesh from pixel data
+// NOTE: Vertex data is uploaded to GPU
+Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
+{
+    #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
+
+    Mesh mesh = { 0 };
+
+    Color *pixels = LoadImageColors(cubicmap);
+
+    // NOTE: Max possible number of triangles numCubes*(12 triangles by cube)
+    int maxTriangles = cubicmap.width*cubicmap.height*12;
+
+    int vCounter = 0;       // Used to count vertices
+    int tcCounter = 0;      // Used to count texcoords
+    int nCounter = 0;       // Used to count normals
+
+    float w = cubeSize.x;
+    float h = cubeSize.z;
+    float h2 = cubeSize.y;
+
+    Vector3 *mapVertices = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
+    Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
+    Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
+
+    // Define the 6 normals of the cube, combined accordingly later
+    Vector3 n1 = { 1.0f, 0.0f, 0.0f };
+    Vector3 n2 = { -1.0f, 0.0f, 0.0f };
+    Vector3 n3 = { 0.0f, 1.0f, 0.0f };
+    Vector3 n4 = { 0.0f, -1.0f, 0.0f };
+    Vector3 n5 = { 0.0f, 0.0f, -1.0f };
+    Vector3 n6 = { 0.0f, 0.0f, 1.0f };
+
+    // NOTE: Using texture rectangles to define different
+    // textures for top-bottom-front-back-right-left (6)
+    typedef struct RectangleF {
+        float x;
+        float y;
+        float width;
+        float height;
+    } RectangleF;
+
+    RectangleF rightTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
+    RectangleF leftTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
+    RectangleF frontTexUV = { 0.0f, 0.0f, 0.5f, 0.5f };
+    RectangleF backTexUV = { 0.5f, 0.0f, 0.5f, 0.5f };
+    RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f };
+    RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f };
+
+    for (int z = 0; z < cubicmap.height; ++z)
+    {
+        for (int x = 0; x < cubicmap.width; x++)
+        {
+            // Define the 8 vertex of the cube, to be combined accordingly later
+            Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
+            Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
+            Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
+            Vector3 v4 = { w*(x + 0.5f), h2, h*(z - 0.5f) };
+            Vector3 v5 = { w*(x + 0.5f), 0, h*(z - 0.5f) };
+            Vector3 v6 = { w*(x - 0.5f), 0, h*(z - 0.5f) };
+            Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
+            Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
+
+            // Check pixel color to be WHITE -> draw full cube
+            if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
+            {
+                // Define triangles and checking collateral cubes
+                //------------------------------------------------
+
+                // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
+                // WARNING: Not required for a WHITE cubes, created to allow seeing the map from outside
+                mapVertices[vCounter] = v1;
+                mapVertices[vCounter + 1] = v2;
+                mapVertices[vCounter + 2] = v3;
+                mapVertices[vCounter + 3] = v1;
+                mapVertices[vCounter + 4] = v3;
+                mapVertices[vCounter + 5] = v4;
+                vCounter += 6;
+
+                mapNormals[nCounter] = n3;
+                mapNormals[nCounter + 1] = n3;
+                mapNormals[nCounter + 2] = n3;
+                mapNormals[nCounter + 3] = n3;
+                mapNormals[nCounter + 4] = n3;
+                mapNormals[nCounter + 5] = n3;
+                nCounter += 6;
+
+                mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
+                mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
+                mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
+                mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
+                mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
+                mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
+                tcCounter += 6;
+
+                // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
+                mapVertices[vCounter] = v6;
+                mapVertices[vCounter + 1] = v8;
+                mapVertices[vCounter + 2] = v7;
+                mapVertices[vCounter + 3] = v6;
+                mapVertices[vCounter + 4] = v5;
+                mapVertices[vCounter + 5] = v8;
+                vCounter += 6;
+
+                mapNormals[nCounter] = n4;
+                mapNormals[nCounter + 1] = n4;
+                mapNormals[nCounter + 2] = n4;
+                mapNormals[nCounter + 3] = n4;
+                mapNormals[nCounter + 4] = n4;
+                mapNormals[nCounter + 5] = n4;
+                nCounter += 6;
+
+                mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
+                mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
+                mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
+                mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
+                mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
+                mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
+                tcCounter += 6;
+
+                // Checking cube on bottom of current cube
+                if (((z < cubicmap.height - 1) && COLOR_EQUAL(pixels[(z + 1)*cubicmap.width + x], BLACK)) || (z == cubicmap.height - 1))
+                {
+                    // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v2;
+                    mapVertices[vCounter + 1] = v7;
+                    mapVertices[vCounter + 2] = v3;
+                    mapVertices[vCounter + 3] = v3;
+                    mapVertices[vCounter + 4] = v7;
+                    mapVertices[vCounter + 5] = v8;
+                    vCounter += 6;
+
+                    mapNormals[nCounter] = n6;
+                    mapNormals[nCounter + 1] = n6;
+                    mapNormals[nCounter + 2] = n6;
+                    mapNormals[nCounter + 3] = n6;
+                    mapNormals[nCounter + 4] = n6;
+                    mapNormals[nCounter + 5] = n6;
+                    nCounter += 6;
+
+                    mapTexcoords[tcCounter] = (Vector2){ frontTexUV.x, frontTexUV.y };
+                    mapTexcoords[tcCounter + 1] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
+                    mapTexcoords[tcCounter + 2] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
+                    mapTexcoords[tcCounter + 3] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y };
+                    mapTexcoords[tcCounter + 4] = (Vector2){ frontTexUV.x, frontTexUV.y + frontTexUV.height };
+                    mapTexcoords[tcCounter + 5] = (Vector2){ frontTexUV.x + frontTexUV.width, frontTexUV.y + frontTexUV.height };
+                    tcCounter += 6;
+                }
+
+                // Checking cube on top of current cube
+                if (((z > 0) && COLOR_EQUAL(pixels[(z - 1)*cubicmap.width + x], BLACK)) || (z == 0))
+                {
+                    // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v1;
+                    mapVertices[vCounter + 1] = v5;
+                    mapVertices[vCounter + 2] = v6;
+                    mapVertices[vCounter + 3] = v1;
+                    mapVertices[vCounter + 4] = v4;
+                    mapVertices[vCounter + 5] = v5;
+                    vCounter += 6;
+
+                    mapNormals[nCounter] = n5;
+                    mapNormals[nCounter + 1] = n5;
+                    mapNormals[nCounter + 2] = n5;
+                    mapNormals[nCounter + 3] = n5;
+                    mapNormals[nCounter + 4] = n5;
+                    mapNormals[nCounter + 5] = n5;
+                    nCounter += 6;
+
+                    mapTexcoords[tcCounter] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
+                    mapTexcoords[tcCounter + 1] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
+                    mapTexcoords[tcCounter + 2] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y + backTexUV.height };
+                    mapTexcoords[tcCounter + 3] = (Vector2){ backTexUV.x + backTexUV.width, backTexUV.y };
+                    mapTexcoords[tcCounter + 4] = (Vector2){ backTexUV.x, backTexUV.y };
+                    mapTexcoords[tcCounter + 5] = (Vector2){ backTexUV.x, backTexUV.y + backTexUV.height };
+                    tcCounter += 6;
+                }
+
+                // Checking cube on right of current cube
+                if (((x < cubicmap.width - 1) && COLOR_EQUAL(pixels[z*cubicmap.width + (x + 1)], BLACK)) || (x == cubicmap.width - 1))
+                {
+                    // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v3;
+                    mapVertices[vCounter + 1] = v8;
+                    mapVertices[vCounter + 2] = v4;
+                    mapVertices[vCounter + 3] = v4;
+                    mapVertices[vCounter + 4] = v8;
+                    mapVertices[vCounter + 5] = v5;
+                    vCounter += 6;
+
+                    mapNormals[nCounter] = n1;
+                    mapNormals[nCounter + 1] = n1;
+                    mapNormals[nCounter + 2] = n1;
+                    mapNormals[nCounter + 3] = n1;
+                    mapNormals[nCounter + 4] = n1;
+                    mapNormals[nCounter + 5] = n1;
+                    nCounter += 6;
+
+                    mapTexcoords[tcCounter] = (Vector2){ rightTexUV.x, rightTexUV.y };
+                    mapTexcoords[tcCounter + 1] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
+                    mapTexcoords[tcCounter + 2] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
+                    mapTexcoords[tcCounter + 3] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y };
+                    mapTexcoords[tcCounter + 4] = (Vector2){ rightTexUV.x, rightTexUV.y + rightTexUV.height };
+                    mapTexcoords[tcCounter + 5] = (Vector2){ rightTexUV.x + rightTexUV.width, rightTexUV.y + rightTexUV.height };
+                    tcCounter += 6;
+                }
+
+                // Checking cube on left of current cube
+                if (((x > 0) && COLOR_EQUAL(pixels[z*cubicmap.width + (x - 1)], BLACK)) || (x == 0))
+                {
+                    // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v1;
+                    mapVertices[vCounter + 1] = v7;
+                    mapVertices[vCounter + 2] = v2;
+                    mapVertices[vCounter + 3] = v1;
+                    mapVertices[vCounter + 4] = v6;
+                    mapVertices[vCounter + 5] = v7;
+                    vCounter += 6;
+
+                    mapNormals[nCounter] = n2;
+                    mapNormals[nCounter + 1] = n2;
+                    mapNormals[nCounter + 2] = n2;
+                    mapNormals[nCounter + 3] = n2;
+                    mapNormals[nCounter + 4] = n2;
+                    mapNormals[nCounter + 5] = n2;
+                    nCounter += 6;
+
+                    mapTexcoords[tcCounter] = (Vector2){ leftTexUV.x, leftTexUV.y };
+                    mapTexcoords[tcCounter + 1] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
+                    mapTexcoords[tcCounter + 2] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y };
+                    mapTexcoords[tcCounter + 3] = (Vector2){ leftTexUV.x, leftTexUV.y };
+                    mapTexcoords[tcCounter + 4] = (Vector2){ leftTexUV.x, leftTexUV.y + leftTexUV.height };
+                    mapTexcoords[tcCounter + 5] = (Vector2){ leftTexUV.x + leftTexUV.width, leftTexUV.y + leftTexUV.height };
+                    tcCounter += 6;
+                }
+            }
+            // Check pixel color to be BLACK, in that case only drawing floor and roof
+            else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
+            {
+                // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
+                mapVertices[vCounter] = v1;
+                mapVertices[vCounter + 1] = v3;
+                mapVertices[vCounter + 2] = v2;
+                mapVertices[vCounter + 3] = v1;
+                mapVertices[vCounter + 4] = v4;
+                mapVertices[vCounter + 5] = v3;
+                vCounter += 6;
+
+                mapNormals[nCounter] = n4;
+                mapNormals[nCounter + 1] = n4;
+                mapNormals[nCounter + 2] = n4;
+                mapNormals[nCounter + 3] = n4;
+                mapNormals[nCounter + 4] = n4;
+                mapNormals[nCounter + 5] = n4;
+                nCounter += 6;
+
+                mapTexcoords[tcCounter] = (Vector2){ topTexUV.x, topTexUV.y };
+                mapTexcoords[tcCounter + 1] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
+                mapTexcoords[tcCounter + 2] = (Vector2){ topTexUV.x, topTexUV.y + topTexUV.height };
+                mapTexcoords[tcCounter + 3] = (Vector2){ topTexUV.x, topTexUV.y };
+                mapTexcoords[tcCounter + 4] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y };
+                mapTexcoords[tcCounter + 5] = (Vector2){ topTexUV.x + topTexUV.width, topTexUV.y + topTexUV.height };
+                tcCounter += 6;
+
+                // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
+                mapVertices[vCounter] = v6;
+                mapVertices[vCounter + 1] = v7;
+                mapVertices[vCounter + 2] = v8;
+                mapVertices[vCounter + 3] = v6;
+                mapVertices[vCounter + 4] = v8;
+                mapVertices[vCounter + 5] = v5;
+                vCounter += 6;
+
+                mapNormals[nCounter] = n3;
+                mapNormals[nCounter + 1] = n3;
+                mapNormals[nCounter + 2] = n3;
+                mapNormals[nCounter + 3] = n3;
+                mapNormals[nCounter + 4] = n3;
+                mapNormals[nCounter + 5] = n3;
+                nCounter += 6;
+
+                mapTexcoords[tcCounter] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
+                mapTexcoords[tcCounter + 1] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y + bottomTexUV.height };
+                mapTexcoords[tcCounter + 2] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
+                mapTexcoords[tcCounter + 3] = (Vector2){ bottomTexUV.x + bottomTexUV.width, bottomTexUV.y };
+                mapTexcoords[tcCounter + 4] = (Vector2){ bottomTexUV.x, bottomTexUV.y + bottomTexUV.height };
+                mapTexcoords[tcCounter + 5] = (Vector2){ bottomTexUV.x, bottomTexUV.y };
+                tcCounter += 6;
+            }
+        }
+    }
+
+    // Move data from mapVertices temp arrays to vertices float array
+    mesh.vertexCount = vCounter;
+    mesh.triangleCount = vCounter/3;
+
+    mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float));
+    mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float));
+    mesh.colors = NULL;
+
+    int fCounter = 0;
+
+    // Move vertices data
+    for (int i = 0; i < vCounter; i++)
+    {
+        mesh.vertices[fCounter] = mapVertices[i].x;
+        mesh.vertices[fCounter + 1] = mapVertices[i].y;
+        mesh.vertices[fCounter + 2] = mapVertices[i].z;
+        fCounter += 3;
+    }
+
+    fCounter = 0;
+
+    // Move normals data
+    for (int i = 0; i < nCounter; i++)
+    {
+        mesh.normals[fCounter] = mapNormals[i].x;
+        mesh.normals[fCounter + 1] = mapNormals[i].y;
+        mesh.normals[fCounter + 2] = mapNormals[i].z;
+        fCounter += 3;
+    }
+
+    fCounter = 0;
+
+    // Move texcoords data
+    for (int i = 0; i < tcCounter; i++)
+    {
+        mesh.texcoords[fCounter] = mapTexcoords[i].x;
+        mesh.texcoords[fCounter + 1] = mapTexcoords[i].y;
+        fCounter += 2;
+    }
+
+    RL_FREE(mapVertices);
+    RL_FREE(mapNormals);
+    RL_FREE(mapTexcoords);
+
+    UnloadImageColors(pixels);   // Unload pixels color data
+
+    // Upload vertex data to GPU (static mesh)
+    UploadMesh(&mesh, false);
+
+    return mesh;
+}
+#endif // SUPPORT_MESH_GENERATION
+
+// Compute mesh bounding box limits
+// NOTE: minVertex and maxVertex should be transformed by model transform matrix
+BoundingBox GetMeshBoundingBox(Mesh mesh)
+{
+    // Get min and max vertex to construct bounds (AABB)
+    Vector3 minVertex = { 0 };
+    Vector3 maxVertex = { 0 };
+
+    if (mesh.vertices != NULL)
+    {
+        minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
+        maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] };
+
+        for (int i = 1; i < mesh.vertexCount; i++)
+        {
+            minVertex = Vector3Min(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
+            maxVertex = Vector3Max(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] });
+        }
+    }
+
+    // Create the bounding box
+    BoundingBox box = { 0 };
+    box.min = minVertex;
+    box.max = maxVertex;
+
+    return box;
+}
+
+// Compute mesh tangents
+void GenMeshTangents(Mesh *mesh)
+{
+    // Check if input mesh data is useful
+    if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
+    {
+        TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
+        return;
+    }
+
+    // Allocate or reallocate tangents data
+    if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
+    else
+    {
+        RL_FREE(mesh->tangents);
+        mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
+    }
+
+    // Allocate temporary arrays for tangents calculation
+    Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
+    Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
+
+    if (tan1 == NULL || tan2 == NULL)
+    {
+        TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
+        if (tan1) RL_FREE(tan1);
+        if (tan2) RL_FREE(tan2);
+        return;
+    }
+
+    // Process all triangles of the mesh
+    // 'triangleCount' must be always valid
+    for (int t = 0; t < mesh->triangleCount; t++)
+    {
+        // Get triangle vertex indices
+        int i0 = 0, i1 = 0, i2 = 0;
+
+        if (mesh->indices != NULL)
+        {
+            // Use indices if available
+            i0 = mesh->indices[t*3 + 0];
+            i1 = mesh->indices[t*3 + 1];
+            i2 = mesh->indices[t*3 + 2];
+        }
+        else
+        {
+            // Sequential access for non-indexed mesh
+            i0 = t*3 + 0;
+            i1 = t*3 + 1;
+            i2 = t*3 + 2;
+        }
+
+        // Get triangle vertices position
+        Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
+        Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
+        Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
+
+        // Get triangle texcoords
+        Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
+        Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
+        Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
+
+        // Calculate triangle edges
+        float x1 = v2.x - v1.x;
+        float y1 = v2.y - v1.y;
+        float z1 = v2.z - v1.z;
+        float x2 = v3.x - v1.x;
+        float y2 = v3.y - v1.y;
+        float z2 = v3.z - v1.z;
+
+        // Calculate texture coordinate differences
+        float s1 = uv2.x - uv1.x;
+        float t1 = uv2.y - uv1.y;
+        float s2 = uv3.x - uv1.x;
+        float t2 = uv3.y - uv1.y;
+
+        // Calculate denominator and check for degenerate UV
+        float div = s1*t2 - s2*t1;
+        float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
+
+        // Calculate tangent and bitangent directions
+        Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
+        Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
+
+        // Accumulate tangents and bitangents for each vertex of the triangle
+        tan1[i0] = Vector3Add(tan1[i0], sdir);
+        tan1[i1] = Vector3Add(tan1[i1], sdir);
+        tan1[i2] = Vector3Add(tan1[i2], sdir);
+
+        tan2[i0] = Vector3Add(tan2[i0], tdir);
+        tan2[i1] = Vector3Add(tan2[i1], tdir);
+        tan2[i2] = Vector3Add(tan2[i2], tdir);
+    }
+
+    // Calculate final tangents for each vertex
+    for (int i = 0; i < mesh->vertexCount; i++)
+    {
+        Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
+        Vector3 tangent = tan1[i];
+
+        // Handle zero tangent (can happen with degenerate UVs)
+        if (Vector3Length(tangent) < 0.0001f)
+        {
+            // Create a tangent perpendicular to the normal
+            if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
+            else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
+
+            mesh->tangents[i*4 + 0] = tangent.x;
+            mesh->tangents[i*4 + 1] = tangent.y;
+            mesh->tangents[i*4 + 2] = tangent.z;
+            mesh->tangents[i*4 + 3] = 1.0f;
+            continue;
+        }
+
+        // Gram-Schmidt orthogonalization to make tangent orthogonal to normal
+        // T_prime = T - N*dot(N, T)
+        Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
+
+        // Handle cases where orthogonalized vector is too small
+        if (Vector3Length(orthogonalized) < 0.0001f)
+        {
+            // Create a tangent perpendicular to the normal
+            if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
+            else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
+        }
+        else
+        {
+            // Normalize the orthogonalized tangent
+            orthogonalized = Vector3Normalize(orthogonalized);
+        }
+
+        // Store the calculated tangent
+        mesh->tangents[i*4 + 0] = orthogonalized.x;
+        mesh->tangents[i*4 + 1] = orthogonalized.y;
+        mesh->tangents[i*4 + 2] = orthogonalized.z;
+
+        // Calculate the handedness (w component)
+        mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
+    }
+
+    // Free temporary arrays
+    RL_FREE(tan1);
+    RL_FREE(tan2);
+
+    // Update vertex buffers if available
+    if (mesh->vboId != NULL)
+    {
+        if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
+        {
+            // Update existing tangent vertex buffer
+            rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
+        }
+        else
+        {
+            // Create new tangent vertex buffer
+            mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
+        }
+
+        // Set up vertex attributes for shader
+        rlEnableVertexArray(mesh->vaoId);
+        rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
+        rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
+        rlDisableVertexArray();
+    }
+
+    TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
+}
+
+// Draw a model (with texture if set)
+void DrawModel(Model model, Vector3 position, float scale, Color tint)
+{
+    Vector3 vScale = { scale, scale, scale };
+    Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
+
+    DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
+}
+
+// Draw a model with custom transform
+void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
+{
+    // Calculate transformation matrix from function parameters
+    // Get transform matrix (rotation -> scale -> translation)
+    Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
+    Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
+    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+
+    Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
+
+    // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
+    model.transform = MatrixMultiply(model.transform, matTransform);
+
+    for (int i = 0; i < model.meshCount; i++)
+    {
+        Material mat = model.materials[model.meshMaterial[i]];
+        Color colDiffuse = mat.maps[MATERIAL_MAP_DIFFUSE].color;
+
+        // Applying color tint directly to material diffuse map,
+        // because it comes as an input parameter to the function
+        Color colTinted = { 0 };
+        colTinted.r = (unsigned char)(((int)colDiffuse.r*(int)tint.r)/255);
+        colTinted.g = (unsigned char)(((int)colDiffuse.g*(int)tint.g)/255);
+        colTinted.b = (unsigned char)(((int)colDiffuse.b*(int)tint.b)/255);
+        colTinted.a = (unsigned char)(((int)colDiffuse.a*(int)tint.a)/255);
+
+        mat.maps[MATERIAL_MAP_DIFFUSE].color = colTinted;
+
+        // Upload runtime bone transforms matrices, to compute skinning on the shader (GPU-skinning)
+        // NOTE: Required location must be found and Mesh bones indices and weights must be also uploaded to shader
+        if ((mat.shader.locs != NULL) && (mat.shader.locs[SHADER_LOC_MATRIX_BONETRANSFORMS] != -1) && (model.boneMatrices != NULL))
+        {
+            rlEnableShader(mat.shader.id); // Enable shader to set bone transform matrices
+            rlSetUniformMatrices(mat.shader.locs[SHADER_LOC_MATRIX_BONETRANSFORMS], model.boneMatrices, model.skeleton.boneCount);
+        }
+
+        DrawMesh(model.meshes[i], mat, model.transform);
+
+        // Restore material diffuse map color (before tint applied)
+        mat.maps[MATERIAL_MAP_DIFFUSE].color = colDiffuse;
+    }
+}
+
+// Draw a model wires (with texture if set)
+void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
+{
+    rlEnableWireMode();
+
+    DrawModel(model, position, scale, tint);
+
+    rlDisableWireMode();
+}
+
+// Draw a model wires with custom transform
+void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
+{
+    rlEnableWireMode();
+
+    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
+
+    rlDisableWireMode();
+}
+
+// Draw a billboard
+void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
+{
+    Rectangle rec = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
+
+    DrawBillboardRec(camera, texture, rec, position, (Vector2){ scale*fabsf((float)rec.width/rec.height), scale }, tint);
+}
+
+// Draw a billboard (part of a texture defined by a rectangle)
+void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector2 size, Color tint)
+{
+    // NOTE: Billboard locked on axis-Y
+    Vector3 up = { 0.0f, 1.0f, 0.0f };
+
+    DrawBillboardPro(camera, texture, rec, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
+}
+
+// Draw a billboard texture defined by source rectangle with scaling and rotation
+void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle rec, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
+{
+    // Compute the up vector and the right vector
+    Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+    Vector3 right = { matView.m0, matView.m4, matView.m8 };
+    right = Vector3Scale(right, size.x);
+    up = Vector3Scale(up, size.y);
+
+    // Flip the content of the billboard while maintaining the counterclockwise edge rendering order
+    if (size.x < 0.0f)
+    {
+        rec.x -= size.x;
+        rec.width *= -1.0;
+        right = Vector3Negate(right);
+        origin.x *= -1.0f;
+    }
+    if (size.y < 0.0f)
+    {
+        rec.y -= size.y;
+        rec.height *= -1.0;
+        up = Vector3Negate(up);
+        origin.y *= -1.0f;
+    }
+
+    // Draw the texture region described by rec on the following rectangle in 3D space:
+    //
+    //                size.x          <--.
+    //  3 ^---------------------------+ 2 \ rotation
+    //    |                           |   /
+    //    |                           |
+    //    |   origin.x   position     |
+    // up |..............             | size.y
+    //    |             .             |
+    //    |             . origin.y    |
+    //    |             .             |
+    //  0 +---------------------------> 1
+    //                right
+    Vector3 forward;
+    if (rotation != 0.0) forward = Vector3CrossProduct(right, up);
+
+    Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(right), origin.x), Vector3Scale(Vector3Normalize(up), origin.y));
+
+    Vector3 points[4];
+    points[0] = Vector3Zero();
+    points[1] = right;
+    points[2] = Vector3Add(up, right);
+    points[3] = up;
+
+    for (int i = 0; i < 4; i++)
+    {
+        points[i] = Vector3Subtract(points[i], origin3D);
+        if (rotation != 0.0) points[i] = Vector3RotateByAxisAngle(points[i], forward, rotation*DEG2RAD);
+        points[i] = Vector3Add(points[i], position);
+    }
+
+    Vector2 texcoords[4];
+    texcoords[0] = (Vector2){ (float)rec.x/texture.width, (float)(rec.y + rec.height)/texture.height };
+    texcoords[1] = (Vector2){ (float)(rec.x + rec.width)/texture.width, (float)(rec.y + rec.height)/texture.height };
+    texcoords[2] = (Vector2){ (float)(rec.x + rec.width)/texture.width, (float)rec.y/texture.height };
+    texcoords[3] = (Vector2){ (float)rec.x/texture.width, (float)rec.y/texture.height };
+
+    rlSetTexture(texture.id);
+    rlBegin(RL_QUADS);
+
+        rlColor4ub(tint.r, tint.g, tint.b, tint.a);
+        for (int i = 0; i < 4; i++)
+        {
+            rlTexCoord2f(texcoords[i].x, texcoords[i].y);
+            rlVertex3f(points[i].x, points[i].y, points[i].z);
+        }
+
+    rlEnd();
+    rlSetTexture(0);
+}
+
+// Draw a bounding box with wires
+void DrawBoundingBox(BoundingBox box, Color color)
+{
+    Vector3 size = { 0 };
+
+    size.x = fabsf(box.max.x - box.min.x);
+    size.y = fabsf(box.max.y - box.min.y);
+    size.z = fabsf(box.max.z - box.min.z);
+
+    Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
+
+    DrawCubeWires(center, size.x, size.y, size.z, color);
+}
+
+// Check collision between two spheres
+bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2)
+{
+    bool collision = false;
+
+    // Simple way to check for collision, checking distance between two points
+    // Unfortunately, sqrtf() is a costly operation, so avoid it with following solution
+    /*
+    float dx = center1.x - center2.x;      // X distance between centers
+    float dy = center1.y - center2.y;      // Y distance between centers
+    float dz = center1.z - center2.z;      // Z distance between centers
+
+    float distance = sqrtf(dx*dx + dy*dy + dz*dz);  // Distance between centers
+
+    if (distance <= (radius1 + radius2)) collision = true;
+    */
+
+    // Check for distances squared to avoid sqrtf()
+    float radSum = radius1 + radius2;
+    if (Vector3DistanceSqr(center1, center2) <= (radSum*radSum)) collision = true;
+
+    return collision;
+}
+
+// Check collision between two boxes
+// NOTE: Boxes are defined by two points minimum and maximum
+bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2)
+{
+    bool collision = true;
+
+    if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x))
+    {
+        if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false;
+        if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false;
+    }
+    else collision = false;
+
+    return collision;
+}
+
+// Check collision between box and sphere
+bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
+{
+    bool collision = false;
+
+    Vector3 closestPoint = {
+        Clamp(center.x, box.min.x, box.max.x),
+        Clamp(center.y, box.min.y, box.max.y),
+        Clamp(center.z, box.min.z, box.max.z)
+    };
+
+    if (Vector3DistanceSqr(center, closestPoint) <= (radius*radius)) collision = true;
+
+    return collision;
+}
+
+// Get collision info between ray and sphere
+RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
+{
+    RayCollision collision = { 0 };
+
+    Vector3 raySpherePos = Vector3Subtract(center, ray.position);
+    float vector = Vector3DotProduct(raySpherePos, ray.direction);
+    float distance = Vector3Length(raySpherePos);
+    float d = radius*radius - (distance*distance - vector*vector);
+
+    collision.hit = d >= 0.0f;
+
+    // Check if ray origin is inside the sphere to calculate the correct collision point
+    if (distance < radius)
+    {
+        collision.distance = vector + sqrtf(d);
+
+        // Calculate collision point
+        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
+
+        // Calculate collision normal (pointing outwards)
+        collision.normal = Vector3Negate(Vector3Normalize(Vector3Subtract(collision.point, center)));
+    }
+    else
+    {
+        collision.distance = vector - sqrtf(d);
+
+        // Calculate collision point
+        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
+
+        // Calculate collision normal (pointing inwards)
+        collision.normal = Vector3Normalize(Vector3Subtract(collision.point, center));
+    }
+
+    return collision;
+}
+
+// Get collision info between ray and box
+RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
+{
+    RayCollision collision = { 0 };
+
+    // NOTE: If ray.position is inside the box, the distance is negative (as if the ray was reversed)
+    // Reversing ray.direction will give use the correct result
+    bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) &&
+                     (ray.position.y > box.min.y) && (ray.position.y < box.max.y) &&
+                     (ray.position.z > box.min.z) && (ray.position.z < box.max.z);
+
+    if (insideBox) ray.direction = Vector3Negate(ray.direction);
+
+    float t[11] = { 0 };
+
+    t[8] = 1.0f/ray.direction.x;
+    t[9] = 1.0f/ray.direction.y;
+    t[10] = 1.0f/ray.direction.z;
+
+    t[0] = (box.min.x - ray.position.x)*t[8];
+    t[1] = (box.max.x - ray.position.x)*t[8];
+    t[2] = (box.min.y - ray.position.y)*t[9];
+    t[3] = (box.max.y - ray.position.y)*t[9];
+    t[4] = (box.min.z - ray.position.z)*t[10];
+    t[5] = (box.max.z - ray.position.z)*t[10];
+    t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
+    t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
+
+    collision.hit = !((t[7] < 0) || (t[6] > t[7]));
+    collision.distance = t[6];
+    collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
+
+    // Get box center point
+    collision.normal = Vector3Lerp(box.min, box.max, 0.5f);
+    // Get vector center point->hit point
+    collision.normal = Vector3Subtract(collision.point, collision.normal);
+    // Scale vector to unit cube
+    // NOTE: Use an additional .01 to fix numerical errors
+    collision.normal = Vector3Scale(collision.normal, 2.01f);
+    collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
+    // The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
+    // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
+    collision.normal.x = (float)((int)collision.normal.x);
+    collision.normal.y = (float)((int)collision.normal.y);
+    collision.normal.z = (float)((int)collision.normal.z);
+
+    collision.normal = Vector3Normalize(collision.normal);
+
+    if (insideBox)
+    {
+        // Reset ray.direction
+        ray.direction = Vector3Negate(ray.direction);
+        // Fix result
+        collision.distance *= -1.0f;
+        collision.normal = Vector3Negate(collision.normal);
+    }
+
+    return collision;
+}
+
+// Get collision info between ray and mesh
+RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
+{
+    RayCollision collision = { 0 };
+
+    // Check if mesh vertex data on CPU for testing
+    if (mesh.vertices != NULL)
+    {
+        int triangleCount = mesh.triangleCount;
+
+        // Test against all triangles in mesh
+        for (int i = 0; i < triangleCount; i++)
+        {
+            Vector3 a = { 0 };
+            Vector3 b = { 0 };
+            Vector3 c = { 0 };
+            Vector3 *vertdata = (Vector3 *)mesh.vertices;
+
+            if (mesh.indices)
+            {
+                a = vertdata[mesh.indices[i*3 + 0]];
+                b = vertdata[mesh.indices[i*3 + 1]];
+                c = vertdata[mesh.indices[i*3 + 2]];
+            }
+            else
+            {
+                a = vertdata[i*3 + 0];
+                b = vertdata[i*3 + 1];
+                c = vertdata[i*3 + 2];
+            }
+
+            a = Vector3Transform(a, transform);
+            b = Vector3Transform(b, transform);
+            c = Vector3Transform(c, transform);
+
+            RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c);
+
+            if (triHitInfo.hit)
+            {
+                // Save the closest hit triangle
+                if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo;
+            }
+        }
+    }
+
+    return collision;
+}
+
+// Get collision info between ray and triangle
+// NOTE: The points are expected to be in counter-clockwise winding
+// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
+RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
+{
+    #define EPSILON 0.000001f        // A small number
+
+    RayCollision collision = { 0 };
+    Vector3 edge1 = { 0 };
+    Vector3 edge2 = { 0 };
+    Vector3 p = { 0 };
+    Vector3 q = { 0 };
+    Vector3 tv = { 0 };
+    float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f;
+
+    // Find vectors for two edges sharing V1
+    edge1 = Vector3Subtract(p2, p1);
+    edge2 = Vector3Subtract(p3, p1);
+
+    // Begin calculating determinant - also used to calculate u parameter
+    p = Vector3CrossProduct(ray.direction, edge2);
+
+    // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
+    det = Vector3DotProduct(edge1, p);
+
+    // Avoid culling!
+    if ((det > -EPSILON) && (det < EPSILON)) return collision;
+
+    invDet = 1.0f/det;
+
+    // Calculate distance from V1 to ray origin
+    tv = Vector3Subtract(ray.position, p1);
+
+    // Calculate u parameter and test bound
+    u = Vector3DotProduct(tv, p)*invDet;
+
+    // The intersection lies outside the triangle
+    if ((u < 0.0f) || (u > 1.0f)) return collision;
+
+    // Prepare to test v parameter
+    q = Vector3CrossProduct(tv, edge1);
+
+    // Calculate V parameter and test bound
+    v = Vector3DotProduct(ray.direction, q)*invDet;
+
+    // The intersection lies outside the triangle
+    if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
+
+    t = Vector3DotProduct(edge2, q)*invDet;
+
+    if (t > EPSILON)
+    {
+        // Ray hit, get hit point and normal
+        collision.hit = true;
+        collision.distance = t;
+        collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
+        collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
+    }
+
+    return collision;
+}
+
+// Get collision info between ray and quad
+// NOTE: The points are expected to be in counter-clockwise winding
+RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
+{
+    RayCollision collision = { 0 };
+
+    collision = GetRayCollisionTriangle(ray, p1, p2, p4);
+
+    if (!collision.hit) collision = GetRayCollisionTriangle(ray, p2, p3, p4);
+
+    return collision;
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+#if SUPPORT_FILEFORMAT_IQM || SUPPORT_FILEFORMAT_GLTF
+// Build pose from parent joints
+// NOTE: Required for animations loading (required by IQM and GLTF)
+static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms)
+{
+    for (int i = 0; i < boneCount; i++)
+    {
+        if (bones[i].parent >= 0)
+        {
+            if (bones[i].parent > i)
+            {
+                TRACELOG(LOG_WARNING, "Skipping bone not topologically sorted: Bone %d has parent %d", i, bones[i].parent);
+                continue;
+            }
+            transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation);
+            transforms[i].scale = Vector3Multiply(transforms[i].scale, transforms[bones[i].parent].scale);
+            transforms[i].translation = Vector3Multiply(transforms[i].translation, transforms[bones[i].parent].scale);
+            transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation);
+            transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation);
+        }
+    }
+}
+#endif
+
+#if SUPPORT_FILEFORMAT_OBJ
+// Load OBJ mesh data
+// Notes to keep in mind:
+//  - A mesh is created for every material present in the obj file
+//  - The model.meshCount is therefore the materialCount returned from tinyobj
+//  - The mesh is automatically triangulated by tinyobj
+static Model LoadOBJ(const char *fileName)
+{
+    tinyobj_attrib_t objAttributes = { 0 };
+    tinyobj_shape_t *objShapes = NULL;
+    unsigned int objShapeCount = 0;
+
+    tinyobj_material_t *objMaterials = NULL;
+    unsigned int objMaterialCount = 0;
+
+    Model model = { 0 };
+    model.transform = MatrixIdentity();
+
+    char *fileText = LoadFileText(fileName);
+
+    if (fileText == NULL)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] Unable to read obj file", fileName);
+        return model;
+    }
+
+    char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
+    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);
+
+    unsigned int dataSize = (unsigned int)strlen(fileText);
+
+    unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
+    int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags);
+
+    if (ret != TINYOBJ_SUCCESS)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: Unable to read obj data %s", fileName);
+        return model;
+    }
+
+    UnloadFileText(fileText);
+
+    unsigned int faceVertIndex = 0;
+    unsigned int nextShape = 1;
+    int lastMaterial = -1;
+    unsigned int meshIndex = 0;
+
+    // Count meshes
+    unsigned int nextShapeEnd = objAttributes.num_face_num_verts;
+
+    // See how many verts till the next shape
+    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
+
+    // Walk all the faces
+    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+    {
+        if (faceId >= nextShapeEnd)
+        {
+            // Try to find the last vert in the next shape
+            nextShape++;
+            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+            else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces
+            meshIndex++;
+        }
+        else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial))
+        {
+            meshIndex++; // If this is a new material, a new mesh is allocated
+        }
+
+        lastMaterial = objAttributes.material_ids[faceId];
+        faceVertIndex += objAttributes.face_num_verts[faceId];
+    }
+
+    // Allocate the base meshes and materials
+    model.meshCount = meshIndex + 1;
+    model.meshes = (Mesh *)MemAlloc(sizeof(Mesh)*model.meshCount);
+
+    if (objMaterialCount > 0)
+    {
+        model.materialCount = objMaterialCount;
+        model.materials = (Material *)MemAlloc(sizeof(Material)*objMaterialCount);
+    }
+    else // Allocate at least one material
+    {
+        model.materialCount = 1;
+        model.materials = (Material *)MemAlloc(sizeof(Material)*1);
+    }
+
+    model.meshMaterial = (int *)MemAlloc(sizeof(int)*model.meshCount);
+
+    // See how many verts are in each mesh
+    unsigned int *localMeshVertexCounts = (unsigned int *)MemAlloc(sizeof(unsigned int)*model.meshCount);
+
+    faceVertIndex = 0;
+    nextShapeEnd = objAttributes.num_face_num_verts;
+    lastMaterial = -1;
+    meshIndex = 0;
+    unsigned int localMeshVertexCount = 0;
+
+    nextShape = 1;
+    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
+
+    // Walk all the faces
+    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+    {
+        bool newMesh = false; // Is a new mesh required?
+        if (faceId >= nextShapeEnd)
+        {
+            // Try to find the last vert in the next shape
+            nextShape++;
+            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+            else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
+
+            newMesh = true;
+        }
+        else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial))
+        {
+            newMesh = true;
+        }
+
+        lastMaterial = objAttributes.material_ids[faceId];
+
+        if (newMesh)
+        {
+            localMeshVertexCounts[meshIndex] = localMeshVertexCount;
+
+            localMeshVertexCount = 0;
+            meshIndex++;
+        }
+
+        faceVertIndex += objAttributes.face_num_verts[faceId];
+        localMeshVertexCount += objAttributes.face_num_verts[faceId];
+    }
+
+    localMeshVertexCounts[meshIndex] = localMeshVertexCount;
+
+    for (int i = 0; i < model.meshCount; i++)
+    {
+        // Allocate the buffers for each mesh
+        unsigned int vertexCount = localMeshVertexCounts[i];
+
+        model.meshes[i].vertexCount = vertexCount;
+        model.meshes[i].triangleCount = vertexCount/3;
+
+        model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3);
+        model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3);
+    #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+        model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
+        model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4);
+    #else
+        if (objAttributes.texcoords != NULL && objAttributes.num_texcoords > 0)
+            model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
+        else model.meshes[i].texcoords = NULL;
+        model.meshes[i].colors = NULL;
+    #endif
+    }
+
+    MemFree(localMeshVertexCounts);
+    localMeshVertexCounts = NULL;
+
+    // Fill meshes
+    faceVertIndex = 0;
+
+    nextShapeEnd = objAttributes.num_face_num_verts;
+
+    // See how many verts till the next shape
+    nextShape = 1;
+    if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
+    lastMaterial = -1;
+    meshIndex = 0;
+    localMeshVertexCount = 0;
+
+    // Walk all the faces
+    for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+    {
+        bool newMesh = false; // Is a new mesh required?
+        if (faceId >= nextShapeEnd)
+        {
+            // Try to find the last vert in the next shape
+            nextShape++;
+            if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+            else nextShapeEnd = objAttributes.num_face_num_verts; // This is actually the total number of face verts in the file, not faces
+            newMesh = true;
+        }
+
+        // If this is a new material, a new mesh is allocated
+        if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;
+        lastMaterial = objAttributes.material_ids[faceId];
+
+        if (newMesh)
+        {
+            localMeshVertexCount = 0;
+            meshIndex++;
+        }
+
+        int matId = 0;
+        if ((lastMaterial >= 0) && (lastMaterial < (int)objMaterialCount)) matId = lastMaterial;
+
+        model.meshMaterial[meshIndex] = matId;
+
+        for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++)
+        {
+            int vertIndex = objAttributes.faces[faceVertIndex].v_idx;
+            int normalIndex = objAttributes.faces[faceVertIndex].vn_idx;
+            int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx;
+
+            for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i];
+
+            if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0) && (model.meshes[meshIndex].texcoords))
+            {
+                for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
+                model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
+            }
+
+            if ((objAttributes.normals != NULL) && (normalIndex != TINYOBJ_INVALID_INDEX) && (normalIndex >= 0))
+            {
+                for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i];
+            }
+            else
+            {
+                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 0] = 0.0f;
+                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 1] = 1.0f;
+                model.meshes[meshIndex].normals[localMeshVertexCount*3 + 2] = 0.0f;
+            }
+        #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+            for (int i = 0; i < 4; i++) model.meshes[meshIndex].colors[localMeshVertexCount*4 + i] = 255;
+        #endif
+            faceVertIndex++;
+            localMeshVertexCount++;
+        }
+    }
+
+    if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount);
+    else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
+
+    tinyobj_attrib_free(&objAttributes);
+    tinyobj_shapes_free(objShapes, objShapeCount);
+    tinyobj_materials_free(objMaterials, objMaterialCount);
+
+    // Restore current working directory
+    if (CHDIR(currentDir) != 0)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
+    }
+
+    return model;
+}
+#endif
+
+#if SUPPORT_FILEFORMAT_IQM
+// Load IQM mesh data
+static Model LoadIQM(const char *fileName)
+{
+    #define IQM_MAGIC        "INTERQUAKEMODEL"  // IQM file magic number
+    #define IQM_VERSION              2          // Only IQM version 2 supported
+
+    #define BONE_NAME_LENGTH        32          // BoneInfo name string length
+    #define MESH_NAME_LENGTH        32          // Mesh name string length
+    #define MATERIAL_NAME_LENGTH    32          // Material name string length
+
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+    unsigned char *fileDataPtr = fileData;
+
+    // IQM file structs
+    //-----------------------------------------------------------------------------------
+    typedef struct IQMHeader {
+        char magic[16];
+        unsigned int version;
+        unsigned int dataSize;
+        unsigned int flags;
+        unsigned int num_text, ofs_text;
+        unsigned int num_meshes, ofs_meshes;
+        unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
+        unsigned int num_triangles, ofs_triangles, ofs_adjacency;
+        unsigned int num_joints, ofs_joints;
+        unsigned int num_poses, ofs_poses;
+        unsigned int num_anims, ofs_anims;
+        unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
+        unsigned int num_comment, ofs_comment;
+        unsigned int num_extensions, ofs_extensions;
+    } IQMHeader;
+
+    typedef struct IQMMesh {
+        unsigned int name;
+        unsigned int material;
+        unsigned int first_vertex, num_vertexes;
+        unsigned int first_triangle, num_triangles;
+    } IQMMesh;
+
+    typedef struct IQMTriangle {
+        unsigned int vertex[3];
+    } IQMTriangle;
+
+    typedef struct IQMJoint {
+        unsigned int name;
+        int parent;
+        float translate[3], rotate[4], scale[3];
+    } IQMJoint;
+
+    typedef struct IQMVertexArray {
+        unsigned int type;
+        unsigned int flags;
+        unsigned int format;
+        unsigned int size;
+        unsigned int offset;
+    } IQMVertexArray;
+
+    // NOTE: Below IQM structures are not used but listed for reference
+    /*
+    typedef struct IQMAdjacency {
+        unsigned int triangle[3];
+    } IQMAdjacency;
+
+    typedef struct IQMPose {
+        int parent;
+        unsigned int mask;
+        float channeloffset[10];
+        float channelscale[10];
+    } IQMPose;
+
+    typedef struct IQMAnim {
+        unsigned int name;
+        unsigned int first_frame, num_frames;
+        float framerate;
+        unsigned int flags;
+    } IQMAnim;
+
+    typedef struct IQMBounds {
+        float bbmin[3], bbmax[3];
+        float xyradius, radius;
+    } IQMBounds;
+    */
+    //-----------------------------------------------------------------------------------
+
+    // IQM vertex data types
+    enum {
+        IQM_POSITION     = 0,
+        IQM_TEXCOORD     = 1,
+        IQM_NORMAL       = 2,
+        IQM_TANGENT      = 3,       // NOTE: Tangents unused by default
+        IQM_BLENDINDEXES = 4,
+        IQM_BLENDWEIGHTS = 5,
+        IQM_COLOR        = 6,
+        IQM_CUSTOM       = 0x10     // NOTE: Custom vertex values unused by default
+    };
+
+    Model model = { 0 };
+
+    IQMMesh *imesh = NULL;
+    IQMTriangle *tri = NULL;
+    IQMVertexArray *va = NULL;
+    IQMJoint *ijoint = NULL;
+
+    float *vertex = NULL;
+    float *normal = NULL;
+    float *text = NULL;
+    char *blendi = NULL;
+    unsigned char *blendw = NULL;
+    unsigned char *color = NULL;
+
+    // In case file can not be read, return an empty model
+    if (fileDataPtr == NULL) return model;
+
+    const char *basePath = GetDirectoryPath(fileName);
+
+    // Read IQM header
+    IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
+
+    if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
+        UnloadFileData(fileData);
+        return model;
+    }
+
+    if (iqmHeader->version != IQM_VERSION)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
+        UnloadFileData(fileData);
+        return model;
+    }
+
+    //fileDataPtr += sizeof(IQMHeader);       // Move file data pointer
+
+    // Meshes data processing
+    imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
+    //fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
+    //fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
+    memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
+
+    model.meshCount = iqmHeader->num_meshes;
+    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+
+    model.materialCount = model.meshCount;
+    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+
+    char name[MESH_NAME_LENGTH] = { 0 };
+    char material[MATERIAL_NAME_LENGTH] = { 0 };
+
+    for (int i = 0; i < model.meshCount; i++)
+    {
+        //fseek(iqmFile, iqmHeader->ofs_text + imesh[a].name, SEEK_SET);
+        //fread(name, sizeof(char), MESH_NAME_LENGTH, iqmFile);
+        memcpy(name, fileDataPtr + iqmHeader->ofs_text + imesh[i].name, MESH_NAME_LENGTH*sizeof(char));
+
+        //fseek(iqmFile, iqmHeader->ofs_text + imesh[a].material, SEEK_SET);
+        //fread(material, sizeof(char), MATERIAL_NAME_LENGTH, iqmFile);
+        memcpy(material, fileDataPtr + iqmHeader->ofs_text + imesh[i].material, MATERIAL_NAME_LENGTH*sizeof(char));
+
+        model.materials[i] = LoadMaterialDefault();
+        model.materials[i].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture(TextFormat("%s/%s", basePath, material));
+
+        model.meshMaterial[i] = i;
+
+        TRACELOG(LOG_DEBUG, "MODEL: [%s] mesh name (%s), material (%s)", fileName, name, material);
+
+        model.meshes[i].vertexCount = imesh[i].num_vertexes;
+
+        model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));       // Default vertex positions
+        model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));        // Default vertex normals
+        model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));      // Default vertex texcoords
+
+        model.meshes[i].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char));  // Up-to 4 bones supported!
+        model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float));      // Up-to 4 bones supported!
+
+        model.meshes[i].triangleCount = imesh[i].num_triangles;
+        model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
+
+#if !SUPPORT_GPU_SKINNING
+        // Animated vertex data, processed for rendering
+        // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
+        model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
+        model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
+#endif
+    }
+
+    // Triangles data processing
+    tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
+    //fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
+    //fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
+    memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
+
+    for (int m = 0; m < model.meshCount; m++)
+    {
+        int tcounter = 0;
+
+        for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
+        {
+            // IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
+            // expecting they point to the counter-clockwise vertex triangle, so triangle indexes need to be reversed
+            // NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
+            model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
+            model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
+            model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
+            tcounter += 3;
+        }
+    }
+
+    // Vertex arrays data processing
+    va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
+    //fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
+    //fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
+    memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
+
+    for (unsigned int i = 0; i < iqmHeader->num_vertexarrays; i++)
+    {
+        switch (va[i].type)
+        {
+            case IQM_POSITION:
+            {
+                vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
+                memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    int vCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
+                    {
+                        model.meshes[m].vertices[vCounter] = vertex[i];
+                        if (model.meshes[m].animVertices != NULL) model.meshes[m].animVertices[vCounter] = vertex[i];
+                        vCounter++;
+                    }
+                }
+            } break;
+            case IQM_NORMAL:
+            {
+                normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
+                memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    int vCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
+                    {
+                        model.meshes[m].normals[vCounter] = normal[i];
+                        if (model.meshes[m].animNormals != NULL) model.meshes[m].animNormals[vCounter] = normal[i];
+                        vCounter++;
+                    }
+                }
+            } break;
+            case IQM_TEXCOORD:
+            {
+                text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
+                memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    int vCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
+                    {
+                        model.meshes[m].texcoords[vCounter] = text[i];
+                        vCounter++;
+                    }
+                }
+            } break;
+            case IQM_BLENDINDEXES:
+            {
+                blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
+                memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    int boneCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
+                    {
+                        model.meshes[m].boneIndices[boneCounter] = blendi[i];
+                        boneCounter++;
+                    }
+                }
+            } break;
+            case IQM_BLENDWEIGHTS:
+            {
+                blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
+                memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    int boneCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
+                    {
+                        model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
+                        boneCounter++;
+                    }
+                }
+            } break;
+            case IQM_COLOR:
+            {
+                color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
+                //fseek(iqmFile, va[a].offset, SEEK_SET);
+                //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
+                memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
+
+                for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
+                {
+                    model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
+
+                    int vCounter = 0;
+                    for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
+                    {
+                        model.meshes[m].colors[vCounter] = color[i];
+                        vCounter++;
+                    }
+                }
+            } break;
+        }
+    }
+
+    // Bones (joints) data processing
+    ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
+    //fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
+    //fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
+    memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
+
+    model.skeleton.boneCount = iqmHeader->num_joints;
+    model.skeleton.bones = (BoneInfo *)RL_CALLOC(iqmHeader->num_joints, sizeof(BoneInfo));
+    model.skeleton.bindPose = (Transform *)RL_CALLOC(iqmHeader->num_joints, sizeof(Transform));
+
+    for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
+    {
+        // Bones
+        model.skeleton.bones[i].parent = ijoint[i].parent;
+        //fseek(iqmFile, iqmHeader->ofs_text + ijoint[a].name, SEEK_SET);
+        //fread(model.bones[a].name, sizeof(char), BONE_NAME_LENGTH, iqmFile);
+        memcpy(model.skeleton.bones[i].name, fileDataPtr + iqmHeader->ofs_text + ijoint[i].name, BONE_NAME_LENGTH*sizeof(char));
+
+        // Bind pose (base pose)
+        model.skeleton.bindPose[i].translation.x = ijoint[i].translate[0];
+        model.skeleton.bindPose[i].translation.y = ijoint[i].translate[1];
+        model.skeleton.bindPose[i].translation.z = ijoint[i].translate[2];
+
+        model.skeleton.bindPose[i].rotation.x = ijoint[i].rotate[0];
+        model.skeleton.bindPose[i].rotation.y = ijoint[i].rotate[1];
+        model.skeleton.bindPose[i].rotation.z = ijoint[i].rotate[2];
+        model.skeleton.bindPose[i].rotation.w = ijoint[i].rotate[3];
+
+        model.skeleton.bindPose[i].scale.x = ijoint[i].scale[0];
+        model.skeleton.bindPose[i].scale.y = ijoint[i].scale[1];
+        model.skeleton.bindPose[i].scale.z = ijoint[i].scale[2];
+    }
+
+    BuildPoseFromParentJoints(model.skeleton.bones, model.skeleton.boneCount, model.skeleton.bindPose);
+
+    // 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 (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
+
+    UnloadFileData(fileData);
+
+    RL_FREE(imesh);
+    RL_FREE(tri);
+    RL_FREE(va);
+    RL_FREE(vertex);
+    RL_FREE(normal);
+    RL_FREE(text);
+    RL_FREE(blendi);
+    RL_FREE(blendw);
+    RL_FREE(ijoint);
+    RL_FREE(color);
+
+    return model;
+}
+
+// Load IQM animation data
+static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCount)
+{
+    #define IQM_MAGIC       "INTERQUAKEMODEL"   // IQM file magic number
+    #define IQM_VERSION     2                   // only IQM version 2 supported
+
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+    unsigned char *fileDataPtr = fileData;
+
+    typedef struct IQMHeader {
+        char magic[16];
+        unsigned int version;
+        unsigned int dataSize;
+        unsigned int flags;
+        unsigned int num_text, ofs_text;
+        unsigned int num_meshes, ofs_meshes;
+        unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
+        unsigned int num_triangles, ofs_triangles, ofs_adjacency;
+        unsigned int num_joints, ofs_joints;
+        unsigned int num_poses, ofs_poses;
+        unsigned int num_anims, ofs_anims;
+        unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
+        unsigned int num_comment, ofs_comment;
+        unsigned int num_extensions, ofs_extensions;
+    } IQMHeader;
+
+    typedef struct IQMJoint {
+        unsigned int name;
+        int parent;
+        float translate[3], rotate[4], scale[3];
+    } IQMJoint;
+
+    typedef struct IQMPose {
+        int parent;
+        unsigned int mask;
+        float channeloffset[10];
+        float channelscale[10];
+    } IQMPose;
+
+    typedef struct IQMAnim {
+        unsigned int name;
+        unsigned int first_frame, num_frames;
+        float framerate;
+        unsigned int flags;
+    } IQMAnim;
+
+    // In case file can not be read, return an empty model
+    if (fileDataPtr == NULL) return NULL;
+
+    // Read IQM header
+    IQMHeader *iqmHeader = (IQMHeader *)fileDataPtr;
+
+    if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
+        UnloadFileData(fileData);
+        return NULL;
+    }
+
+    if (iqmHeader->version != IQM_VERSION)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version);
+        UnloadFileData(fileData);
+        return NULL;
+    }
+
+    // Get bones data
+    IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
+    //fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
+    //fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
+    memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
+
+    // Get animations data
+    *animCount = iqmHeader->num_anims;
+    IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
+    //fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
+    //fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
+    memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
+
+    ModelAnimation *animations = (ModelAnimation *)RL_CALLOC(iqmHeader->num_anims, sizeof(ModelAnimation));
+
+    // frameposes
+    unsigned short *framedata = (unsigned short *)RL_CALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels, sizeof(unsigned short));
+    //fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
+    //fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
+    memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
+
+    // joints
+    IQMJoint *joints = (IQMJoint *)RL_CALLOC(iqmHeader->num_joints, sizeof(IQMJoint));
+    memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
+
+    for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
+    {
+        animations[a].boneCount = iqmHeader->num_poses;
+        BoneInfo *bones = (BoneInfo *)RL_CALLOC(iqmHeader->num_poses, sizeof(BoneInfo));
+
+        animations[a].keyframeCount = anim[a].num_frames;
+        animations[a].keyframePoses = (Transform **)RL_CALLOC(anim[a].num_frames, sizeof(Transform *));
+        memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32);
+        // TODO: Use animation framerate data?
+        //animations[a].framerate = anim.framerate;
+
+        TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Framerate: %f", fileName, animations[a].name, animations[a].keyframeCount, anim[a].framerate);
+
+        for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
+        {
+            bones[j].parent = poses[j].parent;
+
+            // NOTE: No need to store bones names, bones only required to generate keyframe poses
+            //if (iqmHeader->num_joints > 0) memcpy(bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
+            //else memcpy(bones[j].name, "ANIMJOINTNAME", 13); // Default bone name otherwise
+        }
+
+        for (unsigned int j = 0; j < anim[a].num_frames; j++)
+            animations[a].keyframePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
+
+        int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
+
+        for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
+        {
+            for (unsigned int i = 0; i < iqmHeader->num_poses; i++)
+            {
+                animations[a].keyframePoses[frame][i].translation.x = poses[i].channeloffset[0];
+
+                if (poses[i].mask & 0x01)
+                {
+                    animations[a].keyframePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].translation.y = poses[i].channeloffset[1];
+
+                if (poses[i].mask & 0x02)
+                {
+                    animations[a].keyframePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].translation.z = poses[i].channeloffset[2];
+
+                if (poses[i].mask & 0x04)
+                {
+                    animations[a].keyframePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].rotation.x = poses[i].channeloffset[3];
+
+                if (poses[i].mask & 0x08)
+                {
+                    animations[a].keyframePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].rotation.y = poses[i].channeloffset[4];
+
+                if (poses[i].mask & 0x10)
+                {
+                    animations[a].keyframePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].rotation.z = poses[i].channeloffset[5];
+
+                if (poses[i].mask & 0x20)
+                {
+                    animations[a].keyframePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].rotation.w = poses[i].channeloffset[6];
+
+                if (poses[i].mask & 0x40)
+                {
+                    animations[a].keyframePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].scale.x = poses[i].channeloffset[7];
+
+                if (poses[i].mask & 0x80)
+                {
+                    animations[a].keyframePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].scale.y = poses[i].channeloffset[8];
+
+                if (poses[i].mask & 0x100)
+                {
+                    animations[a].keyframePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].scale.z = poses[i].channeloffset[9];
+
+                if (poses[i].mask & 0x200)
+                {
+                    animations[a].keyframePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
+                    dcounter++;
+                }
+
+                animations[a].keyframePoses[frame][i].rotation = QuaternionNormalize(animations[a].keyframePoses[frame][i].rotation);
+            }
+        }
+
+        // Build frameposes
+        for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
+        {
+            for (unsigned int i = 0; i < animations[a].boneCount; i++)
+            {
+                if (bones[i].parent >= 0)
+                {
+                    animations[a].keyframePoses[frame][i].rotation = QuaternionMultiply(animations[a].keyframePoses[frame][bones[i].parent].rotation, animations[a].keyframePoses[frame][i].rotation);
+                    animations[a].keyframePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].keyframePoses[frame][i].translation, animations[a].keyframePoses[frame][bones[i].parent].rotation);
+                    animations[a].keyframePoses[frame][i].translation = Vector3Add(animations[a].keyframePoses[frame][i].translation, animations[a].keyframePoses[frame][bones[i].parent].translation);
+                    animations[a].keyframePoses[frame][i].scale = Vector3Multiply(animations[a].keyframePoses[frame][i].scale, animations[a].keyframePoses[frame][bones[i].parent].scale);
+                }
+            }
+        }
+
+        RL_FREE(bones);
+    }
+
+    UnloadFileData(fileData);
+
+    RL_FREE(joints);
+    RL_FREE(framedata);
+    RL_FREE(poses);
+    RL_FREE(anim);
+
+    return animations;
+}
+
+#endif
+
+#if SUPPORT_FILEFORMAT_GLTF
+// Load file data callback for cgltf
+static cgltf_result LoadFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, const char *path, cgltf_size *size, void **data)
+{
+    int filesize;
+    unsigned char *filedata = LoadFileData(path, &filesize);
+
+    if (filedata == NULL) return cgltf_result_io_error;
+
+    *size = filesize;
+    *data = filedata;
+
+    return cgltf_result_success;
+}
+
+// Release file data callback for cgltf
+static void ReleaseFileGLTFCallback(const struct cgltf_memory_options *memoryOptions, const struct cgltf_file_options *fileOptions, void *data, cgltf_size size)
+{
+    UnloadFileData((unsigned char *)data);
+}
+
+// Load image from different glTF provided methods (uri, path, buffer_view)
+static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPath)
+{
+    Image image = { 0 };
+
+    if (cgltfImage == NULL) return image;
+
+    if (cgltfImage->uri != NULL)     // Check if image data is provided as an uri (base64 or path)
+    {
+        if ((strlen(cgltfImage->uri) > 5) &&
+            (cgltfImage->uri[0] == 'd') &&
+            (cgltfImage->uri[1] == 'a') &&
+            (cgltfImage->uri[2] == 't') &&
+            (cgltfImage->uri[3] == 'a') &&
+            (cgltfImage->uri[4] == ':'))     // Check if image is provided as base64 text data
+        {
+            // Data URI Format: data:<mediatype>;base64,<data>
+
+            // Find the comma
+            int i = 0;
+            while ((cgltfImage->uri[i] != ',') && (cgltfImage->uri[i] != 0)) i++;
+
+            if (cgltfImage->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
+            else
+            {
+                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 >> 3;                         // Actual encoded bytes
+                void *data = NULL;
+
+                cgltf_options options = { 0 };
+                options.file.read = LoadFileGLTFCallback;
+                options.file.release = ReleaseFileGLTFCallback;
+                cgltf_result result = cgltf_load_buffer_base64(&options, outSize, cgltfImage->uri + i + 1, &data);
+
+                if (result == cgltf_result_success)
+                {
+                    image = LoadImageFromMemory(".png", (unsigned char *)data, outSize);
+                    RL_FREE(data);
+                }
+            }
+        }
+        else     // Check if image is provided as image path
+        {
+            image = LoadImage(TextFormat("%s/%s", texPath, cgltfImage->uri));
+        }
+    }
+    else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer
+    {
+        unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size);
+        int offset = (int)cgltfImage->buffer_view->offset;
+        int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
+
+        // Copy buffer data to memory for loading
+        for (unsigned int i = 0; i < cgltfImage->buffer_view->size; i++)
+        {
+            data[i] = ((unsigned char *)cgltfImage->buffer_view->buffer->data)[offset];
+            offset += stride;
+        }
+
+        // Check mime_type for image: (cgltfImage->mime_type == "image/png")
+        // NOTE: Detected that some models define mime_type as "image\\/png"
+        if ((strcmp(cgltfImage->mime_type, "image\\/png") == 0) || (strcmp(cgltfImage->mime_type, "image/png") == 0))
+        {
+            image = LoadImageFromMemory(".png", data, (int)cgltfImage->buffer_view->size);
+        }
+        else if ((strcmp(cgltfImage->mime_type, "image\\/jpeg") == 0) || (strcmp(cgltfImage->mime_type, "image/jpeg") == 0))
+        {
+            image = LoadImageFromMemory(".jpg", data, (int)cgltfImage->buffer_view->size);
+        }
+        else TRACELOG(LOG_WARNING, "MODEL: glTF image data MIME type not recognized", TextFormat("%s/%s", texPath, cgltfImage->uri));
+
+        RL_FREE(data);
+    }
+
+    return image;
+}
+
+// Load bone info from GLTF skin data
+static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount)
+{
+    *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++)
+    {
+        cgltf_node node = *skin.joints[i];
+        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
+        // DCC exporters), until we hit a node that is also in skin.joints.
+        int parentIndex = -1;
+        cgltf_node *ancestor = node.parent;
+        while (ancestor != NULL && parentIndex == -1)
+        {
+            for (unsigned int j = 0; j < skin.joints_count; j++)
+            {
+                if (skin.joints[j] == ancestor) { parentIndex = (int)j; break; }
+            }
+            if (parentIndex == -1) ancestor = ancestor->parent;
+        }
+
+        bones[i].parent = parentIndex;
+    }
+
+    return bones;
+}
+
+// Load glTF file into model struct, .gltf and .glb supported
+static Model LoadGLTF(const char *fileName)
+{
+    /*********************************************************************************************
+
+        Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
+        Transform handling implemented by Paul Melis (@paulmelis)
+        Reviewed by Ramon Santamaria (@raysan5)
+
+        FEATURES:
+          - Supports .gltf and .glb files
+          - Supports embedded (base64) or external textures
+          - Supports PBR metallic/roughness flow, loads material textures, values and colors
+                     PBR specular/glossiness flow and extended texture flows not supported
+          - Supports multiple meshes per model (every primitives is loaded as a separate mesh)
+          - Supports basic animations
+          - Transforms, including parent-child relations, are applied on the mesh data,
+            but the hierarchy is not kept (as it can't be represented)
+          - Mesh instances in the glTF file (a.e. same mesh linked from multiple nodes)
+            are turned into separate raylib Meshes
+
+        RESTRICTIONS:
+          - Only triangle meshes supported
+          - Vertex attribute types and formats supported:
+              > Vertices (position): vec3: float
+              > Normals: vec3: float
+              > Texcoords: vec2: float
+              > Colors: vec4: u8, u16, f32 (normalized)
+              > Indices: u16, u32 (truncated to u16)
+          - Scenes defined in the glTF file are ignored. All nodes in the file are used
+
+    ***********************************************************************************************/
+
+    // Macro to simplify attributes loading code
+    #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType)
+
+    #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
+    { \
+        int n = 0; \
+        srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
+        for (unsigned int k = 0; k < accesor->count; k++) \
+        {\
+            for (int l = 0; l < numComp; l++) \
+            {\
+                dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
+            }\
+            n += (int)(accesor->stride/sizeof(srcType));\
+        }\
+    }
+
+    Model model = { 0 };
+
+    // glTF file loading
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    if (fileData == NULL) return model;
+
+    // glTF data loading
+    cgltf_options options = { 0 };
+    options.file.read = LoadFileGLTFCallback;
+    options.file.release = ReleaseFileGLTFCallback;
+    cgltf_data *data = NULL;
+    cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
+
+    if (result == cgltf_result_success)
+    {
+        if (data->file_type == cgltf_file_type_glb) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glb) loaded successfully", fileName);
+        else if (data->file_type == cgltf_file_type_gltf) TRACELOG(LOG_INFO, "MODEL: [%s] Model basic data (glTF) loaded successfully", fileName);
+        else TRACELOG(LOG_WARNING, "MODEL: [%s] Model format not recognized", fileName);
+
+        TRACELOG(LOG_INFO, "    > Meshes count: %i", data->meshes_count);
+        TRACELOG(LOG_INFO, "    > Materials count: %i (+1 default)", data->materials_count);
+        TRACELOG(LOG_DEBUG, "    > Buffers count: %i", data->buffers_count);
+        TRACELOG(LOG_DEBUG, "    > Images count: %i", data->images_count);
+        TRACELOG(LOG_DEBUG, "    > Textures count: %i", data->textures_count);
+
+        // Force reading data buffers (fills buffer_view->buffer->data)
+        // NOTE: If an uri is defined to base64 data or external path, it's automatically loaded
+        result = cgltf_load_buffers(&options, data, fileName);
+        if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
+
+        int primitivesCount = 0;
+        bool dracoCompression = false;
+
+        // NOTE: Load every primitive in the glTF as a separate raylib Mesh
+        // Determine total number of meshes needed from the node hierarchy
+        for (unsigned int i = 0; i < data->nodes_count; i++)
+        {
+            cgltf_node *node = &(data->nodes[i]);
+            cgltf_mesh *mesh = node->mesh;
+            if (!mesh) continue;
+
+            for (unsigned int p = 0; p < mesh->primitives_count; p++)
+            {
+                if (mesh->primitives[p].has_draco_mesh_compression)
+                {
+                    dracoCompression = true;
+                    TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load mesh data, Draco compression not supported", fileName);
+                    break;
+                }
+                else if (mesh->primitives[p].type == cgltf_primitive_type_triangles) primitivesCount++;
+            }
+        }
+
+        if (dracoCompression)
+        {
+            TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
+            cgltf_free(data);
+            UnloadFileData(fileData);
+            return model;
+        }
+
+        TRACELOG(LOG_DEBUG, "    > Primitives (triangles only) count based on hierarchy : %i", primitivesCount);
+
+        // Load our model data: meshes and materials
+        model.meshCount = primitivesCount;
+        model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+
+        // NOTE: Keep an extra slot for default material, in case some mesh requires it
+        model.materialCount = (int)data->materials_count + 1;
+        model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+        model.materials[0] = LoadMaterialDefault();     // Load default material (index: 0)
+
+        // Load mesh-material indices, by default all meshes are mapped to material index: 0
+        model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+
+        // Load materials data
+        //----------------------------------------------------------------------------------------------------
+        for (unsigned int i = 0, j = 1; i < data->materials_count; i++, j++)
+        {
+            model.materials[j] = LoadMaterialDefault();
+            const char *texPath = GetDirectoryPath(fileName);
+
+            // Check glTF material flow: PBR metallic/roughness flow
+            // NOTE: Alternatively, materials can follow PBR specular/glossiness flow
+            if (data->materials[i].has_pbr_metallic_roughness)
+            {
+                // Load base color texture (albedo)
+                if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
+                {
+                    Image imAlbedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath);
+                    if (imAlbedo.data != NULL)
+                    {
+                        model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo);
+                        UnloadImage(imAlbedo);
+                    }
+                }
+                // Load base color factor (tint)
+                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
+                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
+                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
+                model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
+
+                // Load metallic/roughness texture
+                if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
+                {
+                    Image imMetallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath);
+                    if (imMetallicRoughness.data != NULL)
+                    {
+                        Image imMetallic = { 0 };
+                        Image imRoughness = { 0 };
+
+                        imMetallic.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height);
+                        imRoughness.data = RL_MALLOC(imMetallicRoughness.width*imMetallicRoughness.height);
+
+                        imMetallic.width = imRoughness.width = imMetallicRoughness.width;
+                        imMetallic.height = imRoughness.height = imMetallicRoughness.height;
+
+                        imMetallic.format = imRoughness.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+                        imMetallic.mipmaps = imRoughness.mipmaps = 1;
+
+                        for (int x = 0; x < imRoughness.width; x++)
+                        {
+                            for (int y = 0; y < imRoughness.height; y++)
+                            {
+                                Color color = GetImageColor(imMetallicRoughness, x, y);
+
+                                ((unsigned char *)imRoughness.data)[y*imRoughness.width + x] = color.g; // Roughness color channel
+                                ((unsigned char *)imMetallic.data)[y*imMetallic.width + x] = color.b; // Metallic color channel
+                            }
+                        }
+
+                        model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(imRoughness);
+                        model.materials[j].maps[MATERIAL_MAP_METALNESS].texture = LoadTextureFromImage(imMetallic);
+
+                        UnloadImage(imRoughness);
+                        UnloadImage(imMetallic);
+                        UnloadImage(imMetallicRoughness);
+                    }
+
+                    // Load metallic/roughness material properties
+                    float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
+                    model.materials[j].maps[MATERIAL_MAP_ROUGHNESS].value = roughness;
+
+                    float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
+                    model.materials[j].maps[MATERIAL_MAP_METALNESS].value = metallic;
+                }
+
+                // Load normal texture
+                if (data->materials[i].normal_texture.texture)
+                {
+                    Image imNormal = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath);
+                    if (imNormal.data != NULL)
+                    {
+                        model.materials[j].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(imNormal);
+                        UnloadImage(imNormal);
+                    }
+                }
+
+                // Load ambient occlusion texture
+                if (data->materials[i].occlusion_texture.texture)
+                {
+                    Image imOcclusion = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath);
+                    if (imOcclusion.data != NULL)
+                    {
+                        model.materials[j].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(imOcclusion);
+                        UnloadImage(imOcclusion);
+                    }
+                }
+
+                // Load emissive texture
+                if (data->materials[i].emissive_texture.texture)
+                {
+                    Image imEmissive = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath);
+                    if (imEmissive.data != NULL)
+                    {
+                        model.materials[j].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(imEmissive);
+                        UnloadImage(imEmissive);
+                    }
+
+                    // Load emissive color factor
+                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
+                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
+                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
+                    model.materials[j].maps[MATERIAL_MAP_EMISSION].color.a = 255;
+                }
+            }
+
+            // Other possible materials not supported by raylib pipeline:
+            // has_clearcoat, has_transmission, has_volume, has_ior, has specular, has_sheen
+        }
+        //----------------------------------------------------------------------------------------------------
+
+        // Load meshes data
+        //
+        // NOTE: Visit each node in the hierarchy and process any mesh linked from it
+        //  - Each primitive within a glTF node becomes a raylib Mesh
+        //  - The local-to-world transform of each node is used to transform the points/normals/tangents of the created Mesh(es)
+        //  - Any glTF mesh linked from more than one Node (a.e. instancing) is turned into multiple Mesh's, as each Node will have its own transform applied
+        //
+        // WARNING: The code below disregards the scenes defined in the file, all nodes are used
+        //----------------------------------------------------------------------------------------------------
+        int meshIndex = 0;
+        for (unsigned int i = 0; i < data->nodes_count; i++)
+        {
+            cgltf_node *node = &(data->nodes[i]);
+
+            cgltf_mesh *mesh = node->mesh;
+            if (!mesh) continue;
+
+            cgltf_float worldTransform[16];
+            cgltf_node_transform_world(node, worldTransform);
+
+            Matrix worldMatrix = {
+                worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
+                worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
+                worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
+                worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
+            };
+
+            Matrix worldMatrixNormals = MatrixTranspose(MatrixInvert(worldMatrix));
+
+            for (unsigned int p = 0; p < mesh->primitives_count; p++)
+            {
+                // NOTE: Only support primitives defined by triangles
+                // Other alternatives: points, lines, line_strip, triangle_strip
+                if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
+
+                // NOTE: Attributes data could be provided in several data formats (8, 8u, 16u, 32...),
+                // Only some formats for each attribute type are supported, read info at the top of this function!
+
+                for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
+                {
+                    // Check the different attributes for every primitive
+                    if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_position)      // POSITION, vec3, float
+                    {
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        // WARNING: SPECS: POSITION accessor MUST have its min and max properties defined
+
+                        if (model.meshes[meshIndex].vertices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data already loaded", fileName);
+                        else
+                        {
+                            if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
+                            {
+                                // Init raylib mesh vertices to copy glTF attribute data
+                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
+                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load 3 components of float data type into mesh.vertices
+                                LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
+
+                                // Transform the vertices
+                                float *vertices = model.meshes[meshIndex].vertices;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k+1], vertices[3*k+2] }, worldMatrix);
+                                    vertices[3*k] = vt.x;
+                                    vertices[3*k+1] = vt.y;
+                                    vertices[3*k+2] = vt.z;
+                                }
+                            }
+                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16u))
+                            {
+                                // Init raylib mesh vertices to copy glTF attribute data
+                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
+                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
+                                LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
+
+                                // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
+                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
+
+                                RL_FREE(temp);
+
+                                // Transform the vertices
+                                float *vertices = model.meshes[meshIndex].vertices;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
+                                    vertices[3*k] = vt.x;
+                                    vertices[3*k + 1] = vt.y;
+                                    vertices[3*k + 2] = vt.z;
+                                }
+                            }
+                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
+                            {
+                                // Init raylib mesh vertices to copy glTF attribute data
+                                model.meshes[meshIndex].vertexCount = (int)attribute->count;
+                                model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
+                                LOAD_ATTRIBUTE(attribute, 3, short, temp);
+
+                                // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
+                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
+
+                                RL_FREE(temp);
+
+                                // Transform the vertices
+                                float *vertices = model.meshes[meshIndex].vertices;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
+                                    vertices[3*k] = vt.x;
+                                    vertices[3*k + 1] = vt.y;
+                                    vertices[3*k + 2] = vt.z;
+                                }
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName);
+                        }
+                    }
+                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_normal) // NORMAL, vec3, float
+                    {
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        if (model.meshes[meshIndex].normals != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data already loaded", fileName);
+                        else
+                        {
+                            if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
+                            {
+                                // Init raylib mesh normals to copy glTF attribute data
+                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load 3 components of float data type into mesh.normals
+                                LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
+
+                                // Transform the normals
+                                float *normals = model.meshes[meshIndex].normals;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 nt = Vector3Transform((Vector3){ normals[3*k], normals[3*k+1], normals[3*k+2] }, worldMatrixNormals);
+                                    normals[3*k] = nt.x;
+                                    normals[3*k+1] = nt.y;
+                                    normals[3*k+2] = nt.z;
+                                }
+                            }
+                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
+                            {
+                                // Init raylib mesh normals to copy glTF attribute data
+                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
+                                LOAD_ATTRIBUTE(attribute, 3, short, temp);
+
+                                // Convert data to raylib normal data type (float)
+                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+                                RL_FREE(temp);
+
+                                // Transform the normals
+                                float *normals = model.meshes[meshIndex].normals;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+                                    normals[3*k] = nt.x;
+                                    normals[3*k + 1] = nt.y;
+                                    normals[3*k + 2] = nt.z;
+                                }
+                            }
+                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8u))
+                            {
+                                // Init raylib mesh normals to copy glTF attribute data
+                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
+                                LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
+
+                                // Convert data to raylib normal data type (float)
+                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+                                RL_FREE(temp);
+
+                                // Transform the normals
+                                float *normals = model.meshes[meshIndex].normals;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+                                    normals[3*k] = nt.x;
+                                    normals[3*k + 1] = nt.y;
+                                    normals[3*k + 2] = nt.z;
+                                }
+                            }
+                            else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8))
+                            {
+                                // Init raylib mesh normals to copy glTF attribute data
+                                model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                char *temp = (char *)RL_MALLOC(attribute->count*3*sizeof(char));
+                                LOAD_ATTRIBUTE(attribute, 3, char, temp);
+
+                                // Convert data to raylib normal data type (float)
+                                for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+                                RL_FREE(temp);
+
+                                // Transform the normals
+                                float *normals = model.meshes[meshIndex].normals;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+                                    normals[3*k] = nt.x;
+                                    normals[3*k + 1] = nt.y;
+                                    normals[3*k + 2] = nt.z;
+                                }
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data format not supported, use vec3 float", fileName);
+                        }
+                    }
+                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec4, float, w is tangent basis sign
+                    {
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        if (model.meshes[meshIndex].tangents != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Tangents attribute data already loaded", fileName);
+                        else
+                        {
+                            if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
+                            {
+                                // Init raylib mesh tangent to copy glTF attribute data
+                                model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
+
+                                // Load 4 components of float data type into mesh.tangents
+                                LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
+
+                                // Transform the tangents
+                                float *tangents = model.meshes[meshIndex].tangents;
+                                for (unsigned int k = 0; k < attribute->count; k++)
+                                {
+                                    Vector3 tt = Vector3Transform((Vector3){ tangents[4*k], tangents[4*k+1], tangents[4*k+2] }, worldMatrix);
+                                    tangents[4*k] = tt.x;
+                                    tangents[4*k+1] = tt.y;
+                                    tangents[4*k+2] = tt.z;
+                                }
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangents attribute data format not supported, use vec4 float", fileName);
+                        }
+                    }
+                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) // TEXCOORD_n, vec2, float/u8n/u16n
+                    {
+                        // Support up to 2 texture coordinates attributes
+                        float *texcoordPtr = NULL;
+
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        if (attribute->type == cgltf_type_vec2)
+                        {
+                            if (attribute->component_type == cgltf_component_type_r_32f) // vec2, float
+                            {
+                                // Init raylib mesh texcoords to copy glTF attribute data
+                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
+
+                                // Load 3 components of float data type into mesh.texcoords
+                                LOAD_ATTRIBUTE(attribute, 2, float, texcoordPtr)
+                            }
+                            else if (attribute->component_type == cgltf_component_type_r_8u) // vec2, u8n
+                            {
+                                // Init raylib mesh texcoords to copy glTF attribute data
+                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*2*sizeof(unsigned char));
+                                LOAD_ATTRIBUTE(attribute, 2, unsigned char, temp);
+
+                                // Convert data to raylib texcoord data type (float)
+                                for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/255.0f;
+
+                                RL_FREE(temp);
+                            }
+                            else if (attribute->component_type == cgltf_component_type_r_16u) // vec2, u16n
+                            {
+                                // Init raylib mesh texcoords to copy glTF attribute data
+                                texcoordPtr = (float *)RL_MALLOC(attribute->count*2*sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*2*sizeof(unsigned short));
+                                LOAD_ATTRIBUTE(attribute, 2, unsigned short, temp);
+
+                                // Convert data to raylib texcoord data type (float)
+                                for (unsigned int t = 0; t < attribute->count*2; t++) texcoordPtr[t] = (float)temp[t]/65535.0f;
+
+                                RL_FREE(temp);
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported", fileName);
+                        }
+                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Texcoords attribute data format not supported, use vec2 float", fileName);
+
+                        int index = mesh->primitives[p].attributes[j].index;
+                        if (index == 0) model.meshes[meshIndex].texcoords = texcoordPtr;
+                        else if (index == 1) model.meshes[meshIndex].texcoords2 = texcoordPtr;
+                        else
+                        {
+                            TRACELOG(LOG_WARNING, "MODEL: [%s] No more than 2 texture coordinates attributes supported", fileName);
+                            if (texcoordPtr != NULL) RL_FREE(texcoordPtr);
+                        }
+                    }
+                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_color) // COLOR_n, vec3/vec4, float/u8n/u16n
+                    {
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        // WARNING: SPECS: All components of each COLOR_n accessor element MUST be clamped to [0.0, 1.0] range
+
+                        if (model.meshes[meshIndex].colors != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Colors attribute data already loaded", fileName);
+                        else
+                        {
+                            if (attribute->type == cgltf_type_vec3) // RGB
+                            {
+                                if (attribute->component_type == cgltf_component_type_r_8u)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load data into a temp buffer to be converted to raylib data type
+                                    unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
+                                    LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
+
+                                    // Convert data to raylib color data type (4 bytes)
+                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
+                                    {
+                                        model.meshes[meshIndex].colors[c] = temp[k];
+                                        model.meshes[meshIndex].colors[c + 1] = temp[k + 1];
+                                        model.meshes[meshIndex].colors[c + 2] = temp[k + 2];
+                                        model.meshes[meshIndex].colors[c + 3] = 255;
+                                    }
+
+                                    RL_FREE(temp);
+                                }
+                                else if (attribute->component_type == cgltf_component_type_r_16u)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load data into a temp buffer to be converted to raylib data type
+                                    unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
+                                    LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
+
+                                    // Convert data to raylib color data type (4 bytes)
+                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
+                                    {
+                                        model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[k]/65535.0f)*255.0f);
+                                        model.meshes[meshIndex].colors[c + 1] = (unsigned char)(((float)temp[k + 1]/65535.0f)*255.0f);
+                                        model.meshes[meshIndex].colors[c + 2] = (unsigned char)(((float)temp[k + 2]/65535.0f)*255.0f);
+                                        model.meshes[meshIndex].colors[c + 3] = 255;
+                                    }
+
+                                    RL_FREE(temp);
+                                }
+                                else if (attribute->component_type == cgltf_component_type_r_32f)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load data into a temp buffer to be converted to raylib data type
+                                    float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+                                    LOAD_ATTRIBUTE(attribute, 3, float, temp);
+
+                                    // Convert data to raylib color data type (4 bytes)
+                                    for (unsigned int c = 0, k = 0; c < (attribute->count*4 - 3); c += 4, k += 3)
+                                    {
+                                        model.meshes[meshIndex].colors[c] = (unsigned char)(temp[k]*255.0f);
+                                        model.meshes[meshIndex].colors[c + 1] = (unsigned char)(temp[k + 1]*255.0f);
+                                        model.meshes[meshIndex].colors[c + 2] = (unsigned char)(temp[k + 2]*255.0f);
+                                        model.meshes[meshIndex].colors[c + 3] = 255;
+                                    }
+
+                                    RL_FREE(temp);
+                                }
+                                else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
+                            }
+                            else if (attribute->type == cgltf_type_vec4) // RGBA
+                            {
+                                if (attribute->component_type == cgltf_component_type_r_8u)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load 4 components of unsigned char data type into mesh.colors
+                                    LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
+                                }
+                                else if (attribute->component_type == cgltf_component_type_r_16u)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load data into a temp buffer to be converted to raylib data type
+                                    unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
+                                    LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
+
+                                    // Convert data to raylib color data type (4 bytes)
+                                    for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
+
+                                    RL_FREE(temp);
+                                }
+                                else if (attribute->component_type == cgltf_component_type_r_32f)
+                                {
+                                    // Init raylib mesh color to copy glTF attribute data
+                                    model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+
+                                    // Load data into a temp buffer to be converted to raylib data type
+                                    float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
+                                    LOAD_ATTRIBUTE(attribute, 4, float, temp);
+
+                                    // Convert data to raylib color data type (4 bytes), color data must be normalized
+                                    for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
+
+                                    RL_FREE(temp);
+                                }
+                                else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
+                        }
+                    }
+
+                    // NOTE: Attributes related to animations data are processed after mesh data loading
+                }
+
+                // Load primitive indices data (if provided)
+                if ((mesh->primitives[p].indices != NULL) && (mesh->primitives[p].indices->buffer_view != NULL))
+                {
+                    cgltf_accessor *attribute = mesh->primitives[p].indices;
+
+                    model.meshes[meshIndex].triangleCount = (int)attribute->count/3;
+
+                    if (model.meshes[meshIndex].indices != NULL) TRACELOG(LOG_WARNING, "MODEL: [%s] Indices attribute data already loaded", fileName);
+                    else
+                    {
+                        if (attribute->component_type == cgltf_component_type_r_16u)
+                        {
+                            // Init raylib mesh indices to copy glTF attribute data
+                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
+
+                            // Load unsigned short data type into mesh.indices
+                            LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
+                        }
+                        else if (attribute->component_type == cgltf_component_type_r_8u)
+                        {
+                            // Init raylib mesh indices to copy glTF attribute data
+                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
+                            LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
+
+                        }
+                        else if (attribute->component_type == cgltf_component_type_r_32u)
+                        {
+                            // Init raylib mesh indices to copy glTF attribute data
+                            model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
+                            LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
+
+                            TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
+                        }
+                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
+                    }
+                }
+                else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3;    // Unindexed mesh
+
+                // Assign to the primitive mesh the corresponding material index
+                // NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
+                for (unsigned int m = 0; m < data->materials_count; m++)
+                {
+                    // The primitive actually keeps the pointer to the corresponding material,
+                    // raylib instead assigns to the mesh the by its index, as loaded in model.materials array
+                    // To get the index, check if material pointers match, and assign the corresponding index,
+                    // skipping index 0, the default material
+                    if (&data->materials[m] == mesh->primitives[p].material)
+                    {
+                        model.meshMaterial[meshIndex] = m + 1;
+                        break;
+                    }
+                }
+
+                meshIndex++;       // Move to next mesh
+            }
+        }
+        //----------------------------------------------------------------------------------------------------
+
+        // Load animation data
+        // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
+        // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
+        //
+        // LIMITATIONS:
+        //  - Only supports 1 armature per file, and skips loading it if there are multiple armatures
+        //  - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file)
+        //  - Only supports translation/rotation/scale animation channel.path, weights not considered (a.e. morph targets)
+        //----------------------------------------------------------------------------------------------------
+        if (data->skins_count > 0)
+        {
+            cgltf_skin skin = data->skins[0];
+            model.skeleton.bones = LoadBoneInfoGLTF(skin, &model.skeleton.boneCount);
+            model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
+
+            for (unsigned int i = 0; i < model.skeleton.boneCount; i++)
+            {
+                Matrix bindMatrix = { 0 };
+                cgltf_float inverseBindTransform[16] = { 0 };
+
+                if ((skin.inverse_bind_matrices != NULL) &&
+                    (skin.inverse_bind_matrices->count >= skin.joints_count) &&
+                    cgltf_accessor_read_float(skin.inverse_bind_matrices, i, inverseBindTransform, 16))
+                {
+                    Matrix inverseBindMatrix = {
+                        inverseBindTransform[0], inverseBindTransform[4], inverseBindTransform[8], inverseBindTransform[12],
+                        inverseBindTransform[1], inverseBindTransform[5], inverseBindTransform[9], inverseBindTransform[13],
+                        inverseBindTransform[2], inverseBindTransform[6], inverseBindTransform[10], inverseBindTransform[14],
+                        inverseBindTransform[3], inverseBindTransform[7], inverseBindTransform[11], inverseBindTransform[15]
+                    };
+                    bindMatrix = MatrixInvert(inverseBindMatrix);
+                }
+                else
+                {
+                    cgltf_float worldTransform[16] = { 0 };
+                    cgltf_node_transform_world(skin.joints[i], worldTransform);
+
+                    Matrix worldMatrix = {
+                        worldTransform[0], worldTransform[4], worldTransform[8], worldTransform[12],
+                        worldTransform[1], worldTransform[5], worldTransform[9], worldTransform[13],
+                        worldTransform[2], worldTransform[6], worldTransform[10], worldTransform[14],
+                        worldTransform[3], worldTransform[7], worldTransform[11], worldTransform[15]
+                    };
+                    bindMatrix = worldMatrix;
+                }
+
+                MatrixDecompose(bindMatrix,
+                    &(model.skeleton.bindPose[i].translation),
+                    &(model.skeleton.bindPose[i].rotation),
+                    &(model.skeleton.bindPose[i].scale));
+            }
+
+            if (data->skins_count > 1) TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
+        }
+
+        meshIndex = 0;
+        for (unsigned int i = 0; i < data->nodes_count; i++)
+        {
+            cgltf_node *node = &(data->nodes[i]);
+
+            cgltf_mesh *mesh = node->mesh;
+            if (!mesh) continue;
+
+            for (unsigned int p = 0; p < mesh->primitives_count; p++)
+            {
+                bool hasJoints = false;
+
+                // NOTE: Only support primitives defined by triangles
+                if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
+
+                for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
+                {
+                    // NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
+                    if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
+                    {
+                        hasJoints = true;
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        // NOTE: JOINTS_n can only be vec4 and u8/u16
+                        // SPECS: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview
+
+                        // WARNING: raylib only supports model.meshes[].boneIndices as u8 (unsigned char),
+                        // if data is provided in any other format, it is converted to supported format but
+                        // it could imply data loss (a warning message is issued in that case)
+
+                        if (attribute->type == cgltf_type_vec4)
+                        {
+                            if (attribute->component_type == cgltf_component_type_r_8u)
+                            {
+                                // Init raylib mesh boneIndices to copy glTF attribute data
+                                model.meshes[meshIndex].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
+
+                                // Load attribute: vec4, u8 (unsigned char)
+                                LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIndices)
+                            }
+                            else if (attribute->component_type == cgltf_component_type_r_16u)
+                            {
+                                // Init raylib mesh boneIndices to copy glTF attribute data
+                                model.meshes[meshIndex].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
+                                LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
+
+                                // Convert data to raylib color data type (4 bytes)
+                                bool boneIdOverflowWarning = false;
+                                for (int b = 0; b < model.meshes[meshIndex].vertexCount*4; b++)
+                                {
+                                    if ((temp[b] > 255) && !boneIdOverflowWarning)
+                                    {
+                                        TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format (u16) overflow", fileName);
+                                        boneIdOverflowWarning = true;
+                                    }
+
+                                    // Despite the possible overflow, convert data to unsigned char
+                                    model.meshes[meshIndex].boneIndices[b] = (unsigned char)temp[b];
+                                }
+
+                                RL_FREE(temp);
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
+                        }
+                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported", fileName);
+                    }
+                    else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_weights) // WEIGHTS_n (vec4, u8n/u16n/f32)
+                    {
+                        cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
+
+                        if (attribute->type == cgltf_type_vec4)
+                        {
+                            if (attribute->component_type == cgltf_component_type_r_8u)
+                            {
+                                // Init raylib mesh bone weight to copy glTF attribute data
+                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
+                                LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
+
+                                // Convert data to raylib bone weight data type (4 bytes)
+                                for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/255.0f;
+
+                                RL_FREE(temp);
+                            }
+                            else if (attribute->component_type == cgltf_component_type_r_16u)
+                            {
+                                // Init raylib mesh bone weight to copy glTF attribute data
+                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
+
+                                // Load data into a temp buffer to be converted to raylib data type
+                                unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
+                                LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
+
+                                // Convert data to raylib bone weight data type
+                                for (unsigned int b = 0; b < attribute->count*4; b++) model.meshes[meshIndex].boneWeights[b] = (float)temp[b]/65535.0f;
+
+                                RL_FREE(temp);
+                            }
+                            else if (attribute->component_type == cgltf_component_type_r_32f)
+                            {
+                                // Init raylib mesh bone weight to copy glTF attribute data
+                                model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
+
+                                // Load 4 components of float data type into mesh.boneWeights
+                                // for cgltf_attribute_type_weights:
+                                //   - data.meshes[0] (256 vertices)
+                                //   - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
+                                LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
+                            }
+                            else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
+                        }
+                        else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
+                    }
+                }
+
+                // Check if animated, and the mesh was not given any bone assignments, but is the child of a bone node
+                // in this case, all the verts need to be attached to the parent bone so it will animate with the bone
+                if ((data->skins_count > 0) && !hasJoints && (node->parent != NULL) && (node->parent->mesh == NULL))
+                {
+                    int parentBoneId = -1;
+                    for (unsigned int joint = 0; joint < model.skeleton.boneCount; joint++)
+                    {
+                        if (data->skins[0].joints[joint] == node->parent)
+                        {
+                            parentBoneId = joint;
+                            break;
+                        }
+                    }
+
+                    if (parentBoneId >= 0)
+                    {
+                        model.meshes[meshIndex].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
+                        model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
+
+                        for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
+                        {
+                            model.meshes[meshIndex].boneIndices[vertexIndex] = (unsigned char)parentBoneId;
+                            model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f;
+                        }
+                    }
+                }
+
+#if !SUPPORT_GPU_SKINNING
+                // Animated vertex data (CPU skinning)
+                model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
+                memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
+                model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
+                if (model.meshes[meshIndex].normals != NULL) memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
+#endif
+                model.meshes[meshIndex].boneCount = model.skeleton.boneCount;
+
+                meshIndex++; // Move to next mesh
+            }
+        }
+
+        // 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 (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
+        //----------------------------------------------------------------------------------------------------
+
+        // Free unused allocated memory in case of no bones defined
+        if (model.skeleton.boneCount == 0)
+        {
+            RL_FREE(model.currentPose);
+            RL_FREE(model.boneMatrices);
+            model.currentPose = NULL;
+            model.boneMatrices = NULL;
+        }
+
+        // Free all cgltf loaded data
+        cgltf_free(data);
+    }
+    else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
+
+    // WARNING: cgltf requires the file pointer available while reading data
+    UnloadFileData(fileData);
+
+    return model;
+}
+
+// Get interpolated pose for bone sampler at a specific time. Returns true on success
+static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_accessor *input, cgltf_accessor *output, float time, void *data)
+{
+    if (interpolationType >= cgltf_interpolation_type_max_enum) return false;
+
+    // Input and output should have the same count
+    float tstart = 0.0f;
+    float tend = 0.0f;
+    int keyframe = 0;       // Defaults to first pose
+    bool found = false;
+
+    for (int i = 0; i < (int)input->count - 1; i++)
+    {
+        cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1);
+        if (!r1) return false;
+
+        cgltf_bool r2 = cgltf_accessor_read_float(input, i + 1, &tend, 1);
+        if (!r2) return false;
+
+        if ((tstart <= time) && (time < tend))
+        {
+            keyframe = i;
+            found = true;
+            break;
+        }
+    }
+
+    // No interval contains a time at (or past) the last keyframe, because the
+    // search above requires time < tend: clamp to the edge interval instead of
+    // falling back to keyframe 0, which returns a pose from the start
+    if (!found && ((int)input->count >= 2))
+    {
+        keyframe = (int)input->count - 2;
+
+        float tfirst = 0.0f;
+        if (!cgltf_accessor_read_float(input, 0, &tfirst, 1)) return false;
+        if (time < tfirst) keyframe = 0;
+
+        if (!cgltf_accessor_read_float(input, keyframe, &tstart, 1)) return false;
+        if (!cgltf_accessor_read_float(input, keyframe + 1, &tend, 1)) return false;
+    }
+
+    // Constant animation, no need to interpolate
+    if (FloatEquals(tend, tstart))
+    {
+        interpolationType = cgltf_interpolation_type_step;
+    }
+
+    float duration = fmaxf((tend - tstart), EPSILON);
+    float t = (time - tstart)/duration;
+    t = (t < 0.0f)? 0.0f : t;
+    t = (t > 1.0f)? 1.0f : t;
+
+    if (output->component_type != cgltf_component_type_r_32f) return false;
+
+    if (output->type == cgltf_type_vec3)
+    {
+        switch (interpolationType)
+        {
+            case cgltf_interpolation_type_step:
+            {
+                float tmp[3] = { 0.0f };
+                cgltf_accessor_read_float(output, keyframe, tmp, 3);
+                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
+                Vector3 *r = (Vector3 *)data;
+
+                *r = v1;
+            } break;
+            case cgltf_interpolation_type_linear:
+            {
+                float tmp[3] = { 0.0f };
+                cgltf_accessor_read_float(output, keyframe, tmp, 3);
+                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
+                cgltf_accessor_read_float(output, keyframe+1, tmp, 3);
+                Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
+                Vector3 *r = (Vector3 *)data;
+
+                *r = Vector3Lerp(v1, v2, t);
+            } break;
+            case cgltf_interpolation_type_cubic_spline:
+            {
+                float tmp[3] = { 0.0f };
+                cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 3);
+                Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
+                cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 3);
+                Vector3 tangent1 = {tmp[0], tmp[1], tmp[2]};
+                cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 3);
+                Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
+                cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 3);
+                Vector3 tangent2 = {tmp[0], tmp[1], tmp[2]};
+                Vector3 *r = (Vector3 *)data;
+
+                *r = Vector3CubicHermite(v1, tangent1, v2, tangent2, t);
+            } break;
+            default: break;
+        }
+    }
+    else if (output->type == cgltf_type_vec4)
+    {
+        // Only v4 is for rotations, so it's a quaternion
+        switch (interpolationType)
+        {
+            case cgltf_interpolation_type_step:
+            {
+                float tmp[4] = { 0.0f };
+                cgltf_accessor_read_float(output, keyframe, tmp, 4);
+                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
+                Vector4 *r = (Vector4 *)data;
+
+                *r = v1;
+            } break;
+            case cgltf_interpolation_type_linear:
+            {
+                float tmp[4] = { 0.0f };
+                cgltf_accessor_read_float(output, keyframe, tmp, 4);
+                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
+                cgltf_accessor_read_float(output, keyframe+1, tmp, 4);
+                Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
+                Vector4 *r = (Vector4 *)data;
+
+                *r = QuaternionSlerp(v1, v2, t);
+            } break;
+            case cgltf_interpolation_type_cubic_spline:
+            {
+                float tmp[4] = { 0.0f };
+                cgltf_accessor_read_float(output, 3*keyframe+1, tmp, 4);
+                Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
+                cgltf_accessor_read_float(output, 3*keyframe+2, tmp, 4);
+                Vector4 outTangent1 = {tmp[0], tmp[1], tmp[2], 0.0f};
+                cgltf_accessor_read_float(output, 3*(keyframe+1)+1, tmp, 4);
+                Vector4 v2 = {tmp[0], tmp[1], tmp[2], tmp[3]};
+                cgltf_accessor_read_float(output, 3*(keyframe+1), tmp, 4);
+                Vector4 inTangent2 = {tmp[0], tmp[1], tmp[2], 0.0f};
+                Vector4 *r = (Vector4 *)data;
+
+                v1 = QuaternionNormalize(v1);
+                v2 = QuaternionNormalize(v2);
+
+                if (Vector4DotProduct(v1, v2) < 0.0f)
+                {
+                    v2 = Vector4Negate(v2);
+                }
+
+                outTangent1 = Vector4Scale(outTangent1, duration);
+                inTangent2 = Vector4Scale(inTangent2, duration);
+
+                *r = QuaternionCubicHermiteSpline(v1, outTangent1, v2, inTangent2, t);
+            } break;
+            default: break;
+        }
+    }
+
+    return true;
+}
+
+#define GLTF_FRAMERATE 60.0f    // glTF animation framerate (frames per second)
+
+static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount)
+{
+    // glTF file loading
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    ModelAnimation *animations = NULL;
+
+    // glTF data loading
+    cgltf_options options = { 0 };
+    options.file.read = LoadFileGLTFCallback;
+    options.file.release = ReleaseFileGLTFCallback;
+    cgltf_data *data = NULL;
+    cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
+
+    if (result != cgltf_result_success)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
+        *animCount = 0;
+        return NULL;
+    }
+
+    result = cgltf_load_buffers(&options, data, fileName);
+    if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName);
+
+    if (result == cgltf_result_success)
+    {
+        if (data->skins_count > 0)
+        {
+            cgltf_skin skin = data->skins[0];
+
+            // Precompute, per joint, the static transform contributed by any
+            // intermediate non-joint nodes between the joint and its nearest
+            // joint ancestor. This handles exporters (e.g. wow.export) that
+            // store bone offsets on dummy parent nodes rather than on the
+            // joints themselves. Depends only on the skin, not the animation.
+            int jointCount = (int)skin.joints_count;
+            Matrix *extOffset = (Matrix *)RL_MALLOC(jointCount*sizeof(Matrix));
+
+            if (extOffset == NULL)
+            {
+                // Allocation failed: abort animation loading at the source rather than
+                // propagating a NULL pointer into the per-frame transform loop below
+                TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to allocate joint offset buffer", fileName);
+                cgltf_free(data);
+                UnloadFileData(fileData);
+                *animCount = 0;
+                return NULL;
+            }
+
+            *animCount = (int)data->animations_count;
+            animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
+
+            for (int k = 0; k < jointCount; k++)
+            {
+                extOffset[k] = MatrixIdentity();
+                cgltf_node *n = skin.joints[k]->parent;
+
+                while (n != NULL)
+                {
+                    bool isJoint = false;
+                    for (int jj = 0; jj < jointCount; jj++)
+                    {
+                        if (skin.joints[jj] == n)
+                        {
+                            isJoint = true;
+                            break;
+                        }
+                    }
+
+                    if (isJoint) break;
+
+                    // Compose the intermediate node's local TRS (scale, then rotation, then translation)
+                    Matrix nodeScale = MatrixScale(n->scale[0], n->scale[1], n->scale[2]);
+                    Matrix nodeRotation = QuaternionToMatrix((Quaternion){ n->rotation[0], n->rotation[1], n->rotation[2], n->rotation[3] });
+                    Matrix nodeTranslation = MatrixTranslate(n->translation[0], n->translation[1], n->translation[2]);
+                    Matrix nodeTransform = MatrixMultiply(MatrixMultiply(nodeScale, nodeRotation), nodeTranslation);
+
+                    extOffset[k] = MatrixMultiply(extOffset[k], nodeTransform);
+                    n = n->parent;
+                }
+            }
+
+            for (unsigned int a = 0; a < data->animations_count; a++)
+            {
+                BoneInfo *bones = LoadBoneInfoGLTF(skin, &animations[a].boneCount);
+
+                cgltf_animation animData = data->animations[a];
+
+                struct Channels {
+                    cgltf_animation_channel *translate;
+                    cgltf_animation_channel *rotate;
+                    cgltf_animation_channel *scale;
+                };
+
+                struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[a].boneCount, sizeof(struct Channels));
+                float animDuration = 0.0f;
+
+                for (unsigned int j = 0; j < animData.channels_count; j++)
+                {
+                    cgltf_animation_channel channel = animData.channels[j];
+                    int boneIndex = -1;
+
+                    for (unsigned int k = 0; k < skin.joints_count; k++)
+                    {
+                        if (animData.channels[j].target_node == skin.joints[k])
+                        {
+                            boneIndex = k;
+                            break;
+                        }
+                    }
+
+                    if (boneIndex == -1) continue; // Animation channel for a node not in the skeleton
+
+                    if (animData.channels[j].sampler->interpolation != cgltf_interpolation_type_max_enum)
+                    {
+                        if (channel.target_path == cgltf_animation_path_type_translation)
+                        {
+                            boneChannels[boneIndex].translate = &animData.channels[j];
+                        }
+                        else if (channel.target_path == cgltf_animation_path_type_rotation)
+                        {
+                            boneChannels[boneIndex].rotate = &animData.channels[j];
+                        }
+                        else if (channel.target_path == cgltf_animation_path_type_scale)
+                        {
+                            boneChannels[boneIndex].scale = &animData.channels[j];
+                        }
+                        else
+                        {
+                            TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, a);
+                        }
+                    }
+                    else TRACELOG(LOG_WARNING, "MODEL: [%s] Invalid interpolation curve encountered for GLTF animation.", fileName);
+
+                    float time = 0.0f;
+                    cgltf_bool result = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &time, 1);
+
+                    if (!result)
+                    {
+                        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName);
+                        continue;
+                    }
+
+                    animDuration = (time > animDuration)? time : animDuration;
+                }
+
+                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 *));
+
+                for (int j = 0; j < animations[a].keyframeCount; j++)
+                {
+                    animations[a].keyframePoses[j] = (Transform *)RL_CALLOC(animations[a].boneCount, sizeof(Transform));
+                    float time = (float)j / GLTF_FRAMERATE;
+
+                    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]};
+                        Vector3 scale = {skin.joints[k]->scale[0], skin.joints[k]->scale[1], skin.joints[k]->scale[2]};
+
+                        if (boneChannels[k].translate)
+                        {
+                            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);
+                            }
+                        }
+
+                        if (boneChannels[k].rotate)
+                        {
+                            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);
+                            }
+                        }
+
+                        if (boneChannels[k].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);
+                            }
+                        }
+
+                        // Compose joint local TRS, then prepend the static
+                        // intermediate non-joint offsets so the final TRS is
+                        // expressed relative to the joint's skeleton parent.
+                        Matrix S = MatrixScale(scale.x, scale.y, scale.z);
+                        Matrix R = QuaternionToMatrix(rotation);
+                        Matrix T = MatrixTranslate(translation.x, translation.y, translation.z);
+                        Matrix jointLocal = MatrixMultiply(MatrixMultiply(S, R), T);
+                        Matrix combined = MatrixMultiply(jointLocal, extOffset[k]);
+
+                        Transform tr;
+                        MatrixDecompose(combined, &tr.translation, &tr.rotation, &tr.scale);
+                        animations[a].keyframePoses[j][k] = tr;
+                    }
+
+                    BuildPoseFromParentJoints(bones, animations[a].boneCount, animations[a].keyframePoses[j]);
+                }
+
+                TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Duration: %fs", fileName, (animData.name != NULL)? animData.name : "NULL", animations[a].keyframeCount, animDuration);
+                RL_FREE(boneChannels);
+                RL_FREE(bones);
+            }
+
+            RL_FREE(extOffset);
+        }
+
+        if (data->skins_count > 1)
+        {
+            TRACELOG(LOG_WARNING, "MODEL: [%s] Expected one unique skin to load animation data from, but found %i", fileName, data->skins_count);
+        }
+
+        cgltf_free(data);
+    }
+
+    UnloadFileData(fileData);
+
+    return animations;
+}
+#endif
+
+#if SUPPORT_FILEFORMAT_VOX
+// Load VOX (MagicaVoxel) mesh data
+static Model LoadVOX(const char *fileName)
+{
+    Model model = { 0 };
+
+    int nbvertices = 0;
+    int meshescount = 0;
+
+    // Read vox file into buffer
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    if (fileData == 0)
+    {
+        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX file", fileName);
+        return model;
+    }
+
+    // Read and build voxarray description
+    VoxArray3D voxarray = { 0 };
+    int ret = Vox_LoadFromMemory(fileData, dataSize, &voxarray);
+
+    if (ret != VOX_SUCCESS)
+    {
+        // Error
+        UnloadFileData(fileData);
+
+        TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load VOX data", fileName);
+        return model;
+    }
+    else
+    {
+        // Success: Compute meshes count
+        nbvertices = voxarray.vertices.used;
+        meshescount = 1 + (nbvertices/65536);
+
+        TRACELOG(LOG_INFO, "MODEL: [%s] VOX data loaded successfully : %i vertices/%i meshes", fileName, nbvertices, meshescount);
+    }
+
+    // Build models from meshes
+    model.transform = MatrixIdentity();
+
+    model.meshCount = meshescount;
+    model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+
+    model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+
+    model.materialCount = 1;
+    model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+    model.materials[0] = LoadMaterialDefault();
+
+    // Init model meshes
+    int verticesRemain = voxarray.vertices.used;
+    int verticesMax = 65532; // 5461 voxels x 12 vertices per voxel -> 65532 (must be inf 65536)
+
+    // 6*4 = 12 vertices per voxel
+    Vector3 *pvertices = (Vector3 *)voxarray.vertices.array;
+    Vector3 *pnormals = (Vector3 *)voxarray.normals.array;
+    Color *pcolors = (Color *)voxarray.colors.array;
+
+    unsigned short *pindices = voxarray.indices.array;    // 5461*6*6 = 196596 indices max per mesh
+
+    int size = 0;
+
+    for (int i = 0; i < meshescount; i++)
+    {
+        Mesh *pmesh = &model.meshes[i];
+        memset(pmesh, 0, sizeof(Mesh));
+
+        // Copy vertices
+        pmesh->vertexCount = (int)fmin(verticesMax, verticesRemain);
+
+        size = pmesh->vertexCount*sizeof(float)*3;
+        pmesh->vertices = (float *)RL_MALLOC(size);
+        memcpy(pmesh->vertices, pvertices, size);
+
+        // Copy normals
+        pmesh->normals = (float *)RL_MALLOC(size);
+        memcpy(pmesh->normals, pnormals, size);
+
+        // Copy indices
+        size = voxarray.indices.used*sizeof(unsigned short);
+        pmesh->indices = (unsigned short *)RL_MALLOC(size);
+        memcpy(pmesh->indices, pindices, size);
+
+        pmesh->triangleCount = (pmesh->vertexCount/4)*2;
+
+        // Copy colors
+        size = pmesh->vertexCount*sizeof(Color);
+        pmesh->colors = (unsigned char *)RL_MALLOC(size);
+        memcpy(pmesh->colors, pcolors, size);
+
+        // First material index
+        model.meshMaterial[i] = 0;
+
+        verticesRemain -= verticesMax;
+        pvertices += verticesMax;
+        pnormals += verticesMax;
+        pcolors += verticesMax;
+    }
+
+    // Free buffers
+    Vox_FreeArrays(&voxarray);
+    UnloadFileData(fileData);
+
+    return model;
+}
+#endif
+
+#if SUPPORT_FILEFORMAT_M3D
+// Hook LoadFileData()/UnloadFileData() calls to M3D loaders
+unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, (int *)len); }
+void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); }
+
+// Load M3D mesh data
+static Model LoadM3D(const char *fileName)
+{
+    Model model = { 0 };
+
+    m3d_t *m3d = NULL;
+    m3dp_t *prop = NULL;
+    int i, j, k, l, n, mi = -2, vcolor = 0;
+
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    if (fileData != NULL)
+    {
+        m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
+
+        if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
+        {
+            TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
+            if (m3d) m3d_free(m3d);
+            UnloadFileData(fileData);
+            return model;
+        }
+        else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial);
+
+        // Check if face is found, if not, probably just a material library
+        if (!m3d->numface)
+        {
+            m3d_free(m3d);
+            UnloadFileData(fileData);
+            return model;
+        }
+
+        if (m3d->nummaterial > 0)
+        {
+            model.meshCount = model.materialCount = m3d->nummaterial;
+            TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount);
+        }
+        else
+        {
+            model.meshCount = 1; model.materialCount = 0;
+            TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
+        }
+
+        // A default material is always required, so adding +1
+        model.materialCount++;
+
+        // Faces must be in non-decreasing materialid order. Verify that quickly, sorting them otherwise
+        // WARNING: Sorting is not needed, valid M3D model files should already be sorted
+        // Keeping the sorting function for reference (Check PR #3363 #3385)
+        /*
+        for (a = 1; a < m3d->numface; a++)
+        {
+            if (m3d->face[a-1].materialid <= m3d->face[a].materialid) continue;
+
+            // face[a-1] > face[a].  slide face[a] lower
+            m3df_t slider = m3d->face[a];
+            j = a-1;
+
+            do
+            {   // face[j] > slider, face[j+1] is svailable vacant gap
+                m3d->face[j+1] = m3d->face[j];
+                j = j-1;
+            }
+            while (j >= 0 && m3d->face[j].materialid > slider.materialid);
+
+            m3d->face[j+1] = slider;
+        }
+        */
+
+        model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+        model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+        model.materials = (Material *)RL_CALLOC(model.materialCount + 1, sizeof(Material));
+
+        // Map no material to index 0 with default shader, everything else materialid + 1
+        model.materials[0] = LoadMaterialDefault();
+
+        for (i = l = 0, k = -1; i < (int)m3d->numface; i++, l++)
+        {
+            // Materials are grouped together
+            if (mi != m3d->face[i].materialid)
+            {
+                // There should be only one material switch per material kind,
+                // but be bulletproof for non-optimal model files
+                if (k + 1 >= model.meshCount)
+                {
+                    model.meshCount++;
+
+                    // Create a second buffer for mesh re-allocation
+                    Mesh *tempMeshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
+                    memcpy(tempMeshes, model.meshes, (model.meshCount - 1)*sizeof(Mesh));
+                    RL_FREE(model.meshes);
+                    model.meshes = tempMeshes;
+
+                    // Create a second buffer for material re-allocation
+                    int *tempMeshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
+                    memcpy(tempMeshMaterial, model.meshMaterial, (model.meshCount - 1)*sizeof(int));
+                    RL_FREE(model.meshMaterial);
+                    model.meshMaterial = tempMeshMaterial;
+                }
+
+                k++;
+                mi = m3d->face[i].materialid;
+
+                // Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch
+                // if all colors are fully transparent black for all vertices of this material, then assuming no vertex colors
+                for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++)
+                {
+                    if (!m3d->vertex[m3d->face[j].vertex[0]].color ||
+                        !m3d->vertex[m3d->face[j].vertex[1]].color ||
+                        !m3d->vertex[m3d->face[j].vertex[2]].color) vcolor = 1;
+                }
+
+                model.meshes[k].vertexCount = l*3;
+                model.meshes[k].triangleCount = l;
+                model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
+                model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
+                model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
+
+                // If no map is provided, or colors are defined, allocate storage for vertex colors
+                // M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
+                if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
+
+                // If no map is provided and vertex colors are allocated, set them to white
+                if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
+                {
+                    for (int c = 0; c < model.meshes[k].vertexCount*4; c++) model.meshes[k].colors[c] = 255;
+                }
+
+                if (m3d->numbone && m3d->numskin)
+                {
+                    model.meshes[k].boneIndices = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
+                    model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float));
+#if !SUPPORT_GPU_SKINNING
+                    model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
+                    model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
+#endif
+                }
+
+                model.meshMaterial[k] = mi + 1;
+                l = 0;
+            }
+
+            // Process meshes per material, add triangles
+            model.meshes[k].vertices[l*9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale;
+            model.meshes[k].vertices[l*9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale;
+            model.meshes[k].vertices[l*9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale;
+            model.meshes[k].vertices[l*9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale;
+            model.meshes[k].vertices[l*9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale;
+            model.meshes[k].vertices[l*9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale;
+            model.meshes[k].vertices[l*9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale;
+            model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale;
+            model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale;
+
+            // Without vertex color (full transparency), using the default color
+            if (model.meshes[k].colors != NULL)
+            {
+                if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
+                    memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
+                if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000)
+                    memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
+                if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000)
+                    memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
+            }
+
+            if (m3d->face[i].texcoord[0] != M3D_UNDEF)
+            {
+                model.meshes[k].texcoords[l*6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u;
+                model.meshes[k].texcoords[l*6 + 1] = 1.0f - m3d->tmap[m3d->face[i].texcoord[0]].v;
+                model.meshes[k].texcoords[l*6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u;
+                model.meshes[k].texcoords[l*6 + 3] = 1.0f - m3d->tmap[m3d->face[i].texcoord[1]].v;
+                model.meshes[k].texcoords[l*6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u;
+                model.meshes[k].texcoords[l*6 + 5] = 1.0f - m3d->tmap[m3d->face[i].texcoord[2]].v;
+            }
+
+            if (m3d->face[i].normal[0] != M3D_UNDEF)
+            {
+                model.meshes[k].normals[l*9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x;
+                model.meshes[k].normals[l*9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y;
+                model.meshes[k].normals[l*9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z;
+                model.meshes[k].normals[l*9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x;
+                model.meshes[k].normals[l*9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y;
+                model.meshes[k].normals[l*9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z;
+                model.meshes[k].normals[l*9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x;
+                model.meshes[k].normals[l*9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y;
+                model.meshes[k].normals[l*9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z;
+            }
+
+            // Add skin (vertex / bone weight pairs)
+            if (m3d->numbone && m3d->numskin)
+            {
+                for (n = 0; n < 3; n++)
+                {
+                    int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
+
+                    // Check if there is a skin for this mesh
+                    if ((skinid != M3D_UNDEF) && (skinid < (int)m3d->numskin))
+                    {
+                        for (j = 0; j < 4; j++)
+                        {
+                            model.meshes[k].boneIndices[l*12 + n*4 + j] = m3d->skin[skinid].boneid[j];
+                            model.meshes[k].boneWeights[l*12 + n*4 + j] = m3d->skin[skinid].weight[j];
+                        }
+                    }
+                    else
+                    {
+                        // Boneless meshes with skeletal animations are not supported, so
+                        // putting all vertices without a bone into a special "no bone" bone
+                        model.meshes[k].boneIndices[l*12 + n*4] = m3d->numbone;
+                        model.meshes[k].boneWeights[l*12 + n*4] = 1.0f;
+                    }
+                }
+            }
+        }
+
+        // Load materials
+        for (i = 0; i < (int)m3d->nummaterial; i++)
+        {
+            model.materials[i + 1] = LoadMaterialDefault();
+
+            for (j = 0; j < m3d->material[i].numprop; j++)
+            {
+                prop = &m3d->material[i].prop[j];
+
+                switch (prop->type)
+                {
+                    case m3dp_Kd:
+                    {
+                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4);
+                        model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
+                    } break;
+                    case m3dp_Ks:
+                    {
+                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4);
+                    } break;
+                    case m3dp_Ns:
+                    {
+                        model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = prop->value.fnum;
+                    } break;
+                    case m3dp_Ke:
+                    {
+                        memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4);
+                        model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f;
+                    } break;
+                    case m3dp_Pm:
+                    {
+                        model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum;
+                    } break;
+                    case m3dp_Pr:
+                    {
+                        model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum;
+                    } break;
+                    case m3dp_Ps:
+                    {
+                        model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE;
+                        model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum;
+                    } break;
+                    default:
+                    {
+                        if (prop->type >= 128)
+                        {
+                            Image image = { 0 };
+                            image.data = m3d->texture[prop->value.textureid].d;
+                            image.width = m3d->texture[prop->value.textureid].w;
+                            image.height = m3d->texture[prop->value.textureid].h;
+                            image.mipmaps = 1;
+                            image.format = (m3d->texture[prop->value.textureid].f == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 :
+                                           ((m3d->texture[prop->value.textureid].f == 3)? PIXELFORMAT_UNCOMPRESSED_R8G8B8 :
+                                           ((m3d->texture[prop->value.textureid].f == 2)? PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : PIXELFORMAT_UNCOMPRESSED_GRAYSCALE));
+
+                            switch (prop->type)
+                            {
+                                case m3dp_map_Kd: model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTextureFromImage(image); break;
+                                case m3dp_map_Ks: model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].texture = LoadTextureFromImage(image); break;
+                                case m3dp_map_Ke: model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(image); break;
+                                case m3dp_map_Km: model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(image); break;
+                                case m3dp_map_Ka: model.materials[i + 1].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(image); break;
+                                case m3dp_map_Pm: model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(image); break;
+                                default: break;
+                            }
+                        }
+                    } break;
+                }
+            }
+        }
+
+        // Load bones
+        if (m3d->numbone)
+        {
+            model.skeleton.boneCount = m3d->numbone + 1;
+            model.skeleton.bones = (BoneInfo *)RL_CALLOC(model.skeleton.boneCount, sizeof(BoneInfo));
+            model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
+
+            for (i = 0; i < (int)m3d->numbone; i++)
+            {
+                model.skeleton.bones[i].parent = m3d->bone[i].parent;
+                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;
+                model.skeleton.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x;
+                model.skeleton.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y;
+                model.skeleton.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z;
+                model.skeleton.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w;
+
+                // NOTE: If the orientation quaternion is not normalized, then that's encoding scaling
+                model.skeleton.bindPose[i].rotation = QuaternionNormalize(model.skeleton.bindPose[i].rotation);
+                model.skeleton.bindPose[i].scale.x = model.skeleton.bindPose[i].scale.y = model.skeleton.bindPose[i].scale.z = 1.0f;
+
+                // Child bones are stored in parent bone relative space, convert that into model space
+                if (model.skeleton.bones[i].parent >= 0)
+                {
+                    model.skeleton.bindPose[i].rotation = QuaternionMultiply(model.skeleton.bindPose[model.skeleton.bones[i].parent].rotation, model.skeleton.bindPose[i].rotation);
+                    model.skeleton.bindPose[i].translation = Vector3RotateByQuaternion(model.skeleton.bindPose[i].translation, model.skeleton.bindPose[model.skeleton.bones[i].parent].rotation);
+                    model.skeleton.bindPose[i].translation = Vector3Add(model.skeleton.bindPose[i].translation, model.skeleton.bindPose[model.skeleton.bones[i].parent].translation);
+                    model.skeleton.bindPose[i].scale = Vector3Multiply(model.skeleton.bindPose[i].scale, model.skeleton.bindPose[model.skeleton.bones[i].parent].scale);
+                }
+            }
+
+            // Add a special "no bone" bone
+            model.skeleton.bones[i].parent = -1;
+            memcpy(model.skeleton.bones[i].name, "NO BONE", 7);
+            model.skeleton.bindPose[i].translation.x = 0.0f;
+            model.skeleton.bindPose[i].translation.y = 0.0f;
+            model.skeleton.bindPose[i].translation.z = 0.0f;
+            model.skeleton.bindPose[i].rotation.x = 0.0f;
+            model.skeleton.bindPose[i].rotation.y = 0.0f;
+            model.skeleton.bindPose[i].rotation.z = 0.0f;
+            model.skeleton.bindPose[i].rotation.w = 1.0f;
+            model.skeleton.bindPose[i].scale.x = model.skeleton.bindPose[i].scale.y = model.skeleton.bindPose[i].scale.z = 1.0f;
+        }
+
+        // Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
+        // called, but not before, however DrawMesh uses these if they exist (so not good if they are left empty)
+        if (m3d->numbone && m3d->numskin)
+        {
+            for (i = 0; i < model.meshCount; i++)
+            {
+                model.meshes[i].boneCount = model.skeleton.boneCount;
+
+#if !SUPPORT_GPU_SKINNING
+                // Initialize vertex buffers for CPU skinning
+                memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
+                memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
+#endif
+            }
+
+            // 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 (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
+        }
+
+        m3d_free(m3d);
+        UnloadFileData(fileData);
+    }
+
+    return model;
+}
+
+#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)
+{
+    ModelAnimation *animations = NULL;
+
+    m3d_t *m3d = NULL;
+    int i = 0, j = 0;
+    *animCount = 0;
+
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    if (fileData != NULL)
+    {
+        m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
+
+        if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
+        {
+            TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d? m3d->errcode : -2);
+            UnloadFileData(fileData);
+            return NULL;
+        }
+        else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName, m3d->numaction, m3d->numbone, m3d->numskin);
+
+        // No animation or bones, exit out. skins are not required because some people use one animation for N models
+        if (!m3d->numaction || !m3d->numbone)
+        {
+            m3d_free(m3d);
+            UnloadFileData(fileData);
+            return NULL;
+        }
+
+        animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation));
+        *animCount = m3d->numaction;
+
+        for (unsigned int a = 0; a < m3d->numaction; a++)
+        {
+            animations[a].boneCount = m3d->numbone + 1;
+            BoneInfo *bones = (BoneInfo *)RL_CALLOC((m3d->numbone + 1), sizeof(BoneInfo));
+
+            animations[a].keyframeCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
+            animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
+            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;
+                snprintf(bones[i].name, sizeof(bones[i].name), "%s", m3d->bone[i].name);
+            }
+
+            // A special, never transformed "no bone" bone, used for boneless vertices
+            bones[i].parent = -1;
+            memcpy(bones[i].name, "NO BONE", 7);
+
+            // M3D stores frames at arbitrary intervals with sparse skeletons; Full skeletons is required at
+            // regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
+            for (i = 0; i < animations[a].keyframeCount; i++)
+            {
+                animations[a].keyframePoses[i] = (Transform *)RL_CALLOC((m3d->numbone + 1), sizeof(Transform));
+
+                m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
+
+                if (pose != NULL)
+                {
+                    for (j = 0; j < (int)m3d->numbone; j++)
+                    {
+                        animations[a].keyframePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale;
+                        animations[a].keyframePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale;
+                        animations[a].keyframePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z*m3d->scale;
+                        animations[a].keyframePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x;
+                        animations[a].keyframePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y;
+                        animations[a].keyframePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z;
+                        animations[a].keyframePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w;
+                        animations[a].keyframePoses[i][j].rotation = QuaternionNormalize(animations[a].keyframePoses[i][j].rotation);
+                        animations[a].keyframePoses[i][j].scale.x = animations[a].keyframePoses[i][j].scale.y = animations[a].keyframePoses[i][j].scale.z = 1.0f;
+
+                        // Child bones are stored in parent bone relative space, convert that into model space
+                        if (bones[j].parent >= 0)
+                        {
+                            animations[a].keyframePoses[i][j].rotation = QuaternionMultiply(animations[a].keyframePoses[i][bones[j].parent].rotation, animations[a].keyframePoses[i][j].rotation);
+                            animations[a].keyframePoses[i][j].translation = Vector3RotateByQuaternion(animations[a].keyframePoses[i][j].translation, animations[a].keyframePoses[i][bones[j].parent].rotation);
+                            animations[a].keyframePoses[i][j].translation = Vector3Add(animations[a].keyframePoses[i][j].translation, animations[a].keyframePoses[i][bones[j].parent].translation);
+                            animations[a].keyframePoses[i][j].scale = Vector3Multiply(animations[a].keyframePoses[i][j].scale, animations[a].keyframePoses[i][bones[j].parent].scale);
+                        }
+                    }
+
+                    // Default transform for the "no bone" bone
+                    animations[a].keyframePoses[i][j].translation.x = 0.0f;
+                    animations[a].keyframePoses[i][j].translation.y = 0.0f;
+                    animations[a].keyframePoses[i][j].translation.z = 0.0f;
+                    animations[a].keyframePoses[i][j].rotation.x = 0.0f;
+                    animations[a].keyframePoses[i][j].rotation.y = 0.0f;
+                    animations[a].keyframePoses[i][j].rotation.z = 0.0f;
+                    animations[a].keyframePoses[i][j].rotation.w = 1.0f;
+                    animations[a].keyframePoses[i][j].scale.x = 1.0f;
+                    animations[a].keyframePoses[i][j].scale.y = 1.0f;
+                    animations[a].keyframePoses[i][j].scale.z = 1.0f;
+
+                    RL_FREE(pose);
+                }
+            }
+
+            RL_FREE(bones);
+        }
+
+        m3d_free(m3d);
+        UnloadFileData(fileData);
+    }
+
+    return animations;
+}
+#endif
+
+#endif // SUPPORT_MODULE_RMODELS
diff --git a/raylib/src/rshapes.c b/raylib/src/rshapes.c
--- a/raylib/src/rshapes.c
+++ b/raylib/src/rshapes.c
@@ -8,2476 +8,4545 @@
 *       are used but QUADS implementation can be selected with SUPPORT_QUADS_DRAW_MODE define
 *
 *       Some functions define texture coordinates (rlTexCoord2f()) for the shapes and use a
-*       user-provided texture with SetShapesTexture(), the pourpouse of this implementation
-*       is allowing to reduce draw calls when combined with a texture-atlas
-*
-*       By default, raylib sets the default texture and rectangle at InitWindow()[rcore] to one
-*       white character of default font [rtext], this way, raylib text and shapes can be draw with
-*       a single draw call and it also allows users to configure it the same way with their own fonts
-*
-*   CONFIGURATION:
-*       #define SUPPORT_MODULE_RSHAPES
-*           rshapes module is included in the build
-*
-*       #define SUPPORT_QUADS_DRAW_MODE
-*           Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   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.
-*
-**********************************************************************************************/
-
-#include "raylib.h"     // Declares module functions
-
-#include "config.h"     // Defines module configuration flags
-
-#if defined(SUPPORT_MODULE_RSHAPES)
-
-#include "rlgl.h"       // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
-
-#include <math.h>       // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
-#include <float.h>      // Required for: FLT_EPSILON
-#include <stdlib.h>     // Required for: RL_FREE
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-// Error rate to calculate how many segments we need to draw a smooth circle,
-// taken from https://stackoverflow.com/a/2244088
-#ifndef SMOOTH_CIRCLE_ERROR_RATE
-    #define SMOOTH_CIRCLE_ERROR_RATE    0.5f      // Circle error rate
-#endif
-#ifndef SPLINE_SEGMENT_DIVISIONS
-    #define SPLINE_SEGMENT_DIVISIONS      24      // Spline segment divisions
-#endif
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// Not here...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static Texture2D texShapes = { 1, 1, 1, 1, 7 };                // Texture used on shapes drawing (white pixel loaded by rlgl)
-static Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f };    // Texture source rectangle used on shapes drawing
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static float EaseCubicInOut(float t, float b, float c, float d);    // Cubic easing
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-// Set texture and rectangle to be used on shapes drawing
-// NOTE: It can be useful when using basic shapes and one single font,
-// defining a font char white rectangle would allow drawing everything in a single draw call
-void SetShapesTexture(Texture2D texture, Rectangle source)
-{
-    // Reset texture to default pixel if required
-    // WARNING: Shapes texture should be probably better validated,
-    // it can break the rendering of all shapes if misused
-    if ((texture.id == 0) || (source.width == 0) || (source.height == 0))
-    {
-        texShapes = (Texture2D){ 1, 1, 1, 1, 7 };
-        texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
-    }
-    else
-    {
-        texShapes = texture;
-        texShapesRec = source;
-    }
-}
-
-// Get texture that is used for shapes drawing
-Texture2D GetShapesTexture(void)
-{
-    return texShapes;
-}
-
-// Get texture source rectangle that is used for shapes drawing
-Rectangle GetShapesTextureRectangle(void)
-{
-    return texShapesRec;
-}
-
-// Draw a pixel
-void DrawPixel(int posX, int posY, Color color)
-{
-    DrawPixelV((Vector2){ (float)posX, (float)posY }, color);
-}
-
-// Draw a pixel (Vector version)
-void DrawPixelV(Vector2 position, Color color)
-{
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-
-        rlNormal3f(0.0f, 0.0f, 1.0f);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(position.x, position.y);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(position.x, position.y + 1);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(position.x + 1, position.y + 1);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(position.x + 1, position.y);
-
-    rlEnd();
-
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlVertex2f(position.x, position.y);
-        rlVertex2f(position.x, position.y + 1);
-        rlVertex2f(position.x + 1, position.y);
-
-        rlVertex2f(position.x + 1, position.y);
-        rlVertex2f(position.x, position.y + 1);
-        rlVertex2f(position.x + 1, position.y + 1);
-
-    rlEnd();
-#endif
-}
-
-// Draw a line (using gl lines)
-void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
-{
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f((float)startPosX, (float)startPosY);
-        rlVertex2f((float)endPosX, (float)endPosY);
-    rlEnd();
-}
-
-// Draw a line defining thickness
-void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
-{
-    Vector2 delta = { endPos.x - startPos.x, endPos.y - startPos.y };
-    float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
-
-    if ((length > 0) && (thick > 0))
-    {
-        float scale = thick/(2*length);
-
-        Vector2 radius = { -scale*delta.y, scale*delta.x };
-        Vector2 strip[4] = {
-            { startPos.x - radius.x, startPos.y - radius.y },
-            { startPos.x + radius.x, startPos.y + radius.y },
-            { endPos.x - radius.x, endPos.y - radius.y },
-            { endPos.x + radius.x, endPos.y + radius.y }
-        };
-
-        DrawTriangleStrip(strip, 4, color);
-    }
-}
-
-// Draw a line (using gl lines)
-void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
-{
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(startPos.x, startPos.y);
-        rlVertex2f(endPos.x, endPos.y);
-    rlEnd();
-}
-
-// Draw lines sequuence (using gl lines)
-void DrawLineStrip(const Vector2 *points, int pointCount, Color color)
-{
-    if (pointCount < 2) return; // Security check
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        for (int i = 0; i < pointCount - 1; i++)
-        {
-            rlVertex2f(points[i].x, points[i].y);
-            rlVertex2f(points[i + 1].x, points[i + 1].y);
-        }
-    rlEnd();
-}
-
-// Draw line using cubic-bezier spline, in-out interpolation, no control points
-void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
-{
-    Vector2 previous = startPos;
-    Vector2 current = { 0 };
-
-    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
-    {
-        // Cubic easing in-out
-        // NOTE: Easing is calculated only for y position value
-        current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)SPLINE_SEGMENT_DIVISIONS);
-        current.x = previous.x + (endPos.x - startPos.x)/(float)SPLINE_SEGMENT_DIVISIONS;
-
-        float dy = current.y - previous.y;
-        float dx = current.x - previous.x;
-        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
-
-        if (i == 1)
-        {
-            points[0].x = previous.x + dy*size;
-            points[0].y = previous.y - dx*size;
-            points[1].x = previous.x - dy*size;
-            points[1].y = previous.y + dx*size;
-        }
-
-        points[2*i + 1].x = current.x - dy*size;
-        points[2*i + 1].y = current.y + dx*size;
-        points[2*i].x = current.x + dy*size;
-        points[2*i].y = current.y - dx*size;
-
-        previous = current;
-    }
-
-    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-}
-
-// Draw a dashed line
-void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color)
-{
-    // Calculate the vector and length of the line
-    float dx = endPos.x - startPos.x;
-    float dy = endPos.y - startPos.y;
-    float lineLength = sqrtf(dx*dx + dy*dy);
-
-    // If the line is too short for dashing or dash size is invalid, draw a solid thick line
-    if ((lineLength < (dashSize + spaceSize)) || (dashSize <= 0))
-    {
-        DrawLineV(startPos, endPos, color);
-        return;
-    }
-
-    // Calculate the normalized direction vector of the line
-    float invLineLength = 1.0f/lineLength;
-    float dirX = dx*invLineLength;
-    float dirY = dy*invLineLength;
-
-    Vector2 currentPos = startPos;
-    float distanceTraveled = 0;
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        while (distanceTraveled < lineLength)
-        {
-            // Calculate the end of the current dash
-            float dashEndDist = distanceTraveled + dashSize;
-            if (dashEndDist > lineLength) dashEndDist = lineLength;
-
-            Vector2 dashEndPos = { startPos.x + dashEndDist*dirX, startPos.y + dashEndDist*dirY };
-
-            // Draw the dash segment
-            rlVertex2f(currentPos.x, currentPos.y);
-            rlVertex2f(dashEndPos.x, dashEndPos.y);
-
-            // Update the distance traveled and move the current position for the next dash
-            distanceTraveled = dashEndDist + spaceSize;
-            currentPos.x = startPos.x + distanceTraveled*dirX;
-            currentPos.y = startPos.y + distanceTraveled*dirY;
-        }
-    rlEnd();
-}
-
-// Draw a color-filled circle
-void DrawCircle(int centerX, int centerY, float radius, Color color)
-{
-    DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color);
-}
-
-// Draw a color-filled circle (Vector version)
-// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
-void DrawCircleV(Vector2 center, float radius, Color color)
-{
-    DrawCircleSector(center, radius, 0, 360, 36, color);
-}
-
-// Draw a piece of a circle
-void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
-{
-    if (startAngle == endAngle) return;
-    if (radius <= 0.0f) radius = 0.1f;  // Avoid div by zero
-
-    // Function expects (endAngle > startAngle)
-    if (endAngle < startAngle)
-    {
-        // Swap values
-        float tmp = startAngle;
-        startAngle = endAngle;
-        endAngle = tmp;
-    }
-
-    int minSegments = (int)ceilf((endAngle - startAngle)/90);
-
-    if (segments < minSegments)
-    {
-        // 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)((endAngle - startAngle)*ceilf(2*PI/th)/360);
-
-        if (segments <= 0) segments = minSegments;
-    }
-
-    float stepLength = (endAngle - startAngle)/(float)segments;
-    float angle = startAngle;
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-
-        // NOTE: Every QUAD actually represents two segments
-        for (int i = 0; i < segments/2; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x, center.y);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2.0f))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2.0f))*radius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-
-            angle += (stepLength*2.0f);
-        }
-
-        // NOTE: In case number of segments is odd, we add one last piece to the cake
-        if ((((unsigned int)segments)%2) == 1)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x, center.y);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x, center.y);
-        }
-
-    rlEnd();
-
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-        for (int i = 0; i < segments; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-
-            angle += stepLength;
-        }
-    rlEnd();
-#endif
-}
-
-// Draw a piece of a circle outlines
-void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
-{
-    if (startAngle == endAngle) return;
-    if (radius <= 0.0f) radius = 0.1f;  // Avoid div by zero issue
-
-    // Function expects (endAngle > startAngle)
-    if (endAngle < startAngle)
-    {
-        // Swap values
-        float tmp = startAngle;
-        startAngle = endAngle;
-        endAngle = tmp;
-    }
-
-    int minSegments = (int)ceilf((endAngle - startAngle)/90);
-
-    if (segments < minSegments)
-    {
-        // 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)((endAngle - startAngle)*ceilf(2*PI/th)/360);
-
-        if (segments <= 0) segments = minSegments;
-    }
-
-    float stepLength = (endAngle - startAngle)/(float)segments;
-    float angle = startAngle;
-    bool showCapLines = true;
-
-    rlBegin(RL_LINES);
-        if (showCapLines)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-        }
-
-        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;
-        }
-
-        if (showCapLines)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-        }
-    rlEnd();
-}
-
-// Draw a gradient-filled circle
-void DrawCircleGradient(int centerX, int centerY, float radius, Color inner, Color outer)
-{
-    rlBegin(RL_TRIANGLES);
-        for (int i = 0; i < 360; i += 10)
-        {
-            rlColor4ub(inner.r, inner.g, inner.b, inner.a);
-            rlVertex2f((float)centerX, (float)centerY);
-            rlColor4ub(outer.r, outer.g, outer.b, outer.a);
-            rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius);
-            rlColor4ub(outer.r, outer.g, outer.b, outer.a);
-            rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius);
-        }
-    rlEnd();
-}
-
-// Draw circle outline
-void DrawCircleLines(int centerX, int centerY, float radius, Color color)
-{
-    DrawCircleLinesV((Vector2){ (float)centerX, (float)centerY }, radius, color);
-}
-
-// Draw circle outline (Vector version)
-void DrawCircleLinesV(Vector2 center, float radius, Color color)
-{
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
-        for (int i = 0; i < 360; i += 10)
-        {
-            rlVertex2f(center.x + cosf(DEG2RAD*i)*radius, center.y + sinf(DEG2RAD*i)*radius);
-            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radius, center.y + sinf(DEG2RAD*(i + 10))*radius);
-        }
-    rlEnd();
-}
-
-// Draw ellipse
-void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
-{
-    DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
-}
-
-// Draw ellipse (Vector version)
-void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
-{
-    rlBegin(RL_TRIANGLES);
-        for (int i = 0; i < 360; i += 10)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x,  center.y);
-            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
-            rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
-        }
-    rlEnd();
-}
-
-// Draw ellipse outline
-void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
-{
-    DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
-}
-
-// Draw ellipse outline
-void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
-{
-    rlBegin(RL_LINES);
-        for (int i = 0; i < 360; i += 10)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
-            rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
-        }
-    rlEnd();
-}
-
-// Draw ring
-void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
-{
-    if (startAngle == endAngle) return;
-
-    // Function expects (outerRadius > innerRadius)
-    if (outerRadius < innerRadius)
-    {
-        float tmp = outerRadius;
-        outerRadius = innerRadius;
-        innerRadius = tmp;
-
-        if (outerRadius <= 0.0f) outerRadius = 0.1f;
-    }
-
-    // Function expects (endAngle > startAngle)
-    if (endAngle < startAngle)
-    {
-        // Swap values
-        float tmp = startAngle;
-        startAngle = endAngle;
-        endAngle = tmp;
-    }
-
-    int minSegments = (int)ceilf((endAngle - startAngle)/90);
-
-    if (segments < minSegments)
-    {
-        // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
-        float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
-        segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
-
-        if (segments <= 0) segments = minSegments;
-    }
-
-    // Not a ring
-    if (innerRadius <= 0.0f)
-    {
-        DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color);
-        return;
-    }
-
-    float stepLength = (endAngle - startAngle)/(float)segments;
-    float angle = startAngle;
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        for (int i = 0; i < segments; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
-
-            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);
-
-            angle += stepLength;
-        }
-    rlEnd();
-
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-        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;
-        }
-    rlEnd();
-#endif
-}
-
-// Draw ring outline
-void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
-{
-    if (startAngle == endAngle) return;
-
-    // Function expects (outerRadius > innerRadius)
-    if (outerRadius < innerRadius)
-    {
-        float tmp = outerRadius;
-        outerRadius = innerRadius;
-        innerRadius = tmp;
-
-        if (outerRadius <= 0.0f) outerRadius = 0.1f;
-    }
-
-    // Function expects (endAngle > startAngle)
-    if (endAngle < startAngle)
-    {
-        // Swap values
-        float tmp = startAngle;
-        startAngle = endAngle;
-        endAngle = tmp;
-    }
-
-    int minSegments = (int)ceilf((endAngle - startAngle)/90);
-
-    if (segments < minSegments)
-    {
-        // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
-        float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
-        segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
-
-        if (segments <= 0) segments = minSegments;
-    }
-
-    if (innerRadius <= 0.0f)
-    {
-        DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color);
-        return;
-    }
-
-    float stepLength = (endAngle - startAngle)/(float)segments;
-    float angle = startAngle;
-    bool showCapLines = true;
-
-    rlBegin(RL_LINES);
-        if (showCapLines)
-        {
-            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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
-        }
-
-        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);
-
-            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);
-
-            angle += stepLength;
-        }
-
-        if (showCapLines)
-        {
-            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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
-        }
-    rlEnd();
-}
-
-// Draw a color-filled rectangle
-void DrawRectangle(int posX, int posY, int width, int height, Color color)
-{
-    DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color);
-}
-
-// Draw a color-filled rectangle (Vector version)
-// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues
-void DrawRectangleV(Vector2 position, Vector2 size, Color color)
-{
-    DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
-}
-
-// Draw a color-filled rectangle
-void DrawRectangleRec(Rectangle rec, Color color)
-{
-    DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
-}
-
-// Draw a color-filled rectangle with pro parameters
-void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
-{
-    Vector2 topLeft = { 0 };
-    Vector2 topRight = { 0 };
-    Vector2 bottomLeft = { 0 };
-    Vector2 bottomRight = { 0 };
-
-    // Only calculate rotation if needed
-    if (rotation == 0.0f)
-    {
-        float x = rec.x - origin.x;
-        float y = rec.y - origin.y;
-        topLeft = (Vector2){ x, y };
-        topRight = (Vector2){ x + rec.width, y };
-        bottomLeft = (Vector2){ x, y + rec.height };
-        bottomRight = (Vector2){ x + rec.width, y + rec.height };
-    }
-    else
-    {
-        float sinRotation = sinf(rotation*DEG2RAD);
-        float cosRotation = cosf(rotation*DEG2RAD);
-        float x = rec.x;
-        float y = rec.y;
-        float dx = -origin.x;
-        float dy = -origin.y;
-
-        topLeft.x = x + dx*cosRotation - dy*sinRotation;
-        topLeft.y = y + dx*sinRotation + dy*cosRotation;
-
-        topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation;
-        topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation;
-
-        bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation;
-        bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation;
-
-        bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation;
-        bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation;
-    }
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-
-        rlNormal3f(0.0f, 0.0f, 1.0f);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(topLeft.x, topLeft.y);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(bottomLeft.x, bottomLeft.y);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(bottomRight.x, bottomRight.y);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(topRight.x, topRight.y);
-
-    rlEnd();
-
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlVertex2f(topLeft.x, topLeft.y);
-        rlVertex2f(bottomLeft.x, bottomLeft.y);
-        rlVertex2f(topRight.x, topRight.y);
-
-        rlVertex2f(topRight.x, topRight.y);
-        rlVertex2f(bottomLeft.x, bottomLeft.y);
-        rlVertex2f(bottomRight.x, bottomRight.y);
-
-    rlEnd();
-#endif
-}
-
-// Draw a vertical-gradient-filled rectangle
-void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom)
-{
-    DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, top, bottom, bottom, top);
-}
-
-// Draw a horizontal-gradient-filled rectangle
-void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right)
-{
-    DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, left, left, right, right);
-}
-
-// Draw a gradient-filled rectangle
-void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight)
-{
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        rlNormal3f(0.0f, 0.0f, 1.0f);
-
-        // NOTE: Default raylib font character 95 is a white square
-        rlColor4ub(topLeft.r, topLeft.g, topLeft.b, topLeft.a);
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(rec.x, rec.y);
-
-        rlColor4ub(bottomLeft.r, bottomLeft.g, bottomLeft.b, bottomLeft.a);
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(rec.x, rec.y + rec.height);
-
-        rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(rec.x + rec.width, rec.y + rec.height);
-
-        rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(rec.x + rec.width, rec.y);
-    rlEnd();
-
-    rlSetTexture(0);
-}
-
-// Draw rectangle outline
-// WARNING: All Draw*Lines() functions use RL_LINES for drawing,
-// it implies flushing the current batch and changing draw mode to RL_LINES
-// but it solves another issue: https://github.com/raysan5/raylib/issues/3884
-void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
-{
-    Matrix mat = rlGetMatrixTransform();
-    float xOffset = 0.5f/mat.m0;
-    float yOffset = 0.5f/mat.m5;
-
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
-        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
-
-        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
-        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
-
-        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
-        rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
-
-        rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
-        rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
-    rlEnd();
-
-/*
-// Previous implementation, it has issues... but it does not require view matrix...
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    DrawRectangle(posX, posY, width, 1, color);
-    DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
-    DrawRectangle(posX, posY + height - 1, width, 1, color);
-    DrawRectangle(posX, posY + 1, 1, height - 2, color);
-#else
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f((float)posX, (float)posY);
-        rlVertex2f((float)posX + (float)width, (float)posY + 1);
-
-        rlVertex2f((float)posX + (float)width, (float)posY + 1);
-        rlVertex2f((float)posX + (float)width, (float)posY + (float)height);
-
-        rlVertex2f((float)posX + (float)width, (float)posY + (float)height);
-        rlVertex2f((float)posX + 1, (float)posY + (float)height);
-
-        rlVertex2f((float)posX + 1, (float)posY + (float)height);
-        rlVertex2f((float)posX + 1, (float)posY + 1);
-    rlEnd();
-#endif
-*/
-}
-
-// Draw rectangle outline with extended parameters
-void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color)
-{
-    if ((lineThick > rec.width) || (lineThick > rec.height))
-    {
-        if (rec.width >= rec.height) lineThick = rec.height/2;
-        else if (rec.width <= rec.height) lineThick = rec.width/2;
-    }
-
-    // When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following
-    // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
-    //
-    //   TTTTTTTT
-    //   TTTTTTTT
-    //   LL    RR
-    //   LL    RR
-    //   BBBBBBBB
-    //   BBBBBBBB
-    //
-
-    Rectangle top = { rec.x, rec.y, rec.width, lineThick };
-    Rectangle bottom = { rec.x, rec.y - lineThick + rec.height, rec.width, lineThick };
-    Rectangle left = { rec.x, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f };
-    Rectangle right = { rec.x - lineThick + rec.width, rec.y + lineThick, lineThick, rec.height - lineThick*2.0f };
-
-    DrawRectangleRec(top, color);
-    DrawRectangleRec(bottom, color);
-    DrawRectangleRec(left, color);
-    DrawRectangleRec(right, color);
-}
-
-// Draw rectangle with rounded edges
-void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color)
-{
-    // Not a rounded rectangle
-    if (roundness <= 0.0f)
-    {
-        DrawRectangleRec(rec, 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,
-    there are 9 parts to draw, also mark the 12 points we'll use
-
-          P0____________________P1
-          /|                    |\
-         /1|          2         |3\
-     P7 /__|____________________|__\ P2
-       |   |P8                P9|   |
-       | 8 |          9         | 4 |
-       | __|____________________|__ |
-     P6 \  |P11              P10|  / P3
-         \7|          6         |5/
-          \|____________________|/
-          P5                    P4
-    */
-    // Coordinates of the 12 points that define the rounded rect
-    const Vector2 point[12] = {
-        {(float)rec.x + radius, rec.y}, {(float)(rec.x + rec.width) - radius, rec.y}, { rec.x + rec.width, (float)rec.y + radius },     // PO, P1, P2
-        {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height},           // P3, P4
-        {(float)rec.x + radius, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radius}, {rec.x, (float)rec.y + radius},    // P5, P6, P7
-        {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius},                   // P8, P9
-        {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11
-    };
-
-    const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
-    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        // Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] 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];
-
-            // NOTE: Every QUAD actually represents two segments
-            for (int i = 0; i < segments/2; i++)
-            {
-                rlColor4ub(color.r, color.g, color.b, color.a);
-                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(center.x, center.y);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-
-                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-
-                angle += (stepLength*2);
-            }
-
-            // NOTE: In case number of segments is odd, we add one last piece to the cake
-            if (segments%2)
-            {
-                rlColor4ub(color.r, color.g, color.b, color.a);
-                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(center.x, center.y);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-
-                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(center.x, center.y);
-            }
-        }
-
-        // [2] 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);
-
-        // [4] 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[9].x, point[9].y);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(point[10].x, point[10].y);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(point[3].x, point[3].y);
-
-        // [6] Bottom Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(point[11].x, point[11].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[10].x, point[10].y);
-
-        // [8] Left Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(point[7].x, point[7].y);
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(point[6].x, point[6].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[8].x, point[8].y);
-
-        // [9] Middle Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(point[8].x, point[8].y);
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(point[11].x, point[11].y);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(point[10].x, point[10].y);
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(point[9].x, point[9].y);
-
-    rlEnd();
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-
-        // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] 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, center.y);
-                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
-                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
-                angle += stepLength;
-            }
-        }
-
-        // [2] 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);
-
-        // [4] Right Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(point[9].x, point[9].y);
-        rlVertex2f(point[10].x, point[10].y);
-        rlVertex2f(point[3].x, point[3].y);
-        rlVertex2f(point[2].x, point[2].y);
-        rlVertex2f(point[9].x, point[9].y);
-        rlVertex2f(point[3].x, point[3].y);
-
-        // [6] Bottom Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(point[11].x, point[11].y);
-        rlVertex2f(point[5].x, point[5].y);
-        rlVertex2f(point[4].x, point[4].y);
-        rlVertex2f(point[10].x, point[10].y);
-        rlVertex2f(point[11].x, point[11].y);
-        rlVertex2f(point[4].x, point[4].y);
-
-        // [8] 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[11].x, point[11].y);
-        rlVertex2f(point[8].x, point[8].y);
-        rlVertex2f(point[7].x, point[7].y);
-        rlVertex2f(point[11].x, point[11].y);
-
-        // [9] Middle Rectangle
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(point[8].x, point[8].y);
-        rlVertex2f(point[11].x, point[11].y);
-        rlVertex2f(point[10].x, point[10].y);
-        rlVertex2f(point[9].x, point[9].y);
-        rlVertex2f(point[8].x, point[8].y);
-        rlVertex2f(point[10].x, point[10].y);
-    rlEnd();
-#endif
-}
-
-// Draw rectangle with rounded edges
-void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
-{
-    // NOTE: For line thicknes <=1.0f we use RL_LINES, otherwise wee use RL_QUADS/RL_TRIANGLES
-    DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color);
-}
-
-// Draw rectangle with rounded edges outline
-void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color)
-{
-    if (lineThick < 0) lineThick = 0;
-
-    // Not a rounded rectangle
-    if (roundness <= 0.0f)
-    {
-        DrawRectangleLinesEx((Rectangle){rec.x-lineThick, rec.y-lineThick, rec.width+2*lineThick, rec.height+2*lineThick}, lineThick, 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)/2.0f);
-        if (segments <= 0) segments = 4;
-    }
-
-    float stepLength = 90.0f/(float)segments;
-    const float outerRadius = radius + lineThick, innerRadius = radius;
-
-    /*
-    Quick sketch to make sense of all of this,
-    marks the 16 + 4(corner centers P16-19) points we'll use
-
-           P0 ================== P1
-          // P8                P9 \\
-         //                        \\
-     P7 // P15                  P10 \\ P2
-       ||   *P16             P17*    ||
-       ||                            ||
-       || P14                   P11  ||
-     P6 \\  *P19             P18*   // P3
-         \\                        //
-          \\ P13              P12 //
-           P5 ================== P4
-    */
-    const Vector2 point[16] = {
-        {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f},
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f},
-        {rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2
-        {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4
-        {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f},
-        {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
-        {rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7
-        {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f},
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9
-        {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f},
-        {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f},
-        {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13
-        {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
-        {rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15
-    };
-
-    const Vector2 centers[4] = {
-        {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f},
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17
-        {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f},
-        {(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19
-    };
-
-    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
-
-    if (lineThick > 1)
-    {
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-        rlSetTexture(GetShapesTexture().id);
-        Rectangle shapeRect = GetShapesTextureRectangle();
-
-        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)
-            {
-                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 a triangle
-// NOTE: Vertex must be provided in counter-clockwise order
-void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
-{
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        rlNormal3f(0.0f, 0.0f, 1.0f);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(v1.x, v1.y);
-
-        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(v2.x, v2.y);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-        rlVertex2f(v3.x, v3.y);
-
-        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-        rlVertex2f(v3.x, v3.y);
-    rlEnd();
-
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(v1.x, v1.y);
-        rlVertex2f(v2.x, v2.y);
-        rlVertex2f(v3.x, v3.y);
-    rlEnd();
-#endif
-}
-
-// Draw a triangle using lines
-// NOTE: Vertex must be provided in counter-clockwise order
-void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
-{
-    rlBegin(RL_LINES);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlVertex2f(v1.x, v1.y);
-        rlVertex2f(v2.x, v2.y);
-
-        rlVertex2f(v2.x, v2.y);
-        rlVertex2f(v3.x, v3.y);
-
-        rlVertex2f(v3.x, v3.y);
-        rlVertex2f(v1.x, v1.y);
-    rlEnd();
-}
-
-// Draw a triangle fan defined by points
-// NOTE: First vertex provided is the center, shared by all triangles
-// By default, following vertex should be provided in counter-clockwise order
-void DrawTriangleFan(const Vector2 *points, int pointCount, Color color)
-{
-    if (pointCount >= 3)
-    {
-        rlSetTexture(GetShapesTexture().id);
-        Rectangle shapeRect = GetShapesTextureRectangle();
-
-        rlBegin(RL_QUADS);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            for (int i = 1; i < pointCount - 1; i++)
-            {
-                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(points[0].x, points[0].y);
-
-                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(points[i].x, points[i].y);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-                rlVertex2f(points[i + 1].x, points[i + 1].y);
-
-                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-                rlVertex2f(points[i + 1].x, points[i + 1].y);
-            }
-        rlEnd();
-        rlSetTexture(0);
-    }
-}
-
-// Draw a triangle strip defined by points
-// NOTE: Every new vertex connects with previous two
-void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color)
-{
-    if (pointCount >= 3)
-    {
-        rlBegin(RL_TRIANGLES);
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            for (int i = 2; i < pointCount; i++)
-            {
-                if ((i%2) == 0)
-                {
-                    rlVertex2f(points[i].x, points[i].y);
-                    rlVertex2f(points[i - 2].x, points[i - 2].y);
-                    rlVertex2f(points[i - 1].x, points[i - 1].y);
-                }
-                else
-                {
-                    rlVertex2f(points[i].x, points[i].y);
-                    rlVertex2f(points[i - 1].x, points[i - 1].y);
-                    rlVertex2f(points[i - 2].x, points[i - 2].y);
-                }
-            }
-        rlEnd();
-    }
-}
-
-// Draw a regular polygon of n sides (Vector version)
-void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
-{
-    if (sides < 3) sides = 3;
-    float centralAngle = rotation*DEG2RAD;
-    float angleStep = 360.0f/(float)sides*DEG2RAD;
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        for (int i = 0; i < sides; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            float nextAngle = centralAngle + angleStep;
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x, center.y);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-
-            centralAngle = nextAngle;
-        }
-    rlEnd();
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-        for (int i = 0; i < sides; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlVertex2f(center.x, center.y);
-            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-
-            centralAngle += angleStep;
-        }
-    rlEnd();
-#endif
-}
-
-// Draw a polygon outline of n sides
-void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
-{
-    if (sides < 3) sides = 3;
-    float centralAngle = rotation*DEG2RAD;
-    float angleStep = 360.0f/(float)sides*DEG2RAD;
-
-    rlBegin(RL_LINES);
-        for (int i = 0; i < sides; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
-
-            centralAngle += angleStep;
-        }
-    rlEnd();
-}
-
-void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color)
-{
-    if (sides < 3) sides = 3;
-    float centralAngle = rotation*DEG2RAD;
-    float exteriorAngle = 360.0f/(float)sides*DEG2RAD;
-    float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f));
-
-#if defined(SUPPORT_QUADS_DRAW_MODE)
-    rlSetTexture(GetShapesTexture().id);
-    Rectangle shapeRect = GetShapesTextureRectangle();
-
-    rlBegin(RL_QUADS);
-        for (int i = 0; i < sides; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            float nextAngle = centralAngle + exteriorAngle;
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-
-            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
-            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
-
-            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
-            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
-
-            centralAngle = nextAngle;
-        }
-    rlEnd();
-    rlSetTexture(0);
-#else
-    rlBegin(RL_TRIANGLES);
-        for (int i = 0; i < sides; i++)
-        {
-            rlColor4ub(color.r, color.g, color.b, color.a);
-            float nextAngle = centralAngle + exteriorAngle;
-
-            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
-            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
-            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
-
-            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
-            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
-            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
-
-            centralAngle = nextAngle;
-        }
-    rlEnd();
-#endif
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition - Splines functions
-//----------------------------------------------------------------------------------
-
-// Draw spline: linear, minimum 2 points
-void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color)
-{
-    if (pointCount < 2) return;
-
-#if defined(SUPPORT_SPLINE_MITERS)
-    Vector2 prevNormal = (Vector2){-(points[1].y - points[0].y), (points[1].x - points[0].x)};
-    float prevLength = sqrtf(prevNormal.x*prevNormal.x + prevNormal.y*prevNormal.y);
-
-    if (prevLength > 0.0f)
-    {
-        prevNormal.x /= prevLength;
-        prevNormal.y /= prevLength;
-    }
-    else
-    {
-        prevNormal.x = 0.0f;
-        prevNormal.y = 0.0f;
-    }
-
-    Vector2 prevRadius = { 0.5f*thick*prevNormal.x, 0.5f*thick*prevNormal.y };
-
-    for (int i = 0; i < pointCount - 1; i++)
-    {
-        Vector2 normal = { 0 };
-
-        if (i < pointCount - 2)
-        {
-            normal = (Vector2){-(points[i + 2].y - points[i + 1].y), (points[i + 2].x - points[i + 1].x)};
-            float normalLength = sqrtf(normal.x*normal.x + normal.y*normal.y);
-
-            if (normalLength > 0.0f)
-            {
-                normal.x /= normalLength;
-                normal.y /= normalLength;
-            }
-            else
-            {
-                normal.x = 0.0f;
-                normal.y = 0.0f;
-            }
-        }
-        else
-        {
-            normal = prevNormal;
-        }
-
-        Vector2 radius = { prevNormal.x + normal.x, prevNormal.y + normal.y };
-        float radiusLength = sqrtf(radius.x*radius.x + radius.y*radius.y);
-
-        if (radiusLength > 0.0f)
-        {
-            radius.x /= radiusLength;
-            radius.y /= radiusLength;
-        }
-        else
-        {
-            radius.x = 0.0f;
-            radius.y = 0.0f;
-        }
-
-        float cosTheta = radius.x*normal.x + radius.y*normal.y;
-
-        if (cosTheta != 0.0f)
-        {
-            radius.x *= (thick*0.5f/cosTheta);
-            radius.y *= (thick*0.5f/cosTheta);
-        }
-        else
-        {
-            radius.x = 0.0f;
-            radius.y = 0.0f;
-        }
-
-        Vector2 strip[4] = {
-            { points[i].x - prevRadius.x, points[i].y - prevRadius.y },
-            { points[i].x + prevRadius.x, points[i].y + prevRadius.y },
-            { points[i + 1].x - radius.x, points[i + 1].y - radius.y },
-            { points[i + 1].x + radius.x, points[i + 1].y + radius.y }
-        };
-
-        DrawTriangleStrip(strip, 4, color);
-
-        prevRadius = radius;
-        prevNormal = normal;
-    }
-
-#else   // !SUPPORT_SPLINE_MITERS
-
-    Vector2 delta = { 0 };
-    float length = 0.0f;
-    float scale = 0.0f;
-
-    for (int i = 0; i < pointCount - 1; i++)
-    {
-        delta = (Vector2){ points[i + 1].x - points[i].x, points[i + 1].y - points[i].y };
-        length = sqrtf(delta.x*delta.x + delta.y*delta.y);
-
-        if (length > 0) scale = thick/(2*length);
-
-        Vector2 radius = { -scale*delta.y, scale*delta.x };
-        Vector2 strip[4] = {
-            { points[i].x - radius.x, points[i].y - radius.y },
-            { points[i].x + radius.x, points[i].y + radius.y },
-            { points[i + 1].x - radius.x, points[i + 1].y - radius.y },
-            { points[i + 1].x + radius.x, points[i + 1].y + radius.y }
-        };
-
-        DrawTriangleStrip(strip, 4, color);
-    }
-#endif
-
-#if defined(SUPPORT_SPLINE_SEGMENT_CAPS)
-    // TODO: Add spline segment rounded caps at the begin/end of the spline
-#endif
-}
-
-// Draw spline: B-Spline, minimum 4 points
-void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color)
-{
-    if (pointCount < 4) return;
-
-    float a[4] = { 0 };
-    float b[4] = { 0 };
-    float dy = 0.0f;
-    float dx = 0.0f;
-    float size = 0.0f;
-
-    Vector2 currentPoint = { 0 };
-    Vector2 nextPoint = { 0 };
-    Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    for (int i = 0; i < (pointCount - 3); i++)
-    {
-        float t = 0.0f;
-        Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
-
-        a[0] = (-p1.x + 3.0f*p2.x - 3.0f*p3.x + p4.x)/6.0f;
-        a[1] = (3.0f*p1.x - 6.0f*p2.x + 3.0f*p3.x)/6.0f;
-        a[2] = (-3.0f*p1.x + 3.0f*p3.x)/6.0f;
-        a[3] = (p1.x + 4.0f*p2.x + p3.x)/6.0f;
-
-        b[0] = (-p1.y + 3.0f*p2.y - 3.0f*p3.y + p4.y)/6.0f;
-        b[1] = (3.0f*p1.y - 6.0f*p2.y + 3.0f*p3.y)/6.0f;
-        b[2] = (-3.0f*p1.y + 3.0f*p3.y)/6.0f;
-        b[3] = (p1.y + 4.0f*p2.y + p3.y)/6.0f;
-
-        currentPoint.x = a[3];
-        currentPoint.y = b[3];
-
-        if (i == 0) DrawCircleV(currentPoint, thick/2.0f, color);   // Draw init line circle-cap
-
-        if (i > 0)
-        {
-            vertices[0].x = currentPoint.x + dy*size;
-            vertices[0].y = currentPoint.y - dx*size;
-            vertices[1].x = currentPoint.x - dy*size;
-            vertices[1].y = currentPoint.y + dx*size;
-        }
-
-        for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
-        {
-            t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
-
-            nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
-            nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
-
-            dy = nextPoint.y - currentPoint.y;
-            dx = nextPoint.x - currentPoint.x;
-            size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
-
-            if ((i == 0) && (j == 1))
-            {
-                vertices[0].x = currentPoint.x + dy*size;
-                vertices[0].y = currentPoint.y - dx*size;
-                vertices[1].x = currentPoint.x - dy*size;
-                vertices[1].y = currentPoint.y + dx*size;
-            }
-
-            vertices[2*j + 1].x = nextPoint.x - dy*size;
-            vertices[2*j + 1].y = nextPoint.y + dx*size;
-            vertices[2*j].x = nextPoint.x + dy*size;
-            vertices[2*j].y = nextPoint.y - dx*size;
-
-            currentPoint = nextPoint;
-        }
-
-        DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-    }
-
-    // Cap circle drawing at the end of every segment
-    DrawCircleV(currentPoint, thick/2.0f, color);
-}
-
-// Draw spline: Catmull-Rom, minimum 4 points
-void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color)
-{
-    if (pointCount < 4) return;
-
-    float dy = 0.0f;
-    float dx = 0.0f;
-    float size = 0.0f;
-
-    Vector2 currentPoint = points[1];
-    Vector2 nextPoint = { 0 };
-    Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    DrawCircleV(currentPoint, thick/2.0f, color);   // Draw init line circle-cap
-
-    for (int i = 0; i < (pointCount - 3); i++)
-    {
-        float t = 0.0f;
-        Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
-
-        if (i > 0)
-        {
-            vertices[0].x = currentPoint.x + dy*size;
-            vertices[0].y = currentPoint.y - dx*size;
-            vertices[1].x = currentPoint.x - dy*size;
-            vertices[1].y = currentPoint.y + dx*size;
-        }
-
-        for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
-        {
-            t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
-
-            float q0 = (-1.0f*t*t*t) + (2.0f*t*t) + (-1.0f*t);
-            float q1 = (3.0f*t*t*t) + (-5.0f*t*t) + 2.0f;
-            float q2 = (-3.0f*t*t*t) + (4.0f*t*t) + t;
-            float q3 = t*t*t - t*t;
-
-            nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
-            nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
-
-            dy = nextPoint.y - currentPoint.y;
-            dx = nextPoint.x - currentPoint.x;
-            size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
-
-            if ((i == 0) && (j == 1))
-            {
-                vertices[0].x = currentPoint.x + dy*size;
-                vertices[0].y = currentPoint.y - dx*size;
-                vertices[1].x = currentPoint.x - dy*size;
-                vertices[1].y = currentPoint.y + dx*size;
-            }
-
-            vertices[2*j + 1].x = nextPoint.x - dy*size;
-            vertices[2*j + 1].y = nextPoint.y + dx*size;
-            vertices[2*j].x = nextPoint.x + dy*size;
-            vertices[2*j].y = nextPoint.y - dx*size;
-
-            currentPoint = nextPoint;
-        }
-
-        DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-    }
-
-    // Cap circle drawing at the end of every segment
-    DrawCircleV(currentPoint, thick/2.0f, color);
-}
-
-// Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
-void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color)
-{
-    if (pointCount >= 3)
-    {
-        for (int i = 0; i < pointCount - 2; i += 2) DrawSplineSegmentBezierQuadratic(points[i], points[i + 1], points[i + 2], thick, color);
-
-        // Cap circle drawing at the end of every segment
-        //for (int i = 2; i < pointCount - 2; i += 2) DrawCircleV(points[i], thick/2.0f, color);
-    }
-}
-
-// Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
-void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color)
-{
-    if (pointCount >= 4)
-    {
-        for (int i = 0; i < pointCount - 3; i += 3) DrawSplineSegmentBezierCubic(points[i], points[i + 1], points[i + 2], points[i + 3], thick, color);
-
-        // Cap circle drawing at the end of every segment
-        //for (int i = 3; i < pointCount - 3; i += 3) DrawCircleV(points[i], thick/2.0f, color);
-    }
-}
-
-// Draw spline segment: Linear, 2 points
-void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color)
-{
-    // NOTE: For the linear spline we don't use subdivisions, just a single quad
-
-    Vector2 delta = { p2.x - p1.x, p2.y - p1.y };
-    float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
-
-    if ((length > 0) && (thick > 0))
-    {
-        float scale = thick/(2*length);
-
-        Vector2 radius = { -scale*delta.y, scale*delta.x };
-        Vector2 strip[4] = {
-            { p1.x - radius.x, p1.y - radius.y },
-            { p1.x + radius.x, p1.y + radius.y },
-            { p2.x - radius.x, p2.y - radius.y },
-            { p2.x + radius.x, p2.y + radius.y }
-        };
-
-        DrawTriangleStrip(strip, 4, color);
-    }
-}
-
-// Draw spline segment: B-Spline, 4 points
-void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
-{
-    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
-
-    Vector2 currentPoint = { 0 };
-    Vector2 nextPoint = { 0 };
-    float t = 0.0f;
-
-    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    float a[4] = { 0 };
-    float b[4] = { 0 };
-
-    a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
-    a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
-    a[2] = (-3*p1.x + 3*p3.x)/6.0f;
-    a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
-
-    b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
-    b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
-    b[2] = (-3*p1.y + 3*p3.y)/6.0f;
-    b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
-
-    currentPoint.x = a[3];
-    currentPoint.y = b[3];
-
-    for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
-    {
-        t = step*(float)i;
-
-        nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
-        nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
-
-        float dy = nextPoint.y - currentPoint.y;
-        float dx = nextPoint.x - currentPoint.x;
-        float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
-
-        if (i == 1)
-        {
-            points[0].x = currentPoint.x + dy*size;
-            points[0].y = currentPoint.y - dx*size;
-            points[1].x = currentPoint.x - dy*size;
-            points[1].y = currentPoint.y + dx*size;
-        }
-
-        points[2*i + 1].x = nextPoint.x - dy*size;
-        points[2*i + 1].y = nextPoint.y + dx*size;
-        points[2*i].x = nextPoint.x + dy*size;
-        points[2*i].y = nextPoint.y - dx*size;
-
-        currentPoint = nextPoint;
-    }
-
-    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS+2, color);
-}
-
-// Draw spline segment: Catmull-Rom, 4 points
-void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
-{
-    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
-
-    Vector2 currentPoint = p1;
-    Vector2 nextPoint = { 0 };
-    float t = 0.0f;
-
-    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
-    {
-        t = step*(float)i;
-
-        float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
-        float q1 = (3*t*t*t) + (-5*t*t) + 2;
-        float q2 = (-3*t*t*t) + (4*t*t) + t;
-        float q3 = t*t*t - t*t;
-
-        nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
-        nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
-
-        float dy = nextPoint.y - currentPoint.y;
-        float dx = nextPoint.x - currentPoint.x;
-        float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
-
-        if (i == 1)
-        {
-            points[0].x = currentPoint.x + dy*size;
-            points[0].y = currentPoint.y - dx*size;
-            points[1].x = currentPoint.x - dy*size;
-            points[1].y = currentPoint.y + dx*size;
-        }
-
-        points[2*i + 1].x = nextPoint.x - dy*size;
-        points[2*i + 1].y = nextPoint.y + dx*size;
-        points[2*i].x = nextPoint.x + dy*size;
-        points[2*i].y = nextPoint.y - dx*size;
-
-        currentPoint = nextPoint;
-    }
-
-    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-}
-
-// Draw spline segment: Quadratic Bezier, 2 points, 1 control point
-void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color)
-{
-    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
-
-    Vector2 previous = p1;
-    Vector2 current = { 0 };
-    float t = 0.0f;
-
-    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
-    {
-        t = step*(float)i;
-
-        float a = powf(1.0f - t, 2);
-        float b = 2.0f*(1.0f - t)*t;
-        float c = powf(t, 2);
-
-        // NOTE: The easing functions aren't suitable here because they don't take a control point
-        current.y = a*p1.y + b*c2.y + c*p3.y;
-        current.x = a*p1.x + b*c2.x + c*p3.x;
-
-        float dy = current.y - previous.y;
-        float dx = current.x - previous.x;
-        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
-
-        if (i == 1)
-        {
-            points[0].x = previous.x + dy*size;
-            points[0].y = previous.y - dx*size;
-            points[1].x = previous.x - dy*size;
-            points[1].y = previous.y + dx*size;
-        }
-
-        points[2*i + 1].x = current.x - dy*size;
-        points[2*i + 1].y = current.y + dx*size;
-        points[2*i].x = current.x + dy*size;
-        points[2*i].y = current.y - dx*size;
-
-        previous = current;
-    }
-
-    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-}
-
-// Draw spline segment: Cubic Bezier, 2 points, 2 control points
-void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color)
-{
-    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
-
-    Vector2 previous = p1;
-    Vector2 current = { 0 };
-    float t = 0.0f;
-
-    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
-
-    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
-    {
-        t = step*(float)i;
-
-        float a = powf(1.0f - t, 3);
-        float b = 3.0f*powf(1.0f - t, 2)*t;
-        float c = 3.0f*(1.0f - t)*powf(t, 2);
-        float d = powf(t, 3);
-
-        current.y = a*p1.y + b*c2.y + c*c3.y + d*p4.y;
-        current.x = a*p1.x + b*c2.x + c*c3.x + d*p4.x;
-
-        float dy = current.y - previous.y;
-        float dx = current.x - previous.x;
-        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
-
-        if (i == 1)
-        {
-            points[0].x = previous.x + dy*size;
-            points[0].y = previous.y - dx*size;
-            points[1].x = previous.x - dy*size;
-            points[1].y = previous.y + dx*size;
-        }
-
-        points[2*i + 1].x = current.x - dy*size;
-        points[2*i + 1].y = current.y + dx*size;
-        points[2*i].x = current.x + dy*size;
-        points[2*i].y = current.y - dx*size;
-
-        previous = current;
-    }
-
-    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
-}
-
-// Get spline point for a given t [0.0f .. 1.0f], Linear
-Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t)
-{
-    Vector2 point = { 0 };
-
-    point.x = startPos.x*(1.0f - t) + endPos.x*t;
-    point.y = startPos.y*(1.0f - t) + endPos.y*t;
-
-    return point;
-}
-
-// Get spline point for a given t [0.0f .. 1.0f], B-Spline
-Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
-{
-    Vector2 point = { 0 };
-
-    float a[4] = { 0 };
-    float b[4] = { 0 };
-
-    a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
-    a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
-    a[2] = (-3*p1.x + 3*p3.x)/6.0f;
-    a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
-
-    b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
-    b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
-    b[2] = (-3*p1.y + 3*p3.y)/6.0f;
-    b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
-
-    point.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
-    point.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
-
-    return point;
-}
-
-// Get spline point for a given t [0.0f .. 1.0f], Catmull-Rom
-Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
-{
-    Vector2 point = { 0 };
-
-    float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
-    float q1 = (3*t*t*t) + (-5*t*t) + 2;
-    float q2 = (-3*t*t*t) + (4*t*t) + t;
-    float q3 = t*t*t - t*t;
-
-    point.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
-    point.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
-
-    return point;
-}
-
-// Get spline point for a given t [0.0f .. 1.0f], Quadratic Bezier
-Vector2 GetSplinePointBezierQuad(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
-{
-    Vector2 point = { 0 };
-
-    float a = powf(1.0f - t, 2);
-    float b = 2.0f*(1.0f - t)*t;
-    float c = powf(t, 2);
-
-    point.y = a*startPos.y + b*controlPos.y + c*endPos.y;
-    point.x = a*startPos.x + b*controlPos.x + c*endPos.x;
-
-    return point;
-}
-
-// Get spline point for a given t [0.0f .. 1.0f], Cubic Bezier
-Vector2 GetSplinePointBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
-{
-    Vector2 point = { 0 };
-
-    float a = powf(1.0f - t, 3);
-    float b = 3.0f*powf(1.0f - t, 2)*t;
-    float c = 3.0f*(1.0f - t)*powf(t, 2);
-    float d = powf(t, 3);
-
-    point.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y;
-    point.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x;
-
-    return point;
-}
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition - Collision Detection functions
-//----------------------------------------------------------------------------------
-
-// Check if point is inside rectangle
-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;
-}
-
-// Check if point is inside circle
-bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius)
-{
-    bool collision = false;
-
-    float distanceSquared = (point.x - center.x)*(point.x - center.x) + (point.y - center.y)*(point.y - center.y);
-
-    if (distanceSquared <= radius*radius) collision = true;
-
-    return collision;
-}
-
-// Check if point is inside a triangle defined by three points (p1, p2, p3)
-bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3)
-{
-    bool collision = false;
-
-    float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
-                  ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
-
-    float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
-                 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
-
-    float gamma = 1.0f - alpha - beta;
-
-    if ((alpha > 0) && (beta > 0) && (gamma > 0)) collision = true;
-
-    return collision;
-}
-
-// Check if point is within a polygon described by array of vertices
-// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php
-bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount)
-{
-    bool collision = false;
-
-    if (pointCount > 2)
-    {
-        for (int i = 0, j = pointCount - 1; i < pointCount; j = i++)
-        {
-            if ((points[i].y > point.y) != (points[j].y > point.y) &&
-                (point.x < (points[j].x - points[i].x)*(point.y - points[i].y)/(points[j].y - points[i].y) + points[i].x))
-            {
-                collision = !collision;
-            }
-        }
-    }
-
-    return collision;
-}
-
-// Check collision between two rectangles
-bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
-{
-    bool collision = false;
-
-    if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) &&
-        (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true;
-
-    return collision;
-}
-
-// Check collision between two circles
-bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
-{
-    bool collision = false;
-
-    float dx = center2.x - center1.x;      // X distance between centers
-    float dy = center2.y - center1.y;      // Y distance between centers
-
-    float distanceSquared = dx*dx + dy*dy; // Distance between centers squared
-    float radiusSum = radius1 + radius2;
-
-    collision = (distanceSquared <= (radiusSum*radiusSum));
-
-    return collision;
-}
-
-// Check collision between circle and rectangle
-// NOTE: Reviewed version to take into account corner limit case
-bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
-{
-    bool collision = false;
-
-    float recCenterX = rec.x + rec.width/2.0f;
-    float recCenterY = rec.y + rec.height/2.0f;
-
-    float dx = fabsf(center.x - recCenterX);
-    float dy = fabsf(center.y - recCenterY);
-
-    if (dx > (rec.width/2.0f + radius)) { return false; }
-    if (dy > (rec.height/2.0f + radius)) { return false; }
-
-    if (dx <= (rec.width/2.0f)) { return true; }
-    if (dy <= (rec.height/2.0f)) { return true; }
-
-    float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
-                             (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
-
-    collision = (cornerDistanceSq <= (radius*radius));
-
-    return collision;
-}
-
-// Check the collision between two lines defined by two points each, returns collision point by reference
-bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint)
-{
-    bool collision = false;
-
-    float div = (endPos2.y - startPos2.y)*(endPos1.x - startPos1.x) - (endPos2.x - startPos2.x)*(endPos1.y - startPos1.y);
-
-    if (fabsf(div) >= FLT_EPSILON)
-    {
-        collision = true;
-
-        float xi = ((startPos2.x - endPos2.x)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.x - endPos1.x)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div;
-        float yi = ((startPos2.y - endPos2.y)*(startPos1.x*endPos1.y - startPos1.y*endPos1.x) - (startPos1.y - endPos1.y)*(startPos2.x*endPos2.y - startPos2.y*endPos2.x))/div;
-
-        if (((fabsf(startPos1.x - endPos1.x) > FLT_EPSILON) && (xi < fminf(startPos1.x, endPos1.x) || (xi > fmaxf(startPos1.x, endPos1.x)))) ||
-            ((fabsf(startPos2.x - endPos2.x) > FLT_EPSILON) && (xi < fminf(startPos2.x, endPos2.x) || (xi > fmaxf(startPos2.x, endPos2.x)))) ||
-            ((fabsf(startPos1.y - endPos1.y) > FLT_EPSILON) && (yi < fminf(startPos1.y, endPos1.y) || (yi > fmaxf(startPos1.y, endPos1.y)))) ||
-            ((fabsf(startPos2.y - endPos2.y) > FLT_EPSILON) && (yi < fminf(startPos2.y, endPos2.y) || (yi > fmaxf(startPos2.y, endPos2.y))))) collision = false;
-
-        if (collision && (collisionPoint != 0))
-        {
-            collisionPoint->x = xi;
-            collisionPoint->y = yi;
-        }
-    }
-
-    return collision;
-}
-
-// Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
-bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold)
-{
-    bool collision = false;
-
-    float dxc = point.x - p1.x;
-    float dyc = point.y - p1.y;
-    float dxl = p2.x - p1.x;
-    float dyl = p2.y - p1.y;
-    float cross = dxc*dyl - dyc*dxl;
-
-    if (fabsf(cross) < (threshold*fmaxf(fabsf(dxl), fabsf(dyl))))
-    {
-        if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x));
-        else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y));
-    }
-
-    return collision;
-}
-
-// Check if circle collides with a line created between two points [p1] and [p2]
-bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2)
-{
-    float dx = p1.x - p2.x;
-    float dy = p1.y - p2.y;
-
-    if ((fabsf(dx) + fabsf(dy)) <= FLT_EPSILON)
-    {
-        return CheckCollisionCircles(p1, 0, center, radius);
-    }
-
-    float lengthSQ = ((dx*dx) + (dy*dy));
-    float dotProduct = (((center.x - p1.x)*(p2.x - p1.x)) + ((center.y - p1.y)*(p2.y - p1.y)))/(lengthSQ);
-
-    if (dotProduct > 1.0f) dotProduct = 1.0f;
-    else if (dotProduct < 0.0f) dotProduct = 0.0f;
-
-    float dx2 = (p1.x - (dotProduct*(dx))) - center.x;
-    float dy2 = (p1.y - (dotProduct*(dy))) - center.y;
-    float distanceSQ = ((dx2*dx2) + (dy2*dy2));
-
-    return (distanceSQ <= radius*radius);
-}
-
-// Get collision rectangle for two rectangles collision
-Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
-{
-    Rectangle overlap = { 0 };
-
-    float left = (rec1.x > rec2.x)? rec1.x : rec2.x;
-    float right1 = rec1.x + rec1.width;
-    float right2 = rec2.x + rec2.width;
-    float right = (right1 < right2)? right1 : right2;
-    float top = (rec1.y > rec2.y)? rec1.y : rec2.y;
-    float bottom1 = rec1.y + rec1.height;
-    float bottom2 = rec2.y + rec2.height;
-    float bottom = (bottom1 < bottom2)? bottom1 : bottom2;
-
-    if ((left < right) && (top < bottom))
-    {
-        overlap.x = left;
-        overlap.y = top;
-        overlap.width = right - left;
-        overlap.height = bottom - top;
-    }
-
-    return overlap;
-}
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-
-// Cubic easing in-out
-// NOTE: Used by DrawLineBezier() only
-static float EaseCubicInOut(float t, float b, float c, float d)
-{
-    float result = 0.0f;
-
-    if ((t /= 0.5f*d) < 1) result = 0.5f*c*t*t*t + b;
-    else
-    {
-        t -= 2;
-        result = 0.5f*c*(t*t*t + 2.0f) + b;
-    }
-
-    return result;
-}
-
-#endif      // SUPPORT_MODULE_RSHAPES
+*       user-provided texture with SetShapesTexture(), the purpose of this implementation
+*       is allowing to reduce draw calls when combined with a texture-atlas
+*
+*       By default, raylib sets the default texture and rectangle at InitWindow()[rcore] to one
+*       white character of default font [rtext], this way, raylib text and shapes can be drawn with
+*       a single draw call and it also allows users to configure it the same way with their own fonts
+*
+*   CONFIGURATION:
+*       #define SUPPORT_MODULE_RSHAPES      1
+*           rshapes module is included in the build
+*
+*       #define SUPPORT_QUADS_DRAW_MODE     1
+*           Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   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.
+*
+**********************************************************************************************/
+
+#include "raylib.h"     // Declares module functions
+
+#include "config.h"     // Defines module configuration flags
+
+#if SUPPORT_MODULE_RSHAPES
+
+#include "rlgl.h"       // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
+
+#include <math.h>       // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
+#include <float.h>      // Required for: FLT_EPSILON
+#include <stdlib.h>     // Required for: RL_FREE
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef SMOOTH_CIRCLE_ERROR_RATE
+    // Define error rate to calculate how many segments are needed to draw a smooth circle
+    // REF: https://stackoverflow.com/a/2244088
+    #define SMOOTH_CIRCLE_ERROR_RATE    0.5f      // Circle error rate
+#endif
+#ifndef SPLINE_SEGMENT_DIVISIONS
+    #define SPLINE_SEGMENT_DIVISIONS      24      // Spline segment divisions
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Not here...
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static Texture2D texShapes = { 1, 1, 1, 1, 7 };                // Texture used on shapes drawing (white pixel loaded by rlgl)
+static Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f };    // Texture source rectangle used on shapes drawing
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+static float EaseCubicInOut(float t, float b, float c, float d);    // Cubic easing
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Set texture and rectangle to be used on shapes drawing
+// NOTE: It can be useful when using basic shapes and one single font,
+// defining a font char white rectangle would allow drawing everything in a single draw call
+void SetShapesTexture(Texture2D texture, Rectangle rec)
+{
+    // Reset texture to default pixel if required
+    // WARNING: Shapes texture should be probably better validated,
+    // it can break the rendering of all shapes if misused
+    if ((texture.id == 0) || (rec.width == 0) || (rec.height == 0))
+    {
+        texShapes = (Texture2D){ 1, 1, 1, 1, 7 };
+        texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
+    }
+    else
+    {
+        texShapes = texture;
+        texShapesRec = rec;
+    }
+}
+
+// Get texture that is used for shapes drawing
+Texture2D GetShapesTexture(void)
+{
+    return texShapes;
+}
+
+// Get texture source rectangle that is used for shapes drawing
+Rectangle GetShapesTextureRectangle(void)
+{
+    return texShapesRec;
+}
+
+// Draw a pixel
+void DrawPixel(int posX, int posY, Color color)
+{
+    DrawPixelV((Vector2){ (float)posX, (float)posY }, color);
+}
+
+// Draw a pixel (Vector version)
+void DrawPixelV(Vector2 position, Color color)
+{
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlNormal3f(0.0f, 0.0f, 1.0f);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(position.x, position.y);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(position.x, position.y + 1);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(position.x + 1, position.y + 1);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(position.x + 1, position.y);
+
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlVertex2f(position.x, position.y);
+        rlVertex2f(position.x, position.y + 1);
+        rlVertex2f(position.x + 1, position.y);
+
+        rlVertex2f(position.x + 1, position.y);
+        rlVertex2f(position.x, position.y + 1);
+        rlVertex2f(position.x + 1, position.y + 1);
+
+    rlEnd();
+#endif
+}
+
+// Draw a line (using gl lines)
+void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f((float)startPosX, (float)startPosY);
+        rlVertex2f((float)endPosX, (float)endPosY);
+    rlEnd();
+}
+
+// Draw a line defining thickness
+void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
+{
+    Vector2 delta = { endPos.x - startPos.x, endPos.y - startPos.y };
+    float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
+
+    if ((length > 0) && (thick > 0))
+    {
+        float scale = thick/(2*length);
+
+        Vector2 radius = { -scale*delta.y, scale*delta.x };
+        Vector2 strip[4] = {
+            { startPos.x - radius.x, startPos.y - radius.y },
+            { startPos.x + radius.x, startPos.y + radius.y },
+            { endPos.x - radius.x, endPos.y - radius.y },
+            { endPos.x + radius.x, endPos.y + radius.y }
+        };
+
+        DrawTriangleStrip(strip, 4, color);
+    }
+}
+
+// Draw a line (using gl lines)
+void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f(startPos.x, startPos.y);
+        rlVertex2f(endPos.x, endPos.y);
+    rlEnd();
+}
+
+// Draw lines sequuence (using gl lines)
+void DrawLineStrip(const Vector2 *points, int pointCount, Color color)
+{
+    if (pointCount < 2) return; // Security check
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < pointCount - 1; i++)
+        {
+            rlVertex2f(points[i].x, points[i].y);
+            rlVertex2f(points[i + 1].x, points[i + 1].y);
+        }
+    rlEnd();
+}
+
+// Draw line using cubic-bezier spline, in-out interpolation, no control points
+void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
+{
+    Vector2 previous = startPos;
+    Vector2 current = { 0 };
+
+    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
+    {
+        // Cubic easing in-out
+        // NOTE: Easing is calculated only for y position value
+        current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)SPLINE_SEGMENT_DIVISIONS);
+        current.x = previous.x + (endPos.x - startPos.x)/(float)SPLINE_SEGMENT_DIVISIONS;
+
+        float dy = current.y - previous.y;
+        float dx = current.x - previous.x;
+        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
+
+        if (i == 1)
+        {
+            points[0].x = previous.x + dy*size;
+            points[0].y = previous.y - dx*size;
+            points[1].x = previous.x - dy*size;
+            points[1].y = previous.y + dx*size;
+        }
+
+        points[2*i + 1].x = current.x - dy*size;
+        points[2*i + 1].y = current.y + dx*size;
+        points[2*i].x = current.x + dy*size;
+        points[2*i].y = current.y - dx*size;
+
+        previous = current;
+    }
+
+    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+}
+
+// Draw a dashed line
+void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color)
+{
+    // Calculate the vector and length of the line
+    float dx = endPos.x - startPos.x;
+    float dy = endPos.y - startPos.y;
+    float lineLength = sqrtf(dx*dx + dy*dy);
+
+    // If the line is too short for dashing or dash size is invalid, draw a solid thick line
+    if ((lineLength < (dashSize + spaceSize)) || (dashSize <= 0))
+    {
+        DrawLineV(startPos, endPos, color);
+        return;
+    }
+
+    // Calculate the normalized direction vector of the line
+    float invLineLength = 1.0f/lineLength;
+    float dirX = dx*invLineLength;
+    float dirY = dy*invLineLength;
+
+    Vector2 currentPos = startPos;
+    float distanceTraveled = 0;
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        while (distanceTraveled < lineLength)
+        {
+            // Calculate the end of the current dash
+            float dashEndDist = distanceTraveled + dashSize;
+            if (dashEndDist > lineLength) dashEndDist = lineLength;
+
+            Vector2 dashEndPos = { startPos.x + dashEndDist*dirX, startPos.y + dashEndDist*dirY };
+
+            // Draw the dash segment
+            rlVertex2f(currentPos.x, currentPos.y);
+            rlVertex2f(dashEndPos.x, dashEndPos.y);
+
+            // Update the distance traveled and move the current position for the next dash
+            distanceTraveled = dashEndDist + spaceSize;
+            currentPos.x = startPos.x + distanceTraveled*dirX;
+            currentPos.y = startPos.y + distanceTraveled*dirY;
+        }
+    rlEnd();
+}
+
+// Draw a triangle
+// NOTE: Vertex must be provided in counter-clockwise order
+void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
+{
+    DrawTriangleGradient(v1, v2, v3, color, color, color);
+}
+
+// Draw triangle with interpolated colors (vertex in counter-clockwise order!)
+void DrawTriangleGradient(Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
+{
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        rlNormal3f(0.0f, 0.0f, 1.0f);
+
+        rlColor4ub(c1.r, c1.g, c1.b, c1.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v1.x, v1.y);
+
+        rlColor4ub(c2.r, c2.g, c2.b, c2.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v2.x, v2.y);
+
+        rlColor4ub(c3.r, c3.g, c3.b, c3.a);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v3.x, v3.y);
+
+        rlColor4ub(c3.r, c3.g, c3.b, c3.a);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v3.x, v3.y);
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(c1.r, c1.g, c1.b, c1.a);
+        rlVertex2f(v1.x, v1.y);
+        rlColor4ub(c2.r, c2.g, c2.b, c2.a);
+        rlVertex2f(v2.x, v2.y);
+        rlColor4ub(c3.r, c3.g, c3.b, c3.a);
+        rlVertex2f(v3.x, v3.y);
+    rlEnd();
+#endif
+}
+
+// Draw a triangle using lines
+// NOTE: Vertex must be provided in counter-clockwise order
+void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f(v1.x, v1.y);
+        rlVertex2f(v2.x, v2.y);
+
+        rlVertex2f(v2.x, v2.y);
+        rlVertex2f(v3.x, v3.y);
+
+        rlVertex2f(v3.x, v3.y);
+        rlVertex2f(v1.x, v1.y);
+    rlEnd();
+}
+
+// Draw a triangle using lines with thickness
+// NOTE: Vertex must be provided in counter-clockwise order
+void DrawTriangleLinesEx(Vector2 v1, Vector2 v2, Vector2 v3, float thick, Color color)
+{
+    /*
+    A sketch to make things simpler
+
+    The exterior points are v1-3, the interior points are v4-6, and the exterior edges are e1-3
+
+             v1
+             /\
+            /v4\
+           //  \\
+          //    \\
+      e3 //      \\ e2
+        //        \\
+       //          \\
+      //v5        v6\\
+     v2==============v3
+             e1
+    */
+
+    Vector2 e1 = {v2.x - v3.x, v2.y - v3.y};
+    Vector2 e2 = {v3.x - v1.x, v3.y - v1.y};
+    Vector2 e3 = {v1.x - v2.x, v1.y - v2.y};
+
+    float e1Length = sqrtf(e1.x*e1.x + e1.y*e1.y);
+    float e2Length = sqrtf(e2.x*e2.x + e2.y*e2.y);
+    float e3Length = sqrtf(e3.x*e3.x + e3.y*e3.y);
+
+    float perimeter = e1Length + e2Length + e3Length;
+    float semiperimeter = perimeter/2.0f;
+
+    // The incenter of a triangle is equidistant from each edge, which is useful for drawing a nice looking outline
+    Vector2 incenter = {
+        (e1Length*v1.x + e2Length*v2.x + e3Length*v3.x)/perimeter,
+        (e1Length*v1.y + e2Length*v2.y + e3Length*v3.y)/perimeter
+    };
+
+    // The inradius of a triangle is the radius of the biggest circle that can fit inside of said triangle
+    // That circle is also centered on the incenter
+    float inradius = sqrtf(((semiperimeter - e1Length)*(semiperimeter - e2Length)*(semiperimeter - e3Length))/semiperimeter);
+
+    // The triangle (v1, v2, v3) will be scaled by this to get (v4, v5, v6)
+    float scale = 1.0f - thick/inradius;
+
+    // Just a filled-in triangle
+    if (scale <= 0.0f)
+    {
+        DrawTriangle(v1, v2, v3, color);
+        return;
+    }
+
+    // In order for the scaling to be correct, the incenter has to be at the origin (0, 0) when scaling
+    Vector2 v4 = {incenter.x + (v1.x - incenter.x)*scale, incenter.y + (v1.y - incenter.y)*scale};
+    Vector2 v5 = {incenter.x + (v2.x - incenter.x)*scale, incenter.y + (v2.y - incenter.y)*scale};
+    Vector2 v6 = {incenter.x + (v3.x - incenter.x)*scale, incenter.y + (v3.y - incenter.y)*scale};
+
+    // Swap the vertices so the winding order is correct
+    if (thick < 0.0f)
+    {
+        Vector2 temp = v1;
+        v1 = v4;
+        v4 = temp;
+
+        temp = v2;
+        v2 = v5;
+        v5 = temp;
+
+        temp = v3;
+        v3 = v6;
+        v6 = temp;
+    }
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // Edge 3
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v1.x, v1.y);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v2.x, v2.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v5.x, v5.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v4.x, v4.y);
+
+        // Edge 1
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v2.x, v2.y);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v3.x, v3.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v6.x, v6.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v5.x, v5.y);
+
+        // Edge 2
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v3.x, v3.y);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v1.x, v1.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(v4.x, v4.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(v6.x, v6.y);
+
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // Edge 3
+        rlVertex2f(v1.x, v1.y);
+        rlVertex2f(v2.x, v2.y);
+        rlVertex2f(v4.x, v4.y);
+
+        rlVertex2f(v2.x, v2.y);
+        rlVertex2f(v5.x, v5.y);
+        rlVertex2f(v4.x, v4.y);
+
+        // Edge 1
+        rlVertex2f(v2.x, v2.y);
+        rlVertex2f(v3.x, v3.y);
+        rlVertex2f(v5.x, v5.y);
+
+        rlVertex2f(v3.x, v3.y);
+        rlVertex2f(v6.x, v6.y);
+        rlVertex2f(v5.x, v5.y);
+
+        // Edge 2
+        rlVertex2f(v3.x, v3.y);
+        rlVertex2f(v1.x, v1.y);
+        rlVertex2f(v4.x, v4.y);
+
+        rlVertex2f(v3.x, v3.y);
+        rlVertex2f(v4.x, v4.y);
+        rlVertex2f(v6.x, v6.y);
+
+    rlEnd();
+#endif
+}
+
+// Draw a triangle fan defined by points
+// NOTE: First vertex provided is the center, shared by all triangles
+// By default, following vertex should be provided in counter-clockwise order
+void DrawTriangleFan(const Vector2 *points, int pointCount, Color color)
+{
+    if (pointCount >= 3)
+    {
+        rlSetTexture(GetShapesTexture().id);
+        Rectangle shapeRect = GetShapesTextureRectangle();
+
+        rlBegin(RL_QUADS);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            for (int i = 1; i < pointCount - 1; i++)
+            {
+                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(points[0].x, points[0].y);
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(points[i].x, points[i].y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(points[i + 1].x, points[i + 1].y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(points[i + 1].x, points[i + 1].y);
+            }
+        rlEnd();
+        rlSetTexture(0);
+    }
+}
+
+// Draw a triangle strip defined by points
+// NOTE: Every new vertex connects with previous two
+void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color)
+{
+    if (pointCount >= 3)
+    {
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            for (int i = 2; i < pointCount; i++)
+            {
+                if ((i%2) == 0)
+                {
+                    rlVertex2f(points[i].x, points[i].y);
+                    rlVertex2f(points[i - 2].x, points[i - 2].y);
+                    rlVertex2f(points[i - 1].x, points[i - 1].y);
+                }
+                else
+                {
+                    rlVertex2f(points[i].x, points[i].y);
+                    rlVertex2f(points[i - 1].x, points[i - 1].y);
+                    rlVertex2f(points[i - 2].x, points[i - 2].y);
+                }
+            }
+        rlEnd();
+    }
+}
+
+// Draw a color-filled rectangle
+void DrawRectangle(int posX, int posY, int width, int height, Color color)
+{
+    DrawRectangleV((Vector2){ (float)posX, (float)posY }, (Vector2){ (float)width, (float)height }, color);
+}
+
+// Draw a color-filled rectangle (Vector version)
+// NOTE: On OpenGL 3.3 and ES2 using QUADS to avoid drawing order issues
+void DrawRectangleV(Vector2 position, Vector2 size, Color color)
+{
+    DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
+}
+
+// Draw a color-filled rectangle
+void DrawRectangleRec(Rectangle rec, Color color)
+{
+    DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
+}
+
+// Draw a color-filled rectangle with pro parameters
+void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
+{
+    Vector2 topLeft = { 0 };
+    Vector2 topRight = { 0 };
+    Vector2 bottomLeft = { 0 };
+    Vector2 bottomRight = { 0 };
+
+    // Only calculate rotation if needed
+    if (rotation == 0.0f)
+    {
+        float x = rec.x - origin.x;
+        float y = rec.y - origin.y;
+        topLeft = (Vector2){ x, y };
+        topRight = (Vector2){ x + rec.width, y };
+        bottomLeft = (Vector2){ x, y + rec.height };
+        bottomRight = (Vector2){ x + rec.width, y + rec.height };
+    }
+    else
+    {
+        float sinRotation = sinf(rotation*DEG2RAD);
+        float cosRotation = cosf(rotation*DEG2RAD);
+        float x = rec.x;
+        float y = rec.y;
+        float dx = -origin.x;
+        float dy = -origin.y;
+
+        topLeft.x = x + dx*cosRotation - dy*sinRotation;
+        topLeft.y = y + dx*sinRotation + dy*cosRotation;
+
+        topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation;
+        topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation;
+
+        bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation;
+        bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation;
+
+        bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation;
+        bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation;
+    }
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlNormal3f(0.0f, 0.0f, 1.0f);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(topLeft.x, topLeft.y);
+
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(bottomLeft.x, bottomLeft.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(bottomRight.x, bottomRight.y);
+
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(topRight.x, topRight.y);
+
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlVertex2f(topLeft.x, topLeft.y);
+        rlVertex2f(bottomLeft.x, bottomLeft.y);
+        rlVertex2f(topRight.x, topRight.y);
+
+        rlVertex2f(topRight.x, topRight.y);
+        rlVertex2f(bottomLeft.x, bottomLeft.y);
+        rlVertex2f(bottomRight.x, bottomRight.y);
+
+    rlEnd();
+#endif
+}
+
+// Draw a vertical-gradient-filled rectangle
+void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom)
+{
+    DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, top, bottom, bottom, top);
+}
+
+// Draw a horizontal-gradient-filled rectangle
+void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right)
+{
+    DrawRectangleGradientEx((Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, left, left, right, right);
+}
+
+// Draw a gradient-filled rectangle with custom vertex colors, counter-clockwise color order
+void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
+{
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        rlNormal3f(0.0f, 0.0f, 1.0f);
+
+        // NOTE: Default raylib font character 95 is a white square
+        rlColor4ub(col1.r, col1.g, col1.b, col1.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(rec.x, rec.y);
+
+        rlColor4ub(col2.r, col2.g, col2.b, col2.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(rec.x, rec.y + rec.height);
+
+        rlColor4ub(col3.r, col3.g, col3.b, col3.a);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(rec.x + rec.width, rec.y + rec.height);
+
+        rlColor4ub(col4.r, col4.g, col4.b, col4.a);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(rec.x + rec.width, rec.y);
+    rlEnd();
+
+    rlSetTexture(0);
+}
+
+// Draw rectangle outline
+// WARNING: All Draw*Lines() functions use RL_LINES for drawing,
+// it implies flushing the current batch and changing draw mode to RL_LINES
+// but it solves another issue: https://github.com/raysan5/raylib/issues/3884
+void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
+{
+    Matrix mat = rlGetMatrixTransform();
+    float xOffset = 0.5f/mat.m0;
+    float yOffset = 0.5f/mat.m5;
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
+        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
+
+        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset);
+        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
+
+        rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset);
+        rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
+
+        rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset);
+        rlVertex2f((float)posX + xOffset, (float)posY + yOffset);
+    rlEnd();
+
+/*
+// Previous implementation, it has issues... but it does not require view matrix...
+#if SUPPORT_QUADS_DRAW_MODE
+    DrawRectangle(posX, posY, width, 1, color);
+    DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
+    DrawRectangle(posX, posY + height - 1, width, 1, color);
+    DrawRectangle(posX, posY + 1, 1, height - 2, color);
+#else
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f((float)posX, (float)posY);
+        rlVertex2f((float)posX + (float)width, (float)posY + 1);
+
+        rlVertex2f((float)posX + (float)width, (float)posY + 1);
+        rlVertex2f((float)posX + (float)width, (float)posY + (float)height);
+
+        rlVertex2f((float)posX + (float)width, (float)posY + (float)height);
+        rlVertex2f((float)posX + 1, (float)posY + (float)height);
+
+        rlVertex2f((float)posX + 1, (float)posY + (float)height);
+        rlVertex2f((float)posX + 1, (float)posY + 1);
+    rlEnd();
+#endif
+*/
+}
+
+// Draw rectangle outline with line thickness
+void DrawRectangleLinesEx(Rectangle rec, float thick, Color color)
+{
+    if ((thick > rec.width/2) || (thick > rec.height/2))
+    {
+        if (rec.width >= rec.height) thick = rec.height/2;
+        else if (rec.width <= rec.height) thick = rec.width/2;
+    }
+
+    if (thick > 0.0f)
+    {
+        // When rec = { x, y, 8.0f, 6.0f } and thick = 2, the following
+        // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
+        //
+        //   TTTTTTTT
+        //   TTTTTTTT
+        //   LL    RR
+        //   LL    RR
+        //   BBBBBBBB
+        //   BBBBBBBB
+        //
+
+        Rectangle top = { rec.x, rec.y, rec.width, thick };
+        Rectangle bottom = { rec.x, rec.y - thick + rec.height, rec.width, thick };
+        Rectangle left = { rec.x, rec.y + thick, thick, rec.height - thick*2.0f };
+        Rectangle right = { rec.x - thick + rec.width, rec.y + thick, thick, rec.height - thick*2.0f };
+
+        DrawRectangleRec(top, color);
+        DrawRectangleRec(bottom, color);
+        DrawRectangleRec(left, color);
+        DrawRectangleRec(right, color);
+    }
+    else
+    {
+        // When rec = { x, y, 8.0f, 6.0f } and thick = -2, the following
+        // four rectangles are drawn ([T]op, [B]ottom, [L]eft, [R]ight):
+        //
+        //   TTTTTTTTTTTT
+        //   TTTTTTTTTTTT
+        //   LL        RR
+        //   LL        RR
+        //   LL        RR
+        //   LL        RR
+        //   LL        RR
+        //   LL        RR
+        //   BBBBBBBBBBBB
+        //   BBBBBBBBBBBB
+        //
+
+        thick *= -1.0f;
+
+        Rectangle top = { rec.x - thick, rec.y - thick, rec.width + thick*2.0f, thick };
+        Rectangle bottom = { rec.x - thick, rec.y + rec.height, rec.width + thick*2.0f, thick};
+        Rectangle left = { rec.x - thick, rec.y, thick, rec.height };
+        Rectangle right = { rec.x + rec.width, rec.y, thick, rec.height };
+
+        DrawRectangleRec(top, color);
+        DrawRectangleRec(bottom, color);
+        DrawRectangleRec(left, color);
+        DrawRectangleRec(right, color);
+    }
+}
+
+// Draw rectangle with rounded edges
+void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color)
+{
+    // Not a rounded rectangle
+    if (roundness <= 0.0f)
+    {
+        DrawRectangleRec(rec, 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,
+    there are 9 parts to draw, also mark the 12 points used
+
+          P0____________________P1
+          /|                    |\
+         /1|          2         |3\
+     P7 /__|____________________|__\ P2
+       |   |P8                P9|   |
+       | 8 |          9         | 4 |
+       | __|____________________|__ |
+     P6 \  |P11              P10|  / P3
+         \7|          6         |5/
+          \|____________________|/
+          P5                    P4
+    */
+    // Coordinates of the 12 points that define the rounded rect
+    const Vector2 point[12] = {
+        {(float)rec.x + radius, rec.y}, {(float)(rec.x + rec.width) - radius, rec.y}, { rec.x + rec.width, (float)rec.y + radius },     // PO, P1, P2
+        {rec.x + rec.width, (float)(rec.y + rec.height) - radius}, {(float)(rec.x + rec.width) - radius, rec.y + rec.height},           // P3, P4
+        {(float)rec.x + radius, rec.y + rec.height}, { rec.x, (float)(rec.y + rec.height) - radius}, {rec.x, (float)rec.y + radius},    // P5, P6, P7
+        {(float)rec.x + radius, (float)rec.y + radius}, {(float)(rec.x + rec.width) - radius, (float)rec.y + radius},                   // P8, P9
+        {(float)(rec.x + rec.width) - radius, (float)(rec.y + rec.height) - radius}, {(float)rec.x + radius, (float)(rec.y + rec.height) - radius} // P10, P11
+    };
+
+    const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
+    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        // Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] 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];
+
+            // NOTE: Every QUAD actually represents two segments
+            for (int i = 0; i < segments/2; i++)
+            {
+                rlColor4ub(color.r, color.g, color.b, color.a);
+                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(center.x, center.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
+                angle += (stepLength*2);
+            }
+
+            // NOTE: In case number of segments is odd, adding one last piece to the cake
+            if (segments%2)
+            {
+                rlColor4ub(color.r, color.g, color.b, color.a);
+                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(center.x, center.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(center.x, center.y);
+            }
+        }
+
+        // [2] 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);
+
+        // [4] 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[9].x, point[9].y);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(point[10].x, point[10].y);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(point[3].x, point[3].y);
+
+        // [6] Bottom Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(point[11].x, point[11].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[10].x, point[10].y);
+
+        // [8] Left Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(point[7].x, point[7].y);
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(point[6].x, point[6].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[8].x, point[8].y);
+
+        // [9] Middle Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(point[8].x, point[8].y);
+        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(point[11].x, point[11].y);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+        rlVertex2f(point[10].x, point[10].y);
+        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+        rlVertex2f(point[9].x, point[9].y);
+
+    rlEnd();
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        // Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] 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, center.y);
+                rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+                rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+                angle += stepLength;
+            }
+        }
+
+        // [2] 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);
+
+        // [4] Right Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f(point[9].x, point[9].y);
+        rlVertex2f(point[10].x, point[10].y);
+        rlVertex2f(point[3].x, point[3].y);
+        rlVertex2f(point[2].x, point[2].y);
+        rlVertex2f(point[9].x, point[9].y);
+        rlVertex2f(point[3].x, point[3].y);
+
+        // [6] Bottom Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f(point[11].x, point[11].y);
+        rlVertex2f(point[5].x, point[5].y);
+        rlVertex2f(point[4].x, point[4].y);
+        rlVertex2f(point[10].x, point[10].y);
+        rlVertex2f(point[11].x, point[11].y);
+        rlVertex2f(point[4].x, point[4].y);
+
+        // [8] 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[11].x, point[11].y);
+        rlVertex2f(point[8].x, point[8].y);
+        rlVertex2f(point[7].x, point[7].y);
+        rlVertex2f(point[11].x, point[11].y);
+
+        // [9] Middle Rectangle
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex2f(point[8].x, point[8].y);
+        rlVertex2f(point[11].x, point[11].y);
+        rlVertex2f(point[10].x, point[10].y);
+        rlVertex2f(point[9].x, point[9].y);
+        rlVertex2f(point[8].x, point[8].y);
+        rlVertex2f(point[10].x, point[10].y);
+    rlEnd();
+#endif
+}
+
+// Draw rectangle with rounded edges
+void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color 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
+    */
+
+    // The x-coordinates used for the outline
+    const float x0 = rec.x + radius + 0.5f;
+    const float x1 = (rec.x + rec.width) - radius - 0.5f;
+    const float x2 = rec.x + rec.width - 0.5f;
+    const float x3 = rec.x + 0.5f;
+
+    // The y-coordinates used for the outline
+    const float y0 = rec.y + 0.5f;
+    const float y1 = rec.y + radius + 0.5f;
+    const float y2 = (rec.y + rec.height) - radius - 0.5f;
+    const float y3 = rec.y + rec.height - 0.5f;
+
+    const Vector2 point[8] = {
+        {x0, y0}, // P0
+        {x1, y0}, // P1
+        {x2, y1}, // P2
+        {x2, y2}, // P3
+        {x1, y3}, // P4
+        {x0, y3}, // P5
+        {x3, y2}, // P6
+        {x3, y1}, // P7
+    };
+
+    const Vector2 centers[4] = {
+        {x0, y1}, // P16
+        {x1, y1}, // P17
+        {x1, y2}, // P18
+        {x0, y2}  // 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
+void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color)
+{
+    // Not a rounded rectangle
+    if (roundness <= 0.0f)
+    {
+        DrawRectangleLinesEx(rec, thick, color);
+        return;
+    }
+
+    if (roundness >= 1.0f) roundness = 1.0f;
+
+    float radius = 0.0f;
+    float roundedOutlineThick = 0.0f;
+    float outerRadius = 0.0f;
+    float innerRadius = 0.0f;
+    if (thick >= 0.0f)
+    {
+        // Calculate corner radius
+        radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
+        if (radius <= 0.0f) return;
+
+        outerRadius = radius;
+        innerRadius = outerRadius - thick;
+
+        // The maximum thickness the outline can have and still be rounded on the interior edge is equal to the corner radius
+        // Put another way, when `innerRadius <= 0`, the interior of the outline is just a normal rectangle with no rounding
+        if (innerRadius <= 0.0f)
+        {
+            innerRadius = 0.0f;
+            roundedOutlineThick = outerRadius;
+
+            // Draw the not-rounded portion of the outline
+            DrawRectangleLinesEx((Rectangle){ rec.x + outerRadius, rec.y + outerRadius, rec.width - outerRadius*2.0f, rec.height - outerRadius*2.0f }, thick - outerRadius, color);
+        }
+        else
+        {
+            roundedOutlineThick = thick;
+        }
+
+        // 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/outerRadius, 2) - 1);
+            segments = (int)ceilf((2*PI/th)/4.0f);
+            if (segments <= 0) segments = 4;
+        }
+    }
+    else
+    {
+        thick *= -1.0f;
+
+        // Calculate corner radius
+        radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2;
+        if (radius <= 0.0f) return; // Only possible if the rectangle has 0 width or height
+
+        // Expand the rectangle
+        rec.x -= thick;
+        rec.y -= thick;
+        rec.width += thick*2.0f;
+        rec.height += thick*2.0f;
+
+        innerRadius = radius;
+        outerRadius = innerRadius + thick;
+        roundedOutlineThick = thick;
+
+        // 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/innerRadius, 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 16 + 4(corner centers P16-19) points used
+
+           P0 ================== P1
+          // P8                P9 \\
+         //                        \\
+     P7 // P15                  P10 \\ P2
+       ||   *P16             P17*    ||
+       ||                            ||
+       || P14                   P11  ||
+     P6 \\  *P19             P18*   // P3
+         \\                        //
+          \\ P13              P12 //
+           P5 ================== P4
+    */
+
+    // The x-coordinates used for the outline
+    const float x0 = rec.x + outerRadius;
+    const float x1 = (rec.x + rec.width) - outerRadius;
+    const float x2 = rec.x + rec.width;
+    const float x3 = rec.x;
+    const float x4 = rec.x + rec.width - roundedOutlineThick;
+    const float x5 = rec.x + roundedOutlineThick;
+
+    // The y-coordinates used for the outline
+    const float y0 = rec.y;
+    const float y1 = rec.y + outerRadius;
+    const float y2 = (rec.y + rec.height) - outerRadius;
+    const float y3 = rec.y + rec.height;
+    const float y4 = rec.y + roundedOutlineThick;
+    const float y5 = rec.y + rec.height - roundedOutlineThick;
+
+    const Vector2 point[16] = {
+        {x0, y0}, // P0
+        {x1, y0}, // P1
+        {x2, y1}, // P2
+        {x2, y2}, // P3
+        {x1, y3}, // P4
+        {x0, y3}, // P5
+        {x3, y2}, // P6
+        {x3, y1}, // P7
+        {x0, y4}, // P8
+        {x1, y4}, // P9
+        {x4, y1}, // P10
+        {x4, y2}, // P11
+        {x1, y5}, // P12
+        {x0, y5}, // P13
+        {x5, y2}, // P14
+        {x5, y1}  // P15
+    };
+
+    const Vector2 centers[4] = {
+        {x0, y1}, // P16
+        {x1, y1}, // P17
+        {x1, y2}, // P18
+        {x0, y2}  // P19
+    };
+
+    const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    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
+}
+
+// Draw a polygon of n sides
+void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
+{
+    if (sides < 3) sides = 3;
+    float centralAngle = rotation*DEG2RAD;
+    float angleStep = 360.0f/(float)sides*DEG2RAD;
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        for (int i = 0; i < sides; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            float nextAngle = centralAngle + angleStep;
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x, center.y);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+
+            centralAngle = nextAngle;
+        }
+    rlEnd();
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+        for (int i = 0; i < sides; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+
+            centralAngle += angleStep;
+        }
+    rlEnd();
+#endif
+}
+
+// Draw a polygon outline of n sides
+void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
+{
+    if (sides < 3) sides = 3;
+    float centralAngle = rotation*DEG2RAD;
+    float angleStep = 360.0f/(float)sides*DEG2RAD;
+
+    rlBegin(RL_LINES);
+        for (int i = 0; i < sides; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
+            rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
+
+            centralAngle += angleStep;
+        }
+    rlEnd();
+}
+
+void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float thick, Color color)
+{
+    if (sides < 3) sides = 3;
+    float centralAngle = rotation*DEG2RAD;
+    float exteriorAngle = 360.0f/(float)sides*DEG2RAD;
+    float apothem = radius*cosf(DEG2RAD*180.0f/(float)sides);
+
+    float outerRadius = 0.0f;
+    float innerRadius = 0.0f;
+    if (thick >= 0.0f)
+    {
+        outerRadius = radius;
+        innerRadius = fmaxf(0.0f, radius - thick*(radius/apothem));
+    }
+    else
+    {
+        thick *= -1.0f;
+        outerRadius = radius + thick*(radius/apothem);
+        innerRadius = radius;
+    }
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        for (int i = 0; i < sides; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            float nextAngle = centralAngle + exteriorAngle;
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(centralAngle)*outerRadius, center.y + sinf(centralAngle)*outerRadius);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
+
+            centralAngle = nextAngle;
+        }
+    rlEnd();
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+        for (int i = 0; i < sides; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            float nextAngle = centralAngle + exteriorAngle;
+
+            rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
+            rlVertex2f(center.x + cosf(centralAngle)*outerRadius, center.y + sinf(centralAngle)*outerRadius);
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
+
+            rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
+            rlVertex2f(center.x + cosf(nextAngle)*outerRadius, center.y + sinf(nextAngle)*outerRadius);
+
+            centralAngle = nextAngle;
+        }
+    rlEnd();
+#endif
+}
+
+// Draw a color-filled circle
+void DrawCircle(int centerX, int centerY, float radius, Color color)
+{
+    DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color);
+}
+
+// Draw a color-filled circle (Vector version)
+// NOTE: On OpenGL 3.3 and ES2 using QUADS to avoid drawing order issues
+void DrawCircleV(Vector2 center, float radius, Color color)
+{
+    DrawCircleSector(center, radius, 0, 360, 36, color);
+}
+
+// Draw a gradient-filled circle
+void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer)
+{
+    rlBegin(RL_TRIANGLES);
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlColor4ub(inner.r, inner.g, inner.b, inner.a);
+            rlVertex2f(center.x, center.y);
+            rlColor4ub(outer.r, outer.g, outer.b, outer.a);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radius, center.y + sinf(DEG2RAD*(i + 10))*radius);
+            rlColor4ub(outer.r, outer.g, outer.b, outer.a);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*radius, center.y + sinf(DEG2RAD*i)*radius);
+        }
+    rlEnd();
+}
+
+// Draw a piece of a circle
+void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
+{
+    if (startAngle == endAngle) return;
+    if (radius <= 0.0f) radius = 0.1f;  // Avoid div by zero
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f) endAngle = startAngle + 360.0f;
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // 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((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+    float angle = startAngle;
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        // NOTE: Every QUAD actually represents two segments
+        for (int i = 0; i < segments/2; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x, center.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2.0f))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2.0f))*radius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
+            angle += (stepLength*2.0f);
+        }
+
+        // NOTE: In case number of segments is odd, adding one last piece to the cake
+        if ((((unsigned int)segments)%2) == 1)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x, center.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x, center.y);
+        }
+
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+        for (int i = 0; i < segments; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+
+            angle += stepLength;
+        }
+    rlEnd();
+#endif
+}
+
+// Draw a piece of a circle outlines
+void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color)
+{
+    if (startAngle == endAngle) return;
+    if (radius <= 0.0f) radius = 0.1f;  // Avoid div by zero issue
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    bool showCapLines = true;
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f)
+    {
+        showCapLines = false;
+        endAngle = startAngle + 360.0f;
+    }
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // 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((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+    float angle = startAngle;
+
+    rlBegin(RL_LINES);
+        if (showCapLines)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+        }
+
+        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;
+        }
+
+        if (showCapLines)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
+        }
+    rlEnd();
+}
+
+// Draw a piece of a circle outlines with thickness
+void DrawCircleSectorLinesEx(Vector2 center, float radius, float startAngle, float endAngle, int segments, float thick, Color color)
+{
+    if (startAngle == endAngle) return;
+    if (radius <= 0.0f) radius = 0.1f;  // Avoid div by zero issue
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    bool showCapLines = true;
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f)
+    {
+        showCapLines = thick >= 0.0f;
+        endAngle = startAngle + 360.0f;
+    }
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // 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((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+    float angle = startAngle;
+
+    /*
+    A sketch to help make things clearer
+
+    NOTE: Some considerations are different when `thick` is negative
+          The vertices used here are still relevant, but would instead be outside of the circle
+          S0 is always the center
+
+    The circle sector outline is drawn in 3 main pieces, the circle outline, cap 1, and cap 2
+    The circle outline is self explanatory
+    Cap 1 covers the `startAngle` edge and cap 2 covers the `endAngle` edge
+    S0 is the first shared point between the caps, and also the circle's center
+    S1 is the second shared point (sometimes not shared) between the caps
+      S1 is also C0 and C3 in this sketch. In certain cases, S1 goes outside of
+      the circle and C0 and C3 become different points
+    C1 is one of cap 1's vertices that is on the inside edge of the circle outline
+    C2 is like C1, but is also on the `startAngle` edge
+    C4 is cap 2's vertex that corresponds with C1
+    C5 is cap 2's vertex that corresponds with C2, except on the `endAngle` edge
+
+                   [][][][][]
+               [][]        []
+             []      []C4[]C5
+           []    [][]  {}  {}
+         []    []      {}  {}
+       []    []        {}C {} <- endAngle
+       []  []          {}a {}
+     []    []          {}p {}
+     []  []            {}2 {}
+     []  []            {}  {}
+     []  []            {}  {}     startAngle
+     []  []            {}  S0{}{}{}{}{}{}{}{}C2[][]
+     []  []            {}{}       Cap1       []  []
+     []  []            S1{}{}{}{}{}{}{}{}{}{}C1  []
+     []  []                                  []  []
+     []    []                              []    []
+       []  []       Not filled in          []  []
+       []    []                          []    []
+         []    []                      []    []
+           []    [][]              [][]    []
+             []      [][][][][][][]      []
+               [][]  Circle outline  [][]
+                   [][][][][][][][][]
+
+    [] = Circle outline edge pixel
+    {} = Cap outline edge pixel
+    */
+
+    // We are not drawing a circle, we are drawing an n-sided polygon
+    // So, we need to adjust the outline thickness of the "circle" for it to look correct with fewer segments
+    float apothem = radius*cosf(DEG2RAD*((endAngle - startAngle)/2.0f)/(float)segments);
+    float radiusThick = thick*(radius/apothem);
+
+    float outerRadius = radius;
+    float innerRadius = radius - radiusThick;
+
+    if (thick >= 0.0f)
+    {
+        if (thick >= innerRadius)
+        {
+            DrawCircleSector(center, radius, startAngle, endAngle, segments, color);
+            return;
+        }
+    }
+    else
+    {
+        float tmp = outerRadius;
+        outerRadius = innerRadius;
+        innerRadius = tmp;
+    }
+
+    // Cap 1 vertices
+    Vector2 c0 = { 0 };
+    Vector2 c1 = { 0 };
+    Vector2 c2 = { 0 };
+
+    // Cap 2 vertices
+    Vector2 c3 = { 0 };
+    Vector2 c4 = { 0 };
+    Vector2 c5 = { 0 };
+
+    // The number of angle steps that come before C1 (from `startAngle`, counter clockwise)
+    int stepsBeforeC1 = 0;
+    bool s1OutsideOfCircle = false;
+    // The number of angle steps that come before C0 (from `startAngle`, counter clockwise)
+    // Only used if S1 is outside of the circle
+    int stepsBeforeC0 = 0;
+
+    if (showCapLines)
+    {
+        if (thick >= 0.0f)
+        {
+            c2 = (Vector2){ center.x + cosf(DEG2RAD*startAngle)*innerRadius, center.y + sinf(DEG2RAD*startAngle)*innerRadius };
+            c5 = (Vector2){ center.x + cosf(DEG2RAD*endAngle)*innerRadius, center.y + sinf(DEG2RAD*endAngle)*innerRadius };
+
+            // For C1 and C4, we need to find the point that lies on the circle (n-sided polygon, actually)
+            // We want C1 and C4 to be `thick` pixels perpendicularly from the `startAngle` and `endAngle` edges
+            // and to be on the `innerRadius` edge
+
+            float c1Angle = RAD2DEG*asinf(thick/innerRadius);
+
+            // There are more segments before C1 than there are segments being drawn,
+            // so the whole circle sector must be covered
+            if (c1Angle/stepLength >= (float)segments)
+            {
+                DrawCircleSector(center, radius, startAngle, endAngle, segments, color);
+                return;
+            }
+
+            // Do this after the previous check just in case `stepLength` is really small and
+            // dividing by it produces a very large number
+            stepsBeforeC1 = (int)(c1Angle/stepLength);
+
+            // The angles of the vertices on the circle outline before and after C1
+            float vertexAngleBeforeC1 = stepLength*(float)stepsBeforeC1;
+            float vertexAngleAfterC1 = stepLength*((float)(stepsBeforeC1 + 1));
+
+            /*
+            Here is another sketch
+
+            We know which outline line segment C1 is on (`vertexAngleBeforeC1` and `vertexAngleAfterC1`)
+            Now we just need to know where on that line segment C1 is
+
+            We can change our frame of reference so that `startAngle` is 0 degrees and `center` is at the origin (0, 0)
+            This makes the math much simpler because now we can just go straight down by `thick` pixels and
+            use the horizontal line that passes through that point to determine where C1 is on our line segment
+
+            The line segment is defined by p1 and p2, we need C1, which is on that edge
+            The 'y' axis of C1 is equal to `thick` (within this modified frame of reference)
+
+                         p1
+                         /|
+                        / |
+                       /  |
+                      /   |
+                     /    |
+                    /     |
+                   /      |
+                  /       |
+                C1---------  <-- y axis = `thick`
+                /
+               /
+             p2
+            */
+
+            Vector2 p1 = { cosf(DEG2RAD*vertexAngleBeforeC1)*innerRadius, sinf(DEG2RAD*vertexAngleBeforeC1)*innerRadius };
+            Vector2 p2 = { cosf(DEG2RAD*vertexAngleAfterC1)*innerRadius, sinf(DEG2RAD*vertexAngleAfterC1)*innerRadius };
+
+            // Find the `t` of C1 between p1 and p2 ('t' as in `Lerp(start, end, t)`)
+            // This is used to lerp between the actual vertices (outside of our modified frame of reference)
+            // before and after C1
+            float t = (p1.y - thick)/(p1.y - p2.y);
+
+            Vector2 vertexBeforeCap1Vertex = { center.x + cosf(DEG2RAD*(startAngle + vertexAngleBeforeC1))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + vertexAngleBeforeC1))*innerRadius };
+            Vector2 vertexAfterCap1Vertex = { center.x + cosf(DEG2RAD*(startAngle + vertexAngleAfterC1))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + vertexAngleAfterC1))*innerRadius };
+
+            c1.x = vertexBeforeCap1Vertex.x + (vertexAfterCap1Vertex.x - vertexBeforeCap1Vertex.x)*t;
+            c1.y = vertexBeforeCap1Vertex.y + (vertexAfterCap1Vertex.y - vertexBeforeCap1Vertex.y)*t;
+
+            Vector2 vertexBeforeCap2Vertex = { center.x + cosf(DEG2RAD*(endAngle - vertexAngleBeforeC1))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - vertexAngleBeforeC1))*innerRadius };
+            Vector2 vertexAfterCap2Vertex = { center.x + cosf(DEG2RAD*(endAngle - vertexAngleAfterC1))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - vertexAngleAfterC1))*innerRadius };
+
+            c4.x = vertexBeforeCap2Vertex.x + (vertexAfterCap2Vertex.x - vertexBeforeCap2Vertex.x)*t;
+            c4.y = vertexBeforeCap2Vertex.y + (vertexAfterCap2Vertex.y - vertexBeforeCap2Vertex.y)*t;
+
+            /*
+            Another sketch couldn't hurt
+
+            This is a "zoomed in" view of the center of the circle sector
+            You can see where S0 is, and where we want S1 to be
+            `innerAngleBetweenCapEnds` is the angle of the diagonal line ('//') between the cap ends
+            `S1Length` is the length of that line
+
+            Since the caps are always parallel to `startAngle` and `endAngle`,
+            we always have a right triangle we can use to determine where S1 is
+
+             []      []
+             []      []
+             []  C   [] <- endAngle
+             []  a   []
+             []  p   []
+             []  2   []  startAngle
+             [][][][]S0[][][][][][]
+                   //[]
+                 //  [] Cap 1
+               //    []
+             S1      [][][][][][][]
+            */
+
+            float innerAngleBetweenCapEnds = ((endAngle - 90.0f) - (startAngle + 90.0f))/2.0f;
+            float s1Length = thick/cosf(DEG2RAD*innerAngleBetweenCapEnds);
+
+            // As `startAngle` and `endAngle` draw more of a circle, S1 goes further out from the center
+            // It can go so far that it is outside of the circle, by a lot
+            // This case needs to be detected and handled
+            // If S1 is within the circle, nothing special needs to happen
+            // But, if S1 is outside of the circle, we need to find the two points (C0 and C3) where
+            // the line segments C0->C1 and C0->C3 intersect the circle outline,
+            // using the same method we used to find C1 and C4
+            if ((innerAngleBetweenCapEnds < 90.0f) && (s1Length <= innerRadius))
+            {
+                // S1 is inside of the circle
+
+                float betweenStartAndEndAngle = (endAngle + startAngle)/2.0f;
+                c0 = (Vector2){ center.x + cosf(DEG2RAD*betweenStartAndEndAngle)*s1Length, center.y + sinf(DEG2RAD*betweenStartAndEndAngle)*s1Length };
+                c3 = c0;
+
+                p1 = (Vector2){ c1.x - center.x, c1.y - center.y };
+                p2 = (Vector2){ c0.x - center.x, c0.y - center.y };
+
+                // Copied from "raymath.h" Vector2Angle()
+                float dot = p1.x*p2.x + p1.y*p2.y;
+                float det = p1.x*p2.y - p1.y*p2.x;
+                float c1ToS1Angle = atan2f(det, dot);
+
+                // If C1 and C4 are on the wrong side of S1, the whole circle sector is covered
+                if (c1ToS1Angle < 0.0f)
+                {
+                    DrawCircleSector(center, radius, startAngle, endAngle, segments, color);
+                    return;
+                }
+            }
+            else
+            {
+                // S1 is outside of the circle
+
+                if (endAngle - startAngle <= 180.0f)
+                {
+                    DrawCircleSector(center, radius, startAngle, endAngle, segments, color);
+                    return;
+                }
+
+                s1OutsideOfCircle = true;
+
+                stepsBeforeC0 = (int)((180.0f + RAD2DEG*asinf(thick/-innerRadius))/stepLength);
+
+                // Reuse the code for finding C1 and C4 to find C0 and C3
+
+                float vertexAngleBeforeC0 = stepLength*(float)stepsBeforeC0;
+                float vertexAngleAfterC0 = stepLength*((float)(stepsBeforeC0 + 1));
+
+                p1 = (Vector2){ cosf(DEG2RAD*vertexAngleBeforeC0)*innerRadius, sinf(DEG2RAD*vertexAngleBeforeC0)*innerRadius };
+                p2 = (Vector2){ cosf(DEG2RAD*vertexAngleAfterC0)*innerRadius, sinf(DEG2RAD*vertexAngleAfterC0)*innerRadius };
+
+                t = (p1.y - thick)/(p1.y - p2.y);
+
+                vertexBeforeCap1Vertex = (Vector2){ center.x + cosf(DEG2RAD*(startAngle + vertexAngleBeforeC0))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + vertexAngleBeforeC0))*innerRadius };
+                vertexAfterCap1Vertex = (Vector2){ center.x + cosf(DEG2RAD*(startAngle + vertexAngleAfterC0))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + vertexAngleAfterC0))*innerRadius };
+
+                c0.x = vertexBeforeCap1Vertex.x + (vertexAfterCap1Vertex.x - vertexBeforeCap1Vertex.x)*t;
+                c0.y = vertexBeforeCap1Vertex.y + (vertexAfterCap1Vertex.y - vertexBeforeCap1Vertex.y)*t;
+
+                vertexBeforeCap2Vertex = (Vector2){ center.x + cosf(DEG2RAD*(endAngle - vertexAngleBeforeC0))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - vertexAngleBeforeC0))*innerRadius };
+                vertexAfterCap2Vertex = (Vector2){ center.x + cosf(DEG2RAD*(endAngle - vertexAngleAfterC0))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - vertexAngleAfterC0))*innerRadius };
+
+                c3.x = vertexBeforeCap2Vertex.x + (vertexAfterCap2Vertex.x - vertexBeforeCap2Vertex.x)*t;
+                c3.y = vertexBeforeCap2Vertex.y + (vertexAfterCap2Vertex.y - vertexBeforeCap2Vertex.y)*t;
+            }
+        }
+        else
+        {
+            float outerAngleBetweenCapEnds = ((endAngle + 90.0f) - (startAngle - 90.0f))/2.0f;
+            float s1Length = thick/cosf(DEG2RAD*outerAngleBetweenCapEnds);
+            float betweenStartAndEndAngle = 180.0f + (endAngle + startAngle)/2.0f;
+            c0 = (Vector2){ center.x + cosf(DEG2RAD*betweenStartAndEndAngle)*s1Length, center.y + sinf(DEG2RAD*betweenStartAndEndAngle)*s1Length };
+            c3 = c0;
+
+            c2 = (Vector2){ center.x + cosf(DEG2RAD*startAngle)*outerRadius, center.y + sinf(DEG2RAD*startAngle)*outerRadius };
+            c5 = (Vector2){ center.x + cosf(DEG2RAD*endAngle)*outerRadius, center.y + sinf(DEG2RAD*endAngle)*outerRadius };
+
+            // Change the frame of reference so that `center` is the origin and `startAngle` is 0 degrees
+
+            Vector2 c0Translated = { c0.x - center.x, c0.y - center.y };
+            Vector2 circleVertex1 = { c2.x - center.x, c2.y - center.y };
+            Vector2 circleVertex2 = { cosf(DEG2RAD*(startAngle + stepLength))*outerRadius, sinf(DEG2RAD*(startAngle + stepLength))*outerRadius };
+
+            // Copied from "raymath.h" Vector2Rotate()
+            float tempX = c0Translated.x;
+            c0Translated.x = cosf(-DEG2RAD*startAngle)*tempX - sinf(-DEG2RAD*startAngle)*c0Translated.y;
+            c0Translated.y = sinf(-DEG2RAD*startAngle)*tempX + cosf(-DEG2RAD*startAngle)*c0Translated.y;
+
+            tempX = circleVertex1.x;
+            circleVertex1.x = cosf(-DEG2RAD*startAngle)*tempX - sinf(-DEG2RAD*startAngle)*circleVertex1.y;
+            circleVertex1.y = sinf(-DEG2RAD*startAngle)*tempX + cosf(-DEG2RAD*startAngle)*circleVertex1.y;
+
+            tempX = circleVertex2.x;
+            circleVertex2.x = cosf(-DEG2RAD*startAngle)*tempX - sinf(-DEG2RAD*startAngle)*circleVertex2.y;
+            circleVertex2.y = sinf(-DEG2RAD*startAngle)*tempX + cosf(-DEG2RAD*startAngle)*circleVertex2.y;
+
+            // Figure out the line that `circleVertex1` and `circleVertex2` are on
+            float rise = circleVertex1.y - circleVertex2.y;
+            float run = circleVertex1.x - circleVertex2.x;
+            // Get where that line intersects the horizontal line that `c0Translated` is on
+            float c1Rise = c0Translated.y - circleVertex1.y;
+            float c1Run = (c1Rise/rise)*run;
+            float c1DistanceFromC0 = (circleVertex1.x + c1Run) - c0Translated.x;
+
+            c1 = (Vector2){ c0.x + cosf(DEG2RAD*startAngle)*c1DistanceFromC0, c0.y + sinf(DEG2RAD*startAngle)*c1DistanceFromC0 };
+            c4 = (Vector2){ c0.x + cosf(DEG2RAD*endAngle)*c1DistanceFromC0, c0.y + sinf(DEG2RAD*endAngle)*c1DistanceFromC0 };
+
+            if (c1DistanceFromC0 < 0.0f)
+            {
+                // The caps are intersecting each other
+
+                Vector2 circleVertex3 = { c5.x - center.x, c5.y - center.y };
+                Vector2 circleVertex4 = { cosf(DEG2RAD*(endAngle - stepLength))*outerRadius, sinf(DEG2RAD*(endAngle - stepLength))*outerRadius };
+
+                tempX = circleVertex3.x;
+                circleVertex3.x = cosf(-DEG2RAD*startAngle)*tempX - sinf(-DEG2RAD*startAngle)*circleVertex3.y;
+                circleVertex3.y = sinf(-DEG2RAD*startAngle)*tempX + cosf(-DEG2RAD*startAngle)*circleVertex3.y;
+
+                tempX = circleVertex4.x;
+                circleVertex4.x = cosf(-DEG2RAD*startAngle)*tempX - sinf(-DEG2RAD*startAngle)*circleVertex4.y;
+                circleVertex4.y = sinf(-DEG2RAD*startAngle)*tempX + cosf(-DEG2RAD*startAngle)*circleVertex4.y;
+
+                // `startAngle` is 0 degrees within this frame of reference,
+                // so C1 just goes horizontally out from C0
+                Vector2 c1Translated = { c0Translated.x + c1DistanceFromC0, c0Translated.y };
+
+                // Make `circleVertex2` the origin
+                circleVertex1.x -= circleVertex2.x;
+                circleVertex1.y -= circleVertex2.y;
+                circleVertex3.x -= circleVertex2.x;
+                circleVertex3.y -= circleVertex2.y;
+                circleVertex4.x -= circleVertex2.x;
+                circleVertex4.y -= circleVertex2.y;
+                c1Translated.x -= circleVertex2.x;
+                c1Translated.y -= circleVertex2.y;
+
+                // Make the line between `circleVertex1` and `circleVertex2` a horizontal line
+                float theta = atan2f(circleVertex1.y, circleVertex1.x);
+
+                // Copied from "raymath.h" Vector2Rotate()
+                tempX = circleVertex1.x;
+                circleVertex1.x = cosf(-theta)*tempX - sinf(-theta)*circleVertex1.y;
+                circleVertex1.y = sinf(-theta)*tempX + cosf(-theta)*circleVertex1.y;
+
+                tempX = circleVertex3.x;
+                circleVertex3.x = cosf(-theta)*tempX - sinf(-theta)*circleVertex3.y;
+                circleVertex3.y = sinf(-theta)*tempX + cosf(-theta)*circleVertex3.y;
+
+                tempX = circleVertex4.x;
+                circleVertex4.x = cosf(-theta)*tempX - sinf(-theta)*circleVertex4.y;
+                circleVertex4.y = sinf(-theta)*tempX + cosf(-theta)*circleVertex4.y;
+
+                tempX = c1Translated.x;
+                c1Translated.x = cosf(-theta)*tempX - sinf(-theta)*c1Translated.y;
+                c1Translated.y = sinf(-theta)*tempX + cosf(-theta)*c1Translated.y;
+
+                // Find where the line that `circleVertex3` and `circleVertex4` are on would intersect the
+                // line segment defined by `circleVertex1` and `c1Translated`
+                rise = circleVertex3.y - circleVertex4.y;
+                run = circleVertex3.x - circleVertex4.x;
+                float targetRise = -circleVertex3.y;
+                float targetX = circleVertex3.x + (targetRise/rise)*run;
+
+                float t = (c1Translated.x - targetX)/(c1Translated.x - circleVertex1.x);
+
+                c1 = (Vector2){ c1.x + (c2.x - c1.x)*t, c1.y + (c2.y - c1.y)*t };
+                c4 = c1;
+                c0 = c1;
+                c3 = c1;
+            }
+
+            // Swap vertices to correct the winding order
+            Vector2 temp = c0;
+            c0 = c2;
+            c2 = temp;
+
+            temp = c3;
+            c3 = c5;
+            c5 = temp;
+        }
+    }
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // Draw the circle outline
+        for (int i = 0; i < segments; i++)
+        {
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+
+            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);
+
+            angle += stepLength;
+        }
+
+        // Draw the caps
+        if (showCapLines)
+        {
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x, center.y);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(c0.x, c0.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(c1.x, c1.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(c2.x, c2.y);
+
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x, center.y);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(c5.x, c5.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(c4.x, c4.y);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(c3.x, c3.y);
+
+            // Some extra work may be needed when `thick` is positive
+            if (thick >= 0.0f)
+            {
+                // Fill in the gaps between cap 1 and the circle outline and cap 2 and the circle outline
+                if (stepsBeforeC1 > 0)
+                {
+                    // Draw quads using pairs of vertices on the circle outline
+                    angle = 0;
+                    for (int i = 0; i < stepsBeforeC1/2; i++)
+                    {
+                        // Cap1
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c1.x, c1.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + (angle + stepLength*2.0f)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + (angle + stepLength*2.0f)))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerRadius);
+
+                        // Cap2
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c4.x, c4.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - (angle + stepLength*2.0f)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - (angle + stepLength*2.0f)))*innerRadius);
+
+                        angle += stepLength*2.0f;
+                    }
+
+                    if (stepsBeforeC1%2 == 1)
+                    {
+                        // Cap1
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c1.x, c1.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(c1.x, c1.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerRadius);
+
+                        // Cap2
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c4.x, c4.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(c4.x, c4.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius);
+                    }
+                }
+
+                // Fill in the gap between C0, C3 and the circle outline
+                if (s1OutsideOfCircle)
+                {
+                    int verticesBetweenC0andC3 = (segments - stepsBeforeC0*2) - 1;
+
+                    // No gap to fill
+                    if (verticesBetweenC0andC3 == 0)
+                    {
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(c3.x, c3.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c0.x, c0.y);
+                    }
+                    // There's a gap to fill
+                    else
+                    {
+                        // Triangle touching C0
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(c0.x, c0.y);
+
+                        // Triangle touching C3
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(center.x, center.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(c3.x, c3.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius);
+
+                        // Triangles between the previous two
+                        verticesBetweenC0andC3 -= 1;
+                        angle = startAngle + stepLength*(stepsBeforeC0 + 1);
+                        for (int i = 0; i < verticesBetweenC0andC3/2; i++)
+                        {
+                            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                            rlVertex2f(center.x, center.y);
+
+                            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2.0f))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength*2.0f))*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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+
+                            angle += stepLength*2.0f;
+                        }
+
+                        if (verticesBetweenC0andC3%2 == 1)
+                        {
+                            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                            rlVertex2f(center.x, center.y);
+
+                            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                            rlVertex2f(center.x, center.y);
+
+                            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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+                        }
+                    }
+                }
+            }
+        }
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // Draw the circle outline
+        for (int i = 0; i < segments; i++)
+        {
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+            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);
+
+            angle += stepLength;
+        }
+
+        // Draw the caps
+        if (showCapLines)
+        {
+            // Cap 1
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(c0.x, c0.y);
+            rlVertex2f(c1.x, c1.y);
+
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(c1.x, c1.y);
+            rlVertex2f(c2.x, c2.y);
+
+            // Cap 2
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(c5.x, c5.y);
+            rlVertex2f(c4.x, c4.y);
+
+            rlVertex2f(center.x, center.y);
+            rlVertex2f(c4.x, c4.y);
+            rlVertex2f(c3.x, c3.y);
+
+            // Some extra work may be needed when `thick` is positive
+            if (thick >= 0.0f)
+            {
+                // Fill in the gaps between cap 1 and the circle outline and cap 2 and the circle outline
+                if (stepsBeforeC1 > 0)
+                {
+                    angle = 0;
+                    for (int i = 0; i < stepsBeforeC1; i++)
+                    {
+                        // Cap 1
+                        rlVertex2f(c1.x, c1.y);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + (angle + stepLength)))*innerRadius);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerRadius);
+
+                        // Cap 2
+                        rlVertex2f(c4.x, c4.y);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerRadius);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - (angle + stepLength)))*innerRadius);
+
+                        angle += stepLength;
+                    }
+                }
+
+                // Fill in the gap between C0, C3 and the circle outline
+                if (s1OutsideOfCircle)
+                {
+                    int verticesBetweenC0andC3 = (segments - stepsBeforeC0*2) - 1;
+
+                    // No gap to fill
+                    if (verticesBetweenC0andC3 == 0)
+                    {
+                        rlVertex2f(center.x, center.y);
+                        rlVertex2f(c3.x, c3.y);
+                        rlVertex2f(c0.x, c0.y);
+                    }
+                    // There's a gap to fill
+                    else
+                    {
+                        // Triangle touching C0
+                        rlVertex2f(center.x, center.y);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius, center.y + sinf(DEG2RAD*(startAngle + stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius);
+                        rlVertex2f(c0.x, c0.y);
+
+                        // Triangle touching C3
+                        rlVertex2f(center.x, center.y);
+                        rlVertex2f(c3.x, c3.y);
+                        rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius, center.y + sinf(DEG2RAD*(endAngle - stepLength*(float)(stepsBeforeC0 + 1)))*innerRadius);
+
+                        // Triangles between the previous two
+                        verticesBetweenC0andC3 -= 1;
+                        angle = startAngle + stepLength*(stepsBeforeC0 + 1);
+                        for (int i = 0; i < verticesBetweenC0andC3; i++)
+                        {
+                            rlVertex2f(center.x, center.y);
+                            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
+                            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+
+                            angle += stepLength;
+                        }
+                    }
+                }
+            }
+        }
+
+    rlEnd();
+#endif
+}
+
+// Draw circle outline
+void DrawCircleLines(int centerX, int centerY, float radius, Color color)
+{
+    DrawCircleLinesV((Vector2){ (float)centerX, (float)centerY }, radius, color);
+}
+
+// Draw circle outline (Vector version)
+void DrawCircleLinesV(Vector2 center, float radius, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*radius, center.y + sinf(DEG2RAD*i)*radius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radius, center.y + sinf(DEG2RAD*(i + 10))*radius);
+        }
+    rlEnd();
+}
+
+void DrawCircleLinesEx(Vector2 center, float radius, float thick, Color color)
+{
+    DrawRing(center, radius - thick, radius, 0.0f, 360.0f, 36, color);
+}
+
+// Draw ellipse
+void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
+{
+    DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
+}
+
+// Draw ellipse (Vector version)
+void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
+{
+    rlBegin(RL_TRIANGLES);
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlVertex2f(center.x,  center.y);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
+        }
+    rlEnd();
+}
+
+// Draw ellipse outline
+void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
+{
+    DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
+}
+
+// Draw ellipse outline
+void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
+{
+    rlBegin(RL_LINES);
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
+        }
+    rlEnd();
+}
+
+// Draw ellipse outline with thickness
+void DrawEllipseLinesEx(Vector2 center, float radiusH, float radiusV, float thick, Color color)
+{
+    float outerRadiusH = radiusH, innerRadiusH = radiusH - thick;
+    float outerRadiusV = radiusV, innerRadiusV = radiusV - thick;
+
+    if (thick >= 0.0f) {
+        // Just a filled-in ellipse
+        if (innerRadiusH <= 0.0f || innerRadiusV <= 0.0f)
+        {
+            DrawEllipseV(center, radiusH, radiusV, color);
+            return;
+        }
+    }
+    else
+    {
+        // The outline is growing outside of the ellipse, so swap the inner and outer radius
+        float tmp = outerRadiusH;
+        outerRadiusH = innerRadiusH;
+        innerRadiusH = tmp;
+
+        tmp = outerRadiusV;
+        outerRadiusV = innerRadiusV;
+        innerRadiusV = tmp;
+    }
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*innerRadiusH, center.y + sinf(DEG2RAD*i)*innerRadiusV);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*innerRadiusH, center.y + sinf(DEG2RAD*(i + 10))*innerRadiusV);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*outerRadiusH, center.y + sinf(DEG2RAD*(i + 10))*outerRadiusV);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*outerRadiusH, center.y + sinf(DEG2RAD*i)*outerRadiusV);
+        }
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < 360; i += 10)
+        {
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*innerRadiusH, center.y + sinf(DEG2RAD*i)*innerRadiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*innerRadiusH, center.y + sinf(DEG2RAD*(i + 10))*innerRadiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*outerRadiusH, center.y + sinf(DEG2RAD*(i + 10))*outerRadiusV);
+
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*innerRadiusH, center.y + sinf(DEG2RAD*i)*innerRadiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*outerRadiusH, center.y + sinf(DEG2RAD*(i + 10))*outerRadiusV);
+            rlVertex2f(center.x + cosf(DEG2RAD*i)*outerRadiusH, center.y + sinf(DEG2RAD*i)*outerRadiusV);
+        }
+    rlEnd();
+#endif
+}
+
+// Draw ring
+void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
+{
+    if (startAngle == endAngle) return;
+
+    // Function expects (outerRadius > innerRadius)
+    if (outerRadius < innerRadius)
+    {
+        float tmp = outerRadius;
+        outerRadius = innerRadius;
+        innerRadius = tmp;
+
+        if (outerRadius <= 0.0f) outerRadius = 0.1f;
+    }
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f) endAngle = startAngle + 360.0f;
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
+        float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
+        segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    // Not a ring
+    if (innerRadius <= 0.0f)
+    {
+        DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, color);
+        return;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+    float angle = startAngle;
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+        for (int i = 0; i < segments; i++)
+        {
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
+
+            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);
+
+            angle += stepLength;
+        }
+    rlEnd();
+
+    rlSetTexture(0);
+#else
+    rlBegin(RL_TRIANGLES);
+        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;
+        }
+    rlEnd();
+#endif
+}
+
+// Draw ring outline
+void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color)
+{
+    if (startAngle == endAngle) return;
+
+    // Function expects (outerRadius > innerRadius)
+    if (outerRadius < innerRadius)
+    {
+        float tmp = outerRadius;
+        outerRadius = innerRadius;
+        innerRadius = tmp;
+
+        if (outerRadius <= 0.0f) outerRadius = 0.1f;
+    }
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    bool showCapLines = true;
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f)
+    {
+        showCapLines = false;
+        endAngle = startAngle + 360.0f;
+    }
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
+        float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
+        segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    if (innerRadius <= 0.0f)
+    {
+        DrawCircleSectorLines(center, outerRadius, startAngle, endAngle, segments, color);
+        return;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+    float angle = startAngle;
+
+    rlBegin(RL_LINES);
+        if (showCapLines)
+        {
+            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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+        }
+
+        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);
+
+            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);
+
+            angle += stepLength;
+        }
+
+        if (showCapLines)
+        {
+            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)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
+        }
+    rlEnd();
+}
+
+// Draw ring outline with line thickness
+void DrawRingLinesEx(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, float thick, Color color)
+{
+    if (startAngle == endAngle) return;
+
+    // Function expects (outerRadius > innerRadius)
+    if (outerRadius < innerRadius)
+    {
+        float tmp = outerRadius;
+        outerRadius = innerRadius;
+        innerRadius = tmp;
+
+        if (outerRadius <= 0.0f) outerRadius = 0.1f;
+    }
+
+    // Function expects (endAngle > startAngle)
+    if (endAngle < startAngle)
+    {
+        // Swap values
+        float tmp = startAngle;
+        startAngle = endAngle;
+        endAngle = tmp;
+    }
+
+    bool showCapLines = true;
+    // Drawing a whole circle, things get weird without limiting the circle to 360 degrees
+    if (endAngle - startAngle >= 360.0f)
+    {
+        showCapLines = thick >= 0.0f;
+        endAngle = startAngle + 360.0f;
+    }
+
+    int minSegments = (int)ceilf((endAngle - startAngle)/90);
+
+    if (segments < minSegments)
+    {
+        // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
+        float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
+        segments = (int)ceilf((endAngle - startAngle)*(2*PI/th)/360.0f);
+
+        if (segments <= 0) segments = minSegments;
+    }
+
+    float stepLength = (endAngle - startAngle)/(float)segments;
+
+    // We are not drawing a circle, we are drawing an n-sided polygon
+    // So, we need to adjust the outline thickness of the "circle" for it to look correct with fewer segments
+    float apothem = outerRadius*cosf(DEG2RAD*((endAngle - startAngle)/2.0f)/(float)segments);
+    float radiusThick = thick*(outerRadius/apothem);
+
+    // These names can be confusing, but they are useful
+    // Since 2 rings are being drawn, there are 4 radiuses (or radii)
+    // "Inner" means closer to the center, "outer" means farther from the center
+    // Sorted from farthest to closest you get:
+    //   1. outerOuterRadius (farthest)
+    //   2. innerOuterRadius
+    //   3. outerInnerRadius
+    //   4. innerInnerRadius (closest)
+    float innerOuterRadius = 0.0f;
+    float outerOuterRadius = 0.0f;
+    float innerInnerRadius = 0.0f;
+    float outerInnerRadius = 0.0f;
+
+    if (thick >= 0.0f)
+    {
+        innerRadius = fmaxf(0.0f, innerRadius);
+
+        // Just a filled-in ring
+        if (radiusThick > (outerRadius - innerRadius)/2.0f)
+        {
+            DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, segments, color);
+            return;
+        }
+
+        innerInnerRadius = innerRadius;
+        outerInnerRadius = innerInnerRadius + radiusThick;
+
+        outerOuterRadius = outerRadius;
+        innerOuterRadius = outerOuterRadius - radiusThick;
+    }
+    else
+    {
+        // Just a circle sector outline
+        if (innerRadius <= 0.0f)
+        {
+            DrawCircleSectorLinesEx(center, outerRadius, startAngle, endAngle, segments, thick, color);
+            return;
+        }
+
+        outerInnerRadius = innerRadius;
+        innerInnerRadius = fmaxf(0.0f, outerInnerRadius + radiusThick);
+
+        innerOuterRadius = outerRadius;
+        outerOuterRadius = innerOuterRadius - radiusThick;
+    }
+
+    // For positive `thick` values
+    int stepsBeforeInner = 0;
+    int stepsBeforeOuter = 0;
+    float tInner = 0.0f;
+    float tOuter = 0.0f;
+    bool innerAnglesCrossEachOther = false;
+
+    // For negative `thick` values
+    Vector2 cap1SecondInnerVertex = { 0 };
+    Vector2 cap1SecondOuterVertex = { 0 };
+    Vector2 cap2SecondInnerVertex = { 0 };
+    Vector2 cap2SecondOuterVertex = { 0 };
+    bool capsIntersect = false;
+    Vector2 capIntersectionVertex = { 0 };
+
+    if (showCapLines)
+    {
+        if (thick >= 0.0f)
+        {
+            // Get the angle of the arc that has `thick` length along the inner and outer radii
+            float cap1InnerAngleEnd = RAD2DEG*(thick/outerInnerRadius);
+            float cap1OuterAngleEnd = RAD2DEG*(thick/innerOuterRadius);
+
+            // Just a filled-in ring
+            if (endAngle - startAngle < cap1OuterAngleEnd*2.0f)
+            {
+                DrawRing(center, innerRadius, outerRadius, startAngle, endAngle, segments, color);
+                return;
+            }
+
+            if (endAngle - startAngle < cap1InnerAngleEnd*2.0f) innerAnglesCrossEachOther = true;
+
+            stepsBeforeInner = (int)(cap1InnerAngleEnd/stepLength);
+            stepsBeforeOuter = (int)(cap1OuterAngleEnd/stepLength);
+
+            // We need to find where `cap1InnerAngleEnd` intersects the edge defined
+            // by `beforeInnerVertex` and `afterInnerVertex`
+            //
+            // We can make this easy by making `center` the origin (0, 0) and
+            // making `cap1InnerAngleEnd` 0 degrees (a horizontal line)
+            //
+            // With that, we know these lines intersect when 'y' equals 0,
+            // so we just need to solve for 't' (as in `Lerp(start, end, t)`)
+            Vector2 beforeInnerVertex = { cosf(DEG2RAD*((float)stepsBeforeInner*stepLength - cap1InnerAngleEnd))*outerInnerRadius, sinf(DEG2RAD*((float)stepsBeforeInner*stepLength - cap1InnerAngleEnd))*outerInnerRadius };
+            Vector2 afterInnerVertex = { cosf(DEG2RAD*((float)(stepsBeforeInner + 1)*stepLength - cap1InnerAngleEnd))*outerInnerRadius, sinf(DEG2RAD*((float)(stepsBeforeInner + 1)*stepLength - cap1InnerAngleEnd))*outerInnerRadius };
+            tInner = beforeInnerVertex.y/(beforeInnerVertex.y - afterInnerVertex.y);
+
+            // The same as above, but for the outer edge
+            Vector2 beforeOuterVertex = { cosf(DEG2RAD*((float)stepsBeforeOuter*stepLength - cap1OuterAngleEnd))*innerOuterRadius, sinf(DEG2RAD*((float)stepsBeforeOuter*stepLength - cap1OuterAngleEnd))*innerOuterRadius };
+            Vector2 afterOuterVertex = { cosf(DEG2RAD*((float)(stepsBeforeOuter + 1)*stepLength - cap1OuterAngleEnd))*innerOuterRadius, sinf(DEG2RAD*((float)(stepsBeforeOuter + 1)*stepLength - cap1OuterAngleEnd))*innerOuterRadius };
+            tOuter = beforeOuterVertex.y/(beforeOuterVertex.y - afterOuterVertex.y);
+        }
+        else
+        {
+            // "Cap 1" is the outline on `startAngle` and "Cap 2" is the outline on `endAngle`
+
+            /*
+            A sketch to help make all this a little more understandable
+            (This is an overly simplified representation of cap 1)
+
+             I2[][][][][]O2  <- y = thick
+             []          []
+             []          []
+             I0----------O0  <- angle = 0 degrees, y = 0
+             []          []
+             I1          O1  <- angle = stepLength
+
+            Cap 2 is a mirror copy of cap 1, the inside and outside vertices switch sides
+
+            We're using a frame of reference where `center` is (0, 0) and `startAngle` is 0 degrees
+
+            I0 is `innerInnerRadius` distance from `center` at `starAngle`
+            I1 is `innerInnerRadius` distance from `center` at `starAngle + stepLength`
+            I2 goes out from I0 perpendicular to `startAngle`
+            O0 is the same as I0, except using `outerOuterRadius` instead of `innerInnerRadius`
+            O1 is the same as I1, except using `outerOuterRadius` instead of `innerInnerRadius`
+            O2 is the same as I2, except goes out from O0
+
+            The intersection cases between the caps edges are:
+              1. No intersections, easy
+              2. The I0->I2 and I2->O2 edges intersect between the caps
+              3. The I0->I2 and O0->O2 edges intersect between the caps
+
+            Notice that cap 1 and 2's I2->O2 and O0->O2 edges can't intersect at the same time,
+            and, if there's any intersection, I0->I2 is one of the edges
+            */
+
+            Vector2 cap1O0 = { outerOuterRadius, 0.0f };
+            Vector2 cap1O1 = { cosf(DEG2RAD*stepLength)*outerOuterRadius, sinf(DEG2RAD*stepLength)*outerOuterRadius };
+
+            // Assuming a linear interpolation such as `value = Lerp(start, end, t)`
+            // We can find O2 by getting its 't' between O1.y and O0.y (which is always greater than 1)
+            // We can solve for `t` using `t = (start - value)/(start - end)`
+            // Since we know `end = 0` we can simplify it to `t = (start - value)/start`
+            float tOuter = (cap1O1.y - thick)/cap1O1.y;
+            Vector2 cap1O2 = { cap1O1.x + (cap1O0.x - cap1O1.x)*tOuter, thick };
+
+            //Vector2 cap1I0 = { innerInnerRadius, 0.0f }; // Not used
+
+            float capLongEdgeLength = outerOuterRadius - innerInnerRadius;
+            Vector2 cap1I2 = { cap1O2.x - capLongEdgeLength, thick };
+
+            Vector2 cap2O0 = { cosf(DEG2RAD*(endAngle - startAngle))*outerOuterRadius, sinf(DEG2RAD*(endAngle - startAngle))*outerOuterRadius };
+            Vector2 cap2O1 = { cosf(DEG2RAD*(endAngle - startAngle - stepLength))*outerOuterRadius, sinf(DEG2RAD*(endAngle - startAngle - stepLength))*outerOuterRadius };
+            Vector2 cap2O2 = { cap2O1.x + (cap2O0.x - cap2O1.x)*tOuter, cap2O1.y + (cap2O0.y - cap2O1.y)*tOuter };
+
+            Vector2 cap2I0 = { cosf(DEG2RAD*(endAngle - startAngle))*innerInnerRadius, sinf(DEG2RAD*(endAngle - startAngle))*innerInnerRadius };
+            Vector2 cap2I2 = { cap2O2.x - cosf(DEG2RAD*(endAngle - startAngle))*capLongEdgeLength, cap2O2.y - sinf(DEG2RAD*(endAngle - startAngle))*capLongEdgeLength};
+
+            // The 't' of the intersection between I2 and O2 (`Lerp(I2, O2, t)`)
+            float tCapLongEdgeCross = -1.0f;
+            // Avoid division by zero
+            if (cap2I2.y - cap2O2.y != 0.0f)
+            {
+                // Find where the long edge of cap 2 intersects the long edge of cap 1
+                tCapLongEdgeCross = (cap2I2.y - thick)/(cap2I2.y - cap2O2.y);
+                if ((tCapLongEdgeCross >= 0.0f) && (tCapLongEdgeCross <= 1.0f)) capsIntersect = true;
+            }
+
+            // Rotate the frame of reference so that cap 1's I0->I2 edge is a vertical line
+            float rotateBy = -DEG2RAD*stepLength/2.0f;
+
+            // Copied from "raymath.h" Vector2Rotate()
+            // Though we only use the x axis, so we ignore the y axis
+            float cosres = cosf(rotateBy);
+            float sinres = sinf(rotateBy);
+
+            cap1I2.x = cap1I2.x*cosres - cap1I2.y*sinres;
+            cap1O2.x = cap1O2.x*cosres - cap1O2.y*sinres;
+            cap2I0.x = cap2I0.x*cosres - cap2I0.y*sinres;
+            cap2I2.x = cap2I2.x*cosres - cap2I2.y*sinres;
+            cap2O0.x = cap2O0.x*cosres - cap2O0.y*sinres;
+            cap2O2.x = cap2O2.x*cosres - cap2O2.y*sinres;
+
+            // The 't' of the intersection between I0 and I2 (`Lerp(I0, I2, t)`)
+            float tCrossInner = -1.0f;
+            // Avoid division by zero
+            if (cap2I0.x - cap2I2.x != 0.0f) tCrossInner = (cap2I0.x - cap1I2.x)/(cap2I0.x - cap2I2.x);
+            // Make sure `tCrossInner` is 0 when it should be (mitigate floating-point rounding woes)
+            if (innerInnerRadius <= 0.0f) tCrossInner = 0.0f;
+
+            // The 't' of the intersection between O0 and O2 (`Lerp(O0, O2, t)`)
+            float tCrossOuter = -1.0f;
+            // Avoid division by zero
+            if (cap2O0.x - cap2O2.x != 0.0f) tCrossOuter = (cap2O0.x - cap1O2.x)/(cap2O0.x - cap2O2.x);
+
+            // With our additional information, calculate the vertices we need
+            // outside of our modified frame of reference
+
+            cap1O0 = (Vector2){ center.x + cosf(DEG2RAD*startAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*startAngle)*outerOuterRadius };
+            cap1O1 = (Vector2){ center.x + cosf(DEG2RAD*(startAngle + stepLength))*outerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + stepLength))*outerOuterRadius };
+            cap1O2 = (Vector2){ cap1O1.x + (cap1O0.x - cap1O1.x)*tOuter, cap1O1.y + (cap1O0.y - cap1O1.y)*tOuter };
+
+            cap2O0 = (Vector2){ center.x + cosf(DEG2RAD*endAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*endAngle)*outerOuterRadius };
+            cap2O1 = (Vector2){ center.x + cosf(DEG2RAD*(endAngle - stepLength))*outerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - stepLength))*outerOuterRadius };
+            cap2O2 = (Vector2){ cap2O1.x + (cap2O0.x - cap2O1.x)*tOuter, cap2O1.y + (cap2O0.y - cap2O1.y)*tOuter };
+
+            //cap1I0 = (Vector2){ center.x + cosf(DEG2RAD*startAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*startAngle)*innerInnerRadius };
+            cap1I2 = (Vector2){ cap1O2.x - cosf(DEG2RAD*startAngle)*capLongEdgeLength, cap1O2.y - sinf(DEG2RAD*startAngle)*capLongEdgeLength };
+
+            cap2I0 = (Vector2){ center.x + cosf(DEG2RAD*endAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*endAngle)*innerInnerRadius };
+            cap2I2 = (Vector2){ cap2O2.x - cosf(DEG2RAD*endAngle)*capLongEdgeLength, cap2O2.y - sinf(DEG2RAD*endAngle)*capLongEdgeLength };
+
+            if (capsIntersect)
+            {
+                capIntersectionVertex = (Vector2){ cap2I2.x + (cap2O2.x - cap2I2.x)*tCapLongEdgeCross, cap2I2.y + (cap2O2.y - cap2I2.y)*tCapLongEdgeCross };
+
+                cap2I2 = (Vector2){ cap2I0.x + (cap2I2.x - cap2I0.x)*tCrossInner, cap2I0.y + (cap2I2.y - cap2I0.y)*tCrossInner };
+                cap1I2 = cap2I2;
+            }
+            else if ((tCrossOuter >= 0.0f) && (tCrossOuter <= 1.0f))
+            {
+                cap2O2 = (Vector2){ cap2O0.x + (cap2O2.x - cap2O0.x)*tCrossOuter, cap2O0.y + (cap2O2.y - cap2O0.y)*tCrossOuter };
+                cap1O2 = cap2O2;
+
+                cap2I2 = (Vector2){ cap2I0.x + (cap2I2.x - cap2I0.x)*tCrossInner, cap2I0.y + (cap2I2.y - cap2I0.y)*tCrossInner };
+                cap1I2 = cap2I2;
+            }
+
+            cap1SecondInnerVertex = cap1I2;
+            cap1SecondOuterVertex = cap1O2;
+            cap2SecondInnerVertex = cap2I2;
+            cap2SecondOuterVertex = cap2O2;
+        }
+    }
+
+    float angle = startAngle;
+
+#if SUPPORT_QUADS_DRAW_MODE
+    rlSetTexture(GetShapesTexture().id);
+    Rectangle shapeRect = GetShapesTextureRectangle();
+
+    rlBegin(RL_QUADS);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < segments; i++)
+        {
+            // `innerRadius` outline
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerInnerRadius, center.y + sinf(DEG2RAD*angle)*outerInnerRadius);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerInnerRadius, center.y + sinf(DEG2RAD*angle)*innerInnerRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerInnerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerInnerRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerInnerRadius);
+
+            // `outerRadius` outline
+            rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerOuterRadius, center.y + sinf(DEG2RAD*angle)*outerOuterRadius);
+
+            rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerOuterRadius, center.y + sinf(DEG2RAD*angle)*innerOuterRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerOuterRadius);
+
+            rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerOuterRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerOuterRadius);
+
+            angle += stepLength;
+        }
+
+        if (showCapLines)
+        {
+            if (thick >= 0.0f)
+            {
+                angle = 0.0f;
+
+                for (int i = 0; i < stepsBeforeOuter; i++)
+                {
+                    // Cap 1
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerOuterRadius);
+
+                    // Cap 2
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerOuterRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius);
+
+                    angle += stepLength;
+                }
+
+                // We've already moved `stepsBeforeOuter` steps from each end
+                int totalStepsLeft = segments - stepsBeforeOuter*2;
+                int innerStepsLeft = stepsBeforeInner - stepsBeforeOuter;
+
+                // Cap 1
+                Vector2 cap1OuterVertexBeforeEnd = { center.x + cosf(DEG2RAD*(startAngle + angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerOuterRadius };
+                Vector2 cap1OuterVertexAfterEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius };
+                Vector2 cap1InnerVertexBeforeEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + (float)innerStepsLeft*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + (float)innerStepsLeft*stepLength))*outerInnerRadius };
+                Vector2 cap1InnerVertexAfterEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius };
+                Vector2 cap1InnerVertexEnd = { cap1InnerVertexBeforeEnd.x + (cap1InnerVertexAfterEnd.x - cap1InnerVertexBeforeEnd.x)*tInner, cap1InnerVertexBeforeEnd.y + (cap1InnerVertexAfterEnd.y - cap1InnerVertexBeforeEnd.y)*tInner };
+                Vector2 cap1OuterVertexEnd = { cap1OuterVertexBeforeEnd.x + (cap1OuterVertexAfterEnd.x - cap1OuterVertexBeforeEnd.x)*tOuter, cap1OuterVertexBeforeEnd.y + (cap1OuterVertexAfterEnd.y - cap1OuterVertexBeforeEnd.y)*tOuter };
+
+                // Cap 2
+                Vector2 cap2OuterVertexBeforeEnd = { center.x + cosf(DEG2RAD*(endAngle - angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerOuterRadius };
+                Vector2 cap2OuterVertexAfterEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius };
+                Vector2 cap2InnerVertexBeforeEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - (float)innerStepsLeft*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - (float)innerStepsLeft*stepLength))*outerInnerRadius };
+                Vector2 cap2InnerVertexAfterEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius };
+                Vector2 cap2InnerVertexEnd = { cap2InnerVertexBeforeEnd.x + (cap2InnerVertexAfterEnd.x - cap2InnerVertexBeforeEnd.x)*tInner, cap2InnerVertexBeforeEnd.y + (cap2InnerVertexAfterEnd.y - cap2InnerVertexBeforeEnd.y)*tInner };
+                Vector2 cap2OuterVertexEnd = { cap2OuterVertexBeforeEnd.x + (cap2OuterVertexAfterEnd.x - cap2OuterVertexBeforeEnd.x)*tOuter, cap2OuterVertexBeforeEnd.y + (cap2OuterVertexAfterEnd.y - cap2OuterVertexBeforeEnd.y)*tOuter };
+
+                int stepsCount = (innerAnglesCrossEachOther)? totalStepsLeft/2 : innerStepsLeft;
+
+                // Iterate over pairs of steps
+                for (int i = 0; i < stepsCount/2; i++)
+                {
+                    // Cap 1
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength*2.0f))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength*2.0f))*outerInnerRadius);
+
+                    // Cap 2
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength*2.0f))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength*2.0f))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+
+                    angle += stepLength*2.0f;
+                }
+
+                // Handle the last step if there's an odd amount
+                if (stepsCount%2 == 1)
+                {
+                    // Cap 1
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius);
+
+                    // Cap 2
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+
+                    angle += stepLength;
+                }
+
+                // When the inner angles coming from `startAngle` and `endAngle` cross each other,
+                // the `*innerVertexEnd` vertices go past each other and cause the geometry to intersect itself
+                if (innerAnglesCrossEachOther)
+                {
+                    // We need to find where the line defined by `cap1InnerVertexEnd` and `cap1OuterVertexEnd` intersects
+                    // the line defined by `cap2InnerVertexEnd` and `cap2OuterVertexEnd`
+                    // That point is then used instead to prevent the outline from intersecting itself
+
+                    // Make `cap1InnerVertexEnd` the origin and the angle to `cap1OuterVertexEnd` 0 degrees
+                    Vector2 tempCap1OuterVertexEnd = { cap1OuterVertexEnd.x - cap1InnerVertexEnd.x, cap1OuterVertexEnd.y - cap1InnerVertexEnd.y };
+                    Vector2 tempCap2InnerVertexEnd = { cap2InnerVertexEnd.x - cap1InnerVertexEnd.x, cap2InnerVertexEnd.y - cap1InnerVertexEnd.y };
+                    Vector2 tempCap2OuterVertexEnd = { cap2OuterVertexEnd.x - cap1InnerVertexEnd.x, cap2OuterVertexEnd.y - cap1InnerVertexEnd.y };
+
+                    float rotateBy = -atan2f(tempCap1OuterVertexEnd.y, tempCap1OuterVertexEnd.x);
+                    // We only need the y coordinates, so only rotate the y coordinates
+                    float start = sinf(rotateBy)*tempCap2InnerVertexEnd.x + cosf(rotateBy)*tempCap2InnerVertexEnd.y;
+                    float end = sinf(rotateBy)*tempCap2OuterVertexEnd.x + cosf(rotateBy)*tempCap2OuterVertexEnd.y;
+                    float tCross = start/(start - end);
+
+                    Vector2 intersection = { cap2InnerVertexEnd.x + (cap2OuterVertexEnd.x - cap2InnerVertexEnd.x)*tCross, cap2InnerVertexEnd.y + (cap2OuterVertexEnd.y - cap2InnerVertexEnd.y)*tCross };
+
+                    if (segments%2 == 0)
+                    {
+                        // There are an even number of segments, so there's 1 vertex exactly in the middle
+
+                        Vector2 middleInnerVertex = { center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius };
+
+                        // Cap 1
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(middleInnerVertex.x, middleInnerVertex.y);
+
+                        // Cap 2
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(middleInnerVertex.x, middleInnerVertex.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+                    }
+                    else
+                    {
+                        // There are an odd number of segments, so there are 2 vertices in the middle
+
+                        Vector2 middleInnerVertex1 = { center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius };
+                        Vector2 middleInnerVertex2 = { center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius };
+
+                        // Cap 1
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(middleInnerVertex1.x, middleInnerVertex1.y);
+
+                        // Cap 2
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(middleInnerVertex2.x, middleInnerVertex2.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+
+                        // Triangle between the caps
+                        rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(intersection.x, intersection.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                        rlVertex2f(middleInnerVertex1.x, middleInnerVertex1.y);
+
+                        rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                        rlVertex2f(middleInnerVertex2.x, middleInnerVertex2.y);
+                    }
+                }
+                else
+                {
+                    // Cap 1
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap1InnerVertexBeforeEnd.x, cap1InnerVertexBeforeEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap1InnerVertexEnd.x, cap1InnerVertexEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+
+                    // Cap 2
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap2InnerVertexEnd.x, cap2InnerVertexEnd.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2InnerVertexBeforeEnd.x, cap2InnerVertexBeforeEnd.y);
+                }
+            }
+            else
+            {
+                // Cap 1
+                Vector2 cap1FirstInnerVertex = { center.x + cosf(DEG2RAD*startAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*startAngle)*innerInnerRadius };
+                Vector2 cap1FirstOuterVertex = { center.x + cosf(DEG2RAD*startAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*startAngle)*outerOuterRadius };
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(cap1FirstInnerVertex.x, cap1FirstInnerVertex.y);
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(cap1FirstOuterVertex.x, cap1FirstOuterVertex.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(cap1SecondOuterVertex.x, cap1SecondOuterVertex.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(cap1SecondInnerVertex.x, cap1SecondInnerVertex.y);
+
+                // Cap 2
+                Vector2 cap2FirstInnerVertex = { center.x + cosf(DEG2RAD*endAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*endAngle)*innerInnerRadius };
+                Vector2 cap2FirstOuterVertex = { center.x + cosf(DEG2RAD*endAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*endAngle)*outerOuterRadius };
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(cap2FirstInnerVertex.x, cap2FirstInnerVertex.y);
+
+                rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(cap2SecondInnerVertex.x, cap2SecondInnerVertex.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                rlVertex2f(cap2SecondOuterVertex.x, cap2SecondOuterVertex.y);
+
+                rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                rlVertex2f(cap2FirstOuterVertex.x, cap2FirstOuterVertex.y);
+
+                if (capsIntersect)
+                {
+                    // Cap 1
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap1SecondInnerVertex.x, cap1SecondInnerVertex.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap1SecondInnerVertex.x, cap1SecondInnerVertex.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap1SecondOuterVertex.x, cap1SecondOuterVertex.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(capIntersectionVertex.x, capIntersectionVertex.y);
+
+                    // Cap 2
+                    rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2SecondInnerVertex.x, cap2SecondInnerVertex.y);
+
+                    rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(capIntersectionVertex.x, capIntersectionVertex.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
+                    rlVertex2f(cap2SecondOuterVertex.x, cap2SecondOuterVertex.y);
+
+                    rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
+                    rlVertex2f(cap2SecondInnerVertex.x, cap2SecondInnerVertex.y);
+                }
+            }
+        }
+    rlEnd();
+#else
+    rlBegin(RL_TRIANGLES);
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        for (int i = 0; i < segments; i++)
+        {
+            // `innerRadius` outline
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerInnerRadius, center.y + sinf(DEG2RAD*angle)*outerInnerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerInnerRadius, center.y + sinf(DEG2RAD*angle)*innerInnerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerInnerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerInnerRadius);
+
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerInnerRadius, center.y + sinf(DEG2RAD*angle)*outerInnerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerInnerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerInnerRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerInnerRadius);
+
+            // `outerRadius` outline
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerOuterRadius, center.y + sinf(DEG2RAD*angle)*outerOuterRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerOuterRadius, center.y + sinf(DEG2RAD*angle)*innerOuterRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerOuterRadius);
+
+            rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerOuterRadius, center.y + sinf(DEG2RAD*angle)*outerOuterRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerOuterRadius);
+            rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerOuterRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerOuterRadius);
+
+            angle += stepLength;
+        }
+
+        if (showCapLines)
+        {
+            if (thick >= 0.0f)
+            {
+                angle = 0.0f;
+
+                for (int i = 0; i < stepsBeforeOuter; i++)
+                {
+                    // Cap 1
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius);
+
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerOuterRadius);
+
+                    // Cap 2
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerOuterRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius);
+
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius);
+
+                    angle += stepLength;
+                }
+
+                // We've already moved `stepsBeforeOuter` steps from each end
+                int totalStepsLeft = segments - stepsBeforeOuter*2;
+                int innerStepsLeft = stepsBeforeInner - stepsBeforeOuter;
+
+                // Cap 1
+                Vector2 cap1OuterVertexBeforeEnd = { center.x + cosf(DEG2RAD*(startAngle + angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*innerOuterRadius };
+                Vector2 cap1OuterVertexAfterEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*innerOuterRadius };
+                Vector2 cap1InnerVertexBeforeEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + (float)innerStepsLeft*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + (float)innerStepsLeft*stepLength))*outerInnerRadius };
+                Vector2 cap1InnerVertexAfterEnd = { center.x + cosf(DEG2RAD*(startAngle + angle + (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius };
+                Vector2 cap1InnerVertexEnd = { cap1InnerVertexBeforeEnd.x + (cap1InnerVertexAfterEnd.x - cap1InnerVertexBeforeEnd.x)*tInner, cap1InnerVertexBeforeEnd.y + (cap1InnerVertexAfterEnd.y - cap1InnerVertexBeforeEnd.y)*tInner };
+                Vector2 cap1OuterVertexEnd = { cap1OuterVertexBeforeEnd.x + (cap1OuterVertexAfterEnd.x - cap1OuterVertexBeforeEnd.x)*tOuter, cap1OuterVertexBeforeEnd.y + (cap1OuterVertexAfterEnd.y - cap1OuterVertexBeforeEnd.y)*tOuter };
+
+                // Cap 2
+                Vector2 cap2OuterVertexBeforeEnd = { center.x + cosf(DEG2RAD*(endAngle - angle))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*innerOuterRadius };
+                Vector2 cap2OuterVertexAfterEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*innerOuterRadius };
+                Vector2 cap2InnerVertexBeforeEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - (float)innerStepsLeft*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - (float)innerStepsLeft*stepLength))*outerInnerRadius };
+                Vector2 cap2InnerVertexAfterEnd = { center.x + cosf(DEG2RAD*(endAngle - angle - (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - (float)(innerStepsLeft + 1)*stepLength))*outerInnerRadius };
+                Vector2 cap2InnerVertexEnd = { cap2InnerVertexBeforeEnd.x + (cap2InnerVertexAfterEnd.x - cap2InnerVertexBeforeEnd.x)*tInner, cap2InnerVertexBeforeEnd.y + (cap2InnerVertexAfterEnd.y - cap2InnerVertexBeforeEnd.y)*tInner };
+                Vector2 cap2OuterVertexEnd = { cap2OuterVertexBeforeEnd.x + (cap2OuterVertexAfterEnd.x - cap2OuterVertexBeforeEnd.x)*tOuter, cap2OuterVertexBeforeEnd.y + (cap2OuterVertexAfterEnd.y - cap2OuterVertexBeforeEnd.y)*tOuter };
+
+                int stepsCount = (innerAnglesCrossEachOther)? totalStepsLeft/2 : innerStepsLeft;
+
+                for (int i = 0; i < stepsCount; i++)
+                {
+                    // Cap 1
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle + stepLength))*outerInnerRadius);
+
+                    // Cap 2
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle - stepLength))*outerInnerRadius);
+                    rlVertex2f(center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius);
+
+                    angle += stepLength;
+                }
+
+                // When the inner angles coming from `startAngle` and `endAngle` cross each other,
+                // the `*innerVertexEnd` vertices go past each other and cause the geometry to intersect itself
+                if (innerAnglesCrossEachOther)
+                {
+                    // We need to find where the line defined by `cap1InnerVertexEnd` and `cap1OuterVertexEnd` intersects
+                    // the line defined by `cap2InnerVertexEnd` and `cap2OuterVertexEnd`
+                    // That point is then used instead to prevent the outline from intersecting itself
+
+                    // Make `cap1InnerVertexEnd` the origin and the angle to `cap1OuterVertexEnd` 0 degrees
+                    Vector2 tempCap1OuterVertexEnd = { cap1OuterVertexEnd.x - cap1InnerVertexEnd.x, cap1OuterVertexEnd.y - cap1InnerVertexEnd.y };
+                    Vector2 tempCap2InnerVertexEnd = { cap2InnerVertexEnd.x - cap1InnerVertexEnd.x, cap2InnerVertexEnd.y - cap1InnerVertexEnd.y };
+                    Vector2 tempCap2OuterVertexEnd = { cap2OuterVertexEnd.x - cap1InnerVertexEnd.x, cap2OuterVertexEnd.y - cap1InnerVertexEnd.y };
+
+                    float rotateBy = -atan2f(tempCap1OuterVertexEnd.y, tempCap1OuterVertexEnd.x);
+                    // We only need the y coordinates, so only rotate the y coordinates
+                    float start = sinf(rotateBy)*tempCap2InnerVertexEnd.x + cosf(rotateBy)*tempCap2InnerVertexEnd.y;
+                    float end = sinf(rotateBy)*tempCap2OuterVertexEnd.x + cosf(rotateBy)*tempCap2OuterVertexEnd.y;
+                    float tCross = start/(start - end);
+
+                    Vector2 intersection = { cap2InnerVertexEnd.x + (cap2OuterVertexEnd.x - cap2InnerVertexEnd.x)*tCross, cap2InnerVertexEnd.y + (cap2OuterVertexEnd.y - cap2InnerVertexEnd.y)*tCross };
+
+                    if (segments%2 == 0)
+                    {
+                        // There are an even number of segments, so there's 1 vertex exactly in the middle
+
+                        Vector2 middleInnerVertex = { center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius };
+
+                        // Cap 1
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+                        rlVertex2f(middleInnerVertex.x, middleInnerVertex.y);
+
+                        // Cap 2
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(middleInnerVertex.x, middleInnerVertex.y);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+                        rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+                    }
+                    else
+                    {
+                        // There are an odd number of segments, so there are 2 vertices in the middle
+
+                        Vector2 middleInnerVertex1 = { center.x + cosf(DEG2RAD*(startAngle + angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(startAngle + angle))*outerInnerRadius };
+                        Vector2 middleInnerVertex2 = { center.x + cosf(DEG2RAD*(endAngle - angle))*outerInnerRadius, center.y + sinf(DEG2RAD*(endAngle - angle))*outerInnerRadius };
+
+                        // Cap 1
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+                        rlVertex2f(middleInnerVertex1.x, middleInnerVertex1.y);
+
+                        // Cap 2
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(middleInnerVertex2.x, middleInnerVertex2.y);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+                        rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+
+                        // Triangle between the caps
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(middleInnerVertex1.x, middleInnerVertex1.y);
+
+                        rlVertex2f(intersection.x, intersection.y);
+                        rlVertex2f(middleInnerVertex1.x, middleInnerVertex1.y);
+                        rlVertex2f(middleInnerVertex2.x, middleInnerVertex2.y);
+                    }
+                }
+                else
+                {
+                    // Cap 1
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+                    rlVertex2f(cap1InnerVertexBeforeEnd.x, cap1InnerVertexBeforeEnd.y);
+                    rlVertex2f(cap1InnerVertexEnd.x, cap1InnerVertexEnd.y);
+
+                    rlVertex2f(cap1OuterVertexBeforeEnd.x, cap1OuterVertexBeforeEnd.y);
+                    rlVertex2f(cap1InnerVertexEnd.x, cap1InnerVertexEnd.y);
+                    rlVertex2f(cap1OuterVertexEnd.x, cap1OuterVertexEnd.y);
+
+                    // Cap 2
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+                    rlVertex2f(cap2OuterVertexEnd.x, cap2OuterVertexEnd.y);
+                    rlVertex2f(cap2InnerVertexEnd.x, cap2InnerVertexEnd.y);
+
+                    rlVertex2f(cap2OuterVertexBeforeEnd.x, cap2OuterVertexBeforeEnd.y);
+                    rlVertex2f(cap2InnerVertexEnd.x, cap2InnerVertexEnd.y);
+                    rlVertex2f(cap2InnerVertexBeforeEnd.x, cap2InnerVertexBeforeEnd.y);
+                }
+            }
+            else
+            {
+                // Cap 1
+                Vector2 cap1FirstInnerVertex = { center.x + cosf(DEG2RAD*startAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*startAngle)*innerInnerRadius };
+                Vector2 cap1FirstOuterVertex = { center.x + cosf(DEG2RAD*startAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*startAngle)*outerOuterRadius };
+
+                rlVertex2f(cap1FirstInnerVertex.x, cap1FirstInnerVertex.y);
+                rlVertex2f(cap1FirstOuterVertex.x, cap1FirstOuterVertex.y);
+                rlVertex2f(cap1SecondOuterVertex.x, cap1SecondOuterVertex.y);
+
+                rlVertex2f(cap1FirstInnerVertex.x, cap1FirstInnerVertex.y);
+                rlVertex2f(cap1SecondOuterVertex.x, cap1SecondOuterVertex.y);
+                rlVertex2f(cap1SecondInnerVertex.x, cap1SecondInnerVertex.y);
+
+                // Cap 2
+                Vector2 cap2FirstInnerVertex = { center.x + cosf(DEG2RAD*endAngle)*innerInnerRadius, center.y + sinf(DEG2RAD*endAngle)*innerInnerRadius };
+                Vector2 cap2FirstOuterVertex = { center.x + cosf(DEG2RAD*endAngle)*outerOuterRadius, center.y + sinf(DEG2RAD*endAngle)*outerOuterRadius };
+
+                rlVertex2f(cap2FirstInnerVertex.x, cap2FirstInnerVertex.y);
+                rlVertex2f(cap2SecondInnerVertex.x, cap2SecondInnerVertex.y);
+                rlVertex2f(cap2SecondOuterVertex.x, cap2SecondOuterVertex.y);
+
+                rlVertex2f(cap2FirstInnerVertex.x, cap2FirstInnerVertex.y);
+                rlVertex2f(cap2SecondOuterVertex.x, cap2SecondOuterVertex.y);
+                rlVertex2f(cap2FirstOuterVertex.x, cap2FirstOuterVertex.y);
+
+                if (capsIntersect)
+                {
+                    // Cap 1
+                    rlVertex2f(cap1SecondInnerVertex.x, cap1SecondInnerVertex.y);
+                    rlVertex2f(cap1SecondOuterVertex.x, cap1SecondOuterVertex.y);
+                    rlVertex2f(capIntersectionVertex.x, capIntersectionVertex.y);
+
+                    // Cap 2
+                    rlVertex2f(cap2SecondInnerVertex.x, cap2SecondInnerVertex.y);
+                    rlVertex2f(capIntersectionVertex.x, capIntersectionVertex.y);
+                    rlVertex2f(cap2SecondOuterVertex.x, cap2SecondOuterVertex.y);
+                }
+            }
+        }
+
+    rlEnd();
+#endif
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Splines functions
+//----------------------------------------------------------------------------------
+
+// Draw spline: linear, minimum 2 points
+void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color)
+{
+    if (pointCount < 2) return;
+
+#if SUPPORT_SPLINE_MITERS
+    Vector2 prevNormal = (Vector2){-(points[1].y - points[0].y), (points[1].x - points[0].x)};
+    float prevLength = sqrtf(prevNormal.x*prevNormal.x + prevNormal.y*prevNormal.y);
+
+    if (prevLength > 0.0f)
+    {
+        prevNormal.x /= prevLength;
+        prevNormal.y /= prevLength;
+    }
+    else
+    {
+        prevNormal.x = 0.0f;
+        prevNormal.y = 0.0f;
+    }
+
+    Vector2 prevRadius = { 0.5f*thick*prevNormal.x, 0.5f*thick*prevNormal.y };
+
+    for (int i = 0; i < pointCount - 1; i++)
+    {
+        Vector2 normal = { 0 };
+
+        if (i < pointCount - 2)
+        {
+            normal = (Vector2){-(points[i + 2].y - points[i + 1].y), (points[i + 2].x - points[i + 1].x)};
+            float normalLength = sqrtf(normal.x*normal.x + normal.y*normal.y);
+
+            if (normalLength > 0.0f)
+            {
+                normal.x /= normalLength;
+                normal.y /= normalLength;
+            }
+            else
+            {
+                normal.x = 0.0f;
+                normal.y = 0.0f;
+            }
+        }
+        else
+        {
+            normal = prevNormal;
+        }
+
+        Vector2 radius = { prevNormal.x + normal.x, prevNormal.y + normal.y };
+        float radiusLength = sqrtf(radius.x*radius.x + radius.y*radius.y);
+
+        if (radiusLength > 0.0f)
+        {
+            radius.x /= radiusLength;
+            radius.y /= radiusLength;
+        }
+        else
+        {
+            radius.x = 0.0f;
+            radius.y = 0.0f;
+        }
+
+        float cosTheta = radius.x*normal.x + radius.y*normal.y;
+
+        if (cosTheta != 0.0f)
+        {
+            radius.x *= (thick*0.5f/cosTheta);
+            radius.y *= (thick*0.5f/cosTheta);
+        }
+        else
+        {
+            radius.x = 0.0f;
+            radius.y = 0.0f;
+        }
+
+        Vector2 strip[4] = {
+            { points[i].x - prevRadius.x, points[i].y - prevRadius.y },
+            { points[i].x + prevRadius.x, points[i].y + prevRadius.y },
+            { points[i + 1].x - radius.x, points[i + 1].y - radius.y },
+            { points[i + 1].x + radius.x, points[i + 1].y + radius.y }
+        };
+
+        DrawTriangleStrip(strip, 4, color);
+
+        prevRadius = radius;
+        prevNormal = normal;
+    }
+
+#else   // !SUPPORT_SPLINE_MITERS
+
+    Vector2 delta = { 0 };
+    float length = 0.0f;
+    float scale = 0.0f;
+
+    for (int i = 0; i < pointCount - 1; i++)
+    {
+        delta = (Vector2){ points[i + 1].x - points[i].x, points[i + 1].y - points[i].y };
+        length = sqrtf(delta.x*delta.x + delta.y*delta.y);
+
+        if (length > 0) scale = thick/(2*length);
+
+        Vector2 radius = { -scale*delta.y, scale*delta.x };
+        Vector2 strip[4] = {
+            { points[i].x - radius.x, points[i].y - radius.y },
+            { points[i].x + radius.x, points[i].y + radius.y },
+            { points[i + 1].x - radius.x, points[i + 1].y - radius.y },
+            { points[i + 1].x + radius.x, points[i + 1].y + radius.y }
+        };
+
+        DrawTriangleStrip(strip, 4, color);
+    }
+#endif
+
+#if SUPPORT_SPLINE_SEGMENT_CAPS
+    // TODO: Add spline segment rounded caps at the begin/end of the spline?
+#endif
+}
+
+// Draw spline: B-Spline, minimum 4 points
+void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color)
+{
+    if (pointCount < 4) return;
+
+    float a[4] = { 0 };
+    float b[4] = { 0 };
+    float dy = 0.0f;
+    float dx = 0.0f;
+    float size = 0.0f;
+
+    Vector2 currentPoint = { 0 };
+    Vector2 nextPoint = { 0 };
+    Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    for (int i = 0; i < (pointCount - 3); i++)
+    {
+        float t = 0.0f;
+        Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
+
+        a[0] = (-p1.x + 3.0f*p2.x - 3.0f*p3.x + p4.x)/6.0f;
+        a[1] = (3.0f*p1.x - 6.0f*p2.x + 3.0f*p3.x)/6.0f;
+        a[2] = (-3.0f*p1.x + 3.0f*p3.x)/6.0f;
+        a[3] = (p1.x + 4.0f*p2.x + p3.x)/6.0f;
+
+        b[0] = (-p1.y + 3.0f*p2.y - 3.0f*p3.y + p4.y)/6.0f;
+        b[1] = (3.0f*p1.y - 6.0f*p2.y + 3.0f*p3.y)/6.0f;
+        b[2] = (-3.0f*p1.y + 3.0f*p3.y)/6.0f;
+        b[3] = (p1.y + 4.0f*p2.y + p3.y)/6.0f;
+
+        currentPoint.x = a[3];
+        currentPoint.y = b[3];
+
+        if (i == 0) DrawCircleV(currentPoint, thick/2.0f, color);   // Draw init line circle-cap
+
+        if (i > 0)
+        {
+            vertices[0].x = currentPoint.x + dy*size;
+            vertices[0].y = currentPoint.y - dx*size;
+            vertices[1].x = currentPoint.x - dy*size;
+            vertices[1].y = currentPoint.y + dx*size;
+        }
+
+        for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
+        {
+            t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
+
+            nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
+            nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
+
+            dy = nextPoint.y - currentPoint.y;
+            dx = nextPoint.x - currentPoint.x;
+            size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
+
+            if ((i == 0) && (j == 1))
+            {
+                vertices[0].x = currentPoint.x + dy*size;
+                vertices[0].y = currentPoint.y - dx*size;
+                vertices[1].x = currentPoint.x - dy*size;
+                vertices[1].y = currentPoint.y + dx*size;
+            }
+
+            vertices[2*j + 1].x = nextPoint.x - dy*size;
+            vertices[2*j + 1].y = nextPoint.y + dx*size;
+            vertices[2*j].x = nextPoint.x + dy*size;
+            vertices[2*j].y = nextPoint.y - dx*size;
+
+            currentPoint = nextPoint;
+        }
+
+        DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+    }
+
+    // Cap circle drawing at the end of every segment
+    DrawCircleV(currentPoint, thick/2.0f, color);
+}
+
+// Draw spline: Catmull-Rom, minimum 4 points
+void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color)
+{
+    if (pointCount < 4) return;
+
+    float dy = 0.0f;
+    float dx = 0.0f;
+    float size = 0.0f;
+
+    Vector2 currentPoint = points[1];
+    Vector2 nextPoint = { 0 };
+    Vector2 vertices[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    DrawCircleV(currentPoint, thick/2.0f, color);   // Draw init line circle-cap
+
+    for (int i = 0; i < (pointCount - 3); i++)
+    {
+        float t = 0.0f;
+        Vector2 p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], p4 = points[i + 3];
+
+        if (i > 0)
+        {
+            vertices[0].x = currentPoint.x + dy*size;
+            vertices[0].y = currentPoint.y - dx*size;
+            vertices[1].x = currentPoint.x - dy*size;
+            vertices[1].y = currentPoint.y + dx*size;
+        }
+
+        for (int j = 1; j <= SPLINE_SEGMENT_DIVISIONS; j++)
+        {
+            t = ((float)j)/((float)SPLINE_SEGMENT_DIVISIONS);
+
+            float q0 = (-1.0f*t*t*t) + (2.0f*t*t) + (-1.0f*t);
+            float q1 = (3.0f*t*t*t) + (-5.0f*t*t) + 2.0f;
+            float q2 = (-3.0f*t*t*t) + (4.0f*t*t) + t;
+            float q3 = t*t*t - t*t;
+
+            nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
+            nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
+
+            dy = nextPoint.y - currentPoint.y;
+            dx = nextPoint.x - currentPoint.x;
+            size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
+
+            if ((i == 0) && (j == 1))
+            {
+                vertices[0].x = currentPoint.x + dy*size;
+                vertices[0].y = currentPoint.y - dx*size;
+                vertices[1].x = currentPoint.x - dy*size;
+                vertices[1].y = currentPoint.y + dx*size;
+            }
+
+            vertices[2*j + 1].x = nextPoint.x - dy*size;
+            vertices[2*j + 1].y = nextPoint.y + dx*size;
+            vertices[2*j].x = nextPoint.x + dy*size;
+            vertices[2*j].y = nextPoint.y - dx*size;
+
+            currentPoint = nextPoint;
+        }
+
+        DrawTriangleStrip(vertices, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+    }
+
+    // Cap circle drawing at the end of every segment
+    DrawCircleV(currentPoint, thick/2.0f, color);
+}
+
+// Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
+void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color)
+{
+    if (pointCount >= 3)
+    {
+        for (int i = 0; i < pointCount - 2; i += 2) DrawSplineSegmentBezierQuadratic(points[i], points[i + 1], points[i + 2], thick, color);
+
+        // Cap circle drawing at the end of every segment
+        //for (int i = 2; i < pointCount - 2; i += 2) DrawCircleV(points[i], thick/2.0f, color);
+    }
+}
+
+// Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
+void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color)
+{
+    if (pointCount >= 4)
+    {
+        for (int i = 0; i < pointCount - 3; i += 3) DrawSplineSegmentBezierCubic(points[i], points[i + 1], points[i + 2], points[i + 3], thick, color);
+
+        // Cap circle drawing at the end of every segment
+        //for (int i = 3; i < pointCount - 3; i += 3) DrawCircleV(points[i], thick/2.0f, color);
+    }
+}
+
+// Draw spline segment: Linear, 2 points
+void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color)
+{
+    // NOTE: For the linear spline no subdivisions are used, only a single quad
+
+    Vector2 delta = { p2.x - p1.x, p2.y - p1.y };
+    float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
+
+    if ((length > 0) && (thick > 0))
+    {
+        float scale = thick/(2*length);
+
+        Vector2 radius = { -scale*delta.y, scale*delta.x };
+        Vector2 strip[4] = {
+            { p1.x - radius.x, p1.y - radius.y },
+            { p1.x + radius.x, p1.y + radius.y },
+            { p2.x - radius.x, p2.y - radius.y },
+            { p2.x + radius.x, p2.y + radius.y }
+        };
+
+        DrawTriangleStrip(strip, 4, color);
+    }
+}
+
+// Draw spline segment: B-Spline, 4 points
+void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
+{
+    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
+
+    Vector2 currentPoint = { 0 };
+    Vector2 nextPoint = { 0 };
+    float t = 0.0f;
+
+    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    float a[4] = { 0 };
+    float b[4] = { 0 };
+
+    a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
+    a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
+    a[2] = (-3*p1.x + 3*p3.x)/6.0f;
+    a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
+
+    b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
+    b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
+    b[2] = (-3*p1.y + 3*p3.y)/6.0f;
+    b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
+
+    currentPoint.x = a[3];
+    currentPoint.y = b[3];
+
+    for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
+    {
+        t = step*(float)i;
+
+        nextPoint.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
+        nextPoint.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
+
+        float dy = nextPoint.y - currentPoint.y;
+        float dx = nextPoint.x - currentPoint.x;
+        float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
+
+        if (i == 1)
+        {
+            points[0].x = currentPoint.x + dy*size;
+            points[0].y = currentPoint.y - dx*size;
+            points[1].x = currentPoint.x - dy*size;
+            points[1].y = currentPoint.y + dx*size;
+        }
+
+        points[2*i + 1].x = nextPoint.x - dy*size;
+        points[2*i + 1].y = nextPoint.y + dx*size;
+        points[2*i].x = nextPoint.x + dy*size;
+        points[2*i].y = nextPoint.y - dx*size;
+
+        currentPoint = nextPoint;
+    }
+
+    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS+2, color);
+}
+
+// Draw spline segment: Catmull-Rom, 4 points
+void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color)
+{
+    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
+
+    Vector2 currentPoint = p1;
+    Vector2 nextPoint = { 0 };
+    float t = 0.0f;
+
+    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    for (int i = 0; i <= SPLINE_SEGMENT_DIVISIONS; i++)
+    {
+        t = step*(float)i;
+
+        float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
+        float q1 = (3*t*t*t) + (-5*t*t) + 2;
+        float q2 = (-3*t*t*t) + (4*t*t) + t;
+        float q3 = t*t*t - t*t;
+
+        nextPoint.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
+        nextPoint.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
+
+        float dy = nextPoint.y - currentPoint.y;
+        float dx = nextPoint.x - currentPoint.x;
+        float size = (0.5f*thick)/sqrtf(dx*dx + dy*dy);
+
+        if (i == 1)
+        {
+            points[0].x = currentPoint.x + dy*size;
+            points[0].y = currentPoint.y - dx*size;
+            points[1].x = currentPoint.x - dy*size;
+            points[1].y = currentPoint.y + dx*size;
+        }
+
+        points[2*i + 1].x = nextPoint.x - dy*size;
+        points[2*i + 1].y = nextPoint.y + dx*size;
+        points[2*i].x = nextPoint.x + dy*size;
+        points[2*i].y = nextPoint.y - dx*size;
+
+        currentPoint = nextPoint;
+    }
+
+    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+}
+
+// Draw spline segment: Quadratic Bezier, 2 points, 1 control point
+void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color)
+{
+    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
+
+    Vector2 previous = p1;
+    Vector2 current = { 0 };
+    float t = 0.0f;
+
+    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
+    {
+        t = step*(float)i;
+
+        float a = powf(1.0f - t, 2);
+        float b = 2.0f*(1.0f - t)*t;
+        float c = powf(t, 2);
+
+        // NOTE: The easing functions aren't suitable here because they don't take a control point
+        current.y = a*p1.y + b*c2.y + c*p3.y;
+        current.x = a*p1.x + b*c2.x + c*p3.x;
+
+        float dy = current.y - previous.y;
+        float dx = current.x - previous.x;
+        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
+
+        if (i == 1)
+        {
+            points[0].x = previous.x + dy*size;
+            points[0].y = previous.y - dx*size;
+            points[1].x = previous.x - dy*size;
+            points[1].y = previous.y + dx*size;
+        }
+
+        points[2*i + 1].x = current.x - dy*size;
+        points[2*i + 1].y = current.y + dx*size;
+        points[2*i].x = current.x + dy*size;
+        points[2*i].y = current.y - dx*size;
+
+        previous = current;
+    }
+
+    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+}
+
+// Draw spline segment: Cubic Bezier, 2 points, 2 control points
+void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color)
+{
+    const float step = 1.0f/SPLINE_SEGMENT_DIVISIONS;
+
+    Vector2 previous = p1;
+    Vector2 current = { 0 };
+    float t = 0.0f;
+
+    Vector2 points[2*SPLINE_SEGMENT_DIVISIONS + 2] = { 0 };
+
+    for (int i = 1; i <= SPLINE_SEGMENT_DIVISIONS; i++)
+    {
+        t = step*(float)i;
+
+        float a = powf(1.0f - t, 3);
+        float b = 3.0f*powf(1.0f - t, 2)*t;
+        float c = 3.0f*(1.0f - t)*powf(t, 2);
+        float d = powf(t, 3);
+
+        current.y = a*p1.y + b*c2.y + c*c3.y + d*p4.y;
+        current.x = a*p1.x + b*c2.x + c*c3.x + d*p4.x;
+
+        float dy = current.y - previous.y;
+        float dx = current.x - previous.x;
+        float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
+
+        if (i == 1)
+        {
+            points[0].x = previous.x + dy*size;
+            points[0].y = previous.y - dx*size;
+            points[1].x = previous.x - dy*size;
+            points[1].y = previous.y + dx*size;
+        }
+
+        points[2*i + 1].x = current.x - dy*size;
+        points[2*i + 1].y = current.y + dx*size;
+        points[2*i].x = current.x + dy*size;
+        points[2*i].y = current.y - dx*size;
+
+        previous = current;
+    }
+
+    DrawTriangleStrip(points, 2*SPLINE_SEGMENT_DIVISIONS + 2, color);
+}
+
+// Get spline point for a given t [0.0f .. 1.0f], Linear
+Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t)
+{
+    Vector2 point = { 0 };
+
+    point.x = startPos.x*(1.0f - t) + endPos.x*t;
+    point.y = startPos.y*(1.0f - t) + endPos.y*t;
+
+    return point;
+}
+
+// Get spline point for a given t [0.0f .. 1.0f], B-Spline
+Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
+{
+    Vector2 point = { 0 };
+
+    float a[4] = { 0 };
+    float b[4] = { 0 };
+
+    a[0] = (-p1.x + 3*p2.x - 3*p3.x + p4.x)/6.0f;
+    a[1] = (3*p1.x - 6*p2.x + 3*p3.x)/6.0f;
+    a[2] = (-3*p1.x + 3*p3.x)/6.0f;
+    a[3] = (p1.x + 4*p2.x + p3.x)/6.0f;
+
+    b[0] = (-p1.y + 3*p2.y - 3*p3.y + p4.y)/6.0f;
+    b[1] = (3*p1.y - 6*p2.y + 3*p3.y)/6.0f;
+    b[2] = (-3*p1.y + 3*p3.y)/6.0f;
+    b[3] = (p1.y + 4*p2.y + p3.y)/6.0f;
+
+    point.x = a[3] + t*(a[2] + t*(a[1] + t*a[0]));
+    point.y = b[3] + t*(b[2] + t*(b[1] + t*b[0]));
+
+    return point;
+}
+
+// Get spline point for a given t [0.0f .. 1.0f], Catmull-Rom
+Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t)
+{
+    Vector2 point = { 0 };
+
+    float q0 = (-1*t*t*t) + (2*t*t) + (-1*t);
+    float q1 = (3*t*t*t) + (-5*t*t) + 2;
+    float q2 = (-3*t*t*t) + (4*t*t) + t;
+    float q3 = t*t*t - t*t;
+
+    point.x = 0.5f*((p1.x*q0) + (p2.x*q1) + (p3.x*q2) + (p4.x*q3));
+    point.y = 0.5f*((p1.y*q0) + (p2.y*q1) + (p3.y*q2) + (p4.y*q3));
+
+    return point;
+}
+
+// Get spline point for a given t [0.0f .. 1.0f], Quadratic Bezier
+Vector2 GetSplinePointBezierQuadratic(Vector2 startPos, Vector2 controlPos, Vector2 endPos, float t)
+{
+    Vector2 point = { 0 };
+
+    float a = powf(1.0f - t, 2);
+    float b = 2.0f*(1.0f - t)*t;
+    float c = powf(t, 2);
+
+    point.y = a*startPos.y + b*controlPos.y + c*endPos.y;
+    point.x = a*startPos.x + b*controlPos.x + c*endPos.x;
+
+    return point;
+}
+
+// Get spline point for a given t [0.0f .. 1.0f], Cubic Bezier
+Vector2 GetSplinePointBezierCubic(Vector2 startPos, Vector2 startControlPos, Vector2 endControlPos, Vector2 endPos, float t)
+{
+    Vector2 point = { 0 };
+
+    float a = powf(1.0f - t, 3);
+    float b = 3.0f*powf(1.0f - t, 2)*t;
+    float c = 3.0f*(1.0f - t)*powf(t, 2);
+    float d = powf(t, 3);
+
+    point.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y;
+    point.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x;
+
+    return point;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Collision Detection functions
+//----------------------------------------------------------------------------------
+
+// Check if point is inside rectangle
+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;
+}
+
+// Check if point is inside circle
+bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius)
+{
+    bool collision = false;
+
+    float distanceSquared = (point.x - center.x)*(point.x - center.x) + (point.y - center.y)*(point.y - center.y);
+
+    if (distanceSquared <= radius*radius) collision = true;
+
+    return collision;
+}
+
+// Check if point is inside a triangle defined by three points (p1, p2, p3)
+bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3)
+{
+    bool collision = false;
+
+    float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
+                  ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
+
+    float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
+                 ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
+
+    float gamma = 1.0f - alpha - beta;
+
+    if ((alpha > 0) && (beta > 0) && (gamma > 0)) collision = true;
+
+    return collision;
+}
+
+// Check if point is within a polygon described by array of vertices
+// NOTE: Based on http://jeffreythompson.org/collision-detection/poly-point.php
+bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount)
+{
+    bool collision = false;
+
+    if (pointCount > 2)
+    {
+        for (int i = 0, j = pointCount - 1; i < pointCount; j = i++)
+        {
+            if ((points[i].y > point.y) != (points[j].y > point.y) &&
+                (point.x < (points[j].x - points[i].x)*(point.y - points[i].y)/(points[j].y - points[i].y) + points[i].x))
+            {
+                collision = !collision;
+            }
+        }
+    }
+
+    return collision;
+}
+
+// Check collision between two rectangles
+bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
+{
+    bool collision = false;
+
+    if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) &&
+        (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true;
+
+    return collision;
+}
+
+// Check collision between two circles
+bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
+{
+    bool collision = false;
+
+    float dx = center2.x - center1.x;      // X distance between centers
+    float dy = center2.y - center1.y;      // Y distance between centers
+
+    float distanceSquared = dx*dx + dy*dy; // Distance between centers squared
+    float radiusSum = radius1 + radius2;
+
+    collision = (distanceSquared <= (radiusSum*radiusSum));
+
+    return collision;
+}
+
+// Check collision between circle and rectangle
+// NOTE: Reviewed version to take into account corner limit case
+bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
+{
+    bool collision = false;
+
+    float recCenterX = rec.x + rec.width/2.0f;
+    float recCenterY = rec.y + rec.height/2.0f;
+
+    float dx = fabsf(center.x - recCenterX);
+    float dy = fabsf(center.y - recCenterY);
+
+    if ((dx <= (rec.width/2.0f + radius)) && (dy <= (rec.height/2.0f + radius)))
+    {
+        if (dx <= (rec.width/2.0f)) collision = true;
+        else if (dy <= (rec.height/2.0f)) collision = true;
+        else
+        {
+            float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
+                (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
+
+            collision = (cornerDistanceSq <= (radius*radius));
+        }
+    }
+
+    return collision;
+}
+
+// Check the collision between two lines defined by two points each, returns collision point by reference
+// REF: https://en.wikipedia.org/wiki/Line–line_intersection#Given_two_points_on_each_line_segment
+bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint)
+{
+    bool collision = false;
+
+    float rx = endPos1.x - startPos1.x;
+    float ry = endPos1.y - startPos1.y;
+    float sx = endPos2.x - startPos2.x;
+    float sy = endPos2.y - startPos2.y;
+
+    float div = rx*sy - ry*sx;
+
+    if (fabsf(div) >= FLT_EPSILON)
+    {
+        float s12x = startPos2.x - startPos1.x;
+        float s12y = startPos2.y - startPos1.y;
+
+        float t = (s12x*sy - s12y*sx)/div;
+        float u = (s12x*ry - s12y*rx)/div;
+
+        if ((0.0f <= t) && (t <= 1.0f) && (0.0f <= u) && (u <= 1.0f))
+        {
+            if (collisionPoint)
+            {
+                collisionPoint->x = startPos1.x + t*rx;
+                collisionPoint->y = startPos1.y + t*ry;
+            }
+
+            collision = true;
+        }
+    }
+
+    return collision;
+}
+
+// Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
+bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold)
+{
+    bool collision = false;
+
+    float dxc = point.x - p1.x;
+    float dyc = point.y - p1.y;
+    float dxl = p2.x - p1.x;
+    float dyl = p2.y - p1.y;
+    float cross = dxc*dyl - dyc*dxl;
+
+    if (fabsf(cross) < (threshold*fmaxf(fabsf(dxl), fabsf(dyl))))
+    {
+        if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x));
+        else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y));
+    }
+
+    return collision;
+}
+
+// Check if circle collides with a line created between two points [p1] and [p2]
+bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2)
+{
+    bool collision = false;
+
+    float dx = p1.x - p2.x;
+    float dy = p1.y - p2.y;
+
+    if ((fabsf(dx) + fabsf(dy)) <= FLT_EPSILON)
+    {
+        collision = CheckCollisionCircles(p1, 0, center, radius);
+    }
+    else
+    {
+        float lengthSQ = ((dx*dx) + (dy*dy));
+        float dotProduct = (((center.x - p1.x)*(p2.x - p1.x)) + ((center.y - p1.y)*(p2.y - p1.y)))/(lengthSQ);
+
+        if (dotProduct > 1.0f) dotProduct = 1.0f;
+        else if (dotProduct < 0.0f) dotProduct = 0.0f;
+
+        float dx2 = (p1.x - (dotProduct*(dx))) - center.x;
+        float dy2 = (p1.y - (dotProduct*(dy))) - center.y;
+        float distanceSQ = ((dx2*dx2) + (dy2*dy2));
+
+        if (distanceSQ <= radius*radius) collision = true;
+    }
+
+    return collision;
+}
+
+// Get collision rectangle for two rectangles collision
+Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
+{
+    Rectangle overlap = { 0 };
+
+    float left = (rec1.x > rec2.x)? rec1.x : rec2.x;
+    float right1 = rec1.x + rec1.width;
+    float right2 = rec2.x + rec2.width;
+    float right = (right1 < right2)? right1 : right2;
+    float top = (rec1.y > rec2.y)? rec1.y : rec2.y;
+    float bottom1 = rec1.y + rec1.height;
+    float bottom2 = rec2.y + rec2.height;
+    float bottom = (bottom1 < bottom2)? bottom1 : bottom2;
+
+    if ((left < right) && (top < bottom))
+    {
+        overlap.x = left;
+        overlap.y = top;
+        overlap.width = right - left;
+        overlap.height = bottom - top;
+    }
+
+    return overlap;
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// Cubic easing in-out
+// NOTE: Used by DrawLineBezier() only
+static float EaseCubicInOut(float t, float b, float c, float d)
+{
+    float result = 0.0f;
+
+    if ((t /= 0.5f*d) < 1) result = 0.5f*c*t*t*t + b;
+    else
+    {
+        t -= 2;
+        result = 0.5f*c*(t*t*t + 2.0f) + b;
+    }
+
+    return result;
+}
+
+#endif // SUPPORT_MODULE_RSHAPES
diff --git a/raylib/src/rtext.c b/raylib/src/rtext.c
--- a/raylib/src/rtext.c
+++ b/raylib/src/rtext.c
@@ -3,30 +3,26 @@
 *   rtext - Basic functions to load fonts and draw text
 *
 *   CONFIGURATION:
-*       #define SUPPORT_MODULE_RTEXT
+*       #define SUPPORT_MODULE_RTEXT        1
 *           rtext module is included in the build
 *
-*       #define SUPPORT_DEFAULT_FONT
-*           Load default raylib font on initialization to be used by DrawText() and MeasureText()
-*           If no default font loaded, DrawTextEx() and MeasureTextEx() are required
-*
-*       #define SUPPORT_FILEFORMAT_FNT
-*       #define SUPPORT_FILEFORMAT_TTF
-*       #define SUPPORT_FILEFORMAT_BDF
+*       #define SUPPORT_FILEFORMAT_FNT      1
+*       #define SUPPORT_FILEFORMAT_TTF      1
+*       #define SUPPORT_FILEFORMAT_BDF      0
 *           Selected desired fileformats to be supported for loading. Some of those formats are
-*           supported by default, to remove support, just comment unrequired #define in this module
-*
-*       #define SUPPORT_FONT_ATLAS_WHITE_REC
-*           On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
-*           at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
-*           drawing text and shapes with a single draw call [SetShapesTexture()]
+*           supported by default, to remove support, #define as 0 in this module or your build system
 *
-*       #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
-*           TextSplit() function static buffer max size
+*       #define MAX_TEXT_BUFFER_LENGTH   1024
+*           Text functions using static buffer max size
 *
-*       #define MAX_TEXTSPLIT_COUNT
+*       #define MAX_TEXTSPLIT_COUNT       128
 *           TextSplit() function static substrings pointers array (pointing to static buffer)
 *
+*       #define FONT_ATLAS_CORNER_REC_SIZE  3
+*           On font atlas image generation [GenImageFontAtlas()], add a NxN pixels white rectangle
+*           at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
+*           drawing text and shapes with a single draw call [SetShapesTexture()]
+*
 *   DEPENDENCIES:
 *       stb_truetype  - Load TTF file and rasterize characters data
 *       stb_rect_pack - Rectangles packing algorithms, required for font atlas generation
@@ -57,17 +53,17 @@
 
 #include "config.h"         // Defines module configuration flags
 
-#if defined(SUPPORT_MODULE_RTEXT)
+#if SUPPORT_MODULE_RTEXT
 
 #include "rlgl.h"           // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
 
 #include <stdlib.h>         // Required for: malloc(), free()
-#include <stdio.h>          // Required for: vsprintf()
-#include <string.h>         // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
+#include <stdio.h>          // Required for: vsprintf(), snprintf()
+#include <string.h>         // Required for: strcmp(), strstr(), strncpy(), sscanf() [Used in LoadBMFont()]
 #include <stdarg.h>         // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
 #include <ctype.h>          // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
 
-#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_TTF || SUPPORT_FILEFORMAT_BDF
     #if defined(__GNUC__) // GCC and Clang
         #pragma GCC diagnostic push
         #pragma GCC diagnostic ignored "-Wunused-function"
@@ -83,7 +79,7 @@
     #endif
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_TTF)
+#if SUPPORT_FILEFORMAT_TTF
     #if defined(__GNUC__) // GCC and Clang
         #pragma GCC diagnostic push
         #pragma GCC diagnostic ignored "-Wunused-function"
@@ -105,16 +101,20 @@
 // Defines and Macros
 //----------------------------------------------------------------------------------
 #ifndef MAX_TEXT_BUFFER_LENGTH
-    #define MAX_TEXT_BUFFER_LENGTH              1024        // Size of internal static buffers used on some functions:
-                                                            // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
-#endif
-#ifndef MAX_TEXT_UNICODE_CHARS
-    #define MAX_TEXT_UNICODE_CHARS               512        // Maximum number of unicode codepoints: GetCodepoints()
+    #define MAX_TEXT_BUFFER_LENGTH     1024         // Size of internal static buffers used on some functions:
+                                                    // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
 #endif
 #ifndef MAX_TEXTSPLIT_COUNT
-    #define MAX_TEXTSPLIT_COUNT                  128        // Maximum number of substrings to split: TextSplit()
+    #define MAX_TEXTSPLIT_COUNT         128         // Maximum number of substrings to split: TextSplit()
 #endif
 
+#ifndef FONT_ATLAS_CORNER_REC_SIZE
+    // On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
+    // at the bottom-right corner of the atlas. It can be useful for shapes drawing, to allow
+    // drawing text and shapes with a single draw call [SetShapesTexture()]
+    #define FONT_ATLAS_CORNER_REC_SIZE    3         // Size of white rectangle drawn on font atlas on font loading
+#endif
+
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
@@ -123,13 +123,13 @@
 //----------------------------------------------------------------------------------
 // Global variables
 //----------------------------------------------------------------------------------
-#if defined(SUPPORT_DEFAULT_FONT)
 // Default font provided by raylib
 // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
 static Font defaultFont = { 0 };
-#endif
-static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
 
+// Text vertical line spacing in pixels (between lines)
+static int textLineSpacing = 2;
+
 //----------------------------------------------------------------------------------
 // Other Modules Functions Declaration (required by text)
 //----------------------------------------------------------------------------------
@@ -138,38 +138,36 @@
 //----------------------------------------------------------------------------------
 // Module Internal Functions Declaration
 //----------------------------------------------------------------------------------
-#if defined(SUPPORT_FILEFORMAT_FNT)
+#if SUPPORT_FILEFORMAT_FNT
 static Font LoadBMFont(const char *fileName);   // Load a BMFont file (AngelCode font file)
 #endif
-#if defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_BDF
 static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, const int *codepoints, int codepointCount, int *outFontSize);
 #endif
 
-#if defined(SUPPORT_DEFAULT_FONT)
 extern void LoadFontDefault(void);
 extern void UnloadFontDefault(void);
-#endif
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 //----------------------------------------------------------------------------------
-#if defined(SUPPORT_DEFAULT_FONT)
 // Load raylib default font
 extern void LoadFontDefault(void)
 {
     #define BIT_CHECK(a,b) ((a) & (1u << (b)))
 
-    // Check to see if we have already allocated the font for an image, and if we don't need to upload, then just return
+    // Check to see if the font for an image has already been allocated,
+    // and if no need to upload, then return
     if (defaultFont.glyphs != NULL) return;
 
     // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
     // REF: http://www.utf8-chartable.de/unicode-utf8-table.pl
 
-    defaultFont.glyphCount = 224;   // Number of glyphs included in our default font
-    defaultFont.glyphPadding = 0;   // Characters padding
+    defaultFont.glyphCount = 224; // Number of glyphs included in our default font
+    defaultFont.glyphPadding = 0; // Characters padding
 
     // Default font is directly defined here (data generated from a sprite font image)
-    // This way, we reconstruct Font without creating large global variables
+    // This way, reconstructing Font without creating large global variables
     // This data is automatically allocated to Stack and automatically deallocated at the end of this function
     unsigned int defaultFontData[512] = {
         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f,
@@ -217,7 +215,7 @@
         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
 
     int charsHeight = 10;
-    int charsDivisor = 1;    // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
+    int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
 
     int charsWidth[224] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6,
                             7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5,
@@ -244,8 +242,8 @@
         {
             if (BIT_CHECK(defaultFontData[counter], j))
             {
-                // NOTE: We are unreferencing data as short, so,
-                // we must consider data as little-endian order (alpha + gray)
+                // NOTE: Unreferencing data as short, so,
+                // considering data as little-endian (alpha + gray)
                 ((unsigned short *)imFont.data)[i + j] = 0xffff;
             }
             else
@@ -260,8 +258,8 @@
 
     defaultFont.texture = LoadTextureFromImage(imFont);
 
-    // we have already loaded the font glyph data an image, and the GPU is ready, we are done
-    // if we don't do this, we will leak memory by reallocating the glyphs and rects
+    // Check again if font glyph data has been already loaded
+    // to avoid reallocating the glyphs and rects
     if (defaultFont.glyphs != NULL)
     {
         UnloadImage(imFont);
@@ -270,7 +268,6 @@
 
     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
     //------------------------------------------------------------------------------
-
     // Allocate space for our characters info data
     // NOTE: This memory must be freed at end! --> Done by CloseWindow()
     defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo));
@@ -329,17 +326,11 @@
     defaultFont.glyphs = NULL;
     defaultFont.recs = NULL;
 }
-#endif      // SUPPORT_DEFAULT_FONT
 
-// Get the default font, useful to be used with extended parameters
+// Get the default font
 Font GetFontDefault()
 {
-#if defined(SUPPORT_DEFAULT_FONT)
     return defaultFont;
-#else
-    Font font = { 0 };
-    return font;
-#endif
 }
 
 // Load Font from file into GPU memory (VRAM)
@@ -361,15 +352,15 @@
 
     Font font = { 0 };
 
-#if defined(SUPPORT_FILEFORMAT_TTF)
+#if SUPPORT_FILEFORMAT_TTF
     if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
     else
 #endif
-#if defined(SUPPORT_FILEFORMAT_FNT)
+#if SUPPORT_FILEFORMAT_FNT
     if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName);
     else
 #endif
-#if defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_BDF
     if (IsFileExtension(fileName, ".bdf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
     else
 #endif
@@ -383,16 +374,16 @@
     if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
     else
     {
-        SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
+        SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, set point filter (the best performance)
         TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
     }
 
     return font;
 }
 
-// Load Font from TTF or BDF font file with generation parameters
-// NOTE: You can pass an array with desired characters, those characters should be available in the font
-// if array is NULL, default char set is selected 32..126
+// Load font from file with defined codepoints and generation size
+// NOTE: NULL for codepoints and 0 for codepointCount to load the default character set (32..126),
+// font size is provided in pixels height
 Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount)
 {
     Font font = { 0 };
@@ -426,17 +417,16 @@
     int charSpacing = 0;
     int lineSpacing = 0;
 
-    int x = 0;
-    int y = 0;
-
-    // We allocate a temporal arrays for glyphs data measures,
-    // once we get the actual number of glyphs, we copy data to a sized arrays
+    // Allocate a temporal arrays for glyphs data measures,
+    // once the actual number of glyphs is obtained, copy data to a sized array
     int tempCharValues[MAX_GLYPHS_FROM_IMAGE] = { 0 };
     Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE] = { 0 };
 
     Color *pixels = LoadImageColors(image);
 
     // Parse image data to get charSpacing and lineSpacing
+    int x = 0;
+    int y = 0;
     for (y = 0; y < image.height; y++)
     {
         for (x = 0; x < image.width; x++)
@@ -447,7 +437,12 @@
         if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
     }
 
-    if ((x == 0) || (y == 0)) return font; // Security check
+    // Security check
+    if ((x == 0) || (y == 0))
+    {
+        UnloadImageColors(pixels);
+        return font;
+    }
 
     charSpacing = x;
     lineSpacing = y;
@@ -455,7 +450,8 @@
     int charHeight = 0;
     int j = 0;
 
-    while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
+    while (((lineSpacing + j) < image.height) &&
+        !COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
 
     charHeight = j;
 
@@ -478,7 +474,8 @@
 
             int charWidth = 0;
 
-            while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++;
+            while (((xPosToRead + charWidth) < image.width) &&
+                  !COLOR_EQUAL(pixels[(lineSpacing + (charHeight + lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++;
 
             tempCharRecs[index].width = (float)charWidth;
 
@@ -491,7 +488,7 @@
         xPosToRead = charSpacing;
     }
 
-    // NOTE: We need to remove key color borders from image to avoid weird
+    // NOTE: Key color borders need to be removed from image to avoid weird
     // artifacts on texture scaling when using TEXTURE_FILTER_BILINEAR or TEXTURE_FILTER_TRILINEAR
     for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
 
@@ -509,8 +506,8 @@
     font.glyphCount = index;
     font.glyphPadding = 0;
 
-    // We got tempCharValues and tempCharsRecs populated with glyphs data
-    // Now we move temp data to sized charValues and charRecs arrays
+    // Populate tempCharValues and tempCharsRecs with glyphs data
+    // Move temp data to sized charValues and charRecs arrays
     font.glyphs = (GlyphInfo *)RL_MALLOC(font.glyphCount*sizeof(GlyphInfo));
     font.recs = (Rectangle *)RL_MALLOC(font.glyphCount*sizeof(Rectangle));
 
@@ -543,12 +540,12 @@
     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;
 
-#if defined(SUPPORT_FILEFORMAT_TTF)
+#if SUPPORT_FILEFORMAT_TTF
     if (TextIsEqual(fileExtLower, ".ttf") ||
         TextIsEqual(fileExtLower, ".otf"))
     {
@@ -556,7 +553,7 @@
     }
     else
 #endif
-#if defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_BDF
     if (TextIsEqual(fileExtLower, ".bdf"))
     {
         font.glyphs = LoadFontDataBDF(fileData, dataSize, codepoints, (codepointCount > 0)? codepointCount : 95, &font.baseSize);
@@ -568,7 +565,7 @@
         font.glyphs = NULL;
     }
 
-#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_TTF || SUPPORT_FILEFORMAT_BDF
     if (font.glyphs != NULL)
     {
         font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
@@ -587,15 +584,20 @@
 
         TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
     }
-    else font = GetFontDefault();
+    else
+    {
+        TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
+        font = GetFontDefault();
+    }
 #else
+    TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font");
     font = GetFontDefault();
 #endif
 
     return font;
 }
 
-// Check if a font is valid (font data loaded)
+// Check if font is valid (font data loaded)
 // WARNING: GPU texture not checked
 bool IsFontValid(Font font)
 {
@@ -629,16 +631,17 @@
     GlyphInfo *glyphs = NULL;
     int glyphCounter = 0;
 
-#if defined(SUPPORT_FILEFORMAT_TTF)
+#if SUPPORT_FILEFORMAT_TTF
     // Load font data (including pixel data) from TTF memory file
     // NOTE: Loaded information should be enough to generate font image atlas, using any packaging method
     if (fileData != NULL)
     {
         bool genFontChars = false;
         stbtt_fontinfo fontInfo = { 0 };
-        int *requiredCodepoints = (int *)codepoints; // TODO: Should we create a shallow copy to avoid "dealing" with a const user array?
+        // TODO: Should a shallow copy be created to avoid "dealing" with a const user array?
+        int *requiredCodepoints = (int *)codepoints;
 
-        if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0))     // Initialize font for data reading
+        if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0)) // Initialize font for data reading
         {
             // Calculate font scale factor
             float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
@@ -654,7 +657,7 @@
             codepointCount = (codepointCount > 0)? codepointCount : 95;
 
             // Fill fontChars in case not provided externally
-            // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
+            // NOTE: By default filling glyphCount consecutively, starting at 32 (Space)
             if (requiredCodepoints == NULL)
             {
                 requiredCodepoints = (int *)RL_MALLOC(codepointCount*sizeof(int));
@@ -682,9 +685,9 @@
                 //  Render a unicode codepoint to a bitmap
                 //      stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
                 //      stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be
-                //      stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide
+                //      stbtt_MakeCodepointBitmap()          -- renders into a provided bitmap
 
-                // Check if a glyph is available in the font
+                // Check if glyph is available in the font
                 // WARNING: if (index == 0), glyph not found, it could fallback to default .notdef glyph (if defined in font)
                 int index = stbtt_FindGlyphIndex(&fontInfo, cp);
 
@@ -714,7 +717,7 @@
                         default: break;
                     }
 
-                    if (glyphs[k].image.data != NULL)    // Glyph data has been found in the font
+                    if (glyphs[k].image.data != NULL) // Glyph data has been found in the font
                     {
                         stbtt_GetCodepointHMetrics(&fontInfo, cp, &glyphs[k].advanceX, NULL);
                         glyphs[k].advanceX = (int)((float)glyphs[k].advanceX*scaleFactor);
@@ -732,13 +735,13 @@
                     }
                     //else TRACELOG(LOG_WARNING, "FONT: Glyph [0x%08x] has no image data available", cp); // Only reported for 0x20 and 0x3000
 
-                    // We create an empty image for Space character (0x20), useful for sprite font generation
+                    // Create an empty image for Space character (0x20), useful for sprite font generation
                     // NOTE: Another space to consider: 0x3000 (CJK - Ideographic Space)
                     if ((cp == 0x20) || (cp == 0x3000))
                     {
                         stbtt_GetCodepointHMetrics(&fontInfo, cp, &glyphs[k].advanceX, NULL);
                         glyphs[k].advanceX = (int)((float)glyphs[k].advanceX*scaleFactor);
-                        
+
                         Image imSpace = {
                             .data = NULL,
                             .width = glyphs[k].advanceX,
@@ -789,20 +792,20 @@
 
 // Generate image font atlas using chars info
 // NOTE: Packing method: 0-Default, 1-Skyline
-#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_TTF || SUPPORT_FILEFORMAT_BDF
 Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod)
 {
     Image atlas = { 0 };
 
     if (glyphs == NULL)
     {
-        TRACELOG(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
+        TRACELOG(LOG_WARNING, "FONT: Provided glyphs info not valid, returning empty image atlas");
         return atlas;
     }
 
     *glyphRecs = NULL;
 
-    // In case no chars count provided we suppose default of 95
+    // In case no chars count provided, suppose default of 95
     glyphCount = (glyphCount > 0)? glyphCount : 95;
 
     // NOTE: Rectangles memory is loaded here!
@@ -818,25 +821,11 @@
         totalWidth += glyphs[i].image.width + 2*padding;
     }
 
-//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE
-#if defined(SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE)
-    int rowCount = 0;
-    int imageSize = 64;  // Define minimum starting value to avoid unnecessary calculation steps for very small images
-
-    // NOTE: maxGlyphWidth is maximum possible space left at the end of row
-    while (totalWidth > (imageSize - maxGlyphWidth)*rowCount)
-    {
-        imageSize *= 2;                                 // Double the size of image (to keep POT)
-        rowCount = imageSize/(fontSize + 2*padding);    // Calculate new row count for the new image size
-    }
-
-    atlas.width = imageSize;   // Atlas bitmap width
-    atlas.height = imageSize;  // Atlas bitmap height
-#else
     int paddedFontSize = fontSize + 2*padding;
 
-    // No need for a so-conservative atlas generation
-    // NOTE: Multiplying total expected are by 1.2f scale factor
+    // Estimate image atlas size from available data
+    // NOTE: Multiplying total expected area by 1.2f scale factor but in case
+    // some glyphs do not fit, the atlas height is scaled x2 to fit them
     float totalArea = totalWidth*paddedFontSize*1.2f;
     float imageMinSize = sqrtf(totalArea);
     int imageSize = (int)powf(2, ceilf(logf(imageMinSize)/logf(2)));
@@ -851,17 +840,16 @@
         atlas.width = imageSize;   // Atlas bitmap width
         atlas.height = imageSize;  // Atlas bitmap height
     }
-#endif
 
     int atlasDataSize = atlas.width*atlas.height; // Save total size for bounds checking
     atlas.data = (unsigned char *)RL_CALLOC(atlasDataSize, 1); // Create a bitmap to store characters (8 bpp)
     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
     atlas.mipmaps = 1;
 
-    // DEBUG: We can see padding in the generated image setting a gray background...
+    // DEBUG: View padding in the generated image setting a gray background...
     //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
 
-    if (packMethod == 0)   // Use basic packing algorithm
+    if (packMethod == 0) // Use basic packing algorithm
     {
         int offsetX = padding;
         int offsetY = padding;
@@ -881,16 +869,18 @@
 
                 if (offsetY > (atlas.height - fontSize - padding))
                 {
-                    for (int j = i + 1; j < glyphCount; j++)
-                    {
-                        TRACELOG(LOG_WARNING, "FONT: Failed to package character (0x%02x)", glyphs[j].value);
-                        // Make sure remaining recs contain valid data
-                        recs[j].x = 0;
-                        recs[j].y = 0;
-                        recs[j].width = 0;
-                        recs[j].height = 0;
-                    }
-                    break; // Break for() loop, stop processing glyphs
+                    TRACELOG(LOG_WARNING, "FONT: Updating atlas size to fit all characters");
+
+                    // Update atlas size to fit all characters
+                    int updatedAtlasHeight = atlas.height*2;
+                    int updatedAtlasDataSize = atlas.width*updatedAtlasHeight;
+                    unsigned char *updatedAtlasData = (unsigned char *)RL_CALLOC(updatedAtlasDataSize, 1);
+
+                    memcpy(updatedAtlasData, atlas.data, atlasDataSize);
+                    RL_FREE(atlas.data);
+                    atlas.data = updatedAtlasData;
+                    atlas.height = updatedAtlasHeight;
+                    atlasDataSize = updatedAtlasDataSize;
                 }
             }
 
@@ -921,7 +911,7 @@
             offsetX += (glyphs[i].image.width + 2*padding);
         }
     }
-    else if (packMethod == 1)  // Use Skyline rect packing algorithm (stb_pack_rect)
+    else if (packMethod == 1) // Use Skyline rect packing algorithm (stb_pack_rect)
     {
         stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
         stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes));
@@ -961,13 +951,13 @@
                         // 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];
                         }
                     }
                 }
             }
-            else TRACELOG(LOG_WARNING, "FONT: Failed to package character (0x%02x)", glyphs[i].value);
+            else TRACELOG(LOG_WARNING, "FONT: Failed to package glyph (0x%02x)", glyphs[i].value);
         }
 
         RL_FREE(rects);
@@ -975,13 +965,12 @@
         RL_FREE(context);
     }
 
-#if defined(SUPPORT_FONT_ATLAS_WHITE_REC)
     // Add a 3x3 white rectangle at the bottom-right corner of the generated atlas,
     // useful to use as the white texture to draw shapes with raylib
     // Security: ensure the atlas is large enough to hold a 3x3 rectangle
-    if ((atlas.width >= 3) && (atlas.height >= 3))
+    if ((FONT_ATLAS_CORNER_REC_SIZE > 0) && (atlas.width >= 3) && (atlas.height >= 3))
     {
-        for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
+        for (int i = 0, k = atlas.width*atlas.height - 1; i < FONT_ATLAS_CORNER_REC_SIZE; i++)
         {
             ((unsigned char *)atlas.data)[k - 0] = 255;
             ((unsigned char *)atlas.data)[k - 1] = 255;
@@ -989,7 +978,6 @@
             k -= atlas.width;
         }
     }
-#endif
 
     // Convert image data from GRAYSCALE to GRAY_ALPHA
     unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
@@ -1038,7 +1026,7 @@
 // Export font as code file, returns true on success
 bool ExportFontAsCode(Font font, const char *fileName)
 {
-    bool success = false;
+    bool result = false;
 
 #ifndef TEXT_BYTES_PER_LINE
     #define TEXT_BYTES_PER_LINE     20
@@ -1046,8 +1034,8 @@
 
     // 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
     Image image = LoadImageFromTexture(font.texture);
@@ -1056,13 +1044,13 @@
 
     // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
     //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
-    
+
     // Estimate text code size
     //  - Image data is stored as "0x%02x", so it requires at least 4 char per byte, let's use 6
     //  - font.recs[] data is stored as "{ %1.0f, %1.0f, %1.0f , %1.0f }", let's reserve 64 per rec
     //  - font.glyphs[] data is stored as "{ %i, %i, %i, %i, { 0 }},\n", let's reserve 64 per glyph
     //  - Comments and additional code, let's reserve 32KB
-    int txtDataSize = imageDataSize*6 + font.glyphCount*64 + font.glyphCount*64 + 32768; 
+    int txtDataSize = imageDataSize*6 + font.glyphCount*64 + font.glyphCount*64 + 32768;
     char *txtData = (char *)RL_CALLOC(txtDataSize, sizeof(char));
 
     int byteCount = 0;
@@ -1180,14 +1168,14 @@
     UnloadImage(image);
 
     // NOTE: Text data size exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
+    result = SaveFileText(fileName, txtData);
 
     RL_FREE(txtData);
 
-    if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
+    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName);
 
-    return success;
+    return result;
 }
 
 // Draw current FPS
@@ -1285,14 +1273,14 @@
     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
 
     // Character destination rectangle on screen
-    // NOTE: We consider glyphPadding on drawing
+    // NOTE: Considering glyph padding on drawing
     Rectangle dstRec = { position.x + font.glyphs[index].offsetX*scaleFactor - (float)font.glyphPadding*scaleFactor,
                       position.y + font.glyphs[index].offsetY*scaleFactor - (float)font.glyphPadding*scaleFactor,
                       (font.recs[index].width + 2.0f*font.glyphPadding)*scaleFactor,
                       (font.recs[index].height + 2.0f*font.glyphPadding)*scaleFactor };
 
     // Character source rectangle from font texture atlas
-    // NOTE: We consider glyphs padding when drawing, it could be required for outline/glow shader effects
+    // NOTE: Considering glyphs padding when drawing, it could be required for outline/glow shader effects
     Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding,
                          font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding };
 
@@ -1300,7 +1288,7 @@
     DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
 }
 
-// Draw multiple character (codepoints)
+// Draw multiple characters (codepoints)
 void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint)
 {
     float textOffsetY = 0;          // Offset between lines (on linebreak '\n')
@@ -1411,6 +1399,63 @@
     return textSize;
 }
 
+// Measure string size for an existing array of codepoints for Font
+Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, float fontSize, float spacing)
+{
+    Vector2 textSize = { 0 };
+
+    if ((font.texture.id == 0) || (codepoints == NULL) || (length == 0)) return textSize; // Security check
+
+    float textWidth = 0.0f;
+    // Used to count longer text line width
+    float tempTextWidth = 0.0f;
+
+    // Used to count longer text line num chars
+    int tempGlyphCounter = 0;
+    int glyphCounter = 0;
+
+    float textHeight = fontSize;
+    float scaleFactor = fontSize/(float)font.baseSize;
+
+    // Current character
+    int letter = 0;
+    // Index position in sprite font
+    int index = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+        letter = codepoints[i];
+        index = GetGlyphIndex(font, letter);
+
+        if (letter != '\n')
+        {
+            glyphCounter++;
+
+            if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
+            else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
+        }
+        else
+        {
+            if (tempTextWidth < textWidth) tempTextWidth = textWidth;
+
+            textWidth = 0;
+            glyphCounter = 0;
+
+            // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
+            textHeight += (fontSize + textLineSpacing);
+        }
+
+        if (tempGlyphCounter < glyphCounter) tempGlyphCounter = glyphCounter;
+    }
+
+    if (tempTextWidth < textWidth) tempTextWidth = textWidth;
+
+    textSize.x = tempTextWidth*scaleFactor + (float)((tempGlyphCounter - 1)*spacing);
+    textSize.y = textHeight;
+
+    return textSize;
+}
+
 // Get index position for a unicode character on font
 // NOTE: If codepoint is not found in the font it fallbacks to '?'
 int GetGlyphIndex(Font font, int codepoint)
@@ -1491,7 +1536,7 @@
             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++;
             }
@@ -1511,15 +1556,14 @@
 }
 
 // Get text length in bytes, check for \0 character
+// NOTE: Alternative: use strlen(text)
 unsigned int TextLength(const char *text)
 {
     unsigned int length = 0;
 
     if (text != NULL)
     {
-        // NOTE: Alternative: use strlen(text)
-
-        while (*text++) length++;
+        while (text[length] != '\0') length++;
     }
 
     return length;
@@ -1533,7 +1577,7 @@
     #define MAX_TEXTFORMAT_BUFFERS 4        // Maximum number of static buffers for text formatting
 #endif
 
-    // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
+    // Create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
     static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
     static int index = 0;
 
@@ -1616,7 +1660,6 @@
     return value*sign;
 }
 
-#if defined(SUPPORT_TEXT_MANIPULATION)
 // Copy one string to another, returns bytes copied
 // NOTE: Alternative implementation to strcpy(dst, src) from C standard library
 int TextCopy(char *dst, const char *src)
@@ -1640,7 +1683,7 @@
     return bytes;
 }
 
-// Check if two text string are equal
+// Check if two text strings are equal
 // REQUIRES: strcmp()
 bool TextIsEqual(const char *text1, const char *text2)
 {
@@ -1660,21 +1703,22 @@
     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);
 
-        if (position >= textLength) return buffer; // First char is already '\0' by memset
-
-        int maxLength = textLength - position;
-        if (length > maxLength) length = maxLength;
-        if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
+        if (position < textLength)
+        {
+            int maxLength = textLength - position;
+            if (length > maxLength) length = maxLength;
+            if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
 
-        // NOTE: Alternative: memcpy(buffer, text + position, length)
+            // NOTE: Alternative: memcpy(buffer, text + position, length)
 
-        for (int c = 0; c < length; c++) buffer[c] = text[position + c];
+            for (int c = 0; c < length; c++) buffer[c] = text[position + c];
 
-        buffer[length] = '\0';
+            buffer[length] = '\0';
+        }
     }
 
     return buffer;
@@ -1689,7 +1733,7 @@
     if (text != NULL)
     {
         // Avoid copying the ' ' characters
-        for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++)
+        for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
         {
             if (text[i] != ' ') { buffer[j] = text[i]; j++; }
         }
@@ -1701,8 +1745,6 @@
 // Get text between two strings
 char *GetTextBetween(const char *text, const char *begin, const char *end)
 {
-    #define MAX_TEXT_BETWEEN_SIZE   1024
-
     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
 
@@ -1717,8 +1759,8 @@
         {
             endIndex += (beginIndex + beginLen);
             int len = (endIndex - beginIndex - beginLen);
-            if (len < (MAX_TEXT_BETWEEN_SIZE - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
-            else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BETWEEN_SIZE - 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);
         }
     }
 
@@ -1726,15 +1768,82 @@
 }
 
 // Replace text string
-// REQUIRES: strstr(), strncpy()
-// TODO: If (replacement == "") remove "search" text
-// WARNING: Allocated memory must be manually freed
+// REQUIRES: strstr(), memcpy()
+// NOTE: Limited text replace functionality, using static string
 char *TextReplace(const char *text, const char *search, const char *replacement)
 {
+    static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
+    memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
+
+    if ((text != NULL) && (search != NULL) && (search[0] != '\0'))
+    {
+        if (replacement == NULL) replacement = "";
+
+        char *insertPoint = NULL;   // Next insert point
+        char *tempPtr = NULL;       // Temp pointer
+        int textLen = 0;            // Text string length
+        int searchLen = 0;          // Search string length of (the string to remove)
+        int replaceLen = 0;         // Replacement length (the string to replace by)
+        int lastReplacePos = 0;     // Distance between next search and end of last replace
+        int count = 0;              // Number of replacements
+
+        textLen = TextLength(text);
+        searchLen = TextLength(search);
+        replaceLen = TextLength(replacement);
+
+        // Count the number of replacements needed
+        insertPoint = (char *)text;
+        for (count = 0; (tempPtr = strstr(insertPoint, search)); count++) insertPoint = tempPtr + searchLen;
+
+        if ((textLen + count*(replaceLen - searchLen)) < (MAX_TEXT_BUFFER_LENGTH - 1))
+        {
+            // TODO: Allow copying data replaced up to maximum buffer size and stop
+
+            tempPtr = buffer; // Point to result start
+
+            // First time through the loop, all the variable are set correctly from here on,
+            //  - 'temp' points to the end of the result string
+            //  - 'insertPoint' points to the next occurrence of replace in text
+            //  - 'text' points to the remainder of text after "end of replace"
+            while (count > 0)
+            {
+                insertPoint = (char *)strstr(text, search);
+                lastReplacePos = (int)(insertPoint - text);
+
+                memcpy(tempPtr, text, lastReplacePos);
+                tempPtr += lastReplacePos;
+
+                if (replaceLen > 0)
+                {
+                    memcpy(tempPtr, replacement, replaceLen);
+                    tempPtr += replaceLen;
+                }
+
+                text += (lastReplacePos + searchLen); // Move to next "end of replace"
+                count--;
+            }
+
+            // Copy remaind text part after replacement to result (pointed by moving temp)
+            // NOTE: Text pointer internal copy has been updated along the process
+            memcpy(tempPtr, text, TextLength(text));
+        }
+        else TRACELOG(LOG_WARNING, "Text with replacement is longer than internal buffer, use TextReplaceAlloc()");
+    }
+
+    return buffer;
+}
+
+// Replace text string
+// REQUIRES: strstr(), memcpy()
+// WARNING: Allocated memory must be manually freed
+char *TextReplaceAlloc(const char *text, const char *search, const char *replacement)
+{
     char *result = NULL;
 
-    if ((text != NULL) && (search != NULL))
+    if ((text != NULL) && (search != NULL) && (search[0] != '\0'))
     {
+        if (replacement == NULL) replacement = "";
+
         char *insertPoint = NULL;   // Next insert point
         char *temp = NULL;          // Temp pointer
         int textLen = 0;            // Text string length
@@ -1745,8 +1854,6 @@
 
         textLen = TextLength(text);
         searchLen = TextLength(search);
-        if (searchLen == 0) return NULL;  // Empty search causes infinite loop during count
-
         replaceLen = TextLength(replacement);
 
         // Count the number of replacements needed
@@ -1755,35 +1862,37 @@
 
         // Allocate returning string and point temp to it
         int tempLen = textLen + (replaceLen - searchLen)*count + 1;
-        temp = result = (char *)RL_MALLOC(tempLen);
-
-        if (!result) return NULL;   // Memory could not be allocated
+        temp = result = (char *)RL_CALLOC(tempLen, sizeof(char));
 
-        // First time through the loop, all the variable are set correctly from here on,
-        //  - 'temp' points to the end of the result string
-        //  - 'insertPoint' points to the next occurrence of replace in text
-        //  - 'text' points to the remainder of text after "end of replace"
-        while (count--)
+        if (result != NULL) // Memory was allocated
         {
-            insertPoint = (char *)strstr(text, search);
-            lastReplacePos = (int)(insertPoint - text);
+            // First time through the loop, all the variable are set correctly from here on,
+            //  - 'temp' points to the end of the result string
+            //  - 'insertPoint' points to the next occurrence of replace in text
+            //  - 'text' points to the remainder of text after "end of replace"
+            while (count > 0)
+            {
+                insertPoint = (char *)strstr(text, search);
+                lastReplacePos = (int)(insertPoint - text);
 
-            // TODO: Review logic to avoid strcpy()
-            // OK - Those lines work
-            temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
-            temp = strcpy(temp, replacement) + replaceLen;
-            // WRONG - But not those ones
-            //temp = strncpy(temp, text, tempLen - 1) + lastReplacePos;
-            //tempLen -= lastReplacePos;
-            //temp = strncpy(temp, replacement, tempLen - 1) + replaceLen;
-            //tempLen -= replaceLen;
+                memcpy(temp, text, lastReplacePos);
+                temp += lastReplacePos;
 
-            text += lastReplacePos + searchLen; // Move to next "end of replace"
-        }
+                if (replaceLen > 0)
+                {
+                    memcpy(temp, replacement, replaceLen);
+                    temp += replaceLen;
+                }
 
-        // Copy remaind text part after replacement to result (pointed by moving temp)
-        strcpy(temp, text); // OK
-        //strncpy(temp, text, tempLen - 1); // WRONG
+                text += (lastReplacePos + searchLen); // Move to next "end of replace"
+
+                count--;
+            }
+
+            // Copy remaind text part after replacement to result (pointed by moving temp)
+            // NOTE: Text pointer internal copy has been updated along the process
+            memcpy(temp, text, TextLength(text));
+        }
     }
 
     return result;
@@ -1791,9 +1900,48 @@
 
 // Replace text between two specific strings
 // REQUIRES: strncpy()
+// NOTE: If (replacement == NULL) removes "begin"[ ]"end" text
+char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
+{
+    static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
+    memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
+
+    if ((text != NULL) && (begin != NULL) && (end != NULL))
+    {
+        int beginIndex = TextFindIndex(text, begin);
+
+        if (beginIndex > -1)
+        {
+            int beginLen = TextLength(begin);
+            int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
+
+            if (endIndex > -1)
+            {
+                endIndex += (beginIndex + beginLen);
+
+                int textLen = TextLength(text);
+                int replaceLen = (replacement == NULL)? 0 : TextLength(replacement);
+                //int toreplaceLen = endIndex - beginIndex - beginLen;
+
+                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)");
+            }
+        }
+    }
+
+    return buffer;
+}
+
+// Replace text between two specific strings
+// REQUIRES: strncpy()
 // NOTE: If (replacement == NULL) remove "begin"[ ]"end" text
 // WARNING: Returned string must be freed by user
-char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
+char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement)
 {
     char *result = NULL;
 
@@ -1829,18 +1977,48 @@
 // WARNING: Allocated memory must be manually freed
 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) && (position >= 0))
+    {
+        if (position > textLen) position = textLen; // End of text string
+        int insertLen = TextLength(insert);
+
+        if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1))
+        {
+            // TODO: Allow copying data inserted up to maximum buffer size and stop
+
+            for (int i = 0; i < position; i++) buffer[i] = text[i];
+            for (int i = 0; i < insertLen; i++) buffer[i+position] = insert[i];
+            for (int i = position; i < textLen; i++) buffer[i+insertLen] = text[i];
+
+            buffer[textLen + insertLen] = '\0'; // Add EOL
+        }
+        else TRACELOG(LOG_WARNING, "Text with inserted string is longer than internal buffer, use TextInserExt()");
+    }
+
+    return buffer;
+}
+
+// Insert text in a specific position, moves all text forward
+// WARNING: Allocated memory must be manually freed
+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];
-        for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
+        for (int i = 0; i < insertLen; i++) result[i+position] = insert[i];
+        for (int i = position; i < textLen; i++) result[i+insertLen] = text[i];
 
         result[textLen + insertLen] = '\0'; // Add EOL
     }
@@ -1864,7 +2042,7 @@
         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;
@@ -1903,7 +2081,7 @@
     {
         counter = 1;
 
-        // Count how many substrings we have on text and point to every one
+        // Count how many substrings ar found on text and set pointers to every one
         for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
         {
             buffer[i] = text[i];
@@ -2008,9 +2186,11 @@
             if (text[j] != '_') buffer[i] = text[j];
             else
             {
-                j++;
+                while (text[j] == '_') j++;     // Skip one or more separators
+                if (text[j] == '\0') break;     // Text ends on a separator, nothing left to copy
+
                 if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
-                else if ((text[j] >= '0') && (text[j] <= '9')) buffer[i] = text[j];
+                else buffer[i] = text[j];       // Character can not be upper-cased, copy it as is
             }
         }
     }
@@ -2028,18 +2208,43 @@
     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++;
                 }
+            }
+            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];
+            else
+            {
+                buffer[i] = text[j];
+                i++;
+            }
         }
     }
 
@@ -2065,8 +2270,11 @@
             if (text[j] != '_') buffer[i] = text[j];
             else
             {
-                j++;
+                while (text[j] == '_') j++;     // Skip one or more separators
+                if (text[j] == '\0') break;     // Text ends on a separator, nothing left to copy
+
                 if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
+                else buffer[i] = text[j];       // Character can not be upper-cased, copy it as is
             }
         }
     }
@@ -2083,7 +2291,7 @@
 
     if ((codepoints != NULL) && (length > 0))
     {
-        // We allocate enough memory to fit all possible codepoints
+        // Allocate enough memory to fit all possible codepoints
         // NOTE: 5 bytes for every codepoint should be enough
         text = (char *)RL_CALLOC(length*5, 1);
         const char *utf8 = NULL;
@@ -2209,10 +2417,9 @@
 
     return utf8;
 }
-#endif      // SUPPORT_TEXT_MANIPULATION
 
 // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
-// When an invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
+// When an invalid UTF-8 byte is encountered, exit as soon as possible and a '?'(0x3f) codepoint is returned
 // 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
@@ -2230,12 +2437,11 @@
     0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 */
 
-
     int codepoint = 0x3f;   // Codepoint (defaults to '?')
     *codepointSize = 1;
     if (text == NULL) return codepoint;
 
-    // NOTE: on decode errors we return as soon as possible
+    // NOTE: On decoding errors, return as soon as possible
     int octet = (unsigned char)(text[0]); // The first UTF8 octet
 
     if (octet <= 0x7f)
@@ -2384,7 +2590,7 @@
 //----------------------------------------------------------------------------------
 // Module Internal Functions Definition
 //----------------------------------------------------------------------------------
-#if defined(SUPPORT_FILEFORMAT_FNT) || defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_FNT || SUPPORT_FILEFORMAT_BDF
 // Read a line from memory
 // REQUIRES: memcpy()
 // NOTE: Returns the number of bytes read
@@ -2398,7 +2604,7 @@
 }
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_FNT)
+#if SUPPORT_FILEFORMAT_FNT
 // Load a BMFont file (AngelCode font file)
 // REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
 static Font LoadBMFont(const char *fileName)
@@ -2429,7 +2635,7 @@
 
     char *fileTextPtr = fileText;
 
-    // NOTE: We skip first line, it contains no useful information
+    // NOTE: Skip first line, it contains no useful information
     readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
     fileTextPtr += (readBytes + 1);
 
@@ -2506,8 +2712,8 @@
         for (int i = 1; i < pageCount; i++)
         {
             Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight };
-            Rectangle destRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
-            ImageDraw(&fullFont, imFonts[i], srcRec, destRec, WHITE);
+            Rectangle dstRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
+            ImageDrawImagePro(&fullFont, imFonts[i], srcRec, dstRec, (Vector2){ 0 }, 0.0f, WHITE);
         }
     }
 
@@ -2539,7 +2745,7 @@
                        &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX, &pageID);
         fileTextPtr += (readBytes + 1);
 
-        if (readVars == 9)  // Make sure all char data has been properly read
+        if (readVars == 9) // Make sure all char data has been properly read
         {
             // Get character rectangle in the font atlas texture
             font.recs[i] = (Rectangle){ (float)charX, (float)charY + (float)imHeight*pageID, (float)charWidth, (float)charHeight };
@@ -2575,7 +2781,7 @@
 }
 #endif
 
-#if defined(SUPPORT_FILEFORMAT_BDF)
+#if SUPPORT_FILEFORMAT_BDF
 // Convert hexadecimal to decimal (single digit)
 static unsigned char HexToInt(char hex)
 {
@@ -2632,7 +2838,7 @@
     if (codepoints == NULL)
     {
         // Fill internal codepoints array in case not provided externally
-        // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
+        // NOTE: By default, filling glyph count consecutively, starting at 32 (Space)
         for (int i = 0; i < codepointCount; i++) requiredCodepoints[i] = i + 32;
         internalCodepoints = true;
     }
diff --git a/raylib/src/rtextures.c b/raylib/src/rtextures.c
--- a/raylib/src/rtextures.c
+++ b/raylib/src/rtextures.c
@@ -3,5603 +3,5742 @@
 *   rtextures - Basic functions to load and draw textures
 *
 *   CONFIGURATION:
-*       #define SUPPORT_MODULE_RTEXTURES
-*           rtextures module is included in the build
-*
-*       #define SUPPORT_FILEFORMAT_BMP
-*       #define SUPPORT_FILEFORMAT_PNG
-*       #define SUPPORT_FILEFORMAT_TGA
-*       #define SUPPORT_FILEFORMAT_JPG
-*       #define SUPPORT_FILEFORMAT_GIF
-*       #define SUPPORT_FILEFORMAT_QOI
-*       #define SUPPORT_FILEFORMAT_PSD
-*       #define SUPPORT_FILEFORMAT_HDR
-*       #define SUPPORT_FILEFORMAT_PIC
-*       #define SUPPORT_FILEFORMAT_PNM
-*       #define SUPPORT_FILEFORMAT_DDS
-*       #define SUPPORT_FILEFORMAT_PKM
-*       #define SUPPORT_FILEFORMAT_KTX
-*       #define SUPPORT_FILEFORMAT_PVR
-*       #define SUPPORT_FILEFORMAT_ASTC
-*           Select desired fileformats to be supported for image data loading. Some of those formats are
-*           supported by default, to remove support, just comment unrequired #define in this module
-*
-*       #define SUPPORT_IMAGE_EXPORT
-*           Support image export in multiple file formats
-*
-*       #define SUPPORT_IMAGE_MANIPULATION
-*           Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
-*           If not defined only some image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageResize*()
-*
-*       #define SUPPORT_IMAGE_GENERATION
-*           Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
-*
-*   DEPENDENCIES:
-*       stb_image        - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
-*                          NOTE: stb_image has been slightly modified to support Android platform
-*       stb_image_resize - Multiple image resize algorithms
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   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.
-*
-**********************************************************************************************/
-
-#include "raylib.h"             // Declares module functions
-
-#include "config.h"             // Defines module configuration flags
-
-#if defined(SUPPORT_MODULE_RTEXTURES)
-
-#include "rlgl.h"               // OpenGL abstraction layer to multiple versions
-
-#include <stdlib.h>             // Required for: malloc(), calloc(), free()
-#include <string.h>             // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()]
-#include <math.h>               // Required for: fabsf() [Used in DrawTextureRec()]
-#include <stdio.h>              // Required for: sprintf() [Used in ExportImageAsCode()]
-
-// Support only desired texture formats on stb_image
-#if !defined(SUPPORT_FILEFORMAT_BMP)
-    #define STBI_NO_BMP
-#endif
-#if !defined(SUPPORT_FILEFORMAT_PNG)
-    #define STBI_NO_PNG
-#endif
-#if !defined(SUPPORT_FILEFORMAT_TGA)
-    #define STBI_NO_TGA
-#endif
-#if !defined(SUPPORT_FILEFORMAT_JPG)
-    #define STBI_NO_JPEG        // Image format .jpg and .jpeg
-#endif
-#if !defined(SUPPORT_FILEFORMAT_PSD)
-    #define STBI_NO_PSD
-#endif
-#if !defined(SUPPORT_FILEFORMAT_GIF)
-    #define STBI_NO_GIF
-#endif
-#if !defined(SUPPORT_FILEFORMAT_PIC)
-    #define STBI_NO_PIC
-#endif
-#if !defined(SUPPORT_FILEFORMAT_HDR)
-    #define STBI_NO_HDR
-#endif
-#if !defined(SUPPORT_FILEFORMAT_PNM)
-    #define STBI_NO_PNM
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_DDS)
-    #define RL_GPUTEX_SUPPORT_DDS
-#endif
-#if defined(SUPPORT_FILEFORMAT_PKM)
-    #define RL_GPUTEX_SUPPORT_PKM
-#endif
-#if defined(SUPPORT_FILEFORMAT_KTX)
-    #define RL_GPUTEX_SUPPORT_KTX
-#endif
-#if defined(SUPPORT_FILEFORMAT_PVR)
-    #define RL_GPUTEX_SUPPORT_PVR
-#endif
-#if defined(SUPPORT_FILEFORMAT_ASTC)
-    #define RL_GPUTEX_SUPPORT_ASTC
-#endif
-
-// Image fileformats not supported by default
-#if (defined(SUPPORT_FILEFORMAT_BMP) || \
-     defined(SUPPORT_FILEFORMAT_PNG) || \
-     defined(SUPPORT_FILEFORMAT_TGA) || \
-     defined(SUPPORT_FILEFORMAT_JPG) || \
-     defined(SUPPORT_FILEFORMAT_PSD) || \
-     defined(SUPPORT_FILEFORMAT_GIF) || \
-     defined(SUPPORT_FILEFORMAT_HDR) || \
-     defined(SUPPORT_FILEFORMAT_PIC) || \
-     defined(SUPPORT_FILEFORMAT_PNM))
-
-    #if defined(__GNUC__) // GCC and Clang
-        #pragma GCC diagnostic push
-        #pragma GCC diagnostic ignored "-Wunused-function"
-    #endif
-
-    #define STBI_MALLOC RL_MALLOC
-    #define STBI_FREE RL_FREE
-    #define STBI_REALLOC RL_REALLOC
-
-    #define STBI_NO_THREAD_LOCALS
-
-    #if defined(__TINYC__)
-        #define STBI_NO_SIMD
-    #endif
-
-    #define STB_IMAGE_IMPLEMENTATION
-    #include "external/stb_image.h"         // Required for: stbi_load_from_file()
-                                            // NOTE: Used to read image data (multiple formats support)
-
-    #if defined(__GNUC__) // GCC and Clang
-        #pragma GCC diagnostic pop
-    #endif
-#endif
-
-#if (defined(SUPPORT_FILEFORMAT_DDS) || \
-     defined(SUPPORT_FILEFORMAT_PKM) || \
-     defined(SUPPORT_FILEFORMAT_KTX) || \
-     defined(SUPPORT_FILEFORMAT_PVR) || \
-     defined(SUPPORT_FILEFORMAT_ASTC))
-
-    #if defined(__GNUC__) // GCC and Clang
-        #pragma GCC diagnostic push
-        #pragma GCC diagnostic ignored "-Wunused-function"
-    #endif
-
-    #define RL_GPUTEX_MALLOC RL_MALLOC
-    #define RL_GPUTEX_FREE RL_FREE
-    #define RL_GPUTEX_LOG(...) TRACELOG(LOG_WARNING, "IMAGE: " __VA_ARGS__)
-    #define RL_GPUTEX_SHOW_LOG_INFO
-    #define RL_GPUTEX_IMPLEMENTATION
-    #include "external/rl_gputex.h"         // Required for: rl_load_xxx_from_memory()
-                                            // NOTE: Used to read compressed textures data (multiple formats support)
-    #if defined(__GNUC__) // GCC and Clang
-        #pragma GCC diagnostic pop
-    #endif
-#endif
-
-#if defined(SUPPORT_FILEFORMAT_QOI)
-    #define QOI_MALLOC RL_MALLOC
-    #define QOI_FREE RL_FREE
-
-    #if defined(_MSC_VER)               // Disable some MSVC warning
-        #pragma warning(push)
-        #pragma warning(disable : 4267)
-    #endif
-
-    #define QOI_IMPLEMENTATION
-    #include "external/qoi.h"
-
-    #if defined(_MSC_VER)
-        #pragma warning(pop)            // Disable MSVC warning suppression
-    #endif
-
-#endif
-
-#if defined(SUPPORT_IMAGE_EXPORT)
-    #define STBIW_MALLOC RL_MALLOC
-    #define STBIW_FREE RL_FREE
-    #define STBIW_REALLOC RL_REALLOC
-
-    #define STB_IMAGE_WRITE_IMPLEMENTATION
-    #include "external/stb_image_write.h"   // Required for: stbi_write_*()
-#endif
-
-#if defined(SUPPORT_IMAGE_GENERATION)
-    #define STB_PERLIN_IMPLEMENTATION
-    #include "external/stb_perlin.h"        // Required for: stb_perlin_fbm_noise3
-#endif
-
-#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
-#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
-
-#if defined(__GNUC__) // GCC and Clang
-    #pragma GCC diagnostic push
-    #pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-
-#if defined(__TINYC__)
-    #define STBIR_NO_SIMD
-#endif
-#define STB_IMAGE_RESIZE_IMPLEMENTATION
-#include "external/stb_image_resize2.h"     // Required for: stbir_resize_uint8_linear() [ImageResize()]
-
-#if defined(__GNUC__) // GCC and Clang
-    #pragma GCC diagnostic pop
-#endif
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#ifndef PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD
-    #define PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD  50    // Threshold over 255 to set alpha as 0
-#endif
-
-#ifndef GAUSSIAN_BLUR_ITERATIONS
-    #define GAUSSIAN_BLUR_ITERATIONS  4    // Number of box blur iterations to approximate gaussian blur
-#endif
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-// It's lonely here...
-
-//----------------------------------------------------------------------------------
-// Other Modules Functions Declaration (required by text)
-//----------------------------------------------------------------------------------
-extern void LoadFontDefault(void);          // [Module: text] Loads default font, required by ImageDrawText()
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-static float HalfToFloat(unsigned short x);
-static unsigned short FloatToHalf(float x);
-static Vector4 *LoadImageDataNormalized(Image image);       // Load pixel data from image as Vector4 array (float normalized)
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-// Load image from file into CPU memory (RAM)
-Image LoadImage(const char *fileName)
-{
-    Image image = { 0 };
-
-#if defined(SUPPORT_FILEFORMAT_PNG) || \
-    defined(SUPPORT_FILEFORMAT_BMP) || \
-    defined(SUPPORT_FILEFORMAT_TGA) || \
-    defined(SUPPORT_FILEFORMAT_JPG) || \
-    defined(SUPPORT_FILEFORMAT_GIF) || \
-    defined(SUPPORT_FILEFORMAT_PIC) || \
-    defined(SUPPORT_FILEFORMAT_HDR) || \
-    defined(SUPPORT_FILEFORMAT_PNM) || \
-    defined(SUPPORT_FILEFORMAT_PSD)
-
-    #define STBI_REQUIRED
-#endif
-
-    // Loading file to memory
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    // Loading image from memory data
-    if (fileData != NULL)
-    {
-        image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize);
-
-        UnloadFileData(fileData);
-    }
-
-    return image;
-}
-
-// Load an image from RAW file data
-Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize)
-{
-    Image image = { 0 };
-
-    int dataSize = 0;
-    unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-    if (fileData != NULL)
-    {
-        unsigned char *dataPtr = fileData;
-        int size = GetPixelDataSize(width, height, format);
-
-        if (size <= dataSize)   // Security check
-        {
-            // Offset file data to expected raw image by header size
-            if ((headerSize > 0) && ((headerSize + size) <= dataSize)) dataPtr += headerSize;
-
-            image.data = RL_MALLOC(size);      // Allocate required memory in bytes
-            memcpy(image.data, dataPtr, size); // Copy required data to image
-            image.width = width;
-            image.height = height;
-            image.mipmaps = 1;
-            image.format = format;
-        }
-
-        UnloadFileData(fileData);
-    }
-
-    return image;
-}
-
-// Load animated image data
-//  - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
-//  - Number of frames is returned through 'frames' parameter
-//  - All frames are returned in RGBA format
-//  - Frames delay data is discarded
-Image LoadImageAnim(const char *fileName, int *frames)
-{
-    Image image = { 0 };
-    int frameCount = 0;
-
-#if defined(SUPPORT_FILEFORMAT_GIF)
-    if (IsFileExtension(fileName, ".gif"))
-    {
-        int dataSize = 0;
-        unsigned char *fileData = LoadFileData(fileName, &dataSize);
-
-        if (fileData != NULL)
-        {
-            int comp = 0;
-            int *delays = NULL;
-            image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
-
-            image.mipmaps = 1;
-            image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-            UnloadFileData(fileData);
-            RL_FREE(delays);        // NOTE: Frames delays are discarded
-        }
-    }
-#else
-    if (false) { }
-#endif
-    else
-    {
-        image = LoadImage(fileName);
-        frameCount = 1;
-    }
-
-    *frames = frameCount;
-    return image;
-}
-
-// Load animated image data
-//  - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
-//  - Number of frames is returned through 'frames' parameter
-//  - All frames are returned in RGBA format
-//  - Frames delay data is discarded
-Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames)
-{
-    Image image = { 0 };
-    int frameCount = 0;
-
-    // Security check for input data
-    if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image;
-
-#if defined(SUPPORT_FILEFORMAT_GIF)
-    if ((strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0))
-    {
-        if (fileData != NULL)
-        {
-            int comp = 0;
-            int *delays = NULL;
-            image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
-
-            image.mipmaps = 1;
-            image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-            RL_FREE(delays);        // NOTE: Frames delays are discarded
-        }
-    }
-#else
-    if (false) { }
-#endif
-    else
-    {
-        image = LoadImageFromMemory(fileType, fileData, dataSize);
-        frameCount = 1;
-    }
-
-    *frames = frameCount;
-    return image;
-}
-
-// Load image from memory buffer, fileType refers to extension: i.e. ".png"
-// WARNING: File extension must be provided in lower-case
-Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
-{
-    Image image = { 0 };
-
-    // Security checks for input data
-    if ((fileData == NULL) || (dataSize == 0))
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Invalid file data");
-        return image;
-    }
-    if (fileType == NULL)
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Missing file extension");
-        return image;
-    }
-
-    if ((false)
-#if defined(SUPPORT_FILEFORMAT_PNG)
-        || (strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_BMP)
-        || (strcmp(fileType, ".bmp") == 0) || (strcmp(fileType, ".BMP") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_TGA)
-        || (strcmp(fileType, ".tga") == 0) || (strcmp(fileType, ".TGA") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_JPG)
-        || (strcmp(fileType, ".jpg") == 0) || (strcmp(fileType, ".jpeg") == 0)
-        || (strcmp(fileType, ".JPG") == 0) || (strcmp(fileType, ".JPEG") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_GIF)
-        || (strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_PIC)
-        || (strcmp(fileType, ".pic") == 0) || (strcmp(fileType, ".PIC") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_PNM)
-        || (strcmp(fileType, ".ppm") == 0) || (strcmp(fileType, ".pgm") == 0)
-        || (strcmp(fileType, ".PPM") == 0) || (strcmp(fileType, ".PGM") == 0)
-#endif
-#if defined(SUPPORT_FILEFORMAT_PSD)
-        || (strcmp(fileType, ".psd") == 0) || (strcmp(fileType, ".PSD") == 0)
-#endif
-        )
-    {
-#if defined(STBI_REQUIRED)
-        // NOTE: Using stb_image to load images (Supports multiple image formats)
-
-        if (fileData != NULL)
-        {
-            int comp = 0;
-            image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
-
-            if (image.data != NULL)
-            {
-                image.mipmaps = 1;
-
-                if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-                else if (comp == 2) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
-                else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
-                else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-            }
-        }
-#endif
-    }
-#if defined(SUPPORT_FILEFORMAT_HDR)
-    else if ((strcmp(fileType, ".hdr") == 0) || (strcmp(fileType, ".HDR") == 0))
-    {
-#if defined(STBI_REQUIRED)
-        if (fileData != NULL)
-        {
-            int comp = 0;
-            image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
-
-            image.mipmaps = 1;
-
-            if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_R32;
-            else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
-            else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
-            else
-            {
-                TRACELOG(LOG_WARNING, "IMAGE: HDR file format not supported");
-                UnloadImage(image);
-            }
-        }
-#endif
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_QOI)
-    else if ((strcmp(fileType, ".qoi") == 0) || (strcmp(fileType, ".QOI") == 0))
-    {
-        if (fileData != NULL)
-        {
-            qoi_desc desc = { 0 };
-            image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]);
-            image.width = desc.width;
-            image.height = desc.height;
-            image.format = (desc.channels == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8;
-            image.mipmaps = 1;
-        }
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_DDS)
-    else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0))
-    {
-        image.data = rl_load_dds_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_PKM)
-    else if ((strcmp(fileType, ".pkm") == 0) || (strcmp(fileType, ".PKM") == 0))
-    {
-        image.data = rl_load_pkm_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_KTX)
-    else if ((strcmp(fileType, ".ktx") == 0) || (strcmp(fileType, ".KTX") == 0))
-    {
-        image.data = rl_load_ktx_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_PVR)
-    else if ((strcmp(fileType, ".pvr") == 0) || (strcmp(fileType, ".PVR") == 0))
-    {
-        image.data = rl_load_pvr_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_ASTC)
-    else if ((strcmp(fileType, ".astc") == 0) || (strcmp(fileType, ".ASTC") == 0))
-    {
-        image.data = rl_load_astc_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
-    }
-#endif
-    else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");
-
-    if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: Data loaded successfully (%ix%i | %s | %i mipmaps)", image.width, image.height, rlGetPixelFormatName(image.format), image.mipmaps);
-    else TRACELOG(LOG_WARNING, "IMAGE: Failed to load image data");
-
-    return image;
-}
-
-// Load image from GPU texture data
-// NOTE: Compressed texture formats not supported
-Image LoadImageFromTexture(Texture2D texture)
-{
-    Image image = { 0 };
-
-    if (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
-    {
-        image.data = rlReadTexturePixels(texture.id, texture.width, texture.height, texture.format);
-
-        if (image.data != NULL)
-        {
-            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...
-            image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-#endif
-            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);
-    }
-    else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id);
-
-    return image;
-}
-
-// Load image from screen buffer and (screenshot)
-Image LoadImageFromScreen(void)
-{
-    Image image = { 0 };
-
-    image.width = (int)(GetRenderWidth());
-    image.height = (int)(GetRenderHeight());
-    image.mipmaps = 1;
-    image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-    image.data = rlReadScreenPixels(image.width, image.height);
-
-    return image;
-}
-
-// Check if an image is ready
-bool IsImageValid(Image image)
-{
-    bool result = false;
-
-    if ((image.data != NULL) &&     // Validate pixel data available
-        (image.width > 0) &&        // Validate image width
-        (image.height > 0) &&       // Validate image height
-        (image.format > 0) &&       // Validate image format
-        (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level)
-
-    return result;
-}
-
-// Unload image from CPU memory (RAM)
-void UnloadImage(Image image)
-{
-    RL_FREE(image.data);
-}
-
-// Export image data to file
-// NOTE: File format depends on fileName extension
-bool ExportImage(Image image, const char *fileName)
-{
-    int result = 0;
-
-    // Security check for input data
-    if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result;
-
-#if defined(SUPPORT_IMAGE_EXPORT)
-    int channels = 4;
-    bool allocatedData = false;
-    unsigned char *imgData = (unsigned char *)image.data;
-
-    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
-    else
-    {
-        // NOTE: Getting Color array as RGBA unsigned char values
-        imgData = (unsigned char *)LoadImageColors(image);
-        allocatedData = true;
-    }
-
-    if (false) { } // Required to attach following 'else' cases
-#if defined(SUPPORT_FILEFORMAT_PNG)
-    else if (IsFileExtension(fileName, ".png"))
-    {
-        int dataSize = 0;
-        unsigned char *fileData = stbi_write_png_to_mem((const unsigned char *)imgData, image.width*channels, image.width, image.height, channels, &dataSize);
-        result = SaveFileData(fileName, fileData, dataSize);
-        RL_FREE(fileData);
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_BMP)
-    else if (IsFileExtension(fileName, ".bmp")) result = stbi_write_bmp(fileName, image.width, image.height, channels, imgData);
-#endif
-#if defined(SUPPORT_FILEFORMAT_TGA)
-    else if (IsFileExtension(fileName, ".tga")) result = stbi_write_tga(fileName, image.width, image.height, channels, imgData);
-#endif
-#if defined(SUPPORT_FILEFORMAT_JPG)
-    else if (IsFileExtension(fileName, ".jpg") ||
-             IsFileExtension(fileName, ".jpeg")) result = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90);  // JPG quality: between 1 and 100
-#endif
-#if defined(SUPPORT_FILEFORMAT_QOI)
-    else if (IsFileExtension(fileName, ".qoi"))
-    {
-        channels = 0;
-        if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
-        else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
-        else TRACELOG(LOG_WARNING, "IMAGE: Image pixel format must be R8G8B8 or R8G8B8A8");
-
-        if ((channels == 3) || (channels == 4))
-        {
-            qoi_desc desc = { 0 };
-            desc.width = image.width;
-            desc.height = image.height;
-            desc.channels = channels;
-            desc.colorspace = QOI_SRGB;
-
-            result = qoi_write(fileName, imgData, &desc);
-        }
-    }
-#endif
-#if defined(SUPPORT_FILEFORMAT_KTX)
-    else if (IsFileExtension(fileName, ".ktx"))
-    {
-        result = rl_save_ktx(fileName, image.data, image.width, image.height, image.format, image.mipmaps);
-    }
-#endif
-    else if (IsFileExtension(fileName, ".raw"))
-    {
-        // Export raw pixel data (without header)
-        // NOTE: It's up to the user to track image parameters
-        result = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
-    }
-    else TRACELOG(LOG_WARNING, "IMAGE: Export image format requested not supported");
-
-    if (allocatedData) RL_FREE(imgData);
-#endif      // SUPPORT_IMAGE_EXPORT
-
-    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
-    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
-
-    return result;
-}
-
-// Export image to memory buffer
-unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataSize)
-{
-    unsigned char *fileData = NULL;
-    *dataSize = 0;
-
-    // Security check for input data
-    if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return NULL;
-
-#if defined(SUPPORT_IMAGE_EXPORT)
-    int channels = 4;
-
-    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
-
-#if defined(SUPPORT_FILEFORMAT_PNG)
-    if ((strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0))
-    {
-        fileData = stbi_write_png_to_mem((const unsigned char *)image.data, image.width*channels, image.width, image.height, channels, dataSize);
-    }
-#endif
-
-#endif
-
-    return fileData;
-}
-
-// Export image as code file (.h) defining an array of bytes
-bool ExportImageAsCode(Image image, const char *fileName)
-{
-    bool success = false;
-
-#if defined(SUPPORT_IMAGE_EXPORT)
-
-#ifndef TEXT_BYTES_PER_LINE
-    #define TEXT_BYTES_PER_LINE     20
-#endif
-
-    int dataSize = GetPixelDataSize(image.width, image.height, image.format);
-
-    // NOTE: Text data buffer size is estimated considering image data size in bytes
-    // and requiring 6 char bytes for every byte: "0x00, "
-    char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
-
-    int byteCount = 0;
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes         //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
-    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2026 Ramon Santamaria (@raysan5)                                //\n");
-    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
-    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
-
-    // 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
-    for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
-
-    // Add image information
-    byteCount += sprintf(txtData + byteCount, "// Image data information\n");
-    byteCount += sprintf(txtData + byteCount, "#define %s_WIDTH    %i\n", varFileName, image.width);
-    byteCount += sprintf(txtData + byteCount, "#define %s_HEIGHT   %i\n", varFileName, image.height);
-    byteCount += sprintf(txtData + byteCount, "#define %s_FORMAT   %i          // raylib internal pixel format\n\n", varFileName, image.format);
-
-    byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
-    for (int i = 0; i < dataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
-    byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
-
-    // NOTE: Text data size exported is determined by '\0' (NULL) character
-    success = SaveFileText(fileName, txtData);
-
-    RL_FREE(txtData);
-
-#endif      // SUPPORT_IMAGE_EXPORT
-
-    if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
-    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
-
-    return success;
-}
-
-//------------------------------------------------------------------------------------
-// Image generation functions
-//------------------------------------------------------------------------------------
-// Generate image: plain color
-Image GenImageColor(int width, int height, Color color)
-{
-    Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color));
-
-    for (int i = 0; i < width*height; i++) pixels[i] = color;
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-#if defined(SUPPORT_IMAGE_GENERATION)
-// Generate image: linear gradient
-// The direction value specifies the direction of the gradient (in degrees)
-// with 0 being vertical (from top to bottom), 90 being horizontal (from left to right)
-// The gradient effectively rotates counter-clockwise by the specified amount
-Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    float radianDirection = (float)(90 - direction)/180.f*3.14159f;
-    float cosDir = cosf(radianDirection);
-    float sinDir = sinf(radianDirection);
-
-    // Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
-    float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
-
-    // With directions that lie in the first or third quadrant (i.e. from top-left to
-    // bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
-    // (i.e. the pixel which should become one of the gradient's ends color); while for
-    // directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
-    float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
-    for (int i = 0; i < width; i++)
-    {
-        for (int j = 0; j < height; j++)
-        {
-            // Calculate the relative position of the pixel along the gradient direction
-            float pos = (startingPos + (i*cosDir + j*sinDir))/maxPosValue;
-
-            float factor = pos;
-            factor = (factor > 1.0f)? 1.0f : factor;  // Clamp to [-1,1]
-            factor = (factor < -1.0f)? -1.0f : factor;  // Clamp to [-1,1]
-            factor = factor/2.0f + 0.5f;
-
-            // Generate the color for this pixel
-            pixels[j*width + i].r = (int)((float)end.r*factor + (float)start.r*(1.0f - factor));
-            pixels[j*width + i].g = (int)((float)end.g*factor + (float)start.g*(1.0f - factor));
-            pixels[j*width + i].b = (int)((float)end.b*factor + (float)start.b*(1.0f - factor));
-            pixels[j*width + i].a = (int)((float)end.a*factor + (float)start.a*(1.0f - factor));
-        }
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: radial gradient
-Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-    float radius = (width < height)? (float)width/2.0f : (float)height/2.0f;
-
-    float centerX = (float)width/2.0f;
-    float centerY = (float)height/2.0f;
-
-    for (int y = 0; y < height; y++)
-    {
-        for (int x = 0; x < width; x++)
-        {
-            float dist = hypotf((float)x - centerX, (float)y - centerY);
-            float factor = (dist - radius*density)/(radius*(1.0f - density));
-
-            factor = (float)fmax(factor, 0.0f);
-            factor = (float)fmin(factor, 1.f); // dist can be bigger than radius, so we have to check
-
-            pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
-            pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
-            pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
-            pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor));
-        }
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: square gradient
-Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    float centerX = (float)width/2.0f;
-    float centerY = (float)height/2.0f;
-
-    for (int y = 0; y < height; y++)
-    {
-        for (int x = 0; x < width; x++)
-        {
-            // Calculate the Manhattan distance from the center
-            float distX = fabsf(x - centerX);
-            float distY = fabsf(y - centerY);
-
-            // Normalize the distances by the dimensions of the gradient rectangle
-            float normalizedDistX = distX/centerX;
-            float normalizedDistY = distY/centerY;
-
-            // Calculate the total normalized Manhattan distance
-            float manhattanDist = fmaxf(normalizedDistX, normalizedDistY);
-
-            // Subtract the density from the manhattanDist, then divide by (1 - density)
-            // This makes the gradient start from the center when density is 0, and from the edge when density is 1
-            float factor = (manhattanDist - density)/(1.0f - density);
-
-            // Clamp the factor between 0 and 1
-            factor = fminf(fmaxf(factor, 0.0f), 1.0f);
-
-            // Blend the colors based on the calculated factor
-            pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
-            pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
-            pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
-            pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor));
-        }
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: checked
-Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    for (int y = 0; y < height; y++)
-    {
-        for (int x = 0; x < width; x++)
-        {
-            if ((x/checksX + y/checksY)%2 == 0) pixels[y*width + x] = col1;
-            else pixels[y*width + x] = col2;
-        }
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: white noise
-// NOTE: It requires GetRandomValue(), defined in [rcore]
-Image GenImageWhiteNoise(int width, int height, float factor)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    for (int i = 0; i < width*height; i++)
-    {
-        if (GetRandomValue(0, 99) < (int)(factor*100.0f)) pixels[i] = WHITE;
-        else pixels[i] = BLACK;
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: perlin noise
-Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    float aspectRatio = (float)width/(float)height;
-
-    for (int y = 0; y < height; y++)
-    {
-        for (int x = 0; x < width; x++)
-        {
-            float nx = (float)(x + offsetX)*(scale/(float)width);
-            float ny = (float)(y + offsetY)*(scale/(float)height);
-
-            // Apply aspect ratio compensation to wider side
-            if (width > height) nx *= aspectRatio;
-            else ny /= aspectRatio;
-
-            // Basic perlin noise implementation (not used)
-            //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0);
-
-            // Calculate a better perlin noise using fbm (fractal brownian motion)
-            // Typical values to start playing with:
-            //   lacunarity = ~2.0   -- spacing between successive octaves (use exactly 2.0 for wrapping output)
-            //   gain       =  0.5   -- relative weighting applied to each successive octave
-            //   octaves    =  6     -- number of "octaves" of noise3() to sum
-            float p = stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6);
-
-            // Clamp between -1.0f and 1.0f
-            if (p < -1.0f) p = -1.0f;
-            if (p > 1.0f) p = 1.0f;
-
-            // We need to normalize the data from [-1..1] to [0..1]
-            float np = (p + 1.0f)/2.0f;
-
-            unsigned char intensity = (unsigned char)(np*255.0f);
-            pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 };
-        }
-    }
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: cellular algorithm. Bigger tileSize means bigger cells
-Image GenImageCellular(int width, int height, int tileSize)
-{
-    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
-
-    int seedsPerRow = width/tileSize;
-    int seedsPerCol = height/tileSize;
-    int seedCount = seedsPerRow*seedsPerCol;
-
-    Vector2 *seeds = (Vector2 *)RL_MALLOC(seedCount*sizeof(Vector2));
-
-    for (int i = 0; i < seedCount; i++)
-    {
-        int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
-        int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
-        seeds[i] = (Vector2){ (float)x, (float)y };
-    }
-
-    for (int y = 0; y < height; y++)
-    {
-        int tileY = y/tileSize;
-
-        for (int x = 0; x < width; x++)
-        {
-            int tileX = x/tileSize;
-
-            float minDistance = 65536.0f; //(float)strtod("Inf", NULL);
-
-            // Check all adjacent tiles
-            for (int i = -1; i < 2; i++)
-            {
-                if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue;
-
-                for (int j = -1; j < 2; j++)
-                {
-                    if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue;
-
-                    Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i];
-
-                    float dist = (float)hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y);
-                    minDistance = (float)fmin(minDistance, dist);
-                }
-            }
-
-            // This approach seems to give good results at all tile sizes
-            int intensity = (int)(minDistance*256.0f/tileSize);
-            if (intensity > 255) intensity = 255;
-
-            unsigned char intensityUC = (unsigned char)intensity;
-            pixels[y*width + x] = (Color){ intensityUC, intensityUC, intensityUC, 255 };
-        }
-    }
-
-    RL_FREE(seeds);
-
-    Image image = {
-        .data = pixels,
-        .width = width,
-        .height = height,
-        .mipmaps = 1,
-        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
-    };
-
-    return image;
-}
-
-// Generate image: grayscale image from text data
-Image GenImageText(int width, int height, const char *text)
-{
-    Image image = { 0 };
-
-    int imageSize = width*height;
-    image.width = width;
-    image.height = height;
-    image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-    image.data = RL_CALLOC(imageSize, 1);
-    image.mipmaps = 1;
-
-    if (text != NULL)
-    {
-        int textLength = (int)strlen(text);
-        memcpy(image.data, text, (textLength > imageSize)? imageSize : textLength);
-    }
-
-    return image;
-}
-#endif      // SUPPORT_IMAGE_GENERATION
-
-//------------------------------------------------------------------------------------
-// Image manipulation functions
-//------------------------------------------------------------------------------------
-// Copy an image to a new image
-Image ImageCopy(Image image)
-{
-    Image newImage = { 0 };
-
-    int width = image.width;
-    int height = image.height;
-    int size = 0;
-
-    for (int i = 0; i < image.mipmaps; i++)
-    {
-        size += GetPixelDataSize(width, height, image.format);
-
-        width /= 2;
-        height /= 2;
-
-        // Security check for NPOT textures
-        if (width < 1) width = 1;
-        if (height < 1) height = 1;
-    }
-
-    newImage.data = RL_CALLOC(size, 1);
-
-    if (newImage.data != NULL)
-    {
-        // NOTE: Size must be provided in bytes
-        memcpy(newImage.data, image.data, size);
-
-        newImage.width = image.width;
-        newImage.height = image.height;
-        newImage.mipmaps = image.mipmaps;
-        newImage.format = image.format;
-    }
-
-    return newImage;
-}
-
-// Create an image from another image piece
-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++)
-    {
-        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);
-    }
-
-    return result;
-}
-
-// Crop an image to area defined by a rectangle
-// NOTE: Security checks are performed in case rectangle goes out of bounds
-void ImageCrop(Image *image, Rectangle crop)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    // Security checks to validate crop rectangle
-    if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
-    if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
-    if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
-    if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
-    if ((crop.x > image->width) || (crop.y > image->height))
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds");
-        return;
-    }
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-
-        unsigned char *croppedData = (unsigned char *)RL_MALLOC((int)(crop.width*crop.height)*bytesPerPixel);
-
-        // OPTION 1: Move cropped data line-by-line
-        for (int y = (int)crop.y, offsetSize = 0; y < (int)(crop.y + crop.height); y++)
-        {
-            memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + (int)crop.x)*bytesPerPixel, (int)crop.width*bytesPerPixel);
-            offsetSize += ((int)crop.width*bytesPerPixel);
-        }
-
-        /*
-        // OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte
-        for (int y = (int)crop.y; y < (int)(crop.y + crop.height); y++)
-        {
-            for (int x = (int)crop.x; x < (int)(crop.x + crop.width); x++)
-            {
-                //memcpy(croppedData + ((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
-                for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
-            }
-        }
-        */
-
-        RL_FREE(image->data);
-        image->data = croppedData;
-        image->width = (int)crop.width;
-        image->height = (int)crop.height;
-    }
-}
-
-// Convert image data to desired format
-void ImageFormat(Image *image, int newFormat)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if ((newFormat != 0) && (image->format != newFormat))
-    {
-        if ((image->format < PIXELFORMAT_COMPRESSED_DXT1_RGB) && (newFormat < PIXELFORMAT_COMPRESSED_DXT1_RGB))
-        {
-            Vector4 *pixels = LoadImageDataNormalized(*image);     // Supports 8 to 32 bit per channel
-
-            RL_FREE(image->data);      // WARNING! We loose mipmaps data --> Regenerated at the end...
-            image->data = NULL;
-            image->format = newFormat;
-
-            switch (image->format)
-            {
-                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-                {
-                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*sizeof(unsigned char));
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        ((unsigned char *)image->data)[i] = (unsigned char)((pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)*255.0f);
-                    }
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-                {
-                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*2*sizeof(unsigned char));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*2; i += 2, k++)
-                    {
-                        ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f);
-                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f);
-                    }
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-                {
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
-
-                    unsigned char r = 0;
-                    unsigned char g = 0;
-                    unsigned char b = 0;
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        r = (unsigned char)(round(pixels[i].x*31.0f));
-                        g = (unsigned char)(round(pixels[i].y*63.0f));
-                        b = (unsigned char)(round(pixels[i].z*31.0f));
-
-                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
-                    }
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-                {
-                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned char));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
-                    {
-                        ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
-                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
-                        ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-                {
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
-
-                    unsigned char r = 0;
-                    unsigned char g = 0;
-                    unsigned char b = 0;
-                    unsigned char a = 0;
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        r = (unsigned char)(round(pixels[i].x*31.0f));
-                        g = (unsigned char)(round(pixels[i].y*31.0f));
-                        b = (unsigned char)(round(pixels[i].z*31.0f));
-                        a = (pixels[i].w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
-
-                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
-                    }
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-                {
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
-
-                    unsigned char r = 0;
-                    unsigned char g = 0;
-                    unsigned char b = 0;
-                    unsigned char a = 0;
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        r = (unsigned char)(round(pixels[i].x*15.0f));
-                        g = (unsigned char)(round(pixels[i].y*15.0f));
-                        b = (unsigned char)(round(pixels[i].z*15.0f));
-                        a = (unsigned char)(round(pixels[i].w*15.0f));
-
-                        ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
-                    }
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-                {
-                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned char));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
-                    {
-                        ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
-                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
-                        ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
-                        ((unsigned char *)image->data)[i + 3] = (unsigned char)(pixels[k].w*255.0f);
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32:
-                {
-                    // WARNING: Image is converted to GRAYSCALE equivalent 32bit
-
-                    image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float));
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        ((float *)image->data)[i] = (float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f);
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-                {
-                    image->data = (float *)RL_MALLOC(image->width*image->height*3*sizeof(float));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
-                    {
-                        ((float *)image->data)[i] = pixels[k].x;
-                        ((float *)image->data)[i + 1] = pixels[k].y;
-                        ((float *)image->data)[i + 2] = pixels[k].z;
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-                {
-                    image->data = (float *)RL_MALLOC(image->width*image->height*4*sizeof(float));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
-                    {
-                        ((float *)image->data)[i] = pixels[k].x;
-                        ((float *)image->data)[i + 1] = pixels[k].y;
-                        ((float *)image->data)[i + 2] = pixels[k].z;
-                        ((float *)image->data)[i + 3] = pixels[k].w;
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16:
-                {
-                    // WARNING: Image is converted to GRAYSCALE equivalent 16bit
-
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
-
-                    for (int i = 0; i < image->width*image->height; i++)
-                    {
-                        ((unsigned short *)image->data)[i] = FloatToHalf((float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f));
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-                {
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned short));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
-                    {
-                        ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x);
-                        ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y);
-                        ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z);
-                    }
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-                {
-                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned short));
-
-                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
-                    {
-                        ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x);
-                        ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y);
-                        ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z);
-                        ((unsigned short *)image->data)[i + 3] = FloatToHalf(pixels[k].w);
-                    }
-                } break;
-                default: break;
-            }
-
-            RL_FREE(pixels);
-            pixels = NULL;
-
-            // In case original image had mipmaps, generate mipmaps for formatted image
-            // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
-            if (image->mipmaps > 1)
-            {
-                image->mipmaps = 1;
-            #if defined(SUPPORT_IMAGE_MANIPULATION)
-                if (image->data != NULL) ImageMipmaps(image);
-            #endif
-            }
-        }
-        else TRACELOG(LOG_WARNING, "IMAGE: Data format is compressed, can not be converted");
-    }
-}
-
-// Create an image from text (default font)
-Image ImageText(const char *text, int fontSize, Color color)
-{
-    Image imText = { 0 };
-#if defined(SUPPORT_MODULE_RTEXT)
-    int defaultFontSize = 10;   // Default Font chars height in pixel
-    if (fontSize < defaultFontSize) fontSize = defaultFontSize;
-    int spacing = fontSize/defaultFontSize;
-    imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color);   // WARNING: Module required: rtext
-#else
-    imText = GenImageColor(200, 60, BLACK);     // Generating placeholder black image rectangle
-    TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
-#endif
-    return imText;
-}
-
-// Create an image from text (custom sprite font)
-// WARNING: Module required: rtext
-Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
-{
-    Image imText = { 0 };
-#if defined(SUPPORT_MODULE_RTEXT)
-    if (text == NULL) return imText;
-
-    int textLength = (int)strlen(text); // Get length of text in bytes
-    int textOffsetX = 0;            // Image drawing position X
-    int textOffsetY = 0;            // Offset between lines (on linebreak '\n')
-
-    // NOTE: Text image is generated at font base size, later scaled to desired font size
-    Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);  // WARNING: Module required: rtext
-    Vector2 textSize = MeasureTextEx(font, text, fontSize, spacing);
-
-    // Create image to store text
-    imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
-
-    for (int i = 0; i < textLength;)
-    {
-        // Get next codepoint from byte string and glyph index in font
-        int codepointByteCount = 0;
-        int codepoint = GetCodepointNext(&text[i], &codepointByteCount);    // WARNING: Module required: rtext
-        int index = GetGlyphIndex(font, codepoint);                         // WARNING: Module required: rtext
-
-        if (codepoint == '\n')
-        {
-            // NOTE: Fixed line spacing of 1.5 line-height
-            // TODO: Support custom line spacing defined by user
-            textOffsetY += (font.baseSize + font.baseSize/2);
-            textOffsetX = 0;
-        }
-        else
-        {
-            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 };
-                ImageDraw(&imText, font.glyphs[index].image, (Rectangle){ 0, 0, (float)font.glyphs[index].image.width, (float)font.glyphs[index].image.height }, rec, tint);
-            }
-
-            if (font.glyphs[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing);
-            else textOffsetX += font.glyphs[index].advanceX + (int)spacing;
-        }
-
-        i += codepointByteCount;   // Move text bytes counter to next codepoint
-    }
-
-    // Scale image depending on text size
-    if (textSize.y != imSize.y)
-    {
-        float scaleFactor = textSize.y/imSize.y;
-        TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
-
-        // Using nearest-neighbor scaling algorithm for default font
-        // TODO: Allow defining the preferred scaling mechanism externally
-        if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
-        else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
-    }
-#else
-    imText = GenImageColor(200, 60, BLACK);     // Generating placeholder black image rectangle
-    TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
-#endif
-    return imText;
-}
-
-// Create an image from a selected channel of another image
-Image ImageFromChannel(Image image, int selectedChannel)
-{
-    Image result = { 0 };
-
-    // Security check to avoid program crash
-    if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result;
-
-    // Check selected channel is valid
-    if (selectedChannel < 0)
-    {
-        TRACELOG(LOG_WARNING, "Channel cannot be negative. Setting channel to 0.");
-        selectedChannel = 0;
-    }
-
-    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE ||
-        image.format == PIXELFORMAT_UNCOMPRESSED_R32 ||
-        image.format == PIXELFORMAT_UNCOMPRESSED_R16)
-    {
-        if (selectedChannel > 0)
-        {
-            TRACELOG(LOG_WARNING, "This image has only 1 channel. Setting channel to it.");
-            selectedChannel = 0;
-        }
-    }
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA)
-    {
-        if (selectedChannel > 1)
-        {
-            TRACELOG(LOG_WARNING, "This image has only 2 channels. Setting channel to alpha.");
-            selectedChannel = 1;
-        }
-    }
-    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R5G6B5 ||
-             image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8 ||
-             image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32 ||
-             image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16)
-    {
-        if (selectedChannel > 2)
-        {
-            TRACELOG(LOG_WARNING, "This image has only 3 channels. Setting channel to red.");
-            selectedChannel = 0;
-        }
-    }
-
-    // Check for RGBA formats
-    if (selectedChannel > 3)
-    {
-        TRACELOG(LOG_WARNING, "ImageFromChannel supports channels 0 to 3 (rgba). Setting channel to alpha.");
-        selectedChannel = 3;
-    }
-
-    // TODO: Consider other one-channel formats: R16, R32
-    result.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
-    result.height = image.height;
-    result.width = image.width;
-    result.mipmaps = 1;
-
-    unsigned char *pixels = (unsigned char *)RL_CALLOC(image.width*image.height, sizeof(unsigned char)); // Values from 0 to 255
-
-    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
-    else
-    {
-        for (int i = 0, k = 0; i < image.width*image.height; i++)
-        {
-            float pixelValue = -1;
-            switch (image.format)
-            {
-                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-                {
-                    pixelValue = (float)((unsigned char *)image.data)[i + selectedChannel]/255.0f;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-                {
-                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
-                    k += 2;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
-                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
-                    else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
-                    else if (selectedChannel == 3) pixelValue = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
-                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63);
-                    else if (selectedChannel == 2) pixelValue = (float)(pixel & 0b0000000000011111)*(1.0f/31);
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15);
-                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15);
-                    else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15);
-                    else if (selectedChannel == 3) pixelValue = (float)(pixel & 0b0000000000001111)*(1.0f/15);
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-                {
-                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
-                    k += 4;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-                {
-                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
-                    k += 3;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32:
-                {
-                    pixelValue = ((float *)image.data)[k];
-                    k += 1;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-                {
-                    pixelValue = ((float *)image.data)[k + selectedChannel];
-                    k += 3;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-                {
-                    pixelValue = ((float *)image.data)[k + selectedChannel];
-                    k += 4;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16:
-                {
-                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k]);
-                    k += 1;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-                {
-                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k+selectedChannel]);
-                    k += 3;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-                {
-                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k + selectedChannel]);
-                    k += 4;
-
-                } break;
-                default: break;
-            }
-
-            pixels[i] = (unsigned char)(pixelValue*255);
-        }
-    }
-
-    result.data = pixels;
-
-    return result;
-}
-
-// Resize and image to new size using Nearest-Neighbor scaling algorithm
-void ImageResizeNN(Image *image, int newWidth, int newHeight)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Color *pixels = LoadImageColors(*image);
-    Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
-
-    // EDIT: added +1 to account for an early rounding problem
-    int xRatio = (int)((image->width << 16)/newWidth) + 1;
-    int yRatio = (int)((image->height << 16)/newHeight) + 1;
-
-    int x2 = 0;
-    int y2 = 0;
-    for (int y = 0; y < newHeight; y++)
-    {
-        for (int x = 0; x < newWidth; x++)
-        {
-            x2 = ((x*xRatio) >> 16);
-            y2 = ((y*yRatio) >> 16);
-
-            output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
-        }
-    }
-
-    int format = image->format;
-
-    RL_FREE(image->data);
-
-    image->data = output;
-    image->width = newWidth;
-    image->height = newHeight;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
-
-    UnloadImageColors(pixels);
-}
-
-// Resize and image to new size
-// NOTE: Uses stb default scaling filters (both bicubic):
-// STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
-// STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
-void ImageResize(Image *image, int newWidth, int newHeight)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    // Check if we can use a fast path on image scaling
-    // It can be for 8 bit per channel images with 1 to 4 channels per pixel
-    if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
-        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
-
-        switch (image->format)
-        {
-            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)1); break;
-            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)2); break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)3); break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)4); break;
-            default: break;
-        }
-
-        RL_FREE(image->data);
-        image->data = output;
-        image->width = newWidth;
-        image->height = newHeight;
-    }
-    else
-    {
-        // Get data as Color pixels array to work with it
-        Color *pixels = LoadImageColors(*image);
-        Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
-
-        // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
-        stbir_resize_uint8_linear((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, (stbir_pixel_layout)4);
-
-        int format = image->format;
-
-        UnloadImageColors(pixels);
-        RL_FREE(image->data);
-
-        image->data = output;
-        image->width = newWidth;
-        image->height = newHeight;
-        image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-        ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
-    }
-}
-
-// Resize canvas and fill with color
-// NOTE: Resize offset is relative to the top-left corner of the original image
-void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else if ((newWidth != image->width) || (newHeight != image->height))
-    {
-        Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height };
-        Vector2 dstPos = { (float)offsetX, (float)offsetY };
-
-        if (offsetX < 0)
-        {
-            srcRec.x = (float)-offsetX;
-            srcRec.width += (float)offsetX;
-            dstPos.x = 0;
-        }
-        else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX);
-
-        if (offsetY < 0)
-        {
-            srcRec.y = (float)-offsetY;
-            srcRec.height += (float)offsetY;
-            dstPos.y = 0;
-        }
-        else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY);
-
-        if (newWidth < srcRec.width) srcRec.width = (float)newWidth;
-        if (newHeight < srcRec.height) srcRec.height = (float)newHeight;
-
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
-
-        // Fill resized canvas with fill color
-        // Set first pixel with image->format
-        SetPixelColor(resizedData, fill, image->format);
-
-        // Fill remaining bytes of first row
-        for (int x = 1; x < newWidth; x++)
-        {
-            memcpy(resizedData + x*bytesPerPixel, resizedData, bytesPerPixel);
-        }
-        // Copy the first row into the other rows
-        for (int y = 1; y < newHeight; y++)
-        {
-            memcpy(resizedData + y*newWidth*bytesPerPixel, resizedData, newWidth*bytesPerPixel);
-        }
-
-        // Copy old image to resized canvas
-        int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
-
-        for (int y = 0; y < (int)srcRec.height; y++)
-        {
-            memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel);
-            dstOffsetSize += (newWidth*bytesPerPixel);
-        }
-
-        RL_FREE(image->data);
-        image->data = resizedData;
-        image->width = newWidth;
-        image->height = newHeight;
-    }
-}
-
-#if defined(SUPPORT_IMAGE_MANIPULATION)
-// Convert image to POT (power-of-two)
-// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
-void ImageToPOT(Image *image, Color fill)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    // Calculate next power-of-two values
-    // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
-    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
-    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
-
-    // Check if POT texture generation is required (if texture is not already POT)
-    if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill);
-}
-
-// Crop image depending on alpha value
-// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
-void ImageAlphaCrop(Image *image, float threshold)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Rectangle crop = GetImageAlphaBorder(*image, threshold);
-
-    // Crop if rectangle is valid
-    if (((int)crop.width != 0) && ((int)crop.height != 0)) ImageCrop(image, crop);
-}
-
-// Clear alpha channel to desired color
-// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
-void ImageAlphaClear(Image *image, Color color, float threshold)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        switch (image->format)
-        {
-            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-            {
-                unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
-                for (int i = 1; i < image->width*image->height*2; i += 2)
-                {
-                    if (((unsigned char *)image->data)[i] <= thresholdValue)
-                    {
-                        ((unsigned char *)image->data)[i - 1] = color.r;
-                        ((unsigned char *)image->data)[i] = color.a;
-                    }
-                }
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-            {
-                unsigned char thresholdValue = ((threshold < 0.5f)? 0 : 1);
-
-                unsigned char r = (unsigned char)(round((float)color.r*31.0f));
-                unsigned char g = (unsigned char)(round((float)color.g*31.0f));
-                unsigned char b = (unsigned char)(round((float)color.b*31.0f));
-                unsigned char a = (color.a < 128)? 0 : 1;
-
-                for (int i = 0; i < image->width*image->height; i++)
-                {
-                    if ((((unsigned short *)image->data)[i] & 0b0000000000000001) <= thresholdValue)
-                    {
-                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
-                    }
-                }
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-            {
-                unsigned char thresholdValue = (unsigned char)(threshold*15.0f);
-
-                unsigned char r = (unsigned char)(round((float)color.r*15.0f));
-                unsigned char g = (unsigned char)(round((float)color.g*15.0f));
-                unsigned char b = (unsigned char)(round((float)color.b*15.0f));
-                unsigned char a = (unsigned char)(round((float)color.a*15.0f));
-
-                for (int i = 0; i < image->width*image->height; i++)
-                {
-                    if ((((unsigned short *)image->data)[i] & 0x000f) <= thresholdValue)
-                    {
-                        ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
-                    }
-                }
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-            {
-                unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
-                for (int i = 3; i < image->width*image->height*4; i += 4)
-                {
-                    if (((unsigned char *)image->data)[i] <= thresholdValue)
-                    {
-                        ((unsigned char *)image->data)[i - 3] = color.r;
-                        ((unsigned char *)image->data)[i - 2] = color.g;
-                        ((unsigned char *)image->data)[i - 1] = color.b;
-                        ((unsigned char *)image->data)[i] = color.a;
-                    }
-                }
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-            {
-                for (int i = 3; i < image->width*image->height*4; i += 4)
-                {
-                    if (((float *)image->data)[i] <= threshold)
-                    {
-                        ((float *)image->data)[i - 3] = (float)color.r/255.0f;
-                        ((float *)image->data)[i - 2] = (float)color.g/255.0f;
-                        ((float *)image->data)[i - 1] = (float)color.b/255.0f;
-                        ((float *)image->data)[i] = (float)color.a/255.0f;
-                    }
-                }
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-            {
-                for (int i = 3; i < image->width*image->height*4; i += 4)
-                {
-                    if (HalfToFloat(((unsigned short *)image->data)[i]) <= threshold)
-                    {
-                        ((unsigned short *)image->data)[i - 3] = FloatToHalf((float)color.r/255.0f);
-                        ((unsigned short *)image->data)[i - 2] = FloatToHalf((float)color.g/255.0f);
-                        ((unsigned short *)image->data)[i - 1] = FloatToHalf((float)color.b/255.0f);
-                        ((unsigned short *)image->data)[i] = FloatToHalf((float)color.a/255.0f);
-                    }
-                }
-            } break;
-            default: break;
-        }
-    }
-}
-
-// Apply alpha mask to image
-// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit)
-// NOTE 2: alphaMask should be same size as image
-void ImageAlphaMask(Image *image, Image alphaMask)
-{
-    if ((image->width != alphaMask.width) || (image->height != alphaMask.height))
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Alpha mask must be same size as image");
-    }
-    else if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Alpha mask can not be applied to compressed data formats");
-    }
-    else
-    {
-        // Force mask to be Grayscale
-        Image mask = ImageCopy(alphaMask);
-        if (mask.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
-
-        // In case image is only grayscale, we just add alpha channel
-        if (image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
-        {
-            unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
-
-            // Apply alpha mask to alpha channel
-            for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
-            {
-                data[k] = ((unsigned char *)image->data)[i];
-                data[k + 1] = ((unsigned char *)mask.data)[i];
-            }
-
-            RL_FREE(image->data);
-            image->data = data;
-            image->format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
-        }
-        else
-        {
-            // Convert image to RGBA
-            if (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
-
-            // Apply alpha mask to alpha channel
-            for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4)
-            {
-                ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i];
-            }
-        }
-
-        UnloadImage(mask);
-    }
-}
-
-// Premultiply alpha channel
-void ImageAlphaPremultiply(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    float alpha = 0.0f;
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        if (pixels[i].a == 0)
-        {
-            pixels[i].r = 0;
-            pixels[i].g = 0;
-            pixels[i].b = 0;
-        }
-        else if (pixels[i].a < 255)
-        {
-            alpha = (float)pixels[i].a/255.0f;
-            pixels[i].r = (unsigned char)((float)pixels[i].r*alpha);
-            pixels[i].g = (unsigned char)((float)pixels[i].g*alpha);
-            pixels[i].b = (unsigned char)((float)pixels[i].b*alpha);
-        }
-    }
-
-    RL_FREE(image->data);
-
-    int format = image->format;
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Apply box blur to image
-void ImageBlurGaussian(Image *image, int blurSize)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    ImageAlphaPremultiply(image);
-
-    Color *pixels = LoadImageColors(*image);
-
-    // Loop switches between pixelsCopy1 and pixelsCopy2
-    Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
-    Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
-
-    for (int i = 0; i < (image->height*image->width); i++)
-    {
-        pixelsCopy1[i].x = pixels[i].r;
-        pixelsCopy1[i].y = pixels[i].g;
-        pixelsCopy1[i].z = pixels[i].b;
-        pixelsCopy1[i].w = pixels[i].a;
-    }
-
-    // Repeated convolution of rectangular window signal by itself converges to a gaussian distribution
-    for (int j = 0; j < GAUSSIAN_BLUR_ITERATIONS; j++)
-    {
-        // Horizontal motion blur
-        for (int row = 0; row < image->height; row++)
-        {
-            float avgR = 0.0f;
-            float avgG = 0.0f;
-            float avgB = 0.0f;
-            float avgAlpha = 0.0f;
-            int convolutionSize = blurSize;
-
-            for (int i = 0; i < blurSize; i++)
-            {
-                avgR += pixelsCopy1[row*image->width + i].x;
-                avgG += pixelsCopy1[row*image->width + i].y;
-                avgB += pixelsCopy1[row*image->width + i].z;
-                avgAlpha += pixelsCopy1[row*image->width + i].w;
-            }
-
-            for (int x = 0; x < image->width; x++)
-            {
-                if (x-blurSize-1 >= 0)
-                {
-                    avgR -= pixelsCopy1[row*image->width + x-blurSize-1].x;
-                    avgG -= pixelsCopy1[row*image->width + x-blurSize-1].y;
-                    avgB -= pixelsCopy1[row*image->width + x-blurSize-1].z;
-                    avgAlpha -= pixelsCopy1[row*image->width + x-blurSize-1].w;
-                    convolutionSize--;
-                }
-
-                if (x+blurSize < image->width)
-                {
-                    avgR += pixelsCopy1[row*image->width + x+blurSize].x;
-                    avgG += pixelsCopy1[row*image->width + x+blurSize].y;
-                    avgB += pixelsCopy1[row*image->width + x+blurSize].z;
-                    avgAlpha += pixelsCopy1[row*image->width + x+blurSize].w;
-                    convolutionSize++;
-                }
-
-                pixelsCopy2[row*image->width + x].x = avgR/convolutionSize;
-                pixelsCopy2[row*image->width + x].y = avgG/convolutionSize;
-                pixelsCopy2[row*image->width + x].z = avgB/convolutionSize;
-                pixelsCopy2[row*image->width + x].w = avgAlpha/convolutionSize;
-            }
-        }
-
-        // Vertical motion blur
-        for (int col = 0; col < image->width; col++)
-        {
-            float avgR = 0.0f;
-            float avgG = 0.0f;
-            float avgB = 0.0f;
-            float avgAlpha = 0.0f;
-            int convolutionSize = blurSize;
-
-            for (int i = 0; i < blurSize; i++)
-            {
-                avgR += pixelsCopy2[i*image->width + col].x;
-                avgG += pixelsCopy2[i*image->width + col].y;
-                avgB += pixelsCopy2[i*image->width + col].z;
-                avgAlpha += pixelsCopy2[i*image->width + col].w;
-            }
-
-            for (int y = 0; y < image->height; y++)
-            {
-                if (y-blurSize-1 >= 0)
-                {
-                    avgR -= pixelsCopy2[(y-blurSize-1)*image->width + col].x;
-                    avgG -= pixelsCopy2[(y-blurSize-1)*image->width + col].y;
-                    avgB -= pixelsCopy2[(y-blurSize-1)*image->width + col].z;
-                    avgAlpha -= pixelsCopy2[(y-blurSize-1)*image->width + col].w;
-                    convolutionSize--;
-                }
-                if (y+blurSize < image->height)
-                {
-                    avgR += pixelsCopy2[(y+blurSize)*image->width + col].x;
-                    avgG += pixelsCopy2[(y+blurSize)*image->width + col].y;
-                    avgB += pixelsCopy2[(y+blurSize)*image->width + col].z;
-                    avgAlpha += pixelsCopy2[(y+blurSize)*image->width + col].w;
-                    convolutionSize++;
-                }
-
-                pixelsCopy1[y*image->width + col].x = (unsigned char) (avgR/convolutionSize);
-                pixelsCopy1[y*image->width + col].y = (unsigned char) (avgG/convolutionSize);
-                pixelsCopy1[y*image->width + col].z = (unsigned char) (avgB/convolutionSize);
-                pixelsCopy1[y*image->width + col].w = (unsigned char) (avgAlpha/convolutionSize);
-            }
-        }
-    }
-
-    // Reverse premultiply
-    for (int i = 0; i < (image->width)*(image->height); i++)
-    {
-        if (pixelsCopy1[i].w == 0.0f)
-        {
-            pixels[i].r = 0;
-            pixels[i].g = 0;
-            pixels[i].b = 0;
-            pixels[i].a = 0;
-        }
-        else if (pixelsCopy1[i].w <= 255.0f)
-        {
-            float alpha = (float)pixelsCopy1[i].w/255.0f;
-            pixels[i].r = (unsigned char)fminf((float)pixelsCopy1[i].x/alpha, 255.0);
-            pixels[i].g = (unsigned char)fminf((float)pixelsCopy1[i].y/alpha, 255.0);
-            pixels[i].b = (unsigned char)fminf((float)pixelsCopy1[i].z/alpha, 255.0);
-            pixels[i].a = (unsigned char) pixelsCopy1[i].w;
-        }
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-    RL_FREE(pixelsCopy1);
-    RL_FREE(pixelsCopy2);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Apply custom square convolution kernel to image
-// NOTE: The convolution kernel matrix is expected to be square
-void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
-{
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0) || kernel == NULL) return;
-
-    int kernelWidth = (int)sqrtf((float)kernelSize);
-
-    if (kernelWidth*kernelWidth != kernelSize)
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Convolution kernel must be square to be applied");
-        return;
-    }
-
-    Color *pixels = LoadImageColors(*image);
-
-    Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
-    Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
-
-    for (int i = 0; i < kernelSize; i++)
-    {
-        temp[i].x = 0.0f;
-        temp[i].y = 0.0f;
-        temp[i].z = 0.0f;
-        temp[i].w = 0.0f;
-    }
-
-    float rRes = 0.0f;
-    float gRes = 0.0f;
-    float bRes = 0.0f;
-    float aRes = 0.0f;
-
-    int startRange = 0, endRange = 0;
-
-    if (kernelWidth%2 == 0)
-    {
-        startRange = -kernelWidth/2;
-        endRange = kernelWidth/2;
-    }
-    else
-    {
-        startRange = -kernelWidth/2;
-        endRange = kernelWidth/2 + 1;
-    }
-
-    for (int x = 0; x < image->height; x++)
-    {
-        for (int y = 0; y < image->width; y++)
-        {
-            for (int xk = startRange; xk < endRange; xk++)
-            {
-                for (int yk = startRange; yk < endRange; yk++)
-                {
-                    int xkabs = xk + kernelWidth/2;
-                    int ykabs = yk + kernelWidth/2;
-                    unsigned int imgindex = image->width*(x + xk) + (y + yk);
-
-                    if (imgindex >= (unsigned int)(image->width*image->height))
-                    {
-                        temp[kernelWidth*xkabs + ykabs].x = 0.0f;
-                        temp[kernelWidth*xkabs + ykabs].y = 0.0f;
-                        temp[kernelWidth*xkabs + ykabs].z = 0.0f;
-                        temp[kernelWidth*xkabs + ykabs].w = 0.0f;
-                    }
-                    else
-                    {
-                        temp[kernelWidth*xkabs + ykabs].x = ((float)pixels[imgindex].r)/255.0f*kernel[kernelWidth*xkabs + ykabs];
-                        temp[kernelWidth*xkabs + ykabs].y = ((float)pixels[imgindex].g)/255.0f*kernel[kernelWidth*xkabs + ykabs];
-                        temp[kernelWidth*xkabs + ykabs].z = ((float)pixels[imgindex].b)/255.0f*kernel[kernelWidth*xkabs + ykabs];
-                        temp[kernelWidth*xkabs + ykabs].w = ((float)pixels[imgindex].a)/255.0f*kernel[kernelWidth*xkabs + ykabs];
-                    }
-                }
-            }
-
-            for (int i = 0; i < kernelSize; i++)
-            {
-                rRes += temp[i].x;
-                gRes += temp[i].y;
-                bRes += temp[i].z;
-                aRes += temp[i].w;
-            }
-
-            if (rRes < 0.0f) rRes = 0.0f;
-            if (gRes < 0.0f) gRes = 0.0f;
-            if (bRes < 0.0f) bRes = 0.0f;
-
-            if (rRes > 1.0f) rRes = 1.0f;
-            if (gRes > 1.0f) gRes = 1.0f;
-            if (bRes > 1.0f) bRes = 1.0f;
-
-            imageCopy2[image->width*x + y].x = rRes;
-            imageCopy2[image->width*x + y].y = gRes;
-            imageCopy2[image->width*x + y].z = bRes;
-            imageCopy2[image->width*x + y].w = aRes;
-
-            rRes = 0.0f;
-            gRes = 0.0f;
-            bRes = 0.0f;
-            aRes = 0.0f;
-
-            for (int i = 0; i < kernelSize; i++)
-            {
-                temp[i].x = 0.0f;
-                temp[i].y = 0.0f;
-                temp[i].z = 0.0f;
-                temp[i].w = 0.0f;
-            }
-        }
-    }
-
-    for (int i = 0; i < (image->width*image->height); i++)
-    {
-        float alpha = (float)imageCopy2[i].w;
-
-        pixels[i].r = (unsigned char)((imageCopy2[i].x)*255.0f);
-        pixels[i].g = (unsigned char)((imageCopy2[i].y)*255.0f);
-        pixels[i].b = (unsigned char)((imageCopy2[i].z)*255.0f);
-        pixels[i].a = (unsigned char)((alpha)*255.0f);
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-    RL_FREE(imageCopy2);
-    RL_FREE(temp);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-    ImageFormat(image, format);
-}
-
-// Generate all mipmap levels for a provided image
-// NOTE 1: Supports POT and NPOT images
-// NOTE 2: image.data is scaled to include mipmap levels
-// NOTE 3: Mipmaps format is the same as base image
-void ImageMipmaps(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    int mipCount = 1;                   // Required mipmap levels count (including base level)
-    int mipWidth = image->width;        // Base image width
-    int mipHeight = image->height;      // Base image height
-    int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);  // Image data size (in bytes)
-
-    // Count mipmap levels required
-    while ((mipWidth != 1) || (mipHeight != 1))
-    {
-        if (mipWidth != 1) mipWidth /= 2;
-        if (mipHeight != 1) mipHeight /= 2;
-
-        // Security check for NPOT textures
-        if (mipWidth < 1) mipWidth = 1;
-        if (mipHeight < 1) mipHeight = 1;
-
-        TRACELOG(LOG_DEBUG, "IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
-
-        mipCount++;
-        mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format);       // Add mipmap size (in bytes)
-    }
-
-    if (image->mipmaps < mipCount)
-    {
-        // Create second buffer and copy data manually to it
-        void *temp = RL_CALLOC(mipSize, 1);
-        memcpy(temp, image->data, GetPixelDataSize(image->width, image->height, image->format));
-        RL_FREE(image->data);
-        image->data = temp;
-
-        // Pointer to allocated memory point where store next mipmap level data
-        unsigned char *nextmip = (unsigned char *)image->data;
-
-        mipWidth = image->width;
-        mipHeight = image->height;
-        mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
-        Image imCopy = ImageCopy(*image);
-
-        for (int i = 1; i < mipCount; i++)
-        {
-            nextmip += mipSize;
-
-            mipWidth /= 2;
-            mipHeight /= 2;
-
-            // Security check for NPOT textures
-            if (mipWidth < 1) mipWidth = 1;
-            if (mipHeight < 1) mipHeight = 1;
-
-            mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
-
-            if (i < image->mipmaps) continue;
-
-            TRACELOG(LOG_DEBUG, "IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
-            ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter
-            memcpy(nextmip, imCopy.data, mipSize);
-        }
-
-        UnloadImage(imCopy);
-
-        image->mipmaps = mipCount;
-    }
-    else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps already available");
-}
-
-// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
-// NOTE: In case selected bpp do not represent a known 16bit format,
-// dithered data is stored in the LSB part of the unsigned short
-void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Compressed data formats can not be dithered");
-        return;
-    }
-
-    if ((rBpp + gBpp + bBpp + aBpp) > 16)
-    {
-        TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
-    }
-    else
-    {
-        Color *pixels = LoadImageColors(*image);
-
-        RL_FREE(image->data);      // free old image data
-
-        if ((image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
-        {
-            TRACELOG(LOG_WARNING, "IMAGE: Format is already 16bpp or lower, dithering could have no effect");
-        }
-
-        // Define new image format, check if desired bpp match internal known format
-        if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
-        else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
-        else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
-        else
-        {
-            image->format = 0;
-            TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
-        }
-
-        // NOTE: We will store the dithered data as unsigned short (16bpp)
-        image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
-
-        Color oldPixel = WHITE;
-        Color newPixel = WHITE;
-
-        int rError = 0;
-        int gError = 0;
-        int bError = 0;
-        unsigned short rPixel = 0;   // Used for 16bit pixel composition
-        unsigned short gPixel = 0;
-        unsigned short bPixel = 0;
-        unsigned short aPixel = 0;
-
-        #define MIN(a,b) (((a)<(b))?(a):(b))
-
-        for (int y = 0; y < image->height; y++)
-        {
-            for (int x = 0; x < image->width; x++)
-            {
-                oldPixel = pixels[y*image->width + x];
-
-                // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
-                newPixel.r = oldPixel.r >> (8 - rBpp);     // R bits
-                newPixel.g = oldPixel.g >> (8 - gBpp);     // G bits
-                newPixel.b = oldPixel.b >> (8 - bBpp);     // B bits
-                newPixel.a = oldPixel.a >> (8 - aBpp);     // A bits (not used on dithering)
-
-                // NOTE: Error must be computed between new and old pixel but using same number of bits!
-                // We want to know how much color precision we have lost...
-                rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
-                gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
-                bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
-
-                pixels[y*image->width + x] = newPixel;
-
-                // NOTE: Some cases are out of the array and should be ignored
-                if (x < (image->width - 1))
-                {
-                    pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
-                    pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
-                    pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
-                }
-
-                if ((x > 0) && (y < (image->height - 1)))
-                {
-                    pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
-                }
-
-                if (y < (image->height - 1))
-                {
-                    pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
-                }
-
-                if ((x < (image->width - 1)) && (y < (image->height - 1)))
-                {
-                    pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
-                    pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
-                }
-
-                rPixel = (unsigned short)newPixel.r;
-                gPixel = (unsigned short)newPixel.g;
-                bPixel = (unsigned short)newPixel.b;
-                aPixel = (unsigned short)newPixel.a;
-
-                ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
-            }
-        }
-
-        UnloadImageColors(pixels);
-    }
-}
-
-// Flip image vertically
-void ImageFlipVertical(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
-
-        for (int i = (image->height - 1), offsetSize = 0; i >= 0; i--)
-        {
-            memcpy(flippedData + offsetSize, ((unsigned char *)image->data) + i*image->width*bytesPerPixel, image->width*bytesPerPixel);
-            offsetSize += image->width*bytesPerPixel;
-        }
-
-        RL_FREE(image->data);
-        image->data = flippedData;
-    }
-}
-
-// Flip image horizontally
-void ImageFlipHorizontal(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
-
-        for (int y = 0; y < image->height; y++)
-        {
-            for (int x = 0; x < image->width; x++)
-            {
-                // OPTION 1: Move pixels with memcpy()
-                //memcpy(flippedData + (y*image->width + x)*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - 1 - x))*bytesPerPixel, bytesPerPixel);
-
-                // OPTION 2: Just copy data pixel by pixel
-                for (int i = 0; i < bytesPerPixel; i++) flippedData[(y*image->width + x)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - 1 - x))*bytesPerPixel + i];
-            }
-        }
-
-        RL_FREE(image->data);
-        image->data = flippedData;
-
-        /*
-        // OPTION 3: Faster implementation (specific for 32bit pixels)
-        // NOTE: It does not require additional allocations
-        uint32_t *ptr = (uint32_t *)image->data;
-        for (int y = 0; y < image->height; y++)
-        {
-            for (int x = 0; x < image->width/2; x++)
-            {
-                uint32_t backup = ptr[y*image->width + x];
-                ptr[y*image->width + x] = ptr[y*image->width + (image->width - 1 - x)];
-                ptr[y*image->width + (image->width - 1 - x)] = backup;
-            }
-        }
-        */
-    }
-}
-
-// Rotate image in degrees
-void ImageRotate(Image *image, int degrees)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        float rad = degrees*PI/180.0f;
-        float sinRadius = sinf(rad);
-        float cosRadius = cosf(rad);
-
-        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);
-
-        for (int y = 0; y < height; y++)
-        {
-            for (int x = 0; x < width; x++)
-            {
-                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))
-                {
-                    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 px = oldX - x1;
-                    float py = oldY - y1;
-
-                    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;
-    }
-}
-
-// Rotate image clockwise 90deg
-void ImageRotateCW(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
-
-        for (int y = 0; y < image->height; y++)
-        {
-            for (int x = 0; x < image->width; x++)
-            {
-                //memcpy(rotatedData + (x*image->height + (image->height - y - 1))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
-                for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + (image->height - y - 1))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
-            }
-        }
-
-        RL_FREE(image->data);
-        image->data = rotatedData;
-        int width = image->width;
-        int height = image-> height;
-
-        image->width = height;
-        image->height = width;
-    }
-}
-
-// Rotate image counter-clockwise 90deg
-void ImageRotateCCW(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
-    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
-    else
-    {
-        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
-        unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
-
-        for (int y = 0; y < image->height; y++)
-        {
-            for (int x = 0; x < image->width; x++)
-            {
-                //memcpy(rotatedData + (x*image->height + y))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - x - 1))*bytesPerPixel, bytesPerPixel);
-                for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + y)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - x - 1))*bytesPerPixel + i];
-            }
-        }
-
-        RL_FREE(image->data);
-        image->data = rotatedData;
-        int width = image->width;
-        int height = image-> height;
-
-        image->width = height;
-        image->height = width;
-    }
-}
-
-// Modify image color: tint
-void ImageColorTint(Image *image, Color color)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        unsigned char r = (unsigned char)(((int)pixels[i].r*(int)color.r)/255);
-        unsigned char g = (unsigned char)(((int)pixels[i].g*(int)color.g)/255);
-        unsigned char b = (unsigned char)(((int)pixels[i].b*(int)color.b)/255);
-        unsigned char a = (unsigned char)(((int)pixels[i].a*(int)color.a)/255);
-
-        pixels[i].r = r;
-        pixels[i].g = g;
-        pixels[i].b = b;
-        pixels[i].a = a;
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Modify image color: invert
-void ImageColorInvert(Image *image)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        pixels[i].r = 255 - pixels[i].r;
-        pixels[i].g = 255 - pixels[i].g;
-        pixels[i].b = 255 - pixels[i].b;
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Modify image color: grayscale
-void ImageColorGrayscale(Image *image)
-{
-    ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
-}
-
-// Modify image color: contrast
-// NOTE: Contrast values between -100 and 100
-void ImageColorContrast(Image *image, float contrast)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (contrast < -100) contrast = -100;
-    if (contrast > 100) contrast = 100;
-
-    contrast = (100.0f + contrast)/100.0f;
-    contrast *= contrast;
-
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        float pR = (float)pixels[i].r/255.0f;
-        pR -= 0.5f;
-        pR *= contrast;
-        pR += 0.5f;
-        pR *= 255;
-        if (pR < 0) pR = 0;
-        if (pR > 255) pR = 255;
-
-        float pG = (float)pixels[i].g/255.0f;
-        pG -= 0.5f;
-        pG *= contrast;
-        pG += 0.5f;
-        pG *= 255;
-        if (pG < 0) pG = 0;
-        if (pG > 255) pG = 255;
-
-        float pB = (float)pixels[i].b/255.0f;
-        pB -= 0.5f;
-        pB *= contrast;
-        pB += 0.5f;
-        pB *= 255;
-        if (pB < 0) pB = 0;
-        if (pB > 255) pB = 255;
-
-        pixels[i].r = (unsigned char)pR;
-        pixels[i].g = (unsigned char)pG;
-        pixels[i].b = (unsigned char)pB;
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Modify image color: brightness
-// NOTE: Brightness values between -255 and 255
-void ImageColorBrightness(Image *image, int brightness)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    if (brightness < -255) brightness = -255;
-    if (brightness > 255) brightness = 255;
-
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        int cR = pixels[i].r + brightness;
-        int cG = pixels[i].g + brightness;
-        int cB = pixels[i].b + brightness;
-
-        if (cR < 0) cR = 1;
-        if (cR > 255) cR = 255;
-
-        if (cG < 0) cG = 1;
-        if (cG > 255) cG = 255;
-
-        if (cB < 0) cB = 1;
-        if (cB > 255) cB = 255;
-
-        pixels[i].r = (unsigned char)cR;
-        pixels[i].g = (unsigned char)cG;
-        pixels[i].b = (unsigned char)cB;
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    ImageFormat(image, format);
-}
-
-// Modify image color: replace color
-void ImageColorReplace(Image *image, Color color, Color replace)
-{
-    // Security check to avoid program crash
-    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
-
-    Color *pixels = LoadImageColors(*image);
-
-    for (int i = 0; i < image->width*image->height; i++)
-    {
-        if ((pixels[i].r == color.r) &&
-            (pixels[i].g == color.g) &&
-            (pixels[i].b == color.b) &&
-            (pixels[i].a == color.a))
-        {
-            pixels[i].r = replace.r;
-            pixels[i].g = replace.g;
-            pixels[i].b = replace.b;
-            pixels[i].a = replace.a;
-        }
-    }
-
-    int format = image->format;
-    RL_FREE(image->data);
-
-    image->data = pixels;
-    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-
-    // Only convert back to original format if it supported alpha
-    if ((format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
-        (format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
-        (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
-        (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
-        (format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
-        (format == PIXELFORMAT_COMPRESSED_DXT1_RGB) ||
-        (format == PIXELFORMAT_COMPRESSED_ETC1_RGB) ||
-        (format == PIXELFORMAT_COMPRESSED_ETC2_RGB) ||
-        (format == PIXELFORMAT_COMPRESSED_PVRT_RGB)) ImageFormat(image, format);
-}
-#endif      // SUPPORT_IMAGE_MANIPULATION
-
-// Load color data from image as a Color array (RGBA - 32bit)
-// NOTE: Memory allocated should be freed using UnloadImageColors();
-Color *LoadImageColors(Image image)
-{
-    if ((image.width == 0) || (image.height == 0)) return NULL;
-
-    Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color));
-
-    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
-    else
-    {
-        if ((image.format == PIXELFORMAT_UNCOMPRESSED_R32) ||
-            (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
-            (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 32bit to 8bit per channel");
-
-        if ((image.format == PIXELFORMAT_UNCOMPRESSED_R16) ||
-            (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
-            (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 16bit to 8bit per channel");
-
-        for (int i = 0, k = 0; i < image.width*image.height; i++)
-        {
-            switch (image.format)
-            {
-                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-                {
-                    pixels[i].r = ((unsigned char *)image.data)[i];
-                    pixels[i].g = ((unsigned char *)image.data)[i];
-                    pixels[i].b = ((unsigned char *)image.data)[i];
-                    pixels[i].a = 255;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-                {
-                    pixels[i].r = ((unsigned char *)image.data)[k];
-                    pixels[i].g = ((unsigned char *)image.data)[k];
-                    pixels[i].b = ((unsigned char *)image.data)[k];
-                    pixels[i].a = ((unsigned char *)image.data)[k + 1];
-
-                    k += 2;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
-                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
-                    pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
-                    pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255);
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
-                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
-                    pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
-                    pixels[i].a = 255;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
-                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
-                    pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
-                    pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-                {
-                    pixels[i].r = ((unsigned char *)image.data)[k];
-                    pixels[i].g = ((unsigned char *)image.data)[k + 1];
-                    pixels[i].b = ((unsigned char *)image.data)[k + 2];
-                    pixels[i].a = ((unsigned char *)image.data)[k + 3];
-
-                    k += 4;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-                {
-                    pixels[i].r = (unsigned char)((unsigned char *)image.data)[k];
-                    pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1];
-                    pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2];
-                    pixels[i].a = 255;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32:
-                {
-                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
-                    pixels[i].g = 0;
-                    pixels[i].b = 0;
-                    pixels[i].a = 255;
-
-                    k += 1;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-                {
-                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
-                    pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
-                    pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
-                    pixels[i].a = 255;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-                {
-                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
-                    pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
-                    pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
-                    pixels[i].a = (unsigned char)(((float *)image.data)[k + 3]*255.0f);
-
-                    k += 4;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16:
-                {
-                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
-                    pixels[i].g = 0;
-                    pixels[i].b = 0;
-                    pixels[i].a = 255;
-
-                    k += 1;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-                {
-                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
-                    pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f);
-                    pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f);
-                    pixels[i].a = 255;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-                {
-                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
-                    pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f);
-                    pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f);
-                    pixels[i].a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 3])*255.0f);
-
-                    k += 4;
-                } break;
-                default: break;
-            }
-        }
-    }
-
-    return pixels;
-}
-
-// Load colors palette from image as a Color array (RGBA - 32bit)
-// NOTE: Memory allocated should be freed using UnloadImagePalette()
-Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount)
-{
-    #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
-
-    int palCount = 0;
-    Color *palette = NULL;
-    Color *pixels = LoadImageColors(image);
-
-    if (pixels != NULL)
-    {
-        palette = (Color *)RL_MALLOC(maxPaletteSize*sizeof(Color));
-
-        for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK;   // Set all colors to BLANK
-
-        for (int i = 0; i < image.width*image.height; i++)
-        {
-            if (pixels[i].a > 0)
-            {
-                bool colorInPalette = false;
-
-                // Check if the color is already on palette
-                for (int j = 0; j < maxPaletteSize; j++)
-                {
-                    if (COLOR_EQUAL(pixels[i], palette[j]))
-                    {
-                        colorInPalette = true;
-                        break;
-                    }
-                }
-
-                // Store color if not on the palette
-                if (!colorInPalette)
-                {
-                    palette[palCount] = pixels[i];      // Add pixels[i] to palette
-                    palCount++;
-
-                    // We reached the limit of colors supported by palette
-                    if (palCount >= maxPaletteSize)
-                    {
-                        i = image.width*image.height;   // Finish palette get
-                        TRACELOG(LOG_WARNING, "IMAGE: Palette is greater than %i colors", maxPaletteSize);
-                    }
-                }
-            }
-        }
-
-        UnloadImageColors(pixels);
-    }
-
-    *colorCount = palCount;
-
-    return palette;
-}
-
-// Unload color data loaded with LoadImageColors()
-void UnloadImageColors(Color *colors)
-{
-    RL_FREE(colors);
-}
-
-// Unload colors palette loaded with LoadImagePalette()
-void UnloadImagePalette(Color *colors)
-{
-    RL_FREE(colors);
-}
-
-// Get image alpha border rectangle
-// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
-Rectangle GetImageAlphaBorder(Image image, float threshold)
-{
-    Rectangle crop = { 0 };
-
-    Color *pixels = LoadImageColors(image);
-
-    if (pixels != NULL)
-    {
-        int xMin = 65536;   // Define a big enough number
-        int xMax = 0;
-        int yMin = 65536;
-        int yMax = 0;
-
-        for (int y = 0; y < image.height; y++)
-        {
-            for (int x = 0; x < image.width; x++)
-            {
-                if (pixels[y*image.width + x].a > (unsigned char)(threshold*255.0f))
-                {
-                    if (x < xMin) xMin = x;
-                    if (x > xMax) xMax = x;
-                    if (y < yMin) yMin = y;
-                    if (y > yMax) yMax = y;
-                }
-            }
-        }
-
-        // Check for empty blank image
-        if ((xMin != 65536) && (xMax != 65536))
-        {
-            crop = (Rectangle){ (float)xMin, (float)yMin, (float)((xMax + 1) - xMin), (float)((yMax + 1) - yMin) };
-        }
-
-        UnloadImageColors(pixels);
-    }
-
-    return crop;
-}
-
-// Get image pixel color at (x, y) position
-Color GetImageColor(Image image, int x, int y)
-{
-    Color color = { 0 };
-
-    if ((x >=0) && (x < image.width) && (y >= 0) && (y < image.height))
-    {
-        switch (image.format)
-        {
-            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-            {
-                color.r = ((unsigned char *)image.data)[y*image.width + x];
-                color.g = ((unsigned char *)image.data)[y*image.width + x];
-                color.b = ((unsigned char *)image.data)[y*image.width + x];
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-            {
-                color.r = ((unsigned char *)image.data)[(y*image.width + x)*2];
-                color.g = ((unsigned char *)image.data)[(y*image.width + x)*2];
-                color.b = ((unsigned char *)image.data)[(y*image.width + x)*2];
-                color.a = ((unsigned char *)image.data)[(y*image.width + x)*2 + 1];
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-            {
-                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
-
-                color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
-                color.g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
-                color.b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
-                color.a = (unsigned char)((pixel & 0b0000000000000001)*255);
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-            {
-                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
-
-                color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
-                color.g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
-                color.b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-            {
-                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
-
-                color.r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
-                color.g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
-                color.b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
-                color.a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-            {
-                color.r = ((unsigned char *)image.data)[(y*image.width + x)*4];
-                color.g = ((unsigned char *)image.data)[(y*image.width + x)*4 + 1];
-                color.b = ((unsigned char *)image.data)[(y*image.width + x)*4 + 2];
-                color.a = ((unsigned char *)image.data)[(y*image.width + x)*4 + 3];
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-            {
-                color.r = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3];
-                color.g = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 1];
-                color.b = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 2];
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R32:
-            {
-                color.r = (unsigned char)(((float *)image.data)[y*image.width + x]*255.0f);
-                color.g = 0;
-                color.b = 0;
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-            {
-                color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*3]*255.0f);
-                color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 1]*255.0f);
-                color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 2]*255.0f);
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-            {
-                color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f);
-                color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f);
-                color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f);
-                color.a = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f);
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R16:
-            {
-                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[y*image.width + x])*255.0f);
-                color.g = 0;
-                color.b = 0;
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-            {
-                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3])*255.0f);
-                color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 1])*255.0f);
-                color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 2])*255.0f);
-                color.a = 255;
-
-            } break;
-            case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-            {
-                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f);
-                color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f);
-                color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f);
-                color.a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f);
-
-            } break;
-            default: TRACELOG(LOG_WARNING, "Compressed image format does not support color reading"); break;
-        }
-    }
-    else TRACELOG(LOG_WARNING, "Requested image pixel (%i, %i) out of bounds", x, y);
-
-    return color;
-}
-
-//------------------------------------------------------------------------------------
-// Image drawing functions
-//------------------------------------------------------------------------------------
-// Clear image background with given color
-void ImageClearBackground(Image *dst, Color color)
-{
-    // Security check to avoid program crash
-    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
-
-    // Fill in first pixel based on image format
-    ImageDrawPixel(dst, 0, 0, color);
-
-    unsigned char *pSrcPixel = (unsigned char *)dst->data;
-    int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
-    int totalPixels = dst->width*dst->height;
-
-    // Repeat the first pixel data throughout the image,
-    // doubling the pixels copied on each iteration
-    for (int i = 1; i < totalPixels; i *= 2)
-    {
-        int pixelsToCopy = MIN(i, totalPixels - i);
-        memcpy(pSrcPixel + i*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
-    }
-}
-
-// Draw pixel within an image
-// NOTE: Compressed image formats not supported
-void ImageDrawPixel(Image *dst, int x, int y, Color color)
-{
-    // Security check to avoid program crash
-    if ((dst->data == NULL) || (x < 0) || (x >= dst->width) || (y < 0) || (y >= dst->height)) return;
-
-    switch (dst->format)
-    {
-        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-        {
-            // NOTE: Calculate grayscale equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
-
-            ((unsigned char *)dst->data)[y*dst->width + x] = gray;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-        {
-            // NOTE: Calculate grayscale equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
-
-            ((unsigned char *)dst->data)[(y*dst->width + x)*2] = gray;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*2 + 1] = color.a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        {
-            // NOTE: Calculate R5G6B5 equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*31.0f));
-            unsigned char g = (unsigned char)(round(coln.y*63.0f));
-            unsigned char b = (unsigned char)(round(coln.z*31.0f));
-
-            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        {
-            // NOTE: Calculate R5G5B5A1 equivalent color
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*31.0f));
-            unsigned char g = (unsigned char)(round(coln.y*31.0f));
-            unsigned char b = (unsigned char)(round(coln.z*31.0f));
-            unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
-
-            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-        {
-            // NOTE: Calculate R5G5B5A1 equivalent color
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*15.0f));
-            unsigned char g = (unsigned char)(round(coln.y*15.0f));
-            unsigned char b = (unsigned char)(round(coln.z*15.0f));
-            unsigned char a = (unsigned char)(round(coln.w*15.0f));
-
-            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-        {
-            ((unsigned char *)dst->data)[(y*dst->width + x)*3] = color.r;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 1] = color.g;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 2] = color.b;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-        {
-            ((unsigned char *)dst->data)[(y*dst->width + x)*4] = color.r;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 1] = color.g;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 2] = color.b;
-            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 3] = color.a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R32:
-        {
-            // NOTE: Calculate grayscale equivalent color (normalized to 32bit)
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            ((float *)dst->data)[y*dst->width + x] = coln.x*0.299f + coln.y*0.587f + coln.z*0.114f;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-        {
-            // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit)
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            ((float *)dst->data)[(y*dst->width + x)*3] = coln.x;
-            ((float *)dst->data)[(y*dst->width + x)*3 + 1] = coln.y;
-            ((float *)dst->data)[(y*dst->width + x)*3 + 2] = coln.z;
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-        {
-            // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit)
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            ((float *)dst->data)[(y*dst->width + x)*4] = coln.x;
-            ((float *)dst->data)[(y*dst->width + x)*4 + 1] = coln.y;
-            ((float *)dst->data)[(y*dst->width + x)*4 + 2] = coln.z;
-            ((float *)dst->data)[(y*dst->width + x)*4 + 3] = coln.w;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16:
-        {
-            // NOTE: Calculate grayscale equivalent color (normalized to 32bit)
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            ((unsigned short*)dst->data)[y*dst->width + x] = FloatToHalf(coln.x*0.299f + coln.y*0.587f + coln.z*0.114f);
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-        {
-            // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit)
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            ((unsigned short *)dst->data)[(y*dst->width + x)*3] = FloatToHalf(coln.x);
-            ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 1] = FloatToHalf(coln.y);
-            ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 2] = FloatToHalf(coln.z);
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-        {
-            // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit)
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            ((unsigned short *)dst->data)[(y*dst->width + x)*4] = FloatToHalf(coln.x);
-            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 1] = FloatToHalf(coln.y);
-            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 2] = FloatToHalf(coln.z);
-            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 3] = FloatToHalf(coln.w);
-
-        } break;
-        default: break;
-    }
-}
-
-// Draw pixel within an image (Vector version)
-void ImageDrawPixelV(Image *dst, Vector2 position, Color color)
-{
-    ImageDrawPixel(dst, (int)position.x, (int)position.y, color);
-}
-
-// Draw line within an image
-void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color)
-{
-    // Calculate differences in coordinates
-    int shortLen = endPosY - startPosY;
-    int longLen = endPosX - startPosX;
-    bool yLonger = false;
-
-    // Determine if the line is more vertical than horizontal
-    if (abs(shortLen) > abs(longLen))
-    {
-        // Swap the lengths if the line is more vertical
-        int temp = shortLen;
-        shortLen = longLen;
-        longLen = temp;
-        yLonger = true;
-    }
-
-    // Initialize variables for drawing loop
-    int endVal = longLen;
-    int sgnInc = 1;
-
-    // Adjust direction increment based on longLen sign
-    if (longLen < 0)
-    {
-        longLen = -longLen;
-        sgnInc = -1;
-    }
-
-    // Calculate fixed-point increment for shorter length
-    int decInc = (longLen == 0)? 0 : (shortLen << 16)/longLen;
-
-    // Draw the line pixel by pixel
-    if (yLonger)
-    {
-        // If line is more vertical, iterate over y-axis
-        for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc)
-        {
-            // Calculate pixel position and draw it
-            ImageDrawPixel(dst, startPosX + (j >> 16), startPosY + i, color);
-        }
-    }
-    else
-    {
-        // If line is more horizontal, iterate over x-axis
-        for (int i = 0, j = 0; i != endVal; i += sgnInc, j += decInc)
-        {
-            // Calculate pixel position and draw it
-            ImageDrawPixel(dst, startPosX + i, startPosY + (j >> 16), color);
-        }
-    }
-}
-
-// Draw line within an image (Vector version)
-void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color)
-{
-    // Round start and end positions to nearest integer coordinates
-    int x1 = (int)(start.x + 0.5f);
-    int y1 = (int)(start.y + 0.5f);
-    int x2 = (int)(end.x + 0.5f);
-    int y2 = (int)(end.y + 0.5f);
-
-    // Draw a vertical line using ImageDrawLine function
-    ImageDrawLine(dst, x1, y1, x2, y2, color);
-}
-
-// Draw a line defining thickness within an image
-void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color)
-{
-    // Round start and end positions to nearest integer coordinates
-    int x1 = (int)(start.x + 0.5f);
-    int y1 = (int)(start.y + 0.5f);
-    int x2 = (int)(end.x + 0.5f);
-    int y2 = (int)(end.y + 0.5f);
-
-    // Calculate differences in x and y coordinates
-    int dx = x2 - x1;
-    int dy = y2 - y1;
-
-    // Determine if the line is more horizontal or vertical
-    if ((dx != 0) && (abs(dy/dx) < 1))
-    {
-        // Line is more horizontal
-
-        // How many additional lines to draw
-        int wy = thick - 1;
-
-        // Draw the main line and lower half
-        for (int i = 0; i <= ((wy+1)/2); i++)
-        {
-            ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color);
-        }
-
-        // Draw the upper half
-        for (int i = 1; i <= (wy/2); i++)
-        {
-            ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color);
-        }
-    }
-    else if (dy != 0)
-    {
-        // Line is more vertical or perfectly horizontal
-
-        // How many additional lines to draw
-        int wx = thick - 1;
-
-        //Draw the main line and right half
-        for (int i = 0; i <= ((wx+1)/2); i++)
-        {
-            ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color);
-        }
-
-        // Draw the left half
-        for (int i = 1; i <= (wx/2); i++)
-        {
-            ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color);
-        }
-    }
-}
-
-// Draw circle within an image
-void ImageDrawCircle(Image* dst, int centerX, int centerY, int radius, Color color)
-{
-    int x = 0;
-    int y = radius;
-    int decesionParameter = 3 - 2*radius;
-
-    while (y >= x)
-    {
-        ImageDrawRectangle(dst, centerX - x, centerY + y, x*2, 1, color);
-        ImageDrawRectangle(dst, centerX - x, centerY - y, x*2, 1, color);
-        ImageDrawRectangle(dst, centerX - y, centerY + x, y*2, 1, color);
-        ImageDrawRectangle(dst, centerX - y, centerY - x, y*2, 1, color);
-        x++;
-
-        if (decesionParameter > 0)
-        {
-            y--;
-            decesionParameter = decesionParameter + 4*(x - y) + 10;
-        }
-        else decesionParameter = decesionParameter + 4*x + 6;
-    }
-}
-
-// Draw circle within an image (Vector version)
-void ImageDrawCircleV(Image* dst, Vector2 center, int radius, Color color)
-{
-    ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color);
-}
-
-// Draw circle outline within an image
-void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color)
-{
-    int x = 0;
-    int y = radius;
-    int decesionParameter = 3 - 2*radius;
-
-    while (y >= x)
-    {
-        ImageDrawPixel(dst, centerX + x, centerY + y, color);
-        ImageDrawPixel(dst, centerX - x, centerY + y, color);
-        ImageDrawPixel(dst, centerX + x, centerY - y, color);
-        ImageDrawPixel(dst, centerX - x, centerY - y, color);
-        ImageDrawPixel(dst, centerX + y, centerY + x, color);
-        ImageDrawPixel(dst, centerX - y, centerY + x, color);
-        ImageDrawPixel(dst, centerX + y, centerY - x, color);
-        ImageDrawPixel(dst, centerX - y, centerY - x, color);
-        x++;
-
-        if (decesionParameter > 0)
-        {
-            y--;
-            decesionParameter = decesionParameter + 4*(x - y) + 10;
-        }
-        else decesionParameter = decesionParameter + 4*x + 6;
-    }
-}
-
-// Draw circle outline within an image (Vector version)
-void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color)
-{
-    ImageDrawCircleLines(dst, (int)center.x, (int)center.y, radius, color);
-}
-
-// Draw rectangle within an image
-void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color)
-{
-    ImageDrawRectangleRec(dst, (Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color);
-}
-
-// Draw rectangle within an image (Vector version)
-void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color)
-{
-    ImageDrawRectangle(dst, (int)position.x, (int)position.y, (int)size.x, (int)size.y, color);
-}
-
-// Draw rectangle within an image
-void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
-{
-    // Security check to avoid program crash
-    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
-
-    // Security check to avoid drawing out of bounds in case of bad user data
-    if (rec.x < 0) { rec.width += rec.x; rec.x = 0; }
-    if (rec.y < 0) { rec.height += rec.y; rec.y = 0; }
-    if (rec.width < 0) rec.width = 0;
-    if (rec.height < 0) rec.height = 0;
-
-    // Clamp the size the the image bounds
-    if ((rec.x + rec.width) >= dst->width) rec.width = dst->width - rec.x;
-    if ((rec.y + rec.height) >= dst->height) rec.height = dst->height - rec.y;
-
-    // Check if the rect is even inside the image
-    if ((rec.x >= dst->width) || (rec.y >= dst->height)) return;
-    if (((rec.x + rec.width) <= 0) || (rec.y + rec.height <= 0)) return;
-
-    int sy = (int)rec.y;
-    int sx = (int)rec.x;
-
-    int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
-
-    // Fill in the first pixel of the first row based on image format
-    ImageDrawPixel(dst, sx, sy, color);
-
-    int bytesOffset = ((sy*dst->width) + sx)*bytesPerPixel;
-    unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
-
-    // Repeat the first pixel data throughout the row
-    for (int x = 1; x < (int)rec.width; x *= 2)
-    {
-        int pixelsToCopy = MIN(x, (int)rec.width - x);
-        memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
-    }
-
-    // Repeat the first row data for all other rows
-    int bytesPerRow = bytesPerPixel*(int)rec.width;
-    for (int y = 1; y < (int)rec.height; y++)
-    {
-        memcpy(pSrcPixel + (y*dst->width)*bytesPerPixel, pSrcPixel, bytesPerRow);
-    }
-}
-
-// Draw rectangle lines within an image
-void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
-{
-    ImageDrawRectangle(dst, (int)rec.x, (int)rec.y, (int)rec.width, thick, color);
-    ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
-    ImageDrawRectangle(dst, (int)(rec.x + rec.width - thick), (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
-    ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color);
-}
-
-// Draw triangle within an image
-void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color)
-{
-    // Calculate the 2D bounding box of the triangle
-    // Determine the minimum and maximum x and y coordinates of the triangle vertices
-    int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x));
-    int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y));
-    int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x));
-    int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y));
-
-    // Clamp the bounding box to the image dimensions
-    if (xMin < 0) xMin = 0;
-    if (yMin < 0) yMin = 0;
-    if (xMax > dst->width) xMax = dst->width;
-    if (yMax > dst->height) yMax = dst->height;
-
-    // Check the order of the vertices to determine if it's a front or back face
-    // NOTE: if signedArea is equal to 0, the face is degenerate
-    float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y);
-    bool isBackFace = (signedArea > 0);
-
-    // Barycentric interpolation setup
-    // Calculate the step increments for the barycentric coordinates
-    int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x);
-    int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x);
-    int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x);
-
-    // If the triangle is a back face, invert the steps
-    if (isBackFace)
-    {
-        w1XStep = -w1XStep, w1YStep = -w1YStep;
-        w2XStep = -w2XStep, w2YStep = -w2YStep;
-        w3XStep = -w3XStep, w3YStep = -w3YStep;
-    }
-
-    // Calculate the initial barycentric coordinates for the top-left point of the bounding box
-    int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y));
-    int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y));
-    int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y));
-
-    // Rasterization loop
-    // Iterate through each pixel in the bounding box
-    for (int y = yMin; y <= yMax; y++)
-    {
-        int w1 = w1Row;
-        int w2 = w2Row;
-        int w3 = w3Row;
-
-        for (int x = xMin; x <= xMax; x++)
-        {
-            // Check if the pixel is inside the triangle using barycentric coordinates
-            // If it is then we can draw the pixel with the given color
-            if ((w1 | w2 | w3) >= 0) ImageDrawPixel(dst, x, y, color);
-
-            // Increment the barycentric coordinates for the next pixel
-            w1 += w1XStep;
-            w2 += w2XStep;
-            w3 += w3XStep;
-        }
-
-        // Move to the next row in the bounding box
-        w1Row += w1YStep;
-        w2Row += w2YStep;
-        w3Row += w3YStep;
-    }
-}
-
-// Draw triangle with interpolated colors within an image
-void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
-{
-    // Calculate the 2D bounding box of the triangle
-    // Determine the minimum and maximum x and y coordinates of the triangle vertices
-    int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x));
-    int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y));
-    int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x));
-    int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y));
-
-    // Clamp the bounding box to the image dimensions
-    if (xMin < 0) xMin = 0;
-    if (yMin < 0) yMin = 0;
-    if (xMax > dst->width) xMax = dst->width;
-    if (yMax > dst->height) yMax = dst->height;
-
-    // Check the order of the vertices to determine if it's a front or back face
-    // NOTE: if signedArea is equal to 0, the face is degenerate
-    float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y);
-    bool isBackFace = (signedArea > 0);
-
-    // Barycentric interpolation setup
-    // Calculate the step increments for the barycentric coordinates
-    int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x);
-    int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x);
-    int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x);
-
-    // If the triangle is a back face, invert the steps
-    if (isBackFace)
-    {
-        w1XStep = -w1XStep, w1YStep = -w1YStep;
-        w2XStep = -w2XStep, w2YStep = -w2YStep;
-        w3XStep = -w3XStep, w3YStep = -w3YStep;
-    }
-
-    // Calculate the initial barycentric coordinates for the top-left point of the bounding box
-    int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y));
-    int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y));
-    int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y));
-
-    // Calculate the inverse of the sum of the barycentric coordinates for normalization
-    // NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
-    //         calculations in the loop. This is acceptable because we are only interpolating colors
-    // NOTE 2: This sum remains constant throughout the triangle
-    float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
-
-    // Rasterization loop
-    // Iterate through each pixel in the bounding box
-    for (int y = yMin; y <= yMax; y++)
-    {
-        int w1 = w1Row;
-        int w2 = w2Row;
-        int w3 = w3Row;
-
-        for (int x = xMin; x <= xMax; x++)
-        {
-            // Check if the pixel is inside the triangle using barycentric coordinates
-            if ((w1 | w2 | w3) >= 0)
-            {
-                // Compute the normalized barycentric coordinates
-                unsigned char aW1 = (unsigned char)((float)w1*wInvSum);
-                unsigned char aW2 = (unsigned char)((float)w2*wInvSum);
-                unsigned char aW3 = (unsigned char)((float)w3*wInvSum);
-
-                // Interpolate the color using the barycentric coordinates
-                Color finalColor = { 0 };
-                finalColor.r = (c1.r*aW1 + c2.r*aW2 + c3.r*aW3)/255;
-                finalColor.g = (c1.g*aW1 + c2.g*aW2 + c3.g*aW3)/255;
-                finalColor.b = (c1.b*aW1 + c2.b*aW2 + c3.b*aW3)/255;
-                finalColor.a = (c1.a*aW1 + c2.a*aW2 + c3.a*aW3)/255;
-
-                // Draw the pixel with the interpolated color
-                ImageDrawPixel(dst, x, y, finalColor);
-            }
-
-            // Increment the barycentric coordinates for the next pixel
-            w1 += w1XStep;
-            w2 += w2XStep;
-            w3 += w3XStep;
-        }
-
-        // Move to the next row in the bounding box
-        w1Row += w1YStep;
-        w2Row += w2YStep;
-        w3Row += w3YStep;
-    }
-}
-
-// Draw triangle outline within an image
-void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color)
-{
-    ImageDrawLine(dst, (int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, color);
-    ImageDrawLine(dst, (int)v2.x, (int)v2.y, (int)v3.x, (int)v3.y, color);
-    ImageDrawLine(dst, (int)v3.x, (int)v3.y, (int)v1.x, (int)v1.y, color);
-}
-
-// Draw a triangle fan defined by points within an image (first vertex is the center)
-void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
-{
-    if (pointCount >= 3)
-    {
-        for (int i = 1; i < pointCount - 1; i++)
-        {
-            ImageDrawTriangle(dst, points[0], points[i], points[i + 1], color);
-        }
-    }
-}
-
-// Draw a triangle strip defined by points within an image
-void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
-{
-    if (pointCount >= 3)
-    {
-        for (int i = 2; i < pointCount; i++)
-        {
-            if ((i%2) == 0) ImageDrawTriangle(dst, points[i], points[i - 2], points[i - 1], color);
-            else ImageDrawTriangle(dst, points[i], points[i - 1], points[i - 2], color);
-        }
-    }
-}
-
-// Draw an image (source) within an image (destination)
-// NOTE: Color tint is applied to source image
-void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint)
-{
-    // Security check to avoid program crash
-    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) ||
-        (src.data == NULL) || (src.width == 0) || (src.height == 0)) return;
-
-    if (dst->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image drawing not supported for compressed formats");
-    else
-    {
-        Image srcMod = { 0 };       // Source copy (in case it was required)
-        Image *srcPtr = &src;       // Pointer to source image
-        bool useSrcMod = false;     // Track source copy required
-
-        // Source rectangle out-of-bounds security checks
-        if (srcRec.x < 0) { srcRec.width += srcRec.x; srcRec.x = 0; }
-        if (srcRec.y < 0) { srcRec.height += srcRec.y; srcRec.y = 0; }
-        if ((srcRec.x + srcRec.width) > src.width) srcRec.width = src.width - srcRec.x;
-        if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y;
-
-        // Check if source rectangle needs to be resized to destination rectangle
-        // In that case, we make a copy of source, and we apply all required transform
-        if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height))
-        {
-            srcMod = ImageFromImage(src, srcRec);   // Create image from another image
-            ImageResize(&srcMod, (int)dstRec.width, (int)dstRec.height);   // Resize to destination rectangle
-            srcRec = (Rectangle){ 0, 0, (float)srcMod.width, (float)srcMod.height };
-
-            srcPtr = &srcMod;
-            useSrcMod = true;
-        }
-
-        // Destination rectangle out-of-bounds security checks
-        if (dstRec.x < 0)
-        {
-            srcRec.x -= dstRec.x;
-            srcRec.width += dstRec.x;
-            dstRec.x = 0;
-        }
-        else if ((dstRec.x + srcRec.width) > dst->width) srcRec.width = dst->width - dstRec.x;
-
-        if (dstRec.y < 0)
-        {
-            srcRec.y -= dstRec.y;
-            srcRec.height += dstRec.y;
-            dstRec.y = 0;
-        }
-        else if ((dstRec.y + srcRec.height) > dst->height) srcRec.height = dst->height - dstRec.y;
-
-        if (dst->width < srcRec.width) srcRec.width = (float)dst->width;
-        if (dst->height < srcRec.height) srcRec.height = (float)dst->height;
-
-        // This blitting method is quite fast! The process followed is:
-        // for every pixel -> [get_src_format/get_dst_format -> blend -> format_to_dst]
-        // Some optimization ideas:
-        //    [x] Avoid creating source copy if not required (no resize required)
-        //    [x] Optimize ImageResize() for pixel format (alternative: ImageResizeNN())
-        //    [x] Optimize ColorAlphaBlend() to avoid processing (alpha = 0) and (alpha = 1)
-        //    [x] Optimize ColorAlphaBlend() for faster operations (maybe avoiding divs?)
-        //    [x] Consider fast path: no alpha blending required cases (src has no alpha)
-        //    [x] Consider fast path: same src/dst format with no alpha -> direct line copy
-        //    [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
-        //    [ ] TODO: Support 16bit and 32bit (float) channels drawing
-
-        Color colSrc = { 0 };
-        Color colDst = { 0 };
-        Color blend = { 0 };
-        bool blendRequired = true;
-
-        // Fast path: Avoid blend if source has no alpha to blend
-        if ((tint.a == 255) &&
-            ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16) ||
-            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16G16B16)))
-            blendRequired = false;
-
-        int strideDst = GetPixelDataSize(dst->width, 1, dst->format);
-        int bytesPerPixelDst = strideDst/(dst->width);
-
-        int strideSrc = GetPixelDataSize(srcPtr->width, 1, srcPtr->format);
-        int bytesPerPixelSrc = strideSrc/(srcPtr->width);
-
-        unsigned char *pSrcBase = (unsigned char *)srcPtr->data + ((int)srcRec.y*srcPtr->width + (int)srcRec.x)*bytesPerPixelSrc;
-        unsigned char *pDstBase = (unsigned char *)dst->data + ((int)dstRec.y*dst->width + (int)dstRec.x)*bytesPerPixelDst;
-
-        for (int y = 0; y < (int)srcRec.height; y++)
-        {
-            unsigned char *pSrc = pSrcBase;
-            unsigned char *pDst = pDstBase;
-
-            // Fast path: Avoid moving pixel by pixel if no blend required and same format
-            if (!blendRequired && (srcPtr->format == dst->format)) memcpy(pDst, pSrc, (int)(srcRec.width)*bytesPerPixelSrc);
-            else
-            {
-                for (int x = 0; x < (int)srcRec.width; x++)
-                {
-                    colSrc = GetPixelColor(pSrc, srcPtr->format);
-                    colDst = GetPixelColor(pDst, dst->format);
-
-                    // Fast path: Avoid blend if source has no alpha to blend
-                    if (blendRequired) blend = ColorAlphaBlend(colDst, colSrc, tint);
-                    else blend = colSrc;
-
-                    SetPixelColor(pDst, blend, dst->format);
-
-                    pDst += bytesPerPixelDst;
-                    pSrc += bytesPerPixelSrc;
-                }
-            }
-
-            pSrcBase += strideSrc;
-            pDstBase += strideDst;
-        }
-
-        if (useSrcMod) UnloadImage(srcMod);     // Unload source modified image
-
-        if ((dst->mipmaps > 1) && (src.mipmaps > 1))
-        {
-            Image mipmapDst = *dst;
-            mipmapDst.data = (char *)mipmapDst.data + GetPixelDataSize(mipmapDst.width, mipmapDst.height, mipmapDst.format);
-            mipmapDst.width /= 2;
-            mipmapDst.height /= 2;
-            mipmapDst.mipmaps--;
-
-            Image mipmapSrc = src;
-            mipmapSrc.data = (char *)mipmapSrc.data + GetPixelDataSize(mipmapSrc.width, mipmapSrc.height, mipmapSrc.format);
-            mipmapSrc.width /= 2;
-            mipmapSrc.height /= 2;
-            mipmapSrc.mipmaps--;
-
-            Rectangle mipmapSrcRec = srcRec;
-            mipmapSrcRec.width /= 2;
-            mipmapSrcRec.height /= 2;
-            mipmapSrcRec.x /= 2;
-            mipmapSrcRec.y /= 2;
-
-            Rectangle mipmapDstRec = dstRec;
-            mipmapDstRec.width /= 2;
-            mipmapDstRec.height /= 2;
-            mipmapDstRec.x /= 2;
-            mipmapDstRec.y /= 2;
-
-            ImageDraw(&mipmapDst, mipmapSrc, mipmapSrcRec, mipmapDstRec, tint);
-        }
-    }
-}
-
-// Draw text (default font) within an image (destination)
-void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
-{
-#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
-    // Make sure default font is loaded to be used on image text drawing
-    if (GetFontDefault().texture.id == 0) LoadFontDefault();
-
-    Vector2 position = { (float)posX, (float)posY };
-    ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, 1.0f, color);   // WARNING: Module required: rtext
-#else
-    TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext");
-#endif
-}
-
-// Draw text (custom sprite font) within an image (destination)
-void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
-{
-    Image imText = ImageTextEx(font, text, fontSize, spacing, tint);
-
-    Rectangle srcRec = { 0.0f, 0.0f, (float)imText.width, (float)imText.height };
-    Rectangle dstRec = { position.x, position.y, (float)imText.width, (float)imText.height };
-
-    ImageDraw(dst, imText, srcRec, dstRec, WHITE);
-
-    UnloadImage(imText);
-}
-
-//------------------------------------------------------------------------------------
-// Texture loading functions
-//------------------------------------------------------------------------------------
-// Load texture from file into GPU memory (VRAM)
-Texture2D LoadTexture(const char *fileName)
-{
-    Texture2D texture = { 0 };
-
-    Image image = LoadImage(fileName);
-
-    if (image.data != NULL)
-    {
-        texture = LoadTextureFromImage(image);
-        UnloadImage(image);
-    }
-
-    return texture;
-}
-
-// Load a texture from image data
-// NOTE: image is not unloaded, it must be done manually
-Texture2D LoadTextureFromImage(Image image)
-{
-    Texture2D texture = { 0 };
-
-    if ((image.width != 0) && (image.height != 0))
-    {
-        texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
-    }
-    else TRACELOG(LOG_WARNING, "IMAGE: Data is not valid to load texture");
-
-    texture.width = image.width;
-    texture.height = image.height;
-    texture.mipmaps = image.mipmaps;
-    texture.format = image.format;
-
-    return texture;
-}
-
-// Load cubemap from image, multiple image cubemap layouts supported
-TextureCubemap LoadTextureCubemap(Image image, int layout)
-{
-    TextureCubemap cubemap = { 0 };
-
-    if (layout == CUBEMAP_LAYOUT_AUTO_DETECT)      // Try to automatically guess layout type
-    {
-        // Check image width/height to determine the type of cubemap provided
-        if (image.width > image.height)
-        {
-            if ((image.width/6) == image.height) { layout = CUBEMAP_LAYOUT_LINE_HORIZONTAL; cubemap.width = image.width/6; }
-            else if ((image.width/4) == (image.height/3)) { layout = CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
-        }
-        else if (image.height > image.width)
-        {
-            if ((image.height/6) == image.width) { layout = CUBEMAP_LAYOUT_LINE_VERTICAL; cubemap.width = image.height/6; }
-            else if ((image.width/3) == (image.height/4)) { layout = CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
-        }
-    }
-    else
-    {
-        if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL) cubemap.width = image.height/6;
-        if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) cubemap.width = image.width/6;
-        if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR) cubemap.width = image.width/3;
-        if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE) cubemap.width = image.width/4;
-    }
-
-    cubemap.height = cubemap.width;
-
-    // Layout provided or already auto-detected
-    if (layout != CUBEMAP_LAYOUT_AUTO_DETECT)
-    {
-        int size = cubemap.width;
-
-        Image faces = { 0 };                // Vertical column image
-        Rectangle faceRecs[6] = { 0 };      // Face source rectangles
-
-        for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, (float)size, (float)size };
-
-        if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
-        {
-            faces = ImageCopy(image);       // Image data already follows expected convention
-        }
-        /*else if (layout == CUBEMAP_LAYOUT_PANORAMA)
-        {
-            // TODO: Implement panorama by converting image to square faces...
-            // REF: https://github.com/denivip/panorama/blob/master/panorama.cpp
-        } */
-        else
-        {
-            if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = (float)size*i;
-            else if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR)
-            {
-                faceRecs[0].x = (float)size; faceRecs[0].y = (float)size;
-                faceRecs[1].x = (float)size; faceRecs[1].y = (float)size*3;
-                faceRecs[2].x = (float)size; faceRecs[2].y = 0;
-                faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
-                faceRecs[4].x = 0; faceRecs[4].y = (float)size;
-                faceRecs[5].x = (float)size*2; faceRecs[5].y = (float)size;
-            }
-            else if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE)
-            {
-                faceRecs[0].x = (float)size*2; faceRecs[0].y = (float)size;
-                faceRecs[1].x = 0; faceRecs[1].y = (float)size;
-                faceRecs[2].x = (float)size; faceRecs[2].y = 0;
-                faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
-                faceRecs[4].x = (float)size; faceRecs[4].y = (float)size;
-                faceRecs[5].x = (float)size*3; faceRecs[5].y = (float)size;
-            }
-
-            // Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
-            // NOTE: Image formatting does not work with compressed textures
-            faces = GenImageColor(size, size*6, MAGENTA);
-            ImageFormat(&faces, image.format);
-
-            Image mipmapped = ImageCopy(image);
-        #if defined(SUPPORT_IMAGE_MANIPULATION)
-            if (image.mipmaps > 1)
-            {
-                ImageMipmaps(&mipmapped);
-                ImageMipmaps(&faces);
-            }
-        #endif
-
-            for (int i = 0; i < 6; i++) ImageDraw(&faces, mipmapped, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
-
-            UnloadImage(mipmapped);
-        }
-
-        // NOTE: Cubemap data is expected to be provided as 6 images in a single data array,
-        // one after the other (that's a vertical image), following convention: +X, -X, +Y, -Y, +Z, -Z
-        cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format, faces.mipmaps);
-
-        if (cubemap.id != 0)
-        {
-            cubemap.format = faces.format;
-            cubemap.mipmaps = faces.mipmaps;
-        }
-        else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
-
-        UnloadImage(faces);
-    }
-    else TRACELOG(LOG_WARNING, "IMAGE: Failed to detect cubemap image layout");
-
-    return cubemap;
-}
-
-// Load texture for rendering (framebuffer)
-// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
-RenderTexture2D LoadRenderTexture(int width, int height)
-{
-    RenderTexture2D target = { 0 };
-
-    target.id = rlLoadFramebuffer(); // Load an empty framebuffer
-
-    if (target.id > 0)
-    {
-        rlEnableFramebuffer(target.id);
-
-        // Create color texture (default to RGBA)
-        target.texture.id = rlLoadTexture(NULL, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
-        target.texture.width = width;
-        target.texture.height = height;
-        target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
-        target.texture.mipmaps = 1;
-
-        // Create depth renderbuffer/texture
-        target.depth.id = rlLoadTextureDepth(width, height, true);
-        target.depth.width = width;
-        target.depth.height = height;
-        target.depth.format = 19;       //DEPTH_COMPONENT_24BIT?
-        target.depth.mipmaps = 1;
-
-        // Attach color texture and depth renderbuffer/texture to FBO
-        rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
-        rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
-
-        // Check if fbo is complete with attachments (valid)
-        if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
-
-        rlDisableFramebuffer();
-    }
-    else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
-
-    return target;
-}
-
-// Check if a texture is valid (loaded in GPU)
-bool IsTextureValid(Texture2D texture)
-{
-    bool result = false;
-
-    if ((texture.id > 0) &&         // Validate OpenGL id (texture uplaoded to GPU)
-        (texture.width > 0) &&      // Validate texture width
-        (texture.height > 0) &&     // Validate texture height
-        (texture.format > 0) &&     // Validate texture pixel format
-        (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level)
-
-    return result;
-}
-
-// Unload texture from GPU memory (VRAM)
-void UnloadTexture(Texture2D texture)
-{
-    if (texture.id > 0)
-    {
-        rlUnloadTexture(texture.id);
-
-        TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded texture data from VRAM (GPU)", texture.id);
-    }
-}
-
-// Check if a render texture is valid (loaded in GPU)
-bool IsRenderTextureValid(RenderTexture2D target)
-{
-    bool result = false;
-
-    if ((target.id > 0) &&                  // Validate OpenGL id (loaded on GPU)
-        IsTextureValid(target.depth) &&     // Validate FBO depth texture/renderbuffer attachment
-        IsTextureValid(target.texture)) result = true; // Validate FBO texture attachment
-
-    return result;
-}
-
-// Unload render texture from GPU memory (VRAM)
-void UnloadRenderTexture(RenderTexture2D target)
-{
-    if (target.id > 0)
-    {
-        if (target.texture.id > 0)
-        {
-            // Color texture attached to FBO is deleted
-            rlUnloadTexture(target.texture.id);
-        }
-
-        // NOTE: Depth texture/renderbuffer is automatically
-        // queried and deleted before deleting framebuffer
-        rlUnloadFramebuffer(target.id);
-    }
-}
-
-// Update GPU texture with new data
-// NOTE 1: pixels data must match texture.format
-// NOTE 2: pixels data must contain at least as many pixels as texture
-void UpdateTexture(Texture2D texture, const void *pixels)
-{
-    rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
-}
-
-// Update GPU texture rectangle with new data
-// NOTE 1: pixels data must match texture.format
-// NOTE 2: pixels data must contain as many pixels as rec contains
-// NOTE 3: rec must fit completely within texture's width and height
-void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
-{
-    rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
-}
-
-//------------------------------------------------------------------------------------
-// Texture configuration functions
-//------------------------------------------------------------------------------------
-// Generate GPU mipmaps for a texture
-void GenTextureMipmaps(Texture2D *texture)
-{
-    // NOTE: NPOT textures support check inside function
-    // On WebGL (OpenGL ES 2.0) NPOT textures support is limited
-    rlGenTextureMipmaps(texture->id, texture->width, texture->height, texture->format, &texture->mipmaps);
-}
-
-// Set texture scaling filter mode
-void SetTextureFilter(Texture2D texture, int filter)
-{
-    switch (filter)
-    {
-        case TEXTURE_FILTER_POINT:
-        {
-            if (texture.mipmaps > 1)
-            {
-                // RL_TEXTURE_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_NEAREST);
-
-                // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
-            }
-            else
-            {
-                // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_NEAREST);
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
-            }
-        } break;
-        case TEXTURE_FILTER_BILINEAR:
-        {
-            if (texture.mipmaps > 1)
-            {
-                // RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
-                // Alternative: RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST);
-
-                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
-            }
-            else
-            {
-                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
-            }
-        } break;
-        case TEXTURE_FILTER_TRILINEAR:
-        {
-            if (texture.mipmaps > 1)
-            {
-                // RL_TEXTURE_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR);
-
-                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
-            }
-            else
-            {
-                TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
-
-                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
-                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
-                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
-            }
-        } break;
-        case TEXTURE_FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 4); break;
-        case TEXTURE_FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 8); break;
-        case TEXTURE_FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 16); break;
-        default: break;
-    }
-}
-
-// Set texture wrapping mode
-void SetTextureWrap(Texture2D texture, int wrap)
-{
-    switch (wrap)
-    {
-        case TEXTURE_WRAP_REPEAT:
-        {
-            // NOTE: It only works if NPOT textures are supported, i.e. OpenGL ES 2.0 could not support it
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT);
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT);
-        } break;
-        case TEXTURE_WRAP_CLAMP:
-        {
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_CLAMP);
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_CLAMP);
-        } break;
-        case TEXTURE_WRAP_MIRROR_REPEAT:
-        {
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_REPEAT);
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_REPEAT);
-        } break;
-        case TEXTURE_WRAP_MIRROR_CLAMP:
-        {
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_CLAMP);
-            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_CLAMP);
-        } break;
-        default: break;
-    }
-}
-
-//------------------------------------------------------------------------------------
-// Texture drawing functions
-//------------------------------------------------------------------------------------
-// Draw a texture
-void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
-{
-    DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY }, 0.0f, 1.0f, tint);
-}
-
-// Draw a texture with position defined as Vector2
-void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
-{
-    DrawTextureEx(texture, position, 0, 1.0f, tint);
-}
-
-// Draw a texture with extended parameters
-void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
-{
-    Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
-    Rectangle dest = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale };
-    Vector2 origin = { 0.0f, 0.0f };
-
-    DrawTexturePro(texture, source, dest, origin, rotation, tint);
-}
-
-// Draw a part of a texture (defined by a rectangle)
-void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint)
-{
-    Rectangle dest = { position.x, position.y, fabsf(source.width), fabsf(source.height) };
-    Vector2 origin = { 0.0f, 0.0f };
-
-    DrawTexturePro(texture, source, dest, origin, 0.0f, tint);
-}
-
-// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
-// NOTE: origin is relative to destination rectangle size
-void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint)
-{
-    // Check if texture is valid
-    if (texture.id > 0)
-    {
-        float width = (float)texture.width;
-        float height = (float)texture.height;
-
-        bool flipX = false;
-
-        if (source.width < 0) { flipX = true; source.width *= -1; }
-        if (source.height < 0) source.y -= source.height;
-
-        if (dest.width < 0) dest.width *= -1;
-        if (dest.height < 0) dest.height *= -1;
-
-        Vector2 topLeft = { 0 };
-        Vector2 topRight = { 0 };
-        Vector2 bottomLeft = { 0 };
-        Vector2 bottomRight = { 0 };
-
-        // Only calculate rotation if needed
-        if (rotation == 0.0f)
-        {
-            float x = dest.x - origin.x;
-            float y = dest.y - origin.y;
-            topLeft = (Vector2){ x, y };
-            topRight = (Vector2){ x + dest.width, y };
-            bottomLeft = (Vector2){ x, y + dest.height };
-            bottomRight = (Vector2){ x + dest.width, y + dest.height };
-        }
-        else
-        {
-            float sinRotation = sinf(rotation*DEG2RAD);
-            float cosRotation = cosf(rotation*DEG2RAD);
-            float x = dest.x;
-            float y = dest.y;
-            float dx = -origin.x;
-            float dy = -origin.y;
-
-            topLeft.x = x + dx*cosRotation - dy*sinRotation;
-            topLeft.y = y + dx*sinRotation + dy*cosRotation;
-
-            topRight.x = x + (dx + dest.width)*cosRotation - dy*sinRotation;
-            topRight.y = y + (dx + dest.width)*sinRotation + dy*cosRotation;
-
-            bottomLeft.x = x + dx*cosRotation - (dy + dest.height)*sinRotation;
-            bottomLeft.y = y + dx*sinRotation + (dy + dest.height)*cosRotation;
-
-            bottomRight.x = x + (dx + dest.width)*cosRotation - (dy + dest.height)*sinRotation;
-            bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation;
-        }
-
-        rlSetTexture(texture.id);
-        rlBegin(RL_QUADS);
-
-            rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-            rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
-
-            // Top-left corner for texture and quad
-            if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
-            else rlTexCoord2f(source.x/width, source.y/height);
-            rlVertex2f(topLeft.x, topLeft.y);
-
-            // Bottom-left corner for texture and quad
-            if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
-            else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
-            rlVertex2f(bottomLeft.x, bottomLeft.y);
-
-            // Bottom-right corner for texture and quad
-            if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
-            else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
-            rlVertex2f(bottomRight.x, bottomRight.y);
-
-            // Top-right corner for texture and quad
-            if (flipX) rlTexCoord2f(source.x/width, source.y/height);
-            else rlTexCoord2f((source.x + source.width)/width, source.y/height);
-            rlVertex2f(topRight.x, topRight.y);
-
-        rlEnd();
-        rlSetTexture(0);
-
-        // NOTE: Vertex position can be transformed using matrices
-        // but the process is way more costly than just calculating
-        // the vertex positions manually, like done above
-        // Old implementation is left here for educational purposes,
-        // just in case someone wants to do some performance test
-        /*
-        rlSetTexture(texture.id);
-        rlPushMatrix();
-            rlTranslatef(dest.x, dest.y, 0.0f);
-            if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
-            rlTranslatef(-origin.x, -origin.y, 0.0f);
-
-            rlBegin(RL_QUADS);
-                rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-                rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
-
-                // Bottom-left corner for texture and quad
-                if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height);
-                else rlTexCoord2f(source.x/width, source.y/height);
-                rlVertex2f(0.0f, 0.0f);
-
-                // Bottom-right corner for texture and quad
-                if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
-                else rlTexCoord2f(source.x/width, (source.y + source.height)/height);
-                rlVertex2f(0.0f, dest.height);
-
-                // Top-right corner for texture and quad
-                if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height);
-                else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height);
-                rlVertex2f(dest.width, dest.height);
-
-                // Top-left corner for texture and quad
-                if (flipX) rlTexCoord2f(source.x/width, source.y/height);
-                else rlTexCoord2f((source.x + source.width)/width, source.y/height);
-                rlVertex2f(dest.width, 0.0f);
-            rlEnd();
-        rlPopMatrix();
-        rlSetTexture(0);
-        */
-    }
-}
-
-// Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info
-void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint)
-{
-    if (texture.id > 0)
-    {
-        float width = (float)texture.width;
-        float height = (float)texture.height;
-
-        float patchWidth = ((int)dest.width <= 0)? 0.0f : dest.width;
-        float patchHeight = ((int)dest.height <= 0)? 0.0f : dest.height;
-
-        if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width;
-        if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height;
-        if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL) patchHeight = nPatchInfo.source.height;
-        if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL) patchWidth = nPatchInfo.source.width;
-
-        bool drawCenter = true;
-        bool drawMiddle = true;
-        float leftBorder = (float)nPatchInfo.left;
-        float topBorder = (float)nPatchInfo.top;
-        float rightBorder = (float)nPatchInfo.right;
-        float bottomBorder = (float)nPatchInfo.bottom;
-
-        // Adjust the lateral (left and right) border widths in case patchWidth < texture.width
-        if (patchWidth <= (leftBorder + rightBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_VERTICAL)
-        {
-            drawCenter = false;
-            leftBorder = (leftBorder/(leftBorder + rightBorder))*patchWidth;
-            rightBorder = patchWidth - leftBorder;
-        }
-
-        // Adjust the lateral (top and bottom) border heights in case patchHeight < texture.height
-        if (patchHeight <= (topBorder + bottomBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_HORIZONTAL)
-        {
-            drawMiddle = false;
-            topBorder = (topBorder/(topBorder + bottomBorder))*patchHeight;
-            bottomBorder = patchHeight - topBorder;
-        }
-
-        Vector2 vertA = { 0 };
-        Vector2 vertB = { 0 };
-        Vector2 vertC = { 0 };
-        Vector2 vertD = { 0 };
-        vertA.x = 0.0f;                             // Outer left
-        vertA.y = 0.0f;                             // Outer top
-        vertB.x = leftBorder;                       // Inner left
-        vertB.y = topBorder;                        // Inner top
-        vertC.x = patchWidth  - rightBorder;        // Inner right
-        vertC.y = patchHeight - bottomBorder;       // Inner bottom
-        vertD.x = patchWidth;                       // Outer right
-        vertD.y = patchHeight;                      // Outer bottom
-
-        Vector2 coordA = { 0 };
-        Vector2 coordB = { 0 };
-        Vector2 coordC = { 0 };
-        Vector2 coordD = { 0 };
-        coordA.x = nPatchInfo.source.x/width;
-        coordA.y = nPatchInfo.source.y/height;
-        coordB.x = (nPatchInfo.source.x + leftBorder)/width;
-        coordB.y = (nPatchInfo.source.y + topBorder)/height;
-        coordC.x = (nPatchInfo.source.x + nPatchInfo.source.width  - rightBorder)/width;
-        coordC.y = (nPatchInfo.source.y + nPatchInfo.source.height - bottomBorder)/height;
-        coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width;
-        coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height;
-
-        rlSetTexture(texture.id);
-
-        rlPushMatrix();
-            rlTranslatef(dest.x, dest.y, 0.0f);
-            rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
-            rlTranslatef(-origin.x, -origin.y, 0.0f);
-
-            rlBegin(RL_QUADS);
-                rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-                rlNormal3f(0.0f, 0.0f, 1.0f);               // Normal vector pointing towards viewer
-
-                if (nPatchInfo.layout == NPATCH_NINE_PATCH)
-                {
-                    // ------------------------------------------------------------
-                    // TOP-LEFT QUAD
-                    rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
-                    if (drawCenter)
-                    {
-                        // TOP-CENTER QUAD
-                        rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
-                    }
-                    // TOP-RIGHT QUAD
-                    rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
-                    if (drawMiddle)
-                    {
-                        // ------------------------------------------------------------
-                        // MIDDLE-LEFT QUAD
-                        rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
-                        if (drawCenter)
-                        {
-                            // MIDDLE-CENTER QUAD
-                            rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-left corner for texture and quad
-                            rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-right corner for texture and quad
-                            rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-right corner for texture and quad
-                            rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-left corner for texture and quad
-                        }
-
-                        // MIDDLE-RIGHT QUAD
-                        rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-left corner for texture and quad
-                    }
-
-                    // ------------------------------------------------------------
-                    // BOTTOM-LEFT QUAD
-                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
-                    if (drawCenter)
-                    {
-                        // BOTTOM-CENTER QUAD
-                        rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-left corner for texture and quad
-                    }
-
-                    // BOTTOM-RIGHT QUAD
-                    rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-left corner for texture and quad
-                }
-                else if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL)
-                {
-                    // TOP QUAD
-                    // -----------------------------------------------------------
-                    // Texture coords                 Vertices
-                    rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
-                    if (drawCenter)
-                    {
-                        // MIDDLE QUAD
-                        // -----------------------------------------------------------
-                        // Texture coords                 Vertices
-                        rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
-                    }
-                    // BOTTOM QUAD
-                    // -----------------------------------------------------------
-                    // Texture coords                 Vertices
-                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
-                }
-                else if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL)
-                {
-                    // LEFT QUAD
-                    // -----------------------------------------------------------
-                    // Texture coords                 Vertices
-                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
-                    if (drawCenter)
-                    {
-                        // CENTER QUAD
-                        // -----------------------------------------------------------
-                        // Texture coords                 Vertices
-                        rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
-                        rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
-                        rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
-                    }
-                    // RIGHT QUAD
-                    // -----------------------------------------------------------
-                    // Texture coords                 Vertices
-                    rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
-                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
-                    rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
-                }
-            rlEnd();
-        rlPopMatrix();
-
-        rlSetTexture(0);
-    }
-}
-
-// Check if two colors are equal
-bool ColorIsEqual(Color col1, Color col2)
-{
-    bool result = false;
-
-    if ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) result = true;
-
-    return result;
-}
-
-// Get color with alpha applied, alpha goes from 0.0f to 1.0f
-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;
-}
-
-// Get hexadecimal value for a Color
-int ColorToInt(Color color)
-{
-    int result = 0;
-
-    result = (int)(((unsigned int)color.r << 24) |
-                   ((unsigned int)color.g << 16) |
-                   ((unsigned int)color.b << 8) |
-                    (unsigned int)color.a);
-
-    return result;
-}
-
-// Get color normalized as float [0..1]
-Vector4 ColorNormalize(Color color)
-{
-    Vector4 result;
-
-    result.x = (float)color.r/255.0f;
-    result.y = (float)color.g/255.0f;
-    result.z = (float)color.b/255.0f;
-    result.w = (float)color.a/255.0f;
-
-    return result;
-}
-
-// Get color from normalized values [0..1]
-Color ColorFromNormalized(Vector4 normalized)
-{
-    Color result;
-
-    result.r = (unsigned char)(normalized.x*255.0f);
-    result.g = (unsigned char)(normalized.y*255.0f);
-    result.b = (unsigned char)(normalized.z*255.0f);
-    result.a = (unsigned char)(normalized.w*255.0f);
-
-    return result;
-}
-
-// Get HSV values for a Color
-// NOTE: Hue is returned as degrees [0..360]
-Vector3 ColorToHSV(Color color)
-{
-    Vector3 hsv = { 0 };
-    Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-    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 = NAN;        // Undefined
-        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;
-}
-
-// Get a Color from HSV values
-// Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion
-// NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors
-// Hue is provided in degrees: [0..360]
-// Saturation/Value are provided normalized: [0.0f..1.0f]
-Color ColorFromHSV(float hue, float saturation, float value)
-{
-    Color color = { 0, 0, 0, 255 };
-
-    // Red channel
-    float k = fmodf((5.0f + hue/60.0f), 6);
-    float t = 4.0f - k;
-    k = (t < k)? t : k;
-    k = (k < 1)? k : 1;
-    k = (k > 0)? k : 0;
-    color.r = (unsigned char)((value - value*saturation*k)*255.0f);
-
-    // Green channel
-    k = fmodf((3.0f + hue/60.0f), 6);
-    t = 4.0f - k;
-    k = (t < k)? t : k;
-    k = (k < 1)? k : 1;
-    k = (k > 0)? k : 0;
-    color.g = (unsigned char)((value - value*saturation*k)*255.0f);
-
-    // Blue channel
-    k = fmodf((1.0f + hue/60.0f), 6);
-    t = 4.0f - k;
-    k = (t < k)? t : k;
-    k = (k < 1)? k : 1;
-    k = (k > 0)? k : 0;
-    color.b = (unsigned char)((value - value*saturation*k)*255.0f);
-
-    return color;
-}
-
-// Get color multiplied with another color
-Color ColorTint(Color color, Color tint)
-{
-    Color result = color;
-
-    unsigned char r = (unsigned char)(((int)color.r*(int)tint.r)/255);
-    unsigned char g = (unsigned char)(((int)color.g*(int)tint.g)/255);
-    unsigned char b = (unsigned char)(((int)color.b*(int)tint.b)/255);
-    unsigned char a = (unsigned char)(((int)color.a*(int)tint.a)/255);
-
-    result.r = r;
-    result.g = g;
-    result.b = b;
-    result.a = a;
-
-    return result;
-}
-
-// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
-Color ColorBrightness(Color color, float factor)
-{
-    Color result = color;
-
-    if (factor > 1.0f) factor = 1.0f;
-    else if (factor < -1.0f) factor = -1.0f;
-
-    float red = (float)color.r;
-    float green = (float)color.g;
-    float blue = (float)color.b;
-
-    if (factor < 0.0f)
-    {
-        factor = 1.0f + factor;
-        red *= factor;
-        green *= factor;
-        blue *= factor;
-    }
-    else
-    {
-        red = (255 - red)*factor + red;
-        green = (255 - green)*factor + green;
-        blue = (255 - blue)*factor + blue;
-    }
-
-    result.r = (unsigned char)red;
-    result.g = (unsigned char)green;
-    result.b = (unsigned char)blue;
-
-    return result;
-}
-
-// Get color with contrast correction
-// NOTE: Contrast values between -1.0f and 1.0f
-Color ColorContrast(Color color, float contrast)
-{
-    Color result = color;
-
-    if (contrast < -1.0f) contrast = -1.0f;
-    else if (contrast > 1.0f) contrast = 1.0f;
-
-    contrast = (1.0f + contrast);
-    contrast *= contrast;
-
-    float pR = (float)color.r/255.0f;
-    pR -= 0.5f;
-    pR *= contrast;
-    pR += 0.5f;
-    pR *= 255;
-    if (pR < 0) pR = 0;
-    else if (pR > 255) pR = 255;
-
-    float pG = (float)color.g/255.0f;
-    pG -= 0.5f;
-    pG *= contrast;
-    pG += 0.5f;
-    pG *= 255;
-    if (pG < 0) pG = 0;
-    else if (pG > 255) pG = 255;
-
-    float pB = (float)color.b/255.0f;
-    pB -= 0.5f;
-    pB *= contrast;
-    pB += 0.5f;
-    pB *= 255;
-    if (pB < 0) pB = 0;
-    else if (pB > 255) pB = 255;
-
-    result.r = (unsigned char)pR;
-    result.g = (unsigned char)pG;
-    result.b = (unsigned char)pB;
-
-    return result;
-}
-
-// Get color with alpha applied, alpha goes from 0.0f to 1.0f
-Color ColorAlpha(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;
-}
-
-// Get src alpha-blended into dst color with tint
-Color ColorAlphaBlend(Color dst, Color src, Color tint)
-{
-    Color out = WHITE;
-
-    // Apply color tint to source color
-    src.r = (unsigned char)(((unsigned int)src.r*((unsigned int)tint.r+1)) >> 8);
-    src.g = (unsigned char)(((unsigned int)src.g*((unsigned int)tint.g+1)) >> 8);
-    src.b = (unsigned char)(((unsigned int)src.b*((unsigned int)tint.b+1)) >> 8);
-    src.a = (unsigned char)(((unsigned int)src.a*((unsigned int)tint.a+1)) >> 8);
-
-//#define COLORALPHABLEND_FLOAT
-#define COLORALPHABLEND_INTEGERS
-#if defined(COLORALPHABLEND_INTEGERS)
-    if (src.a == 0) out = dst;
-    else if (src.a == 255) out = src;
-    else
-    {
-        unsigned int alpha = (unsigned int)src.a + 1;     // We are shifting by 8 (dividing by 256), so we need to take that excess into account
-        out.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8);
-
-        if (out.a > 0)
-        {
-            out.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
-            out.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
-            out.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8);
-        }
-    }
-#endif
-#if defined(COLORALPHABLEND_FLOAT)
-    if (src.a == 0) out = dst;
-    else if (src.a == 255) out = src;
-    else
-    {
-        Vector4 fdst = ColorNormalize(dst);
-        Vector4 fsrc = ColorNormalize(src);
-        Vector4 ftint = ColorNormalize(tint);
-        Vector4 fout = { 0 };
-
-        fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w);
-
-        if (fout.w > 0.0f)
-        {
-            fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w;
-            fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w;
-            fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
-        }
-
-        out = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) };
-    }
-#endif
-
-    return out;
-}
-
-// Get color lerp interpolation between two colors, factor [0.0f..1.0f]
-Color ColorLerp(Color color1, Color color2, float factor)
-{
-    Color color = { 0 };
-
-    if (factor < 0.0f) factor = 0.0f;
-    else if (factor > 1.0f) factor = 1.0f;
-
-    color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r);
-    color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g);
-    color.b = (unsigned char)((1.0f - factor)*color1.b + factor*color2.b);
-    color.a = (unsigned char)((1.0f - factor)*color1.a + factor*color2.a);
-
-    return color;
-}
-
-// Get a Color struct from hexadecimal value
-Color GetColor(unsigned 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 from a pixel from certain format
-Color GetPixelColor(void *srcPtr, int format)
-{
-    Color color = { 0 };
-
-    switch (format)
-    {
-        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], 255 }; break;
-        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1] }; break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        {
-            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
-            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 5) & 0b0000000000111111)*255/63);
-            color.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31);
-            color.a = 255;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        {
-            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
-            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 6) & 0b0000000000011111)*255/31);
-            color.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31);
-            color.a = (((unsigned short *)srcPtr)[0] & 0b0000000000000001)? 255 : 0;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-        {
-            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 12)*255/15);
-            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 8) & 0b0000000000001111)*255/15);
-            color.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 4) & 0b0000000000001111)*255/15);
-            color.a = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000001111)*255/15);
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], ((unsigned char *)srcPtr)[3] }; break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], 255 }; break;
-        case PIXELFORMAT_UNCOMPRESSED_R32:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
-            color.g = (unsigned char)(((float *)srcPtr)[0]*255.0f);
-            color.b = (unsigned char)(((float *)srcPtr)[0]*255.0f);
-            color.a = 255;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
-            color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f);
-            color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f);
-            color.a = 255;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
-            color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f);
-            color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f);
-            color.a = (unsigned char)(((float *)srcPtr)[3]*255.0f);
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
-            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
-            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
-            color.a = 255;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
-            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f);
-            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f);
-            color.a = 255;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-        {
-            // NOTE: Pixel normalized float value is converted to [0..255]
-            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
-            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f);
-            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f);
-            color.a = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[3])*255.0f);
-
-        } break;
-        default: break;
-    }
-
-    return color;
-}
-
-// Set pixel color formatted into destination pointer
-void SetPixelColor(void *dstPtr, Color color, int format)
-{
-    switch (format)
-    {
-        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-        {
-            // NOTE: Calculate grayscale equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
-
-            ((unsigned char *)dstPtr)[0] = gray;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-        {
-            // NOTE: Calculate grayscale equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
-
-            ((unsigned char *)dstPtr)[0] = gray;
-            ((unsigned char *)dstPtr)[1] = color.a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        {
-            // NOTE: Calculate R5G6B5 equivalent color
-            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*31.0f));
-            unsigned char g = (unsigned char)(round(coln.y*63.0f));
-            unsigned char b = (unsigned char)(round(coln.z*31.0f));
-
-            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        {
-            // NOTE: Calculate R5G5B5A1 equivalent color
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*31.0f));
-            unsigned char g = (unsigned char)(round(coln.y*31.0f));
-            unsigned char b = (unsigned char)(round(coln.z*31.0f));
-            unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
-
-            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-        {
-            // NOTE: Calculate R5G5B5A1 equivalent color
-            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
-
-            unsigned char r = (unsigned char)(round(coln.x*15.0f));
-            unsigned char g = (unsigned char)(round(coln.y*15.0f));
-            unsigned char b = (unsigned char)(round(coln.z*15.0f));
-            unsigned char a = (unsigned char)(round(coln.w*15.0f));
-
-            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-        {
-            ((unsigned char *)dstPtr)[0] = color.r;
-            ((unsigned char *)dstPtr)[1] = color.g;
-            ((unsigned char *)dstPtr)[2] = color.b;
-
-        } break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-        {
-            ((unsigned char *)dstPtr)[0] = color.r;
-            ((unsigned char *)dstPtr)[1] = color.g;
-            ((unsigned char *)dstPtr)[2] = color.b;
-            ((unsigned char *)dstPtr)[3] = color.a;
-
-        } break;
-        default: break;
-    }
-}
-
-// Get pixel data size in bytes for certain format
-// NOTE: Size can be requested for Image or Texture data
-int GetPixelDataSize(int width, int height, int format)
-{
-    int dataSize = 0;       // Size in bytes
-    int bpp = 0;            // Bits per pixel
-
-    switch (format)
-    {
-        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
-        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
-        case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
-        case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
-        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
-        case PIXELFORMAT_UNCOMPRESSED_R16: bpp = 16; break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 16*3; break;
-        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 16*4; break;
-        case PIXELFORMAT_COMPRESSED_DXT1_RGB:
-        case PIXELFORMAT_COMPRESSED_DXT1_RGBA:
-        case PIXELFORMAT_COMPRESSED_ETC1_RGB:
-        case PIXELFORMAT_COMPRESSED_ETC2_RGB:
-        case PIXELFORMAT_COMPRESSED_PVRT_RGB:
-        case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
-        case PIXELFORMAT_COMPRESSED_DXT3_RGBA:
-        case PIXELFORMAT_COMPRESSED_DXT5_RGBA:
-        case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
-        case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
-        case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
-        default: break;
-    }
-
-    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 ((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;
-    }
-
-    return dataSize;
-}
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-// Convert half-float (stored as unsigned short) to float
-// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
-static float HalfToFloat(unsigned short x)
-{
-    float result = 0.0f;
-
-    union {
-        float fm;
-        unsigned int ui;
-    } uni;
-
-    const unsigned int e = (x & 0x7c00) >> 10; // Exponent
-    const unsigned int m = (x & 0x03ff) << 13; // Mantissa
-    uni.fm = (float)m;
-    const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
-    uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
-
-    result = uni.fm;
-
-    return result;
-}
-
-// Convert float to half-float (stored as unsigned short)
-static unsigned short FloatToHalf(float x)
-{
-    unsigned short result = 0;
-
-    union {
-        float fm;
-        unsigned int ui;
-    } uni;
-    uni.fm = x;
-
-    const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
-    const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
-    const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
-
-    result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
-
-    return result;
-}
-
-// Get pixel data from image as Vector4 array (float normalized)
-static Vector4 *LoadImageDataNormalized(Image image)
-{
-    Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4));
-
-    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
-    else
-    {
-        for (int i = 0, k = 0; i < image.width*image.height; i++)
-        {
-            switch (image.format)
-            {
-                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
-                {
-                    pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f;
-                    pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f;
-                    pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f;
-                    pixels[i].w = 1.0f;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
-                {
-                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
-                    pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f;
-                    pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f;
-                    pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f;
-
-                    k += 2;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
-                    pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
-                    pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
-                    pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
-                    pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63);
-                    pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31);
-                    pixels[i].w = 1.0f;
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
-                {
-                    unsigned short pixel = ((unsigned short *)image.data)[i];
-
-                    pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15);
-                    pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15);
-                    pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15);
-                    pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15);
-
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
-                {
-                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
-                    pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
-                    pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
-                    pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f;
-
-                    k += 4;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
-                {
-                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
-                    pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
-                    pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
-                    pixels[i].w = 1.0f;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32:
-                {
-                    pixels[i].x = ((float *)image.data)[k];
-                    pixels[i].y = 0.0f;
-                    pixels[i].z = 0.0f;
-                    pixels[i].w = 1.0f;
-
-                    k += 1;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
-                {
-                    pixels[i].x = ((float *)image.data)[k];
-                    pixels[i].y = ((float *)image.data)[k + 1];
-                    pixels[i].z = ((float *)image.data)[k + 2];
-                    pixels[i].w = 1.0f;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
-                {
-                    pixels[i].x = ((float *)image.data)[k];
-                    pixels[i].y = ((float *)image.data)[k + 1];
-                    pixels[i].z = ((float *)image.data)[k + 2];
-                    pixels[i].w = ((float *)image.data)[k + 3];
-
-                    k += 4;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16:
-                {
-                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
-                    pixels[i].y = 0.0f;
-                    pixels[i].z = 0.0f;
-                    pixels[i].w = 1.0f;
-
-                    k += 1;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
-                {
-                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
-                    pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]);
-                    pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]);
-                    pixels[i].w = 1.0f;
-
-                    k += 3;
-                } break;
-                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
-                {
-                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
-                    pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]);
-                    pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]);
-                    pixels[i].w = HalfToFloat(((unsigned short *)image.data)[k + 3]);
-
-                    k += 4;
-                } break;
-                default: break;
-            }
-        }
-    }
-
-    return pixels;
-}
-
-#endif      // SUPPORT_MODULE_RTEXTURES
+*       #define SUPPORT_MODULE_RTEXTURES    1
+*           rtextures module is included in the build
+*
+*       #define SUPPORT_FILEFORMAT_BMP      1
+*       #define SUPPORT_FILEFORMAT_PNG      1
+*       #define SUPPORT_FILEFORMAT_TGA      0
+*       #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
+*       #define SUPPORT_FILEFORMAT_PNM      0
+*       #define SUPPORT_FILEFORMAT_DDS      1
+*       #define SUPPORT_FILEFORMAT_PKM      0
+*       #define SUPPORT_FILEFORMAT_KTX      0
+*       #define SUPPORT_FILEFORMAT_PVR      0
+*       #define SUPPORT_FILEFORMAT_ASTC     0
+*           Selected desired fileformats to be supported for image data loading. Some of those formats are
+*           supported by default, to remove support, #define as 0 in this module or your build system
+*
+*       #define SUPPORT_IMAGE_EXPORT        1
+*           Support image export in multiple file formats
+*
+*       #define SUPPORT_IMAGE_GENERATION    1
+*           Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
+*
+*   DEPENDENCIES:
+*       stb_image        - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
+*                          NOTE: stb_image has been slightly modified to support Android platform
+*       stb_image_resize - Multiple image resize algorithms
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   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.
+*
+**********************************************************************************************/
+
+#include "raylib.h"             // Declares module functions
+
+#include "config.h"             // Defines module configuration flags
+
+#if SUPPORT_MODULE_RTEXTURES
+
+#include "rlgl.h"               // OpenGL abstraction layer to multiple versions
+
+#include <stdlib.h>             // Required for: malloc(), calloc(), free()
+#include <string.h>             // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()]
+#include <math.h>               // Required for: fabsf() [Used in DrawTextureRec()]
+#include <stdio.h>              // Required for: sprintf() [Used in ExportImageAsCode()]
+#include <limits.h>             // Required for: INT_MAX
+
+// Support only desired texture formats on stb_image
+#if !SUPPORT_FILEFORMAT_BMP
+    #define STBI_NO_BMP
+#endif
+#if !SUPPORT_FILEFORMAT_PNG
+    #define STBI_NO_PNG
+#endif
+#if !SUPPORT_FILEFORMAT_TGA
+    #define STBI_NO_TGA
+#endif
+#if !SUPPORT_FILEFORMAT_JPG
+    #define STBI_NO_JPEG        // Image format .jpg and .jpeg
+#endif
+#if !SUPPORT_FILEFORMAT_PSD
+    #define STBI_NO_PSD
+#endif
+#if !SUPPORT_FILEFORMAT_GIF
+    #define STBI_NO_GIF
+#endif
+#if !SUPPORT_FILEFORMAT_PIC
+    #define STBI_NO_PIC
+#endif
+#if !SUPPORT_FILEFORMAT_HDR
+    #define STBI_NO_HDR
+#endif
+#if !SUPPORT_FILEFORMAT_PNM
+    #define STBI_NO_PNM
+#endif
+
+#if SUPPORT_FILEFORMAT_DDS
+    #define RLTEXGPU_SUPPORT_DDS
+#endif
+#if SUPPORT_FILEFORMAT_PKM
+    #define RLTEXGPU_SUPPORT_PKM
+#endif
+#if SUPPORT_FILEFORMAT_KTX
+    #define RLTEXGPU_SUPPORT_KTX
+#endif
+#if SUPPORT_FILEFORMAT_PVR
+    #define RLTEXGPU_SUPPORT_PVR
+#endif
+#if SUPPORT_FILEFORMAT_ASTC
+    #define RLTEXGPU_SUPPORT_ASTC
+#endif
+
+// Image fileformats not supported by default
+#if (SUPPORT_FILEFORMAT_BMP || \
+     SUPPORT_FILEFORMAT_PNG || \
+     SUPPORT_FILEFORMAT_TGA || \
+     SUPPORT_FILEFORMAT_JPG || \
+     SUPPORT_FILEFORMAT_PSD || \
+     SUPPORT_FILEFORMAT_GIF || \
+     SUPPORT_FILEFORMAT_HDR || \
+     SUPPORT_FILEFORMAT_PIC || \
+     SUPPORT_FILEFORMAT_PNM)
+
+    #if defined(__GNUC__) // GCC and Clang
+        #pragma GCC diagnostic push
+        #pragma GCC diagnostic ignored "-Wunused-function"
+    #endif
+
+    #define STBI_MALLOC RL_MALLOC
+    #define STBI_FREE RL_FREE
+    #define STBI_REALLOC RL_REALLOC
+
+    #define STBI_NO_THREAD_LOCALS
+
+    #if defined(__TINYC__)
+        #define STBI_NO_SIMD
+    #endif
+
+    #define STB_IMAGE_IMPLEMENTATION
+    #include "external/stb_image.h"         // Required for: stbi_load_from_file()
+                                            // NOTE: Used to read image data (multiple formats support)
+
+    #if defined(__GNUC__) // GCC and Clang
+        #pragma GCC diagnostic pop
+    #endif
+#endif
+
+#if (SUPPORT_FILEFORMAT_DDS || \
+     SUPPORT_FILEFORMAT_PKM || \
+     SUPPORT_FILEFORMAT_KTX || \
+     SUPPORT_FILEFORMAT_PVR || \
+     SUPPORT_FILEFORMAT_ASTC)
+
+    #if defined(__GNUC__) // GCC and Clang
+        #pragma GCC diagnostic push
+        #pragma GCC diagnostic ignored "-Wunused-function"
+    #endif
+
+    #define RLTEXGPU_MALLOC RL_MALLOC
+    #define RLTEXGPU_FREE RL_FREE
+    #define RLTEXGPU_LOG(...) TRACELOG(LOG_WARNING, "IMAGE: " __VA_ARGS__)
+    #define RLTEXGPU_SHOW_LOG_INFO
+    #define RLTEXGPU_IMPLEMENTATION
+    #include "external/rltexgpu.h"         // Required for: rl_load_xxx_from_memory()
+                                           // NOTE: Used to read compressed textures data (multiple formats support)
+    #if defined(__GNUC__) // GCC and Clang
+        #pragma GCC diagnostic pop
+    #endif
+#endif
+
+#if SUPPORT_FILEFORMAT_QOI
+    #define QOI_MALLOC RL_MALLOC
+    #define QOI_FREE RL_FREE
+
+    #if defined(_MSC_VER)               // Disable some MSVC warning
+        #pragma warning(push)
+        #pragma warning(disable : 4267)
+    #endif
+
+    #define QOI_IMPLEMENTATION
+    #include "external/qoi.h"
+
+    #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
+    #define STBIW_MALLOC RL_MALLOC
+    #define STBIW_FREE RL_FREE
+    #define STBIW_REALLOC RL_REALLOC
+
+    #define STB_IMAGE_WRITE_IMPLEMENTATION
+    #include "external/stb_image_write.h"   // Required for: stbi_write_*()
+#endif
+
+#if SUPPORT_IMAGE_GENERATION
+    #define STB_PERLIN_IMPLEMENTATION
+    #include "external/stb_perlin.h"        // Required for: stb_perlin_fbm_noise3
+#endif
+
+#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
+#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
+
+#if defined(__GNUC__) // GCC and Clang
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#if defined(__TINYC__)
+    #define STBIR_NO_SIMD
+#endif
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "external/stb_image_resize2.h"     // Required for: stbir_resize_uint8_linear() [ImageResize()]
+
+#if defined(__GNUC__) // GCC and Clang
+    #pragma GCC diagnostic pop
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD
+    #define PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD  50    // Threshold over 255 to set alpha as 0
+#endif
+
+#ifndef GAUSSIAN_BLUR_ITERATIONS
+    #define GAUSSIAN_BLUR_ITERATIONS  4    // Number of box blur iterations to approximate gaussian blur
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+// It's lonely here...
+
+//----------------------------------------------------------------------------------
+// Other Modules Functions Declaration (required by text)
+//----------------------------------------------------------------------------------
+extern void LoadFontDefault(void);          // [Module: text] Loads default font, required by ImageDrawText()
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+static float HalfToFloat(unsigned short x);
+static unsigned short FloatToHalf(float x);
+static Vector4 *LoadImageDataNormalized(Image image);       // Load pixel data from image as Vector4 array (float normalized)
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Load image from file into CPU memory (RAM)
+Image LoadImage(const char *fileName)
+{
+    Image image = { 0 };
+
+#if SUPPORT_FILEFORMAT_PNG || \
+    SUPPORT_FILEFORMAT_BMP || \
+    SUPPORT_FILEFORMAT_TGA || \
+    SUPPORT_FILEFORMAT_JPG || \
+    SUPPORT_FILEFORMAT_GIF || \
+    SUPPORT_FILEFORMAT_PIC || \
+    SUPPORT_FILEFORMAT_HDR || \
+    SUPPORT_FILEFORMAT_PNM || \
+    SUPPORT_FILEFORMAT_PSD
+
+    #define STBI_REQUIRED
+#endif
+
+    // Loading file to memory
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    // Loading image from memory data
+    if (fileData != NULL)
+    {
+        image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize);
+
+        UnloadFileData(fileData);
+    }
+
+    return image;
+}
+
+// Load an image from RAW file data
+Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize)
+{
+    Image image = { 0 };
+
+    int dataSize = 0;
+    unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+    if (fileData != NULL)
+    {
+        unsigned char *dataPtr = fileData;
+        int size = GetPixelDataSize(width, height, format);
+
+        if (size <= dataSize) // Security check
+        {
+            // Offset file data to expected raw image by header size
+            if ((headerSize > 0) && ((headerSize + size) <= dataSize)) dataPtr += headerSize;
+
+            image.data = RL_MALLOC(size);      // Allocate required memory in bytes
+            memcpy(image.data, dataPtr, size); // Copy required data to image
+            image.width = width;
+            image.height = height;
+            image.mipmaps = 1;
+            image.format = format;
+        }
+
+        UnloadFileData(fileData);
+    }
+
+    return image;
+}
+
+// Load animated image data
+//  - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
+//  - Number of frames is returned through 'frames' parameter
+//  - All frames are returned in RGBA format
+//  - Frames delay data is discarded
+Image LoadImageAnim(const char *fileName, int *frames)
+{
+    Image image = { 0 };
+    int frameCount = 0;
+
+#if SUPPORT_FILEFORMAT_GIF
+    if (IsFileExtension(fileName, ".gif"))
+    {
+        int dataSize = 0;
+        unsigned char *fileData = LoadFileData(fileName, &dataSize);
+
+        if (fileData != NULL)
+        {
+            int comp = 0;
+            int *delays = NULL;
+            image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
+
+            image.mipmaps = 1;
+            image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+            UnloadFileData(fileData);
+            RL_FREE(delays);        // NOTE: Frames delays are discarded
+        }
+    }
+#else
+    if (false) { }
+#endif
+    else
+    {
+        image = LoadImage(fileName);
+        frameCount = 1;
+    }
+
+    *frames = frameCount;
+    return image;
+}
+
+// Load animated image data from memory
+//  - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
+//  - Number of frames is returned through 'frames' parameter
+//  - All frames are returned in RGBA format
+//  - Frames delay data is discarded
+Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames)
+{
+    Image image = { 0 };
+    int frameCount = 0;
+
+    if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image; // Security check
+
+#if SUPPORT_FILEFORMAT_GIF
+    if ((strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0))
+    {
+        if (fileData != NULL)
+        {
+            int comp = 0;
+            int *delays = NULL;
+            image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
+
+            image.mipmaps = 1;
+            image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+            RL_FREE(delays);        // NOTE: Frames delays are discarded
+        }
+    }
+#else
+    if (false) { }
+#endif
+    else
+    {
+        image = LoadImageFromMemory(fileType, fileData, dataSize);
+        frameCount = 1;
+    }
+
+    *frames = frameCount;
+    return image;
+}
+
+// Load image from memory buffer, fileType refers to extension: i.e. ".png"
+// WARNING: File extension must be provided in lower-case
+Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
+{
+    Image image = { 0 };
+
+    // Security checks for input data
+    if ((fileData == NULL) || (dataSize == 0))
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Invalid file data");
+        return image;
+    }
+    if (fileType == NULL)
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Missing file extension");
+        return image;
+    }
+
+    if ((false)
+#if SUPPORT_FILEFORMAT_PNG
+        || (strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_BMP
+        || (strcmp(fileType, ".bmp") == 0) || (strcmp(fileType, ".BMP") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_TGA
+        || (strcmp(fileType, ".tga") == 0) || (strcmp(fileType, ".TGA") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_JPG
+        || (strcmp(fileType, ".jpg") == 0) || (strcmp(fileType, ".jpeg") == 0)
+        || (strcmp(fileType, ".JPG") == 0) || (strcmp(fileType, ".JPEG") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_GIF
+        || (strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_PIC
+        || (strcmp(fileType, ".pic") == 0) || (strcmp(fileType, ".PIC") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_PNM
+        || (strcmp(fileType, ".ppm") == 0) || (strcmp(fileType, ".pgm") == 0)
+        || (strcmp(fileType, ".PPM") == 0) || (strcmp(fileType, ".PGM") == 0)
+#endif
+#if SUPPORT_FILEFORMAT_PSD
+        || (strcmp(fileType, ".psd") == 0) || (strcmp(fileType, ".PSD") == 0)
+#endif
+        )
+    {
+#if defined(STBI_REQUIRED)
+        // NOTE: Using stb_image to load images (Supports multiple image formats)
+
+        if (fileData != NULL)
+        {
+            int comp = 0;
+            image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
+
+            if (image.data != NULL)
+            {
+                image.mipmaps = 1;
+
+                if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+                else if (comp == 2) image.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
+                else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+                else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+            }
+        }
+#endif
+    }
+#if SUPPORT_FILEFORMAT_HDR
+    else if ((strcmp(fileType, ".hdr") == 0) || (strcmp(fileType, ".HDR") == 0))
+    {
+#if defined(STBI_REQUIRED)
+        if (fileData != NULL)
+        {
+            int comp = 0;
+            image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
+
+            image.mipmaps = 1;
+
+            if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_R32;
+            else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
+            else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
+            else
+            {
+                TRACELOG(LOG_WARNING, "IMAGE: HDR file format not supported");
+                UnloadImage(image);
+            }
+        }
+#endif
+    }
+#endif
+#if SUPPORT_FILEFORMAT_QOI
+    else if ((strcmp(fileType, ".qoi") == 0) || (strcmp(fileType, ".QOI") == 0))
+    {
+        if (fileData != NULL)
+        {
+            qoi_desc desc = { 0 };
+            image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]);
+            image.width = desc.width;
+            image.height = desc.height;
+            image.format = (desc.channels == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+            image.mipmaps = 1;
+        }
+    }
+#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))
+    {
+        image.data = rl_load_dds_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
+    }
+#endif
+#if SUPPORT_FILEFORMAT_PKM
+    else if ((strcmp(fileType, ".pkm") == 0) || (strcmp(fileType, ".PKM") == 0))
+    {
+        image.data = rl_load_pkm_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
+    }
+#endif
+#if SUPPORT_FILEFORMAT_KTX
+    else if ((strcmp(fileType, ".ktx") == 0) || (strcmp(fileType, ".KTX") == 0))
+    {
+        image.data = rl_load_ktx_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
+    }
+#endif
+#if SUPPORT_FILEFORMAT_PVR
+    else if ((strcmp(fileType, ".pvr") == 0) || (strcmp(fileType, ".PVR") == 0))
+    {
+        image.data = rl_load_pvr_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
+    }
+#endif
+#if SUPPORT_FILEFORMAT_ASTC
+    else if ((strcmp(fileType, ".astc") == 0) || (strcmp(fileType, ".ASTC") == 0))
+    {
+        image.data = rl_load_astc_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
+    }
+#endif
+    else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");
+
+    if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: Data loaded successfully (%ix%i | %s | %i mipmaps)", image.width, image.height, rlGetPixelFormatName(image.format), image.mipmaps);
+    else TRACELOG(LOG_WARNING, "IMAGE: Failed to load image data");
+
+    return image;
+}
+
+// Load image from GPU texture data
+// NOTE: Compressed texture formats not supported
+Image LoadImageFromTexture(Texture2D texture)
+{
+    Image image = { 0 };
+
+    if (texture.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
+    {
+        image.data = rlReadTexturePixels(texture.id, texture.width, texture.height, texture.format);
+
+        if (image.data != NULL)
+        {
+            image.width = texture.width;
+            image.height = texture.height;
+#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);
+    }
+    else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id);
+
+    return image;
+}
+
+// Load image from screen buffer (screenshot)
+Image LoadImageFromScreen(void)
+{
+    Image image = { 0 };
+
+    image.width = (int)(GetRenderWidth());
+    image.height = (int)(GetRenderHeight());
+    image.mipmaps = 1;
+    image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+    image.data = rlReadScreenPixels(image.width, image.height);
+
+    return image;
+}
+
+// Check if an image is ready
+bool IsImageValid(Image image)
+{
+    bool result = false;
+
+    if ((image.data != NULL) &&     // Validate pixel data available
+        (image.width > 0) &&        // Validate image width
+        (image.height > 0) &&       // Validate image height
+        (image.format > 0) &&       // Validate image format
+        (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level)
+
+    return result;
+}
+
+// Unload image from CPU memory (RAM)
+void UnloadImage(Image image)
+{
+    RL_FREE(image.data);
+}
+
+// Export image data to file
+// NOTE: File format depends on fileName extension
+bool ExportImage(Image image, const char *fileName)
+{
+    int result = 0;
+
+    if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result; // Security check
+
+#if SUPPORT_IMAGE_EXPORT
+    int channels = 4;
+    bool allocatedData = false;
+    unsigned char *imgData = (unsigned char *)image.data;
+
+    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
+    else
+    {
+        // NOTE: Getting Color array as RGBA unsigned char values
+        imgData = (unsigned char *)LoadImageColors(image);
+        allocatedData = true;
+    }
+
+    if (false) { } // Required to attach following 'else' cases
+#if SUPPORT_FILEFORMAT_PNG
+    else if (IsFileExtension(fileName, ".png"))
+    {
+        int dataSize = 0;
+        unsigned char *fileData = stbi_write_png_to_mem((const unsigned char *)imgData, image.width*channels, image.width, image.height, channels, &dataSize);
+        result = SaveFileData(fileName, fileData, dataSize);
+        RL_FREE(fileData);
+    }
+#endif
+#if SUPPORT_FILEFORMAT_BMP
+    else if (IsFileExtension(fileName, ".bmp")) result = stbi_write_bmp(fileName, image.width, image.height, channels, imgData);
+#endif
+#if SUPPORT_FILEFORMAT_TGA
+    else if (IsFileExtension(fileName, ".tga")) result = stbi_write_tga(fileName, image.width, image.height, channels, imgData);
+#endif
+#if SUPPORT_FILEFORMAT_JPG
+    else if (IsFileExtension(fileName, ".jpg") ||
+             IsFileExtension(fileName, ".jpeg")) result = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90);  // JPG quality: between 1 and 100
+#endif
+#if SUPPORT_FILEFORMAT_QOI
+    else if (IsFileExtension(fileName, ".qoi"))
+    {
+        channels = 0;
+        if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
+        else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
+        else TRACELOG(LOG_WARNING, "IMAGE: Image pixel format must be R8G8B8 or R8G8B8A8");
+
+        if ((channels == 3) || (channels == 4))
+        {
+            qoi_desc desc = { 0 };
+            desc.width = image.width;
+            desc.height = image.height;
+            desc.channels = channels;
+            desc.colorspace = QOI_SRGB;
+
+            result = qoi_write(fileName, imgData, &desc);
+        }
+    }
+#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"))
+    {
+        result = rl_save_ktx(fileName, image.data, image.width, image.height, image.format, image.mipmaps);
+    }
+#endif
+    else if (IsFileExtension(fileName, ".raw"))
+    {
+        // Export raw pixel data (without header)
+        // NOTE: It's up to the user to track image parameters
+        result = SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
+    }
+    else TRACELOG(LOG_WARNING, "IMAGE: Export image format requested not supported");
+
+    if (allocatedData) RL_FREE(imgData);
+#endif // SUPPORT_IMAGE_EXPORT
+
+    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
+    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
+
+    return result;
+}
+
+// Export image to memory buffer
+unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataSize)
+{
+    unsigned char *fileData = NULL;
+    *dataSize = 0;
+
+    if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return fileData; // Security check
+
+    int channels = 4;
+
+    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) channels = 1;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) channels = 2;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
+
+#if SUPPORT_IMAGE_EXPORT
+    if ((strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0))
+    {
+        fileData = stbi_write_png_to_mem((const unsigned char *)image.data, image.width*channels, image.width, image.height, channels, dataSize);
+    }
+#else
+    TRACELOG(LOG_WARNING, "IMAGE: To export image, enable flag SUPPORT_IMAGE_EXPORT");
+#endif
+
+    return fileData;
+}
+
+// Export image as code file (.h) defining an array of bytes
+bool ExportImageAsCode(Image image, const char *fileName)
+{
+    bool result = false;
+
+#ifndef TEXT_BYTES_PER_LINE
+    #define TEXT_BYTES_PER_LINE     20
+#endif
+
+    int dataSize = GetPixelDataSize(image.width, image.height, image.format);
+
+    // NOTE: Text data buffer size is estimated considering image data size in bytes
+    // and requiring 6 char bytes for every byte: "0x00, "
+    char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
+
+    int byteCount = 0;
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes         //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
+    byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2026 Ramon Santamaria (@raysan5)                                //\n");
+    byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
+    byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
+
+    // Get file name from path and convert variable name to uppercase
+    char varFileName[256] = { 0 };
+    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
+    byteCount += sprintf(txtData + byteCount, "// Image data information\n");
+    byteCount += sprintf(txtData + byteCount, "#define %s_WIDTH    %i\n", varFileName, image.width);
+    byteCount += sprintf(txtData + byteCount, "#define %s_HEIGHT   %i\n", varFileName, image.height);
+    byteCount += sprintf(txtData + byteCount, "#define %s_FORMAT   %i          // raylib internal pixel format\n\n", varFileName, image.format);
+
+    byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
+    for (int i = 0; i < dataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
+    byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
+
+    // NOTE: Text data size exported is determined by '\0' (NULL) character
+    result = SaveFileText(fileName, txtData);
+
+    RL_FREE(txtData);
+
+    if (result != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
+    else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
+
+    return result;
+}
+
+//------------------------------------------------------------------------------------
+// Image generation functions
+//------------------------------------------------------------------------------------
+// Generate image: plain color
+Image GenImageColor(int width, int height, Color color)
+{
+    int dataSize = GetPixelDataSize(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
+    Color *pixels = (Color *)RL_CALLOC(dataSize, 1);
+
+    for (int i = 0; (pixels != NULL) && (i < width*height); i++) pixels[i] = color;
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+#if SUPPORT_IMAGE_GENERATION
+// Generate image: linear gradient
+// The direction value specifies the direction of the gradient (in degrees)
+// with 0 being vertical (from top to bottom), 90 being horizontal (from left to right)
+// The gradient effectively rotates counter-clockwise by the specified amount
+Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    float radianDirection = (float)(90 - direction)/180.f*3.14159f;
+    float cosDir = cosf(radianDirection);
+    float sinDir = sinf(radianDirection);
+
+    // Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
+    float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
+
+    // With directions that lie in the first or third quadrant (i.e. from top-left to
+    // bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
+    // (i.e. the pixel which should become one of the gradient's ends color); while for
+    // directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
+    float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
+    for (int i = 0; i < width; i++)
+    {
+        for (int j = 0; j < height; j++)
+        {
+            // Calculate the relative position of the pixel along the gradient direction
+            float pos = (startingPos + (i*cosDir + j*sinDir))/maxPosValue;
+
+            float factor = pos;
+            factor = (factor > 1.0f)? 1.0f : factor;  // Clamp to [-1,1]
+            factor = (factor < -1.0f)? -1.0f : factor;  // Clamp to [-1,1]
+            factor = factor/2.0f + 0.5f;
+
+            // Generate the color for this pixel
+            pixels[j*width + i].r = (int)((float)end.r*factor + (float)start.r*(1.0f - factor));
+            pixels[j*width + i].g = (int)((float)end.g*factor + (float)start.g*(1.0f - factor));
+            pixels[j*width + i].b = (int)((float)end.b*factor + (float)start.b*(1.0f - factor));
+            pixels[j*width + i].a = (int)((float)end.a*factor + (float)start.a*(1.0f - factor));
+        }
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: radial gradient
+Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+    float radius = (width < height)? (float)width/2.0f : (float)height/2.0f;
+
+    float centerX = (float)width/2.0f;
+    float centerY = (float)height/2.0f;
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            float dist = hypotf((float)x - centerX, (float)y - centerY);
+            float factor = (dist - radius*density)/(radius*(1.0f - density));
+
+            factor = (float)fmax(factor, 0.0f);
+            factor = (float)fmin(factor, 1.f); // Distance can be bigger than radius, so it needs to be checked
+
+            pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
+            pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
+            pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
+            pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor));
+        }
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: square gradient
+Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    float centerX = (float)width/2.0f;
+    float centerY = (float)height/2.0f;
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            // Calculate the Manhattan distance from the center
+            float distX = fabsf(x - centerX);
+            float distY = fabsf(y - centerY);
+
+            // Normalize the distances by the dimensions of the gradient rectangle
+            float normalizedDistX = distX/centerX;
+            float normalizedDistY = distY/centerY;
+
+            // Calculate the total normalized Manhattan distance
+            float manhattanDist = fmaxf(normalizedDistX, normalizedDistY);
+
+            // Subtract the density from the manhattanDist, then divide by (1 - density)
+            // This makes the gradient start from the center when density is 0, and from the edge when density is 1
+            float factor = (manhattanDist - density)/(1.0f - density);
+
+            // Clamp the factor between 0 and 1
+            factor = fminf(fmaxf(factor, 0.0f), 1.0f);
+
+            // Blend the colors based on the calculated factor
+            pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor));
+            pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor));
+            pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor));
+            pixels[y*width + x].a = (int)((float)outer.a*factor + (float)inner.a*(1.0f - factor));
+        }
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: checked
+Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            if ((x/checksX + y/checksY)%2 == 0) pixels[y*width + x] = col1;
+            else pixels[y*width + x] = col2;
+        }
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: white noise
+// NOTE: It requires GetRandomValue(), defined in [rcore]
+Image GenImageWhiteNoise(int width, int height, float factor)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    for (int i = 0; i < width*height; i++)
+    {
+        if (GetRandomValue(0, 99) < (int)(factor*100.0f)) pixels[i] = WHITE;
+        else pixels[i] = BLACK;
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: perlin noise
+Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    float aspectRatio = (float)width/(float)height;
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            float nx = (float)(x + offsetX)*(scale/(float)width);
+            float ny = (float)(y + offsetY)*(scale/(float)height);
+
+            // Apply aspect ratio compensation to wider side
+            if (width > height) nx *= aspectRatio;
+            else ny /= aspectRatio;
+
+            // Basic perlin noise implementation (not used)
+            //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0);
+
+            // Calculate a better perlin noise using fbm (fractal brownian motion)
+            // Typical values to start playing with:
+            //   lacunarity = ~2.0   -- spacing between successive octaves (use exactly 2.0 for wrapping output)
+            //   gain       =  0.5   -- relative weighting applied to each successive octave
+            //   octaves    =  6     -- number of "octaves" of noise3() to sum
+            float p = stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6);
+
+            // Clamp between -1.0f and 1.0f
+            if (p < -1.0f) p = -1.0f;
+            if (p > 1.0f) p = 1.0f;
+
+            // Data needs to be normalized from [-1..1] to [0..1]
+            float np = (p + 1.0f)/2.0f;
+
+            unsigned char intensity = (unsigned char)(np*255.0f);
+            pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 };
+        }
+    }
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: cellular algorithm. Bigger tileSize means bigger cells
+Image GenImageCellular(int width, int height, int tileSize)
+{
+    Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
+
+    int seedsPerRow = width/tileSize;
+    int seedsPerCol = height/tileSize;
+    int seedCount = seedsPerRow*seedsPerCol;
+
+    Vector2 *seeds = (Vector2 *)RL_MALLOC(seedCount*sizeof(Vector2));
+
+    for (int i = 0; i < seedCount; i++)
+    {
+        int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
+        int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
+        seeds[i] = (Vector2){ (float)x, (float)y };
+    }
+
+    for (int y = 0; y < height; y++)
+    {
+        int tileY = y/tileSize;
+
+        for (int x = 0; x < width; x++)
+        {
+            int tileX = x/tileSize;
+
+            float minDistance = 65536.0f; //(float)strtod("Inf", NULL);
+
+            // Check all adjacent tiles
+            for (int i = -1; i < 2; i++)
+            {
+                if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue;
+
+                for (int j = -1; j < 2; j++)
+                {
+                    if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue;
+
+                    Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i];
+
+                    float dist = (float)hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y);
+                    minDistance = (float)fmin(minDistance, dist);
+                }
+            }
+
+            // This approach seems to give good results at all tile sizes
+            int intensity = (int)(minDistance*256.0f/tileSize);
+            if (intensity > 255) intensity = 255;
+
+            unsigned char intensityUC = (unsigned char)intensity;
+            pixels[y*width + x] = (Color){ intensityUC, intensityUC, intensityUC, 255 };
+        }
+    }
+
+    RL_FREE(seeds);
+
+    Image image = {
+        .data = pixels,
+        .width = width,
+        .height = height,
+        .mipmaps = 1,
+        .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
+    };
+
+    return image;
+}
+
+// Generate image: grayscale image from text data
+Image GenImageText(int width, int height, const char *text)
+{
+    Image image = { 0 };
+
+    int imageSize = width*height;
+    image.width = width;
+    image.height = height;
+    image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+    image.data = RL_CALLOC(imageSize, 1);
+    image.mipmaps = 1;
+
+    if (text != NULL)
+    {
+        int textLength = (int)strlen(text);
+        memcpy(image.data, text, (textLength > imageSize)? imageSize : textLength);
+    }
+
+    return image;
+}
+#endif // SUPPORT_IMAGE_GENERATION
+
+//------------------------------------------------------------------------------------
+// Image manipulation functions
+//------------------------------------------------------------------------------------
+// Copy an image to a new image
+Image ImageCopy(Image image)
+{
+    Image newImage = { 0 };
+
+    int width = image.width;
+    int height = image.height;
+    int size = 0;
+
+    for (int i = 0; i < image.mipmaps; i++)
+    {
+        size += GetPixelDataSize(width, height, image.format);
+
+        width /= 2;
+        height /= 2;
+
+        // Security check for NPOT textures
+        if (width < 1) width = 1;
+        if (height < 1) height = 1;
+    }
+
+    newImage.data = RL_CALLOC(size, 1);
+
+    if (newImage.data != NULL)
+    {
+        // NOTE: Size must be provided in bytes
+        memcpy(newImage.data, image.data, size);
+
+        newImage.width = image.width;
+        newImage.height = image.height;
+        newImage.mipmaps = image.mipmaps;
+        newImage.format = image.format;
+    }
+
+    return newImage;
+}
+
+// Create an image from another image piece
+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;
+
+    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;
+            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: ImageToImage(), rectangle provided not valid");
+	}
+    else TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats");
+
+    return result;
+}
+
+// Crop an image to area defined by a rectangle
+// NOTE: Security checks are performed in case rectangle goes out of bounds
+void ImageCrop(Image *image, Rectangle crop)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    // Security checks to validate crop rectangle
+    if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
+    if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
+    if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
+    if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
+    if ((crop.x > image->width) || (crop.y > image->height))
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds");
+        return;
+    }
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+
+        unsigned char *croppedData = (unsigned char *)RL_MALLOC((int)(crop.width*crop.height)*bytesPerPixel);
+
+        // OPTION 1: Move cropped data line-by-line
+        for (int y = (int)crop.y, offsetSize = 0; y < (int)(crop.y + crop.height); y++)
+        {
+            memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + (int)crop.x)*bytesPerPixel, (int)crop.width*bytesPerPixel);
+            offsetSize += ((int)crop.width*bytesPerPixel);
+        }
+
+        /*
+        // OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte
+        for (int y = (int)crop.y; y < (int)(crop.y + crop.height); y++)
+        {
+            for (int x = (int)crop.x; x < (int)(crop.x + crop.width); x++)
+            {
+                //memcpy(croppedData + ((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
+                for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
+            }
+        }
+        */
+
+        RL_FREE(image->data);
+        image->data = croppedData;
+        image->width = (int)crop.width;
+        image->height = (int)crop.height;
+    }
+}
+
+// Convert image data to desired format
+void ImageFormat(Image *image, int newFormat)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if ((newFormat != 0) && (image->format != newFormat))
+    {
+        if ((image->format < PIXELFORMAT_COMPRESSED_DXT1_RGB) && (newFormat < PIXELFORMAT_COMPRESSED_DXT1_RGB))
+        {
+            Vector4 *pixels = LoadImageDataNormalized(*image);     // Supports 8 to 32 bit per channel
+
+            RL_FREE(image->data);      // WARNING! Loosing mipmaps data --> Regenerated at the end
+            image->data = NULL;
+            image->format = newFormat;
+
+            switch (image->format)
+            {
+                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+                {
+                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*sizeof(unsigned char));
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        ((unsigned char *)image->data)[i] = (unsigned char)((pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)*255.0f);
+                    }
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+                {
+                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*2*sizeof(unsigned char));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*2; i += 2, k++)
+                    {
+                        ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f);
+                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f);
+                    }
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+                {
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
+
+                    unsigned char r = 0;
+                    unsigned char g = 0;
+                    unsigned char b = 0;
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        r = (unsigned char)(round(pixels[i].x*31.0f));
+                        g = (unsigned char)(round(pixels[i].y*63.0f));
+                        b = (unsigned char)(round(pixels[i].z*31.0f));
+
+                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
+                    }
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+                {
+                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned char));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
+                    {
+                        ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
+                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
+                        ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+                {
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
+
+                    unsigned char r = 0;
+                    unsigned char g = 0;
+                    unsigned char b = 0;
+                    unsigned char a = 0;
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        r = (unsigned char)(round(pixels[i].x*31.0f));
+                        g = (unsigned char)(round(pixels[i].y*31.0f));
+                        b = (unsigned char)(round(pixels[i].z*31.0f));
+                        a = (pixels[i].w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
+
+                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
+                    }
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+                {
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
+
+                    unsigned char r = 0;
+                    unsigned char g = 0;
+                    unsigned char b = 0;
+                    unsigned char a = 0;
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        r = (unsigned char)(round(pixels[i].x*15.0f));
+                        g = (unsigned char)(round(pixels[i].y*15.0f));
+                        b = (unsigned char)(round(pixels[i].z*15.0f));
+                        a = (unsigned char)(round(pixels[i].w*15.0f));
+
+                        ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
+                    }
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+                {
+                    image->data = (unsigned char *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned char));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
+                    {
+                        ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f);
+                        ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f);
+                        ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f);
+                        ((unsigned char *)image->data)[i + 3] = (unsigned char)(pixels[k].w*255.0f);
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32:
+                {
+                    // WARNING: Image is converted to GRAYSCALE equivalent 32bit
+
+                    image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float));
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        ((float *)image->data)[i] = (float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f);
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+                {
+                    image->data = (float *)RL_MALLOC(image->width*image->height*3*sizeof(float));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
+                    {
+                        ((float *)image->data)[i] = pixels[k].x;
+                        ((float *)image->data)[i + 1] = pixels[k].y;
+                        ((float *)image->data)[i + 2] = pixels[k].z;
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+                {
+                    image->data = (float *)RL_MALLOC(image->width*image->height*4*sizeof(float));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
+                    {
+                        ((float *)image->data)[i] = pixels[k].x;
+                        ((float *)image->data)[i + 1] = pixels[k].y;
+                        ((float *)image->data)[i + 2] = pixels[k].z;
+                        ((float *)image->data)[i + 3] = pixels[k].w;
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16:
+                {
+                    // WARNING: Image is converted to GRAYSCALE equivalent 16bit
+
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
+
+                    for (int i = 0; i < image->width*image->height; i++)
+                    {
+                        ((unsigned short *)image->data)[i] = FloatToHalf((float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f));
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+                {
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned short));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++)
+                    {
+                        ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x);
+                        ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y);
+                        ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z);
+                    }
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+                {
+                    image->data = (unsigned short *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned short));
+
+                    for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++)
+                    {
+                        ((unsigned short *)image->data)[i] = FloatToHalf(pixels[k].x);
+                        ((unsigned short *)image->data)[i + 1] = FloatToHalf(pixels[k].y);
+                        ((unsigned short *)image->data)[i + 2] = FloatToHalf(pixels[k].z);
+                        ((unsigned short *)image->data)[i + 3] = FloatToHalf(pixels[k].w);
+                    }
+                } break;
+                default: break;
+            }
+
+            RL_FREE(pixels);
+            pixels = NULL;
+
+            // In case original image had mipmaps, generate mipmaps for formatted image
+            // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost
+            if (image->mipmaps > 1)
+            {
+                image->mipmaps = 1;
+                if (image->data != NULL) ImageMipmaps(image);
+            }
+        }
+        else TRACELOG(LOG_WARNING, "IMAGE: Data format is compressed, can not be converted");
+    }
+}
+
+// Create an image from text (default font)
+Image ImageText(const char *text, int fontSize, Color color)
+{
+    Image imText = { 0 };
+#if SUPPORT_MODULE_RTEXT
+    int defaultFontSize = 10;   // Default Font chars height in pixel
+    if (fontSize < defaultFontSize) fontSize = defaultFontSize;
+    int spacing = fontSize/defaultFontSize;
+    imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color);   // WARNING: Module required: rtext
+#else
+    imText = GenImageColor(200, 60, BLACK);     // Generating placeholder black image rectangle
+    TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
+#endif
+    return imText;
+}
+
+// Create an image from text (custom sprite font)
+// WARNING: Module required: rtext
+Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
+{
+    Image imText = { 0 };
+#if SUPPORT_MODULE_RTEXT
+    if (text == NULL) return imText;
+
+    int textLength = (int)strlen(text); // Get length of text in bytes
+    int textOffsetX = 0;            // Image drawing position X
+    int textOffsetY = 0;            // Offset between lines (on linebreak '\n')
+
+    // NOTE: Text image is generated at font base size, later scaled to desired font size
+    Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);  // WARNING: Module required: rtext
+    Vector2 textSize = MeasureTextEx(font, text, fontSize, spacing);
+
+    // Create image to store text
+    imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
+
+    for (int i = 0; i < textLength;)
+    {
+        // Get next codepoint from byte string and glyph index in font
+        int codepointByteCount = 0;
+        int codepoint = GetCodepointNext(&text[i], &codepointByteCount);    // WARNING: Module required: rtext
+        int index = GetGlyphIndex(font, codepoint);                         // WARNING: Module required: rtext
+
+        if (codepoint == '\n')
+        {
+            // NOTE: Fixed line spacing of 1.5 line-height
+            // TODO: Support custom line spacing defined by user
+            textOffsetY += (font.baseSize + font.baseSize/2);
+            textOffsetX = 0;
+        }
+        else
+        {
+            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 },
+                    rec, (Vector2){ 0 }, 0.0f, tint);
+            }
+
+            if (font.glyphs[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing);
+            else textOffsetX += font.glyphs[index].advanceX + (int)spacing;
+        }
+
+        i += codepointByteCount;   // Move text bytes counter to next codepoint
+    }
+
+    // Scale image depending on text size
+    if (textSize.y != imSize.y)
+    {
+        float scaleFactor = textSize.y/imSize.y;
+        TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
+
+        // Using nearest-neighbor scaling algorithm for default font
+        // TODO: Allow defining the preferred scaling mechanism externally
+        if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
+        else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
+    }
+#else
+    imText = GenImageColor(200, 60, BLACK);     // Generating placeholder black image rectangle
+    TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
+#endif
+    return imText;
+}
+
+// Create an image from a selected channel of another image
+Image ImageFromChannel(Image image, int selectedChannel)
+{
+    Image result = { 0 };
+
+    if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result; // Security check
+
+    // Check selected channel is valid
+    if (selectedChannel < 0)
+    {
+        TRACELOG(LOG_WARNING, "Channel cannot be negative. Setting channel to 0.");
+        selectedChannel = 0;
+    }
+
+    if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE ||
+        image.format == PIXELFORMAT_UNCOMPRESSED_R32 ||
+        image.format == PIXELFORMAT_UNCOMPRESSED_R16)
+    {
+        if (selectedChannel > 0)
+        {
+            TRACELOG(LOG_WARNING, "This image has only 1 channel. Setting channel to it.");
+            selectedChannel = 0;
+        }
+    }
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA)
+    {
+        if (selectedChannel > 1)
+        {
+            TRACELOG(LOG_WARNING, "This image has only 2 channels. Setting channel to alpha.");
+            selectedChannel = 1;
+        }
+    }
+    else if (image.format == PIXELFORMAT_UNCOMPRESSED_R5G6B5 ||
+             image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8 ||
+             image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32 ||
+             image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16)
+    {
+        if (selectedChannel > 2)
+        {
+            TRACELOG(LOG_WARNING, "This image has only 3 channels. Setting channel to red.");
+            selectedChannel = 0;
+        }
+    }
+
+    // Check for RGBA formats
+    if (selectedChannel > 3)
+    {
+        TRACELOG(LOG_WARNING, "ImageFromChannel supports channels 0 to 3 (RGBA). Setting channel to alpha.");
+        selectedChannel = 3;
+    }
+
+    // TODO: Consider other one-channel formats: R16, R32
+    result.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
+    result.height = image.height;
+    result.width = image.width;
+    result.mipmaps = 1;
+
+    unsigned char *pixels = (unsigned char *)RL_CALLOC(image.width*image.height, sizeof(unsigned char)); // Values from 0 to 255
+
+    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
+    else
+    {
+        for (int i = 0, k = 0; i < image.width*image.height; i++)
+        {
+            float pixelValue = -1;
+            switch (image.format)
+            {
+                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+                {
+                    pixelValue = (float)((unsigned char *)image.data)[i + selectedChannel]/255.0f;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+                {
+                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
+                    k += 2;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
+                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
+                    else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
+                    else if (selectedChannel == 3) pixelValue = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
+                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63);
+                    else if (selectedChannel == 2) pixelValue = (float)(pixel & 0b0000000000011111)*(1.0f/31);
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    if (selectedChannel == 0) pixelValue = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15);
+                    else if (selectedChannel == 1) pixelValue = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15);
+                    else if (selectedChannel == 2) pixelValue = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15);
+                    else if (selectedChannel == 3) pixelValue = (float)(pixel & 0b0000000000001111)*(1.0f/15);
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+                {
+                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
+                    k += 4;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+                {
+                    pixelValue = (float)((unsigned char *)image.data)[k + selectedChannel]/255.0f;
+                    k += 3;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32:
+                {
+                    pixelValue = ((float *)image.data)[k];
+                    k += 1;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+                {
+                    pixelValue = ((float *)image.data)[k + selectedChannel];
+                    k += 3;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+                {
+                    pixelValue = ((float *)image.data)[k + selectedChannel];
+                    k += 4;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16:
+                {
+                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k]);
+                    k += 1;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+                {
+                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k+selectedChannel]);
+                    k += 3;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+                {
+                    pixelValue = HalfToFloat(((unsigned short *)image.data)[k + selectedChannel]);
+                    k += 4;
+
+                } break;
+                default: break;
+            }
+
+            pixels[i] = (unsigned char)(pixelValue*255);
+        }
+    }
+
+    result.data = pixels;
+
+    return result;
+}
+
+// Resize and image to new size using Nearest-Neighbor scaling algorithm
+void ImageResizeNN(Image *image, int newWidth, int newHeight)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Color *pixels = LoadImageColors(*image);
+    Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
+
+    // EDIT: added +1 to account for an early rounding problem
+    int xRatio = (int)((image->width << 16)/newWidth) + 1;
+    int yRatio = (int)((image->height << 16)/newHeight) + 1;
+
+    int x2 = 0;
+    int y2 = 0;
+    for (int y = 0; y < newHeight; y++)
+    {
+        for (int x = 0; x < newWidth; x++)
+        {
+            x2 = ((x*xRatio) >> 16);
+            y2 = ((y*yRatio) >> 16);
+
+            output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
+        }
+    }
+
+    int format = image->format;
+
+    RL_FREE(image->data);
+
+    image->data = output;
+    image->width = newWidth;
+    image->height = newHeight;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
+
+    UnloadImageColors(pixels);
+}
+
+// Resize and image to new size
+// NOTE: Uses stb default scaling filters (both bicubic):
+// STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
+// STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
+void ImageResize(Image *image, int newWidth, int newHeight)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    // Check if fast path can be used on image scaling
+    // It can be for 8 bit per channel images with 1 to 4 channels per pixel
+    if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
+        (image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
+
+        switch (image->format)
+        {
+            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)1); break;
+            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)2); break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)3); break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: stbir_resize_uint8_linear((unsigned char *)image->data, image->width, image->height, 0, output, newWidth, newHeight, 0, (stbir_pixel_layout)4); break;
+            default: break;
+        }
+
+        RL_FREE(image->data);
+        image->data = output;
+        image->width = newWidth;
+        image->height = newHeight;
+    }
+    else
+    {
+        // Get data as Color pixels array to work with it
+        Color *pixels = LoadImageColors(*image);
+        Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
+
+        // NOTE: Color data is cast to (unsigned char *), there shouldn't been any problem...
+        stbir_resize_uint8_linear((unsigned char *)pixels, image->width, image->height, 0, (unsigned char *)output, newWidth, newHeight, 0, (stbir_pixel_layout)4);
+
+        int format = image->format;
+
+        UnloadImageColors(pixels);
+        RL_FREE(image->data);
+
+        image->data = output;
+        image->width = newWidth;
+        image->height = newHeight;
+        image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+        ImageFormat(image, format);  // Reformat 32bit RGBA image to original format
+    }
+}
+
+// Resize canvas and fill with color
+// NOTE: Resize offset is relative to the top-left corner of the original image
+void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else if ((newWidth != image->width) || (newHeight != image->height))
+    {
+        Rectangle srcRec = { 0, 0, (float)image->width, (float)image->height };
+        Vector2 dstPos = { (float)offsetX, (float)offsetY };
+
+        if (offsetX < 0)
+        {
+            srcRec.x = (float)-offsetX;
+            srcRec.width += (float)offsetX;
+            dstPos.x = 0;
+        }
+        else if ((offsetX + image->width) > newWidth) srcRec.width = (float)(newWidth - offsetX);
+
+        if (offsetY < 0)
+        {
+            srcRec.y = (float)-offsetY;
+            srcRec.height += (float)offsetY;
+            dstPos.y = 0;
+        }
+        else if ((offsetY + image->height) > newHeight) srcRec.height = (float)(newHeight - offsetY);
+
+        if (newWidth < srcRec.width) srcRec.width = (float)newWidth;
+        if (newHeight < srcRec.height) srcRec.height = (float)newHeight;
+
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
+
+        // Fill resized canvas with fill color
+        // Set first pixel with image->format
+        SetPixelColor(resizedData, fill, image->format);
+
+        // Fill remaining bytes of first row
+        for (int x = 1; x < newWidth; x++)
+        {
+            memcpy(resizedData + x*bytesPerPixel, resizedData, bytesPerPixel);
+        }
+        // Copy the first row into the other rows
+        for (int y = 1; y < newHeight; y++)
+        {
+            memcpy(resizedData + y*newWidth*bytesPerPixel, resizedData, newWidth*bytesPerPixel);
+        }
+
+        // Copy old image to resized canvas
+        int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
+
+        for (int y = 0; y < (int)srcRec.height; y++)
+        {
+            memcpy(resizedData + dstOffsetSize, ((unsigned char *)image->data) + ((y + (int)srcRec.y)*image->width + (int)srcRec.x)*bytesPerPixel, (int)srcRec.width*bytesPerPixel);
+            dstOffsetSize += (newWidth*bytesPerPixel);
+        }
+
+        RL_FREE(image->data);
+        image->data = resizedData;
+        image->width = newWidth;
+        image->height = newHeight;
+    }
+}
+
+// Convert image to POT (power-of-two)
+// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
+void ImageToPOT(Image *image, Color fill)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    // Calculate next power-of-two values
+    // NOTE: Add the required amount of pixels at the right and bottom sides of image...
+    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
+    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
+
+    // Check if POT texture generation is required (if texture is not already POT)
+    if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill);
+}
+
+// Crop image depending on alpha value
+// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
+void ImageAlphaCrop(Image *image, float threshold)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Rectangle crop = GetImageAlphaBorder(*image, threshold);
+
+    // Crop if rectangle is valid
+    if (((int)crop.width != 0) && ((int)crop.height != 0)) ImageCrop(image, crop);
+}
+
+// Clear alpha channel to desired color
+// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
+void ImageAlphaClear(Image *image, Color color, float threshold)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        switch (image->format)
+        {
+            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+            {
+                unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
+                for (int i = 1; i < image->width*image->height*2; i += 2)
+                {
+                    if (((unsigned char *)image->data)[i] <= thresholdValue)
+                    {
+                        ((unsigned char *)image->data)[i - 1] = color.r;
+                        ((unsigned char *)image->data)[i] = color.a;
+                    }
+                }
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+            {
+                unsigned char thresholdValue = ((threshold < 0.5f)? 0 : 1);
+
+                unsigned char r = (unsigned char)(round((float)color.r*31.0f));
+                unsigned char g = (unsigned char)(round((float)color.g*31.0f));
+                unsigned char b = (unsigned char)(round((float)color.b*31.0f));
+                unsigned char a = (color.a < 128)? 0 : 1;
+
+                for (int i = 0; i < image->width*image->height; i++)
+                {
+                    if ((((unsigned short *)image->data)[i] & 0b0000000000000001) <= thresholdValue)
+                    {
+                        ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
+                    }
+                }
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+            {
+                unsigned char thresholdValue = (unsigned char)(threshold*15.0f);
+
+                unsigned char r = (unsigned char)(round((float)color.r*15.0f));
+                unsigned char g = (unsigned char)(round((float)color.g*15.0f));
+                unsigned char b = (unsigned char)(round((float)color.b*15.0f));
+                unsigned char a = (unsigned char)(round((float)color.a*15.0f));
+
+                for (int i = 0; i < image->width*image->height; i++)
+                {
+                    if ((((unsigned short *)image->data)[i] & 0x000f) <= thresholdValue)
+                    {
+                        ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
+                    }
+                }
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+            {
+                unsigned char thresholdValue = (unsigned char)(threshold*255.0f);
+                for (int i = 3; i < image->width*image->height*4; i += 4)
+                {
+                    if (((unsigned char *)image->data)[i] <= thresholdValue)
+                    {
+                        ((unsigned char *)image->data)[i - 3] = color.r;
+                        ((unsigned char *)image->data)[i - 2] = color.g;
+                        ((unsigned char *)image->data)[i - 1] = color.b;
+                        ((unsigned char *)image->data)[i] = color.a;
+                    }
+                }
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+            {
+                for (int i = 3; i < image->width*image->height*4; i += 4)
+                {
+                    if (((float *)image->data)[i] <= threshold)
+                    {
+                        ((float *)image->data)[i - 3] = (float)color.r/255.0f;
+                        ((float *)image->data)[i - 2] = (float)color.g/255.0f;
+                        ((float *)image->data)[i - 1] = (float)color.b/255.0f;
+                        ((float *)image->data)[i] = (float)color.a/255.0f;
+                    }
+                }
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+            {
+                for (int i = 3; i < image->width*image->height*4; i += 4)
+                {
+                    if (HalfToFloat(((unsigned short *)image->data)[i]) <= threshold)
+                    {
+                        ((unsigned short *)image->data)[i - 3] = FloatToHalf((float)color.r/255.0f);
+                        ((unsigned short *)image->data)[i - 2] = FloatToHalf((float)color.g/255.0f);
+                        ((unsigned short *)image->data)[i - 1] = FloatToHalf((float)color.b/255.0f);
+                        ((unsigned short *)image->data)[i] = FloatToHalf((float)color.a/255.0f);
+                    }
+                }
+            } break;
+            default: break;
+        }
+    }
+}
+
+// Apply alpha mask to image
+// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit)
+// NOTE 2: alphaMask should be same size as image
+void ImageAlphaMask(Image *image, Image alphaMask)
+{
+    if ((image->width != alphaMask.width) || (image->height != alphaMask.height))
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Alpha mask must be same size as image");
+    }
+    else if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Alpha mask can not be applied to compressed data formats");
+    }
+    else
+    {
+        // Force mask to be Grayscale
+        Image mask = ImageCopy(alphaMask);
+        if (mask.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
+
+        // In case image is only grayscale, add alpha channel
+        if (image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
+        {
+            unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
+
+            // Apply alpha mask to alpha channel
+            for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
+            {
+                data[k] = ((unsigned char *)image->data)[i];
+                data[k + 1] = ((unsigned char *)mask.data)[i];
+            }
+
+            RL_FREE(image->data);
+            image->data = data;
+            image->format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
+        }
+        else
+        {
+            // Convert image to RGBA
+            if (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
+
+            // Apply alpha mask to alpha channel
+            for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4)
+            {
+                ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i];
+            }
+        }
+
+        UnloadImage(mask);
+    }
+}
+
+// Premultiply alpha channel
+void ImageAlphaPremultiply(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    float alpha = 0.0f;
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        if (pixels[i].a == 0)
+        {
+            pixels[i].r = 0;
+            pixels[i].g = 0;
+            pixels[i].b = 0;
+        }
+        else if (pixels[i].a < 255)
+        {
+            alpha = (float)pixels[i].a/255.0f;
+            pixels[i].r = (unsigned char)((float)pixels[i].r*alpha);
+            pixels[i].g = (unsigned char)((float)pixels[i].g*alpha);
+            pixels[i].b = (unsigned char)((float)pixels[i].b*alpha);
+        }
+    }
+
+    RL_FREE(image->data);
+
+    int format = image->format;
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Apply box blur to image
+void ImageBlurGaussian(Image *image, int blurSize)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    ImageAlphaPremultiply(image);
+
+    Color *pixels = LoadImageColors(*image);
+
+    // Loop switches between pixelsCopy1 and pixelsCopy2
+    Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
+    Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
+
+    for (int i = 0; i < (image->height*image->width); i++)
+    {
+        pixelsCopy1[i].x = pixels[i].r;
+        pixelsCopy1[i].y = pixels[i].g;
+        pixelsCopy1[i].z = pixels[i].b;
+        pixelsCopy1[i].w = pixels[i].a;
+    }
+
+    // Repeated convolution of rectangular window signal by itself converges to a gaussian distribution
+    for (int j = 0; j < GAUSSIAN_BLUR_ITERATIONS; j++)
+    {
+        // Horizontal motion blur
+        for (int row = 0; row < image->height; row++)
+        {
+            float avgR = 0.0f;
+            float avgG = 0.0f;
+            float avgB = 0.0f;
+            float avgAlpha = 0.0f;
+            int convolutionSize = blurSize;
+
+            for (int i = 0; i < blurSize; i++)
+            {
+                avgR += pixelsCopy1[row*image->width + i].x;
+                avgG += pixelsCopy1[row*image->width + i].y;
+                avgB += pixelsCopy1[row*image->width + i].z;
+                avgAlpha += pixelsCopy1[row*image->width + i].w;
+            }
+
+            for (int x = 0; x < image->width; x++)
+            {
+                if (x-blurSize-1 >= 0)
+                {
+                    avgR -= pixelsCopy1[row*image->width + x-blurSize-1].x;
+                    avgG -= pixelsCopy1[row*image->width + x-blurSize-1].y;
+                    avgB -= pixelsCopy1[row*image->width + x-blurSize-1].z;
+                    avgAlpha -= pixelsCopy1[row*image->width + x-blurSize-1].w;
+                    convolutionSize--;
+                }
+
+                if (x+blurSize < image->width)
+                {
+                    avgR += pixelsCopy1[row*image->width + x+blurSize].x;
+                    avgG += pixelsCopy1[row*image->width + x+blurSize].y;
+                    avgB += pixelsCopy1[row*image->width + x+blurSize].z;
+                    avgAlpha += pixelsCopy1[row*image->width + x+blurSize].w;
+                    convolutionSize++;
+                }
+
+                pixelsCopy2[row*image->width + x].x = avgR/convolutionSize;
+                pixelsCopy2[row*image->width + x].y = avgG/convolutionSize;
+                pixelsCopy2[row*image->width + x].z = avgB/convolutionSize;
+                pixelsCopy2[row*image->width + x].w = avgAlpha/convolutionSize;
+            }
+        }
+
+        // Vertical motion blur
+        for (int col = 0; col < image->width; col++)
+        {
+            float avgR = 0.0f;
+            float avgG = 0.0f;
+            float avgB = 0.0f;
+            float avgAlpha = 0.0f;
+            int convolutionSize = blurSize;
+
+            for (int i = 0; i < blurSize; i++)
+            {
+                avgR += pixelsCopy2[i*image->width + col].x;
+                avgG += pixelsCopy2[i*image->width + col].y;
+                avgB += pixelsCopy2[i*image->width + col].z;
+                avgAlpha += pixelsCopy2[i*image->width + col].w;
+            }
+
+            for (int y = 0; y < image->height; y++)
+            {
+                if (y-blurSize-1 >= 0)
+                {
+                    avgR -= pixelsCopy2[(y-blurSize-1)*image->width + col].x;
+                    avgG -= pixelsCopy2[(y-blurSize-1)*image->width + col].y;
+                    avgB -= pixelsCopy2[(y-blurSize-1)*image->width + col].z;
+                    avgAlpha -= pixelsCopy2[(y-blurSize-1)*image->width + col].w;
+                    convolutionSize--;
+                }
+                if (y+blurSize < image->height)
+                {
+                    avgR += pixelsCopy2[(y+blurSize)*image->width + col].x;
+                    avgG += pixelsCopy2[(y+blurSize)*image->width + col].y;
+                    avgB += pixelsCopy2[(y+blurSize)*image->width + col].z;
+                    avgAlpha += pixelsCopy2[(y+blurSize)*image->width + col].w;
+                    convolutionSize++;
+                }
+
+                pixelsCopy1[y*image->width + col].x = (unsigned char) (avgR/convolutionSize);
+                pixelsCopy1[y*image->width + col].y = (unsigned char) (avgG/convolutionSize);
+                pixelsCopy1[y*image->width + col].z = (unsigned char) (avgB/convolutionSize);
+                pixelsCopy1[y*image->width + col].w = (unsigned char) (avgAlpha/convolutionSize);
+            }
+        }
+    }
+
+    // Reverse premultiply
+    for (int i = 0; i < (image->width)*(image->height); i++)
+    {
+        if (pixelsCopy1[i].w == 0.0f)
+        {
+            pixels[i].r = 0;
+            pixels[i].g = 0;
+            pixels[i].b = 0;
+            pixels[i].a = 0;
+        }
+        else if (pixelsCopy1[i].w <= 255.0f)
+        {
+            float alpha = (float)pixelsCopy1[i].w/255.0f;
+            pixels[i].r = (unsigned char)fminf((float)pixelsCopy1[i].x/alpha, 255.0);
+            pixels[i].g = (unsigned char)fminf((float)pixelsCopy1[i].y/alpha, 255.0);
+            pixels[i].b = (unsigned char)fminf((float)pixelsCopy1[i].z/alpha, 255.0);
+            pixels[i].a = (unsigned char) pixelsCopy1[i].w;
+        }
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+    RL_FREE(pixelsCopy1);
+    RL_FREE(pixelsCopy2);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Apply custom square convolution kernel to image
+// NOTE: The convolution kernel matrix is expected to be square
+void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
+{
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0) || kernel == NULL) return;
+
+    int kernelWidth = (int)sqrtf((float)kernelSize);
+
+    if (kernelWidth*kernelWidth != kernelSize)
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Convolution kernel must be square to be applied");
+        return;
+    }
+
+    Color *pixels = LoadImageColors(*image);
+
+    Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
+    Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
+
+    for (int i = 0; i < kernelSize; i++)
+    {
+        temp[i].x = 0.0f;
+        temp[i].y = 0.0f;
+        temp[i].z = 0.0f;
+        temp[i].w = 0.0f;
+    }
+
+    float rRes = 0.0f;
+    float gRes = 0.0f;
+    float bRes = 0.0f;
+    float aRes = 0.0f;
+
+    int startRange = 0, endRange = 0;
+
+    if (kernelWidth%2 == 0)
+    {
+        startRange = -kernelWidth/2;
+        endRange = kernelWidth/2;
+    }
+    else
+    {
+        startRange = -kernelWidth/2;
+        endRange = kernelWidth/2 + 1;
+    }
+
+    for (int x = 0; x < image->height; x++)
+    {
+        for (int y = 0; y < image->width; y++)
+        {
+            for (int xk = startRange; xk < endRange; xk++)
+            {
+                for (int yk = startRange; yk < endRange; yk++)
+                {
+                    int xkabs = xk + kernelWidth/2;
+                    int ykabs = yk + kernelWidth/2;
+                    unsigned int imgindex = image->width*(x + xk) + (y + yk);
+
+                    if (imgindex >= (unsigned int)(image->width*image->height))
+                    {
+                        temp[kernelWidth*xkabs + ykabs].x = 0.0f;
+                        temp[kernelWidth*xkabs + ykabs].y = 0.0f;
+                        temp[kernelWidth*xkabs + ykabs].z = 0.0f;
+                        temp[kernelWidth*xkabs + ykabs].w = 0.0f;
+                    }
+                    else
+                    {
+                        temp[kernelWidth*xkabs + ykabs].x = ((float)pixels[imgindex].r)/255.0f*kernel[kernelWidth*xkabs + ykabs];
+                        temp[kernelWidth*xkabs + ykabs].y = ((float)pixels[imgindex].g)/255.0f*kernel[kernelWidth*xkabs + ykabs];
+                        temp[kernelWidth*xkabs + ykabs].z = ((float)pixels[imgindex].b)/255.0f*kernel[kernelWidth*xkabs + ykabs];
+                        temp[kernelWidth*xkabs + ykabs].w = ((float)pixels[imgindex].a)/255.0f*kernel[kernelWidth*xkabs + ykabs];
+                    }
+                }
+            }
+
+            for (int i = 0; i < kernelSize; i++)
+            {
+                rRes += temp[i].x;
+                gRes += temp[i].y;
+                bRes += temp[i].z;
+                aRes += temp[i].w;
+            }
+
+            if (rRes < 0.0f) rRes = 0.0f;
+            if (gRes < 0.0f) gRes = 0.0f;
+            if (bRes < 0.0f) bRes = 0.0f;
+
+            if (rRes > 1.0f) rRes = 1.0f;
+            if (gRes > 1.0f) gRes = 1.0f;
+            if (bRes > 1.0f) bRes = 1.0f;
+
+            imageCopy2[image->width*x + y].x = rRes;
+            imageCopy2[image->width*x + y].y = gRes;
+            imageCopy2[image->width*x + y].z = bRes;
+            imageCopy2[image->width*x + y].w = aRes;
+
+            rRes = 0.0f;
+            gRes = 0.0f;
+            bRes = 0.0f;
+            aRes = 0.0f;
+
+            for (int i = 0; i < kernelSize; i++)
+            {
+                temp[i].x = 0.0f;
+                temp[i].y = 0.0f;
+                temp[i].z = 0.0f;
+                temp[i].w = 0.0f;
+            }
+        }
+    }
+
+    for (int i = 0; i < (image->width*image->height); i++)
+    {
+        float alpha = (float)imageCopy2[i].w;
+
+        pixels[i].r = (unsigned char)((imageCopy2[i].x)*255.0f);
+        pixels[i].g = (unsigned char)((imageCopy2[i].y)*255.0f);
+        pixels[i].b = (unsigned char)((imageCopy2[i].z)*255.0f);
+        pixels[i].a = (unsigned char)((alpha)*255.0f);
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+    RL_FREE(imageCopy2);
+    RL_FREE(temp);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+    ImageFormat(image, format);
+}
+
+// Generate all mipmap levels for a provided image
+// NOTE 1: Supports POT and NPOT images
+// NOTE 2: image.data is scaled to include mipmap levels
+// NOTE 3: Mipmaps format is the same as base image
+void ImageMipmaps(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    int mipCount = 1;                   // Required mipmap levels count (including base level)
+    int mipWidth = image->width;        // Base image width
+    int mipHeight = image->height;      // Base image height
+    int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);  // Image data size (in bytes)
+
+    // Count mipmap levels required
+    while ((mipWidth != 1) || (mipHeight != 1))
+    {
+        if (mipWidth != 1) mipWidth /= 2;
+        if (mipHeight != 1) mipHeight /= 2;
+
+        // Security check for NPOT textures
+        if (mipWidth < 1) mipWidth = 1;
+        if (mipHeight < 1) mipHeight = 1;
+
+        TRACELOG(LOG_DEBUG, "IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
+
+        mipCount++;
+        mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format);       // Add mipmap size (in bytes)
+    }
+
+    if (image->mipmaps < mipCount)
+    {
+        // Create second buffer and copy data manually to it
+        void *temp = RL_CALLOC(mipSize, 1);
+        memcpy(temp, image->data, GetPixelDataSize(image->width, image->height, image->format));
+        RL_FREE(image->data);
+        image->data = temp;
+
+        // Pointer to allocated memory point where store next mipmap level data
+        unsigned char *nextmip = (unsigned char *)image->data;
+
+        mipWidth = image->width;
+        mipHeight = image->height;
+        mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
+        Image imCopy = ImageCopy(*image);
+
+        for (int i = 1; i < mipCount; i++)
+        {
+            nextmip += mipSize;
+
+            mipWidth /= 2;
+            mipHeight /= 2;
+
+            // Security check for NPOT textures
+            if (mipWidth < 1) mipWidth = 1;
+            if (mipHeight < 1) mipHeight = 1;
+
+            mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format);
+
+            if (i < image->mipmaps) continue;
+
+            TRACELOG(LOG_DEBUG, "IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
+            ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter
+            memcpy(nextmip, imCopy.data, mipSize);
+        }
+
+        UnloadImage(imCopy);
+
+        image->mipmaps = mipCount;
+    }
+    else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps already available");
+}
+
+// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
+// NOTE: In case selected bpp do not represent a known 16bit format,
+// dithered data is stored in the LSB part of the unsigned short
+void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Compressed data formats can not be dithered");
+        return;
+    }
+
+    if ((rBpp + gBpp + bBpp + aBpp) > 16)
+    {
+        TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
+    }
+    else
+    {
+        Color *pixels = LoadImageColors(*image);
+
+        RL_FREE(image->data);      // free old image data
+
+        if ((image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
+        {
+            TRACELOG(LOG_WARNING, "IMAGE: Format is already 16bpp or lower, dithering could have no effect");
+        }
+
+        // Define new image format, check if desired bpp match internal known format
+        if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
+        else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
+        else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
+        else
+        {
+            image->format = 0;
+            TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
+        }
+
+        // NOTE: Storing the dithered data as unsigned short (16bpp)
+        image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short));
+
+        Color oldPixel = WHITE;
+        Color newPixel = WHITE;
+
+        int rError = 0;
+        int gError = 0;
+        int bError = 0;
+        unsigned short rPixel = 0;   // Used for 16bit pixel composition
+        unsigned short gPixel = 0;
+        unsigned short bPixel = 0;
+        unsigned short aPixel = 0;
+
+        #define MIN(a,b) (((a)<(b))?(a):(b))
+
+        for (int y = 0; y < image->height; y++)
+        {
+            for (int x = 0; x < image->width; x++)
+            {
+                oldPixel = pixels[y*image->width + x];
+
+                // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
+                newPixel.r = oldPixel.r >> (8 - rBpp);     // R bits
+                newPixel.g = oldPixel.g >> (8 - gBpp);     // G bits
+                newPixel.b = oldPixel.b >> (8 - bBpp);     // B bits
+                newPixel.a = oldPixel.a >> (8 - aBpp);     // A bits (not used on dithering)
+
+                // NOTE: Error must be computed between new and old pixel but using same number of bits,
+                // to know how much color precision has been lost
+                rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
+                gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
+                bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
+
+                pixels[y*image->width + x] = newPixel;
+
+                // NOTE: Some cases are out of the array and should be ignored
+                if (x < (image->width - 1))
+                {
+                    pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
+                    pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
+                    pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
+                }
+
+                if ((x > 0) && (y < (image->height - 1)))
+                {
+                    pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
+                }
+
+                if (y < (image->height - 1))
+                {
+                    pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
+                }
+
+                if ((x < (image->width - 1)) && (y < (image->height - 1)))
+                {
+                    pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
+                    pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
+                }
+
+                rPixel = (unsigned short)newPixel.r;
+                gPixel = (unsigned short)newPixel.g;
+                bPixel = (unsigned short)newPixel.b;
+                aPixel = (unsigned short)newPixel.a;
+
+                ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
+            }
+        }
+
+        UnloadImageColors(pixels);
+    }
+}
+
+// Flip image vertically
+void ImageFlipVertical(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
+
+        for (int i = (image->height - 1), offsetSize = 0; i >= 0; i--)
+        {
+            memcpy(flippedData + offsetSize, ((unsigned char *)image->data) + i*image->width*bytesPerPixel, image->width*bytesPerPixel);
+            offsetSize += image->width*bytesPerPixel;
+        }
+
+        RL_FREE(image->data);
+        image->data = flippedData;
+    }
+}
+
+// Flip image horizontally
+void ImageFlipHorizontal(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
+
+        for (int y = 0; y < image->height; y++)
+        {
+            for (int x = 0; x < image->width; x++)
+            {
+                // OPTION 1: Move pixels with memcpy()
+                //memcpy(flippedData + (y*image->width + x)*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - 1 - x))*bytesPerPixel, bytesPerPixel);
+
+                // OPTION 2: Copy data pixel by pixel
+                for (int i = 0; i < bytesPerPixel; i++) flippedData[(y*image->width + x)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - 1 - x))*bytesPerPixel + i];
+            }
+        }
+
+        RL_FREE(image->data);
+        image->data = flippedData;
+
+        /*
+        // OPTION 3: Faster implementation (specific for 32bit pixels)
+        // NOTE: It does not require additional allocations
+        uint32_t *ptr = (uint32_t *)image->data;
+        for (int y = 0; y < image->height; y++)
+        {
+            for (int x = 0; x < image->width/2; x++)
+            {
+                uint32_t backup = ptr[y*image->width + x];
+                ptr[y*image->width + x] = ptr[y*image->width + (image->width - 1 - x)];
+                ptr[y*image->width + (image->width - 1 - x)] = backup;
+            }
+        }
+        */
+    }
+}
+
+// Rotate image in degrees
+void ImageRotate(Image *image, int degrees)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        float rad = degrees*PI/180.0f;
+        float sinRadius = sinf(rad);
+        float cosRadius = cosf(rad);
+
+        int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
+        int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
+
+        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)
+        {
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    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))
+                    {
+                        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 px = oldX - x1;
+                        float py = oldY - y1;
+
+                        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;
+        }
+    }
+}
+
+// Rotate image clockwise 90deg
+void ImageRotateCW(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
+
+        for (int y = 0; y < image->height; y++)
+        {
+            for (int x = 0; x < image->width; x++)
+            {
+                //memcpy(rotatedData + (x*image->height + (image->height - y - 1))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel);
+                for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + (image->height - y - 1))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i];
+            }
+        }
+
+        RL_FREE(image->data);
+        image->data = rotatedData;
+        int width = image->width;
+        int height = image-> height;
+
+        image->width = height;
+        image->height = width;
+    }
+}
+
+// Rotate image counter-clockwise 90deg
+void ImageRotateCCW(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (image->mipmaps > 1) TRACELOG(LOG_WARNING, "Image manipulation only applied to base mipmap level");
+    if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image manipulation not supported for compressed formats");
+    else
+    {
+        int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
+        unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel);
+
+        for (int y = 0; y < image->height; y++)
+        {
+            for (int x = 0; x < image->width; x++)
+            {
+                //memcpy(rotatedData + (x*image->height + y))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - x - 1))*bytesPerPixel, bytesPerPixel);
+                for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + y)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - x - 1))*bytesPerPixel + i];
+            }
+        }
+
+        RL_FREE(image->data);
+        image->data = rotatedData;
+        int width = image->width;
+        int height = image-> height;
+
+        image->width = height;
+        image->height = width;
+    }
+}
+
+// Modify image color: tint
+void ImageColorTint(Image *image, Color color)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        unsigned char r = (unsigned char)(((int)pixels[i].r*(int)color.r)/255);
+        unsigned char g = (unsigned char)(((int)pixels[i].g*(int)color.g)/255);
+        unsigned char b = (unsigned char)(((int)pixels[i].b*(int)color.b)/255);
+        unsigned char a = (unsigned char)(((int)pixels[i].a*(int)color.a)/255);
+
+        pixels[i].r = r;
+        pixels[i].g = g;
+        pixels[i].b = b;
+        pixels[i].a = a;
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Modify image color: invert
+void ImageColorInvert(Image *image)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        pixels[i].r = 255 - pixels[i].r;
+        pixels[i].g = 255 - pixels[i].g;
+        pixels[i].b = 255 - pixels[i].b;
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Modify image color: grayscale
+void ImageColorGrayscale(Image *image)
+{
+    ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
+}
+
+// Modify image color: contrast
+// NOTE: Contrast values between -100 and 100
+void ImageColorContrast(Image *image, int contrast)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (contrast < -100) contrast = -100;
+    if (contrast > 100) contrast = 100;
+
+    float factor = (float)(100.0f + contrast)/100.0f;
+    factor *= factor;
+
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        float pR = (float)pixels[i].r/255.0f;
+        pR -= 0.5f;
+        pR *= factor;
+        pR += 0.5f;
+        pR *= 255;
+        if (pR < 0) pR = 0;
+        if (pR > 255) pR = 255;
+
+        float pG = (float)pixels[i].g/255.0f;
+        pG -= 0.5f;
+        pG *= factor;
+        pG += 0.5f;
+        pG *= 255;
+        if (pG < 0) pG = 0;
+        if (pG > 255) pG = 255;
+
+        float pB = (float)pixels[i].b/255.0f;
+        pB -= 0.5f;
+        pB *= factor;
+        pB += 0.5f;
+        pB *= 255;
+        if (pB < 0) pB = 0;
+        if (pB > 255) pB = 255;
+
+        pixels[i].r = (unsigned char)pR;
+        pixels[i].g = (unsigned char)pG;
+        pixels[i].b = (unsigned char)pB;
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Modify image color: brightness
+// NOTE: Brightness values between -255 and 255
+void ImageColorBrightness(Image *image, int brightness)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    if (brightness < -255) brightness = -255;
+    if (brightness > 255) brightness = 255;
+
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        int cR = pixels[i].r + brightness;
+        int cG = pixels[i].g + brightness;
+        int cB = pixels[i].b + brightness;
+
+        if (cR < 0) cR = 1;
+        if (cR > 255) cR = 255;
+
+        if (cG < 0) cG = 1;
+        if (cG > 255) cG = 255;
+
+        if (cB < 0) cB = 1;
+        if (cB > 255) cB = 255;
+
+        pixels[i].r = (unsigned char)cR;
+        pixels[i].g = (unsigned char)cG;
+        pixels[i].b = (unsigned char)cB;
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    ImageFormat(image, format);
+}
+
+// Modify image color: replace color
+void ImageColorReplace(Image *image, Color color, Color replace)
+{
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
+    Color *pixels = LoadImageColors(*image);
+
+    for (int i = 0; i < image->width*image->height; i++)
+    {
+        if ((pixels[i].r == color.r) &&
+            (pixels[i].g == color.g) &&
+            (pixels[i].b == color.b) &&
+            (pixels[i].a == color.a))
+        {
+            pixels[i].r = replace.r;
+            pixels[i].g = replace.g;
+            pixels[i].b = replace.b;
+            pixels[i].a = replace.a;
+        }
+    }
+
+    int format = image->format;
+    RL_FREE(image->data);
+
+    image->data = pixels;
+    image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+
+    // Only convert back to original format if it supported alpha
+    if ((format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
+        (format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
+        (format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
+        (format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
+        (format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
+        (format == PIXELFORMAT_COMPRESSED_DXT1_RGB) ||
+        (format == PIXELFORMAT_COMPRESSED_ETC1_RGB) ||
+        (format == PIXELFORMAT_COMPRESSED_ETC2_RGB) ||
+        (format == PIXELFORMAT_COMPRESSED_PVRT_RGB)) ImageFormat(image, format);
+}
+
+// Load color data from image as a Color array (RGBA - 32bit)
+// NOTE: Memory allocated should be freed using UnloadImageColors();
+Color *LoadImageColors(Image image)
+{
+    if ((image.width == 0) || (image.height == 0)) return NULL; // Security check
+
+    Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color));
+
+    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
+    else
+    {
+        if ((image.format == PIXELFORMAT_UNCOMPRESSED_R32) ||
+            (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
+            (image.format == PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 32bit to 8bit per channel");
+
+        if ((image.format == PIXELFORMAT_UNCOMPRESSED_R16) ||
+            (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
+            (image.format == PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 16bit to 8bit per channel");
+
+        for (int i = 0, k = 0; i < image.width*image.height; i++)
+        {
+            switch (image.format)
+            {
+                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+                {
+                    pixels[i].r = ((unsigned char *)image.data)[i];
+                    pixels[i].g = ((unsigned char *)image.data)[i];
+                    pixels[i].b = ((unsigned char *)image.data)[i];
+                    pixels[i].a = 255;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+                {
+                    pixels[i].r = ((unsigned char *)image.data)[k];
+                    pixels[i].g = ((unsigned char *)image.data)[k];
+                    pixels[i].b = ((unsigned char *)image.data)[k];
+                    pixels[i].a = ((unsigned char *)image.data)[k + 1];
+
+                    k += 2;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
+                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
+                    pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
+                    pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255);
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
+                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
+                    pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
+                    pixels[i].a = 255;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
+                    pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
+                    pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
+                    pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+                {
+                    pixels[i].r = ((unsigned char *)image.data)[k];
+                    pixels[i].g = ((unsigned char *)image.data)[k + 1];
+                    pixels[i].b = ((unsigned char *)image.data)[k + 2];
+                    pixels[i].a = ((unsigned char *)image.data)[k + 3];
+
+                    k += 4;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+                {
+                    pixels[i].r = (unsigned char)((unsigned char *)image.data)[k];
+                    pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1];
+                    pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2];
+                    pixels[i].a = 255;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32:
+                {
+                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
+                    pixels[i].g = 0;
+                    pixels[i].b = 0;
+                    pixels[i].a = 255;
+
+                    k += 1;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+                {
+                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
+                    pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
+                    pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
+                    pixels[i].a = 255;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+                {
+                    pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f);
+                    pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f);
+                    pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f);
+                    pixels[i].a = (unsigned char)(((float *)image.data)[k + 3]*255.0f);
+
+                    k += 4;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16:
+                {
+                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
+                    pixels[i].g = 0;
+                    pixels[i].b = 0;
+                    pixels[i].a = 255;
+
+                    k += 1;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+                {
+                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
+                    pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f);
+                    pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f);
+                    pixels[i].a = 255;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+                {
+                    pixels[i].r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k])*255.0f);
+                    pixels[i].g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 1])*255.0f);
+                    pixels[i].b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 2])*255.0f);
+                    pixels[i].a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[k + 3])*255.0f);
+
+                    k += 4;
+                } break;
+                default: break;
+            }
+        }
+    }
+
+    return pixels;
+}
+
+// Load colors palette from image as a Color array (RGBA - 32bit)
+// NOTE: Memory allocated should be freed using UnloadImagePalette()
+Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount)
+{
+    #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
+
+    int palCount = 0;
+    Color *palette = NULL;
+    Color *pixels = LoadImageColors(image);
+
+    if (pixels != NULL)
+    {
+        palette = (Color *)RL_MALLOC(maxPaletteSize*sizeof(Color));
+
+        for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK;   // Set all colors to BLANK
+
+        for (int i = 0; i < image.width*image.height; i++)
+        {
+            if (pixels[i].a > 0)
+            {
+                bool colorInPalette = false;
+
+                // Check if the color is already on palette
+                for (int j = 0; j < maxPaletteSize; j++)
+                {
+                    if (COLOR_EQUAL(pixels[i], palette[j]))
+                    {
+                        colorInPalette = true;
+                        break;
+                    }
+                }
+
+                // Store color if not on the palette
+                if (!colorInPalette)
+                {
+                    palette[palCount] = pixels[i];      // Add pixels[i] to palette
+                    palCount++;
+
+                    // Reached the limit of colors supported by palette
+                    if (palCount >= maxPaletteSize)
+                    {
+                        i = image.width*image.height;   // Finish palette get
+                        TRACELOG(LOG_WARNING, "IMAGE: Palette is greater than %i colors", maxPaletteSize);
+                    }
+                }
+            }
+        }
+
+        UnloadImageColors(pixels);
+    }
+
+    *colorCount = palCount;
+
+    return palette;
+}
+
+// Unload color data loaded with LoadImageColors()
+void UnloadImageColors(Color *colors)
+{
+    RL_FREE(colors);
+}
+
+// Unload colors palette loaded with LoadImagePalette()
+void UnloadImagePalette(Color *colors)
+{
+    RL_FREE(colors);
+}
+
+// Get image alpha border rectangle
+// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f
+Rectangle GetImageAlphaBorder(Image image, float threshold)
+{
+    Rectangle crop = { 0 };
+
+    Color *pixels = LoadImageColors(image);
+
+    if (pixels != NULL)
+    {
+        int xMin = 65536;   // Define a big enough number
+        int xMax = 0;
+        int yMin = 65536;
+        int yMax = 0;
+
+        for (int y = 0; y < image.height; y++)
+        {
+            for (int x = 0; x < image.width; x++)
+            {
+                if (pixels[y*image.width + x].a > (unsigned char)(threshold*255.0f))
+                {
+                    if (x < xMin) xMin = x;
+                    if (x > xMax) xMax = x;
+                    if (y < yMin) yMin = y;
+                    if (y > yMax) yMax = y;
+                }
+            }
+        }
+
+        // Check for empty blank image
+        if ((xMin != 65536) && (xMax != 65536))
+        {
+            crop = (Rectangle){ (float)xMin, (float)yMin, (float)((xMax + 1) - xMin), (float)((yMax + 1) - yMin) };
+        }
+
+        UnloadImageColors(pixels);
+    }
+
+    return crop;
+}
+
+// Get image pixel color at (x, y) position
+Color GetImageColor(Image image, int x, int y)
+{
+    Color color = { 0 };
+
+    if ((x >=0) && (x < image.width) && (y >= 0) && (y < image.height))
+    {
+        switch (image.format)
+        {
+            case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+            {
+                color.r = ((unsigned char *)image.data)[y*image.width + x];
+                color.g = ((unsigned char *)image.data)[y*image.width + x];
+                color.b = ((unsigned char *)image.data)[y*image.width + x];
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+            {
+                color.r = ((unsigned char *)image.data)[(y*image.width + x)*2];
+                color.g = ((unsigned char *)image.data)[(y*image.width + x)*2];
+                color.b = ((unsigned char *)image.data)[(y*image.width + x)*2];
+                color.a = ((unsigned char *)image.data)[(y*image.width + x)*2 + 1];
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+            {
+                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
+
+                color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
+                color.g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31));
+                color.b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31));
+                color.a = (unsigned char)((pixel & 0b0000000000000001)*255);
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+            {
+                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
+
+                color.r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31));
+                color.g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63));
+                color.b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31));
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+            {
+                unsigned short pixel = ((unsigned short *)image.data)[y*image.width + x];
+
+                color.r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15));
+                color.g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15));
+                color.b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15));
+                color.a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15));
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+            {
+                color.r = ((unsigned char *)image.data)[(y*image.width + x)*4];
+                color.g = ((unsigned char *)image.data)[(y*image.width + x)*4 + 1];
+                color.b = ((unsigned char *)image.data)[(y*image.width + x)*4 + 2];
+                color.a = ((unsigned char *)image.data)[(y*image.width + x)*4 + 3];
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+            {
+                color.r = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3];
+                color.g = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 1];
+                color.b = (unsigned char)((unsigned char *)image.data)[(y*image.width + x)*3 + 2];
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R32:
+            {
+                color.r = (unsigned char)(((float *)image.data)[y*image.width + x]*255.0f);
+                color.g = 0;
+                color.b = 0;
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+            {
+                color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*3]*255.0f);
+                color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 1]*255.0f);
+                color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*3 + 2]*255.0f);
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+            {
+                color.r = (unsigned char)(((float *)image.data)[(y*image.width + x)*4]*255.0f);
+                color.g = (unsigned char)(((float *)image.data)[(y*image.width + x)*4 + 1]*255.0f);
+                color.b = (unsigned char)(((float *)image.data)[(y*image.width + x)*4 + 2]*255.0f);
+                color.a = (unsigned char)(((float *)image.data)[(y*image.width + x)*4 + 3]*255.0f);
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R16:
+            {
+                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[y*image.width + x])*255.0f);
+                color.g = 0;
+                color.b = 0;
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+            {
+                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3])*255.0f);
+                color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 1])*255.0f);
+                color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*3 + 2])*255.0f);
+                color.a = 255;
+
+            } break;
+            case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+            {
+                color.r = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4])*255.0f);
+                color.g = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4 + 1])*255.0f);
+                color.b = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4 + 2])*255.0f);
+                color.a = (unsigned char)(HalfToFloat(((unsigned short *)image.data)[(y*image.width + x)*4 + 3])*255.0f);
+
+            } break;
+            default: TRACELOG(LOG_WARNING, "Compressed image format does not support color reading"); break;
+        }
+    }
+    else TRACELOG(LOG_WARNING, "Requested image pixel (%i, %i) out of bounds", x, y);
+
+    return color;
+}
+
+//------------------------------------------------------------------------------------
+// Image drawing functions
+//------------------------------------------------------------------------------------
+// Clear image background with given color
+void ImageClearBackground(Image *dst, Color color)
+{
+    // Security check to avoid program crash
+    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
+
+    // Fill in first pixel based on image format
+    ImageDrawPixel(dst, 0, 0, color);
+
+    unsigned char *pSrcPixel = (unsigned char *)dst->data;
+    int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
+    int totalPixels = dst->width*dst->height;
+
+    // Repeat the first pixel data throughout the image,
+    // doubling the pixels copied on each iteration
+    for (int i = 1; i < totalPixels; i *= 2)
+    {
+        int pixelsToCopy = MIN(i, totalPixels - i);
+        memcpy(pSrcPixel + i*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
+    }
+}
+
+// Draw pixel within an image
+// NOTE: Compressed image formats not supported
+void ImageDrawPixel(Image *dst, int x, int y, Color color)
+{
+    // Security check to avoid program crash
+    if ((dst->data == NULL) || (x < 0) || (x >= dst->width) || (y < 0) || (y >= dst->height)) return;
+
+    switch (dst->format)
+    {
+        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+        {
+            // NOTE: Calculate grayscale equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
+
+            ((unsigned char *)dst->data)[y*dst->width + x] = gray;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+        {
+            // NOTE: Calculate grayscale equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
+
+            ((unsigned char *)dst->data)[(y*dst->width + x)*2] = gray;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*2 + 1] = color.a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+        {
+            // NOTE: Calculate R5G6B5 equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*31.0f));
+            unsigned char g = (unsigned char)(round(coln.y*63.0f));
+            unsigned char b = (unsigned char)(round(coln.z*31.0f));
+
+            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+        {
+            // NOTE: Calculate R5G5B5A1 equivalent color
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*31.0f));
+            unsigned char g = (unsigned char)(round(coln.y*31.0f));
+            unsigned char b = (unsigned char)(round(coln.z*31.0f));
+            unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
+
+            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+        {
+            // NOTE: Calculate R5G5B5A1 equivalent color
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*15.0f));
+            unsigned char g = (unsigned char)(round(coln.y*15.0f));
+            unsigned char b = (unsigned char)(round(coln.z*15.0f));
+            unsigned char a = (unsigned char)(round(coln.w*15.0f));
+
+            ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+        {
+            ((unsigned char *)dst->data)[(y*dst->width + x)*3] = color.r;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 1] = color.g;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 2] = color.b;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+        {
+            ((unsigned char *)dst->data)[(y*dst->width + x)*4] = color.r;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 1] = color.g;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 2] = color.b;
+            ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 3] = color.a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R32:
+        {
+            // NOTE: Calculate grayscale equivalent color (normalized to 32bit)
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            ((float *)dst->data)[y*dst->width + x] = coln.x*0.299f + coln.y*0.587f + coln.z*0.114f;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+        {
+            // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit)
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            ((float *)dst->data)[(y*dst->width + x)*3] = coln.x;
+            ((float *)dst->data)[(y*dst->width + x)*3 + 1] = coln.y;
+            ((float *)dst->data)[(y*dst->width + x)*3 + 2] = coln.z;
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+        {
+            // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit)
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            ((float *)dst->data)[(y*dst->width + x)*4] = coln.x;
+            ((float *)dst->data)[(y*dst->width + x)*4 + 1] = coln.y;
+            ((float *)dst->data)[(y*dst->width + x)*4 + 2] = coln.z;
+            ((float *)dst->data)[(y*dst->width + x)*4 + 3] = coln.w;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16:
+        {
+            // NOTE: Calculate grayscale equivalent color (normalized to 32bit)
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            ((unsigned short*)dst->data)[y*dst->width + x] = FloatToHalf(coln.x*0.299f + coln.y*0.587f + coln.z*0.114f);
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+        {
+            // NOTE: Calculate R32G32B32 equivalent color (normalized to 32bit)
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            ((unsigned short *)dst->data)[(y*dst->width + x)*3] = FloatToHalf(coln.x);
+            ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 1] = FloatToHalf(coln.y);
+            ((unsigned short *)dst->data)[(y*dst->width + x)*3 + 2] = FloatToHalf(coln.z);
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+        {
+            // NOTE: Calculate R32G32B32A32 equivalent color (normalized to 32bit)
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            ((unsigned short *)dst->data)[(y*dst->width + x)*4] = FloatToHalf(coln.x);
+            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 1] = FloatToHalf(coln.y);
+            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 2] = FloatToHalf(coln.z);
+            ((unsigned short *)dst->data)[(y*dst->width + x)*4 + 3] = FloatToHalf(coln.w);
+
+        } break;
+        default: break;
+    }
+}
+
+// Draw pixel within an image (Vector version)
+void ImageDrawPixelV(Image *dst, Vector2 position, Color color)
+{
+    ImageDrawPixel(dst, (int)position.x, (int)position.y, color);
+}
+
+// Draw line within an image
+void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color)
+{
+    // Calculate differences in coordinates
+    int shortLen = endPosY - startPosY;
+    int longLen = endPosX - startPosX;
+    bool yLonger = false;
+
+    // Determine if the line is more vertical than horizontal
+    if (abs(shortLen) > abs(longLen))
+    {
+        // Swap the lengths if the line is more vertical
+        int temp = shortLen;
+        shortLen = longLen;
+        longLen = temp;
+        yLonger = true;
+    }
+
+    // Initialize variables for drawing loop
+    int endVal = longLen + 1;
+    int sgnInc = 1;
+
+    // Adjust direction increment based on longLen sign
+    if (longLen < 0)
+    {
+        longLen = -longLen;
+        sgnInc = -1;
+        endVal -= 2;
+    }
+
+    // Calculate fixed-point increment for shorter length
+    int decInc = (longLen == 0)? 0 : (shortLen << 16)/longLen;
+
+    // Draw the line pixel by pixel
+    if (yLonger)
+    {
+        // If line is more vertical, iterate over y-axis
+		// Init j with 0.5 in 16-bit fixed point (1 << 15) for better rounding.
+        for (int i = 0, j = (1 << 15); i != endVal; i += sgnInc, j += decInc)
+        {
+            // Calculate pixel position and draw it
+            ImageDrawPixel(dst, startPosX + (j >> 16), startPosY + i, color);
+        }
+    }
+    else
+    {
+        // If line is more horizontal, iterate over x-axis
+        for (int i = 0, j = (1 << 15); i != endVal; i += sgnInc, j += decInc)
+        {
+            // Calculate pixel position and draw it
+            ImageDrawPixel(dst, startPosX + i, startPosY + (j >> 16), color);
+        }
+    }
+}
+
+// Draw line within an image (Vector version)
+void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color)
+{
+    // Round start and end positions to nearest integer coordinates
+    int x1 = (int)(start.x + 0.5f);
+    int y1 = (int)(start.y + 0.5f);
+    int x2 = (int)(end.x + 0.5f);
+    int y2 = (int)(end.y + 0.5f);
+
+    // Draw a vertical line using ImageDrawLine function
+    ImageDrawLine(dst, x1, y1, x2, y2, color);
+}
+
+// Draw a line defining thickness within an image
+void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color)
+{
+    // Round start and end positions to nearest integer coordinates
+    int x1 = (int)(start.x + 0.5f);
+    int y1 = (int)(start.y + 0.5f);
+    int x2 = (int)(end.x + 0.5f);
+    int y2 = (int)(end.y + 0.5f);
+
+    // Calculate differences in x and y coordinates
+    int dx = x2 - x1;
+    int dy = y2 - y1;
+
+    // Determine if the line is more horizontal or vertical
+    if ((dx != 0) && (abs(dy/dx) < 1))
+    {
+        // Line is more horizontal
+
+        // How many additional lines to draw
+        int wy = thick - 1;
+
+        // Draw the main line and lower half
+        for (int i = 0; i <= ((wy+1)/2); i++)
+        {
+            ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color);
+        }
+
+        // Draw the upper half
+        for (int i = 1; i <= (wy/2); i++)
+        {
+            ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color);
+        }
+    }
+    else if (dy != 0)
+    {
+        // Line is more vertical or perfectly horizontal
+
+        // How many additional lines to draw
+        int wx = thick - 1;
+
+        //Draw the main line and right half
+        for (int i = 0; i <= ((wx+1)/2); i++)
+        {
+            ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color);
+        }
+
+        // Draw the left half
+        for (int i = 1; i <= (wx/2); i++)
+        {
+            ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color);
+        }
+    }
+}
+
+// Draw a lines sequence within an image
+void ImageDrawLineStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
+{
+    for (int i = 0; i < pointCount - 1; i++)
+    {
+        ImageDrawLineV(dst, points[i], points[i + 1], color);
+    }
+}
+
+// Draw triangle within an image
+void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color)
+{
+    // Calculate the 2D bounding box of the triangle
+    // Determine the minimum and maximum x and y coordinates of the triangle vertices
+    int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x));
+    int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y));
+    int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x));
+    int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y));
+
+    // Clamp the bounding box to the image dimensions
+    if (xMin < 0) xMin = 0;
+    if (yMin < 0) yMin = 0;
+    if (xMax > dst->width) xMax = dst->width;
+    if (yMax > dst->height) yMax = dst->height;
+
+    // Check the order of the vertices to determine if it's a front or back face
+    // NOTE: if signedArea is equal to 0, the face is degenerate
+    float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y);
+    bool isBackFace = (signedArea > 0);
+
+    // Barycentric interpolation setup
+    // Calculate the step increments for the barycentric coordinates
+    int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x);
+    int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x);
+    int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x);
+
+    // If the triangle is a back face, invert the steps
+    if (isBackFace)
+    {
+        w1XStep = -w1XStep, w1YStep = -w1YStep;
+        w2XStep = -w2XStep, w2YStep = -w2YStep;
+        w3XStep = -w3XStep, w3YStep = -w3YStep;
+    }
+
+    // Calculate the initial barycentric coordinates for the top-left point of the bounding box
+    int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y));
+    int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y));
+    int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y));
+
+    // Rasterization loop
+    // Iterate through each pixel in the bounding box
+    for (int y = yMin; y <= yMax; y++)
+    {
+        int w1 = w1Row;
+        int w2 = w2Row;
+        int w3 = w3Row;
+
+        for (int x = xMin; x <= xMax; x++)
+        {
+            // Check if the pixel is inside the triangle using barycentric coordinates
+            // If it is, the pixel can be drawn with the given color
+            if ((w1 | w2 | w3) >= 0) ImageDrawPixel(dst, x, y, color);
+
+            // Increment the barycentric coordinates for the next pixel
+            w1 += w1XStep;
+            w2 += w2XStep;
+            w3 += w3XStep;
+        }
+
+        // Move to the next row in the bounding box
+        w1Row += w1YStep;
+        w2Row += w2YStep;
+        w3Row += w3YStep;
+    }
+}
+
+// Draw triangle with interpolated colors within an image
+void ImageDrawTriangleGradient(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3)
+{
+    // Calculate the 2D bounding box of the triangle
+    // Determine the minimum and maximum x and y coordinates of the triangle vertices
+    int xMin = (int)((v1.x < v2.x)? ((v1.x < v3.x)? v1.x : v3.x) : ((v2.x < v3.x)? v2.x : v3.x));
+    int yMin = (int)((v1.y < v2.y)? ((v1.y < v3.y)? v1.y : v3.y) : ((v2.y < v3.y)? v2.y : v3.y));
+    int xMax = (int)((v1.x > v2.x)? ((v1.x > v3.x)? v1.x : v3.x) : ((v2.x > v3.x)? v2.x : v3.x));
+    int yMax = (int)((v1.y > v2.y)? ((v1.y > v3.y)? v1.y : v3.y) : ((v2.y > v3.y)? v2.y : v3.y));
+
+    // Clamp the bounding box to the image dimensions
+    if (xMin < 0) xMin = 0;
+    if (yMin < 0) yMin = 0;
+    if (xMax > dst->width) xMax = dst->width;
+    if (yMax > dst->height) yMax = dst->height;
+
+    // Check the order of the vertices to determine if it's a front or back face
+    // NOTE: if signedArea is equal to 0, the face is degenerate
+    float signedArea = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y);
+    bool isBackFace = (signedArea > 0);
+
+    // Barycentric interpolation setup
+    // Calculate the step increments for the barycentric coordinates
+    int w1XStep = (int)(v3.y - v2.y), w1YStep = (int)(v2.x - v3.x);
+    int w2XStep = (int)(v1.y - v3.y), w2YStep = (int)(v3.x - v1.x);
+    int w3XStep = (int)(v2.y - v1.y), w3YStep = (int)(v1.x - v2.x);
+
+    // If the triangle is a back face, invert the steps
+    if (isBackFace)
+    {
+        w1XStep = -w1XStep, w1YStep = -w1YStep;
+        w2XStep = -w2XStep, w2YStep = -w2YStep;
+        w3XStep = -w3XStep, w3YStep = -w3YStep;
+    }
+
+    // Calculate the initial barycentric coordinates for the top-left point of the bounding box
+    int w1Row = (int)((xMin - v2.x)*w1XStep + w1YStep*(yMin - v2.y));
+    int w2Row = (int)((xMin - v3.x)*w2XStep + w2YStep*(yMin - v3.y));
+    int w3Row = (int)((xMin - v1.x)*w3XStep + w3YStep*(yMin - v1.y));
+
+    // Calculate the inverse of the sum of the barycentric coordinates for normalization
+    float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
+
+    // Rasterization loop
+    // Iterate through each pixel in the bounding box
+    for (int y = yMin; y <= yMax; y++)
+    {
+        int w1 = w1Row;
+        int w2 = w2Row;
+        int w3 = w3Row;
+
+        for (int x = xMin; x <= xMax; x++)
+        {
+            // Check if the pixel is inside the triangle using barycentric coordinates
+            if ((w1 | w2 | w3) >= 0)
+            {
+                // Compute the normalized barycentric coordinates
+                unsigned char aW1 = (unsigned char)((float)w1*wInvSum);
+                unsigned char aW2 = (unsigned char)((float)w2*wInvSum);
+                unsigned char aW3 = (unsigned char)((float)w3*wInvSum);
+
+                // Interpolate the color using the barycentric coordinates
+                Color finalColor = { 0 };
+                finalColor.r = (c1.r*aW1 + c2.r*aW2 + c3.r*aW3)/255;
+                finalColor.g = (c1.g*aW1 + c2.g*aW2 + c3.g*aW3)/255;
+                finalColor.b = (c1.b*aW1 + c2.b*aW2 + c3.b*aW3)/255;
+                finalColor.a = (c1.a*aW1 + c2.a*aW2 + c3.a*aW3)/255;
+
+                // Draw the pixel with the interpolated color
+                ImageDrawPixel(dst, x, y, finalColor);
+            }
+
+            // Increment the barycentric coordinates for the next pixel
+            w1 += w1XStep;
+            w2 += w2XStep;
+            w3 += w3XStep;
+        }
+
+        // Move to the next row in the bounding box
+        w1Row += w1YStep;
+        w2Row += w2YStep;
+        w3Row += w3YStep;
+    }
+}
+
+// Draw triangle outline within an image
+void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color)
+{
+    ImageDrawLine(dst, (int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, color);
+    ImageDrawLine(dst, (int)v2.x, (int)v2.y, (int)v3.x, (int)v3.y, color);
+    ImageDrawLine(dst, (int)v3.x, (int)v3.y, (int)v1.x, (int)v1.y, color);
+}
+
+// Draw a triangle fan defined by points within an image (first vertex is the center)
+void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
+{
+    if (pointCount >= 3)
+    {
+        for (int i = 1; i < pointCount - 1; i++)
+        {
+            ImageDrawTriangle(dst, points[0], points[i], points[i + 1], color);
+        }
+    }
+}
+
+// Draw a triangle strip defined by points within an image
+void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
+{
+    if (pointCount >= 3)
+    {
+        for (int i = 2; i < pointCount; i++)
+        {
+            if ((i%2) == 0) ImageDrawTriangle(dst, points[i], points[i - 2], points[i - 1], color);
+            else ImageDrawTriangle(dst, points[i], points[i - 1], points[i - 2], color);
+        }
+    }
+}
+
+// Draw rectangle within an image
+void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color)
+{
+    ImageDrawRectangleRec(dst, (Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color);
+}
+
+// Draw rectangle within an image (Vector version)
+void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color)
+{
+    ImageDrawRectangle(dst, (int)position.x, (int)position.y, (int)size.x, (int)size.y, color);
+}
+
+// Draw rectangle within an image
+void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
+{
+    // Security check to avoid program crash
+    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
+
+    // Security check to avoid drawing out of bounds in case of bad user data
+    if (rec.x < 0) { rec.width += rec.x; rec.x = 0; }
+    if (rec.y < 0) { rec.height += rec.y; rec.y = 0; }
+    if (rec.width < 0) rec.width = 0;
+    if (rec.height < 0) rec.height = 0;
+
+    // Clamp the size the the image bounds
+    if ((rec.x + rec.width) >= dst->width) rec.width = dst->width - rec.x;
+    if ((rec.y + rec.height) >= dst->height) rec.height = dst->height - rec.y;
+
+    // Check if the rect is even inside the image
+    if ((rec.x >= dst->width) || (rec.y >= dst->height)) return;
+    if (((rec.x + rec.width) <= 0) || (rec.y + rec.height <= 0)) return;
+
+    int sy = (int)rec.y;
+    int sx = (int)rec.x;
+
+    int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
+
+    // Fill in the first pixel of the first row based on image format
+    ImageDrawPixel(dst, sx, sy, color);
+
+    int bytesOffset = ((sy*dst->width) + sx)*bytesPerPixel;
+    unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
+
+    // Repeat the first pixel data throughout the row
+    for (int x = 1; x < (int)rec.width; x *= 2)
+    {
+        int pixelsToCopy = MIN(x, (int)rec.width - x);
+        memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
+    }
+
+    // Repeat the first row data for all other rows
+    int bytesPerRow = bytesPerPixel*(int)rec.width;
+    for (int y = 1; y < (int)rec.height; y++)
+    {
+        memcpy(pSrcPixel + (y*dst->width)*bytesPerPixel, pSrcPixel, bytesPerRow);
+    }
+}
+
+// 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)
+{
+    Rectangle rec = { (float)posX, (float)posY, (float)width, (float)height };
+    ImageDrawRectangleLinesEx(dst, rec, 1, color);
+}
+
+// Draw rectangle lines within an image with line thickness
+void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color)
+{
+    ImageDrawRectangle(dst, (int)rec.x, (int)rec.y, (int)rec.width, thick, color);
+    ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color);
+    ImageDrawRectangle(dst, (int)(rec.x + rec.width - thick), (int)(rec.y + thick), thick, (int)(rec.height - thick*2), 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)
+{
+    int x = 0;
+    int y = radius;
+    int decesionParameter = 3 - 2*radius;
+
+    while (y >= x)
+    {
+        ImageDrawRectangle(dst, centerX - x, centerY + y, x*2 + 1, 1, color);
+        ImageDrawRectangle(dst, centerX - x, centerY - y, x*2 + 1, 1, color);
+        ImageDrawRectangle(dst, centerX - y, centerY + x, y*2 + 1, 1, color);
+        ImageDrawRectangle(dst, centerX - y, centerY - x, y*2 + 1, 1, color);
+        x++;
+
+        if (decesionParameter > 0)
+        {
+            y--;
+            decesionParameter = decesionParameter + 4*(x - y) + 10;
+        }
+        else decesionParameter = decesionParameter + 4*x + 6;
+    }
+}
+
+// Draw circle within an image (Vector version)
+void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color)
+{
+    ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color);
+}
+
+// Draw circle outline within an image
+void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color)
+{
+    int x = 0;
+    int y = radius;
+    int decesionParameter = 3 - 2*radius;
+
+    while (y >= x)
+    {
+        ImageDrawPixel(dst, centerX + x, centerY + y, color);
+        ImageDrawPixel(dst, centerX - x, centerY + y, color);
+        ImageDrawPixel(dst, centerX + x, centerY - y, color);
+        ImageDrawPixel(dst, centerX - x, centerY - y, color);
+        ImageDrawPixel(dst, centerX + y, centerY + x, color);
+        ImageDrawPixel(dst, centerX - y, centerY + x, color);
+        ImageDrawPixel(dst, centerX + y, centerY - x, color);
+        ImageDrawPixel(dst, centerX - y, centerY - x, color);
+        x++;
+
+        if (decesionParameter > 0)
+        {
+            y--;
+            decesionParameter = decesionParameter + 4*(x - y) + 10;
+        }
+        else decesionParameter = decesionParameter + 4*x + 6;
+    }
+}
+
+// Draw circle outline within an image (Vector version)
+void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color)
+{
+    ImageDrawCircleLines(dst, (int)center.x, (int)center.y, radius, color);
+}
+
+// Draw a gradient-filled circle within an image
+void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer)
+{
+    // TODO: NEW: Implement ImageDrawCircleGradient()
+}
+
+// Draw an image within an image
+void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint)
+{
+    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);
+}
+
+// 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)
+{
+    Rectangle dstRec = { position.x, position.y, srcRec.width, srcRec.height };
+    ImageDrawImagePro(dst, src, srcRec, dstRec, (Vector2){ 0 }, 0.0f, tint);
+}
+
+// Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image
+// 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
+    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) ||
+        (src.data == NULL) || (src.width == 0) || (src.height == 0)) return;
+
+    if (dst->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image drawing not supported for compressed formats");
+    else
+    {
+        Image srcMod = { 0 };       // Source copy (in case it was required)
+        Image *srcPtr = &src;       // Pointer to source image
+        bool useSrcMod = false;     // Track source copy required
+
+        // Source rectangle out-of-bounds security checks
+        if (srcRec.x < 0) { srcRec.width += srcRec.x; srcRec.x = 0; }
+        if (srcRec.y < 0) { srcRec.height += srcRec.y; srcRec.y = 0; }
+        if ((srcRec.x + srcRec.width) > src.width) srcRec.width = src.width - srcRec.x;
+        if ((srcRec.y + srcRec.height) > src.height) srcRec.height = src.height - srcRec.y;
+
+        // Check if source rectangle needs to be resized to destination rectangle
+        // In that case, make a copy of source, and apply all required transform
+        if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height))
+        {
+            srcMod = ImageFromImage(src, srcRec); // Create image from another image
+            ImageResize(&srcMod, (int)dstRec.width, (int)dstRec.height); // Resize to destination rectangle
+            srcRec = (Rectangle){ 0, 0, (float)srcMod.width, (float)srcMod.height };
+
+            srcPtr = &srcMod;
+            useSrcMod = true;
+        }
+
+        // Destination rectangle out-of-bounds security checks
+        if (dstRec.x < 0)
+        {
+            srcRec.x -= dstRec.x;
+            srcRec.width += dstRec.x;
+            dstRec.x = 0;
+        }
+        else if ((dstRec.x + srcRec.width) > dst->width) srcRec.width = dst->width - dstRec.x;
+
+        if (dstRec.y < 0)
+        {
+            srcRec.y -= dstRec.y;
+            srcRec.height += dstRec.y;
+            dstRec.y = 0;
+        }
+        else if ((dstRec.y + srcRec.height) > dst->height) srcRec.height = dst->height - dstRec.y;
+
+        if (dst->width < srcRec.width) srcRec.width = (float)dst->width;
+        if (dst->height < srcRec.height) srcRec.height = (float)dst->height;
+
+        // This blitting method is quite fast! The process followed is:
+        // for every pixel -> [get_src_format/get_dst_format -> blend -> format_to_dst]
+        // Some optimization ideas:
+        //    [x] Avoid creating source copy if not required (no resize required)
+        //    [x] Optimize ImageResize() for pixel format (alternative: ImageResizeNN())
+        //    [x] Optimize ColorAlphaBlend() to avoid processing (alpha = 0) and (alpha = 1)
+        //    [x] Optimize ColorAlphaBlend() for faster operations (maybe avoiding divs?)
+        //    [x] Consider fast path: no alpha blending required cases (src has no alpha)
+        //    [x] Consider fast path: same src/dst format with no alpha -> direct line copy
+        //    [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
+        //    [-] Support 16bit and 32bit (float) channels drawing
+
+        Color colSrc = { 0 };
+        Color colDst = { 0 };
+        Color blend = { 0 };
+        bool blendRequired = true;
+
+        // Fast path: Avoid blend if source has no alpha to blend
+        if ((tint.a == 255) &&
+            ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16) ||
+            (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16G16B16)))
+            blendRequired = false;
+
+        int strideDst = GetPixelDataSize(dst->width, 1, dst->format);
+        int bytesPerPixelDst = strideDst/(dst->width);
+
+        int strideSrc = GetPixelDataSize(srcPtr->width, 1, srcPtr->format);
+        int bytesPerPixelSrc = strideSrc/(srcPtr->width);
+
+        unsigned char *pSrcBase = (unsigned char *)srcPtr->data + ((int)srcRec.y*srcPtr->width + (int)srcRec.x)*bytesPerPixelSrc;
+        unsigned char *pDstBase = (unsigned char *)dst->data + ((int)dstRec.y*dst->width + (int)dstRec.x)*bytesPerPixelDst;
+
+        for (int y = 0; y < (int)srcRec.height; y++)
+        {
+            unsigned char *pSrc = pSrcBase;
+            unsigned char *pDst = pDstBase;
+
+            // Fast path: Avoid moving pixel by pixel if no blend required and same format
+            if (!blendRequired && (srcPtr->format == dst->format)) memcpy(pDst, pSrc, (int)(srcRec.width)*bytesPerPixelSrc);
+            else
+            {
+                for (int x = 0; x < (int)srcRec.width; x++)
+                {
+                    colSrc = GetPixelColor(pSrc, srcPtr->format);
+                    colDst = GetPixelColor(pDst, dst->format);
+
+                    // Fast path: Avoid blend if source has no alpha to blend
+                    if (blendRequired) blend = ColorAlphaBlend(colDst, colSrc, tint);
+                    else blend = colSrc;
+
+                    SetPixelColor(pDst, blend, dst->format);
+
+                    pDst += bytesPerPixelDst;
+                    pSrc += bytesPerPixelSrc;
+                }
+            }
+
+            pSrcBase += strideSrc;
+            pDstBase += strideDst;
+        }
+
+        if (useSrcMod) UnloadImage(srcMod);     // Unload source modified image
+
+        if ((dst->mipmaps > 1) && (src.mipmaps > 1))
+        {
+            Image mipmapDst = *dst;
+            mipmapDst.data = (char *)mipmapDst.data + GetPixelDataSize(mipmapDst.width, mipmapDst.height, mipmapDst.format);
+            mipmapDst.width /= 2;
+            mipmapDst.height /= 2;
+            mipmapDst.mipmaps--;
+
+            Image mipmapSrc = src;
+            mipmapSrc.data = (char *)mipmapSrc.data + GetPixelDataSize(mipmapSrc.width, mipmapSrc.height, mipmapSrc.format);
+            mipmapSrc.width /= 2;
+            mipmapSrc.height /= 2;
+            mipmapSrc.mipmaps--;
+
+            Rectangle mipmapSrcRec = srcRec;
+            mipmapSrcRec.width /= 2;
+            mipmapSrcRec.height /= 2;
+            mipmapSrcRec.x /= 2;
+            mipmapSrcRec.y /= 2;
+
+            Rectangle mipmapDstRec = dstRec;
+            mipmapDstRec.width /= 2;
+            mipmapDstRec.height /= 2;
+            mipmapDstRec.x /= 2;
+            mipmapDstRec.y /= 2;
+
+            ImageDrawImagePro(&mipmapDst, mipmapSrc, mipmapSrcRec, mipmapDstRec, (Vector2){ 0 }, 0.0f, tint);
+        }
+    }
+}
+
+// Draw text (default font) within an image (destination)
+void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
+{
+#if SUPPORT_MODULE_RTEXT
+    // Make sure default font is loaded to be used on image text drawing
+    if (GetFontDefault().texture.id == 0) LoadFontDefault();
+
+    Vector2 position = { (float)posX, (float)posY };
+    ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, 1.0f, color);   // WARNING: Module required: rtext
+#else
+    TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext");
+#endif
+}
+
+// Draw text (custom sprite font) within an image (destination)
+void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
+{
+    Image imText = ImageTextEx(font, text, fontSize, spacing, tint);
+
+    Rectangle srcRec = { 0.0f, 0.0f, (float)imText.width, (float)imText.height };
+    Rectangle dstRec = { position.x, position.y, (float)imText.width, (float)imText.height };
+
+    ImageDrawImagePro(dst, imText, srcRec, dstRec, (Vector2){ 0 }, 0.0f, WHITE);
+
+    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 ImageDrawTextPro()
+}
+
+//------------------------------------------------------------------------------------
+// Texture loading functions
+//------------------------------------------------------------------------------------
+// Load texture from file into GPU memory (VRAM)
+Texture2D LoadTexture(const char *fileName)
+{
+    Texture2D texture = { 0 };
+
+    Image image = LoadImage(fileName);
+
+    if (image.data != NULL)
+    {
+        texture = LoadTextureFromImage(image);
+        UnloadImage(image);
+    }
+
+    return texture;
+}
+
+// Load a texture from image data
+// NOTE: image is not unloaded, it must be done manually
+Texture2D LoadTextureFromImage(Image image)
+{
+    Texture2D texture = { 0 };
+
+    if ((image.width != 0) && (image.height != 0))
+    {
+        texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
+    }
+    else TRACELOG(LOG_WARNING, "IMAGE: Data is not valid to load texture");
+
+    texture.width = image.width;
+    texture.height = image.height;
+    texture.mipmaps = image.mipmaps;
+    texture.format = image.format;
+
+    return texture;
+}
+
+// Load cubemap from image, multiple image cubemap layouts supported
+TextureCubemap LoadTextureCubemap(Image image, int layout)
+{
+    TextureCubemap cubemap = { 0 };
+
+    if (layout == CUBEMAP_LAYOUT_AUTO_DETECT) // Try to automatically guess layout type
+    {
+        // Check image width/height to determine the type of cubemap provided
+        if (image.width > image.height)
+        {
+            if ((image.width/6) == image.height) { layout = CUBEMAP_LAYOUT_LINE_HORIZONTAL; cubemap.width = image.width/6; }
+            else if ((image.width/4) == (image.height/3)) { layout = CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
+        }
+        else if (image.height > image.width)
+        {
+            if ((image.height/6) == image.width) { layout = CUBEMAP_LAYOUT_LINE_VERTICAL; cubemap.width = image.height/6; }
+            else if ((image.width/3) == (image.height/4)) { layout = CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
+        }
+    }
+    else
+    {
+        if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL) cubemap.width = image.height/6;
+        if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) cubemap.width = image.width/6;
+        if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR) cubemap.width = image.width/3;
+        if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE) cubemap.width = image.width/4;
+    }
+
+    cubemap.height = cubemap.width;
+
+    // Layout provided or already auto-detected
+    if (layout != CUBEMAP_LAYOUT_AUTO_DETECT)
+    {
+        int size = cubemap.width;
+
+        Image faces = { 0 };                // Vertical column image
+        Rectangle faceRecs[6] = { 0 };      // Face source rectangles
+
+        for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, (float)size, (float)size };
+
+        if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
+        {
+            faces = ImageCopy(image);       // Image data already follows expected convention
+        }
+        /*else if (layout == CUBEMAP_LAYOUT_PANORAMA)
+        {
+            // TODO: Implement panorama by converting image to square faces...
+            // REF: https://github.com/denivip/panorama/blob/master/panorama.cpp
+        } */
+        else
+        {
+            if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = (float)size*i;
+            else if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR)
+            {
+                faceRecs[0].x = (float)size; faceRecs[0].y = (float)size;
+                faceRecs[1].x = (float)size; faceRecs[1].y = (float)size*3;
+                faceRecs[2].x = (float)size; faceRecs[2].y = 0;
+                faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
+                faceRecs[4].x = 0; faceRecs[4].y = (float)size;
+                faceRecs[5].x = (float)size*2; faceRecs[5].y = (float)size;
+            }
+            else if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE)
+            {
+                faceRecs[0].x = (float)size*2; faceRecs[0].y = (float)size;
+                faceRecs[1].x = 0; faceRecs[1].y = (float)size;
+                faceRecs[2].x = (float)size; faceRecs[2].y = 0;
+                faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2;
+                faceRecs[4].x = (float)size; faceRecs[4].y = (float)size;
+                faceRecs[5].x = (float)size*3; faceRecs[5].y = (float)size;
+            }
+
+            // Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
+            // NOTE: Image formatting does not work with compressed textures
+            faces = GenImageColor(size, size*6, MAGENTA);
+            ImageFormat(&faces, image.format);
+
+            Image mipmapped = ImageCopy(image);
+            if (image.mipmaps > 1)
+            {
+                ImageMipmaps(&mipmapped);
+                ImageMipmaps(&faces);
+            }
+
+            for (int i = 0; i < 6; i++) ImageDrawImagePro(&faces, mipmapped, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, (Vector2){ 0 }, 0.0f, WHITE);
+
+            UnloadImage(mipmapped);
+        }
+
+        // NOTE: Cubemap data is expected to be provided as 6 images in a single data array,
+        // one after the other (that's a vertical image), following convention: +X, -X, +Y, -Y, +Z, -Z
+        cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format, faces.mipmaps);
+
+        if (cubemap.id != 0)
+        {
+            cubemap.format = faces.format;
+            cubemap.mipmaps = faces.mipmaps;
+        }
+        else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
+
+        UnloadImage(faces);
+    }
+    else TRACELOG(LOG_WARNING, "IMAGE: Failed to detect cubemap image layout");
+
+    return cubemap;
+}
+
+// Load RGBA texture for rendering (framebuffer)
+RenderTexture2D LoadRenderTexture(int width, int height)
+{
+    return LoadRenderTextureEx(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
+}
+
+// Load texture for rendering (framebuffer), with specific format
+// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
+RLAPI RenderTexture2D LoadRenderTextureEx(int width, int height, int format)
+{
+    RenderTexture2D target = { 0 };
+
+    if (format >= PIXELFORMAT_COMPRESSED_DXT1_RGB)
+    {
+        TRACELOG(LOG_WARNING, "FBO: Render texture format not supported");
+        return target;
+    }
+
+    target.id = rlLoadFramebuffer(); // Load an empty framebuffer
+
+    if (target.id > 0)
+    {
+        rlEnableFramebuffer(target.id);
+
+        // Create color texture (default to RGBA)
+        target.texture.id = rlLoadTexture(NULL, width, height, format, 1);
+        target.texture.width = width;
+        target.texture.height = height;
+        target.texture.format = format;
+        target.texture.mipmaps = 1;
+
+        // Create depth renderbuffer/texture
+        target.depth.id = rlLoadTextureDepth(width, height, true);
+        target.depth.width = width;
+        target.depth.height = height;
+        target.depth.format = 19;       //DEPTH_COMPONENT_24BIT?
+        target.depth.mipmaps = 1;
+
+        // Attach color texture and depth renderbuffer/texture to FBO
+        rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
+        rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
+
+        // Check if fbo is complete with attachments (valid)
+        if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
+
+        rlDisableFramebuffer();
+    }
+    else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
+
+    return target;
+}
+
+// Check if texture is valid (loaded in GPU)
+bool IsTextureValid(Texture2D texture)
+{
+    bool result = false;
+
+    if ((texture.id > 0) &&         // Validate OpenGL id (texture uploaded to GPU)
+        (texture.width > 0) &&      // Validate texture width
+        (texture.height > 0) &&     // Validate texture height
+        (texture.format > 0) &&     // Validate texture pixel format
+        (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level)
+
+    return result;
+}
+
+// Unload texture from GPU memory (VRAM)
+void UnloadTexture(Texture2D texture)
+{
+    if (texture.id > 0)
+    {
+        rlUnloadTexture(texture.id);
+
+        TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded texture data from VRAM (GPU)", texture.id);
+    }
+}
+
+// Check if render texture is valid (loaded in GPU)
+bool IsRenderTextureValid(RenderTexture2D target)
+{
+    bool result = false;
+
+    if ((target.id > 0) &&                  // Validate OpenGL id (loaded on GPU)
+        IsTextureValid(target.depth) &&     // Validate FBO depth texture/renderbuffer attachment
+        IsTextureValid(target.texture)) result = true; // Validate FBO texture attachment
+
+    return result;
+}
+
+// Unload render texture from GPU memory (VRAM)
+void UnloadRenderTexture(RenderTexture2D target)
+{
+    if (target.id > 0)
+    {
+        if (target.texture.id > 0)
+        {
+            // Color texture attached to FBO is deleted
+            rlUnloadTexture(target.texture.id);
+        }
+
+        // NOTE: Depth texture/renderbuffer is automatically
+        // queried and deleted before deleting framebuffer
+        rlUnloadFramebuffer(target.id);
+    }
+}
+
+// Update GPU texture with new data
+// NOTE 1: pixels data must match texture.format
+// NOTE 2: pixels data must contain at least as many pixels as texture
+void UpdateTexture(Texture2D texture, const void *pixels)
+{
+    rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
+}
+
+// Update GPU texture rectangle with new data
+// NOTE 1: pixels data must match texture.format
+// NOTE 2: pixels data must contain as many pixels as rec contains
+// NOTE 3: rec must fit completely within texture's width and height
+void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
+{
+    rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
+}
+
+//------------------------------------------------------------------------------------
+// Texture configuration functions
+//------------------------------------------------------------------------------------
+// Generate GPU mipmaps for a texture
+void GenTextureMipmaps(Texture2D *texture)
+{
+    // NOTE: NPOT textures support check inside function
+    // On WebGL (OpenGL ES 2.0) NPOT textures support is limited
+    rlGenTextureMipmaps(texture->id, texture->width, texture->height, texture->format, &texture->mipmaps);
+}
+
+// Set texture scaling filter mode
+void SetTextureFilter(Texture2D texture, int filter)
+{
+    switch (filter)
+    {
+        case TEXTURE_FILTER_POINT:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_TEXTURE_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_NEAREST);
+
+                // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
+            }
+            else
+            {
+                // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_NEAREST);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST);
+            }
+        } break;
+        case TEXTURE_FILTER_BILINEAR:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
+                // Alternative: RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST);
+
+                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
+            }
+            else
+            {
+                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
+            }
+        } break;
+        case TEXTURE_FILTER_TRILINEAR:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_TEXTURE_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR);
+
+                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
+            }
+            else
+            {
+                TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
+
+                // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
+            }
+        } break;
+        case TEXTURE_FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 4); break;
+        case TEXTURE_FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 8); break;
+        case TEXTURE_FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 16); break;
+        default: break;
+    }
+}
+
+// Set texture wrapping mode
+void SetTextureWrap(Texture2D texture, int wrap)
+{
+    switch (wrap)
+    {
+        case TEXTURE_WRAP_REPEAT:
+        {
+            // NOTE: It only works if NPOT textures are supported, i.e. OpenGL ES 2.0 could not support it
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT);
+        } break;
+        case TEXTURE_WRAP_CLAMP:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_CLAMP);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_CLAMP);
+        } break;
+        case TEXTURE_WRAP_MIRROR_REPEAT:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_REPEAT);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_REPEAT);
+        } break;
+        case TEXTURE_WRAP_MIRROR_CLAMP:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_CLAMP);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_CLAMP);
+        } break;
+        default: break;
+    }
+}
+
+//------------------------------------------------------------------------------------
+// Texture drawing functions
+//------------------------------------------------------------------------------------
+// Draw a texture
+void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
+{
+    DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY }, 0.0f, 1.0f, tint);
+}
+
+// Draw a texture with position defined as Vector2
+void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
+{
+    DrawTextureEx(texture, position, 0, 1.0f, tint);
+}
+
+// Draw a texture with rotation and scale
+void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
+{
+    Rectangle srcrec = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
+    Rectangle dstrec = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale };
+    Vector2 origin = { 0.0f, 0.0f };
+
+    DrawTexturePro(texture, srcrec, dstrec, origin, rotation, tint);
+}
+
+// Draw a part of a texture (defined by a rectangle)
+void DrawTextureRec(Texture2D texture, Rectangle rec, Vector2 position, Color tint)
+{
+    Rectangle dstrec = { position.x, position.y, fabsf(rec.width), fabsf(rec.height) };
+    Vector2 origin = { 0.0f, 0.0f };
+
+    DrawTexturePro(texture, rec, dstrec, origin, 0.0f, tint);
+}
+
+// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
+// NOTE: origin is relative to destination rectangle size
+void DrawTexturePro(Texture2D texture, Rectangle srcrec, Rectangle dstrec, Vector2 origin, float rotation, Color tint)
+{
+    // Check if texture is valid
+    if (texture.id > 0)
+    {
+        float width = (float)texture.width;
+        float height = (float)texture.height;
+
+        bool flipX = false;
+
+        if (srcrec.width < 0) { flipX = true; srcrec.width *= -1; }
+        if (srcrec.height < 0) srcrec.y -= srcrec.height;
+
+        if (dstrec.width < 0) dstrec.width *= -1;
+        if (dstrec.height < 0) dstrec.height *= -1;
+
+        Vector2 topLeft = { 0 };
+        Vector2 topRight = { 0 };
+        Vector2 bottomLeft = { 0 };
+        Vector2 bottomRight = { 0 };
+
+        // Only calculate rotation if needed
+        if (rotation == 0.0f)
+        {
+            float x = dstrec.x - origin.x;
+            float y = dstrec.y - origin.y;
+            topLeft = (Vector2){ x, y };
+            topRight = (Vector2){ x + dstrec.width, y };
+            bottomLeft = (Vector2){ x, y + dstrec.height };
+            bottomRight = (Vector2){ x + dstrec.width, y + dstrec.height };
+        }
+        else
+        {
+            float sinRotation = sinf(rotation*DEG2RAD);
+            float cosRotation = cosf(rotation*DEG2RAD);
+            float x = dstrec.x;
+            float y = dstrec.y;
+            float dx = -origin.x;
+            float dy = -origin.y;
+
+            topLeft.x = x + dx*cosRotation - dy*sinRotation;
+            topLeft.y = y + dx*sinRotation + dy*cosRotation;
+
+            topRight.x = x + (dx + dstrec.width)*cosRotation - dy*sinRotation;
+            topRight.y = y + (dx + dstrec.width)*sinRotation + dy*cosRotation;
+
+            bottomLeft.x = x + dx*cosRotation - (dy + dstrec.height)*sinRotation;
+            bottomLeft.y = y + dx*sinRotation + (dy + dstrec.height)*cosRotation;
+
+            bottomRight.x = x + (dx + dstrec.width)*cosRotation - (dy + dstrec.height)*sinRotation;
+            bottomRight.y = y + (dx + dstrec.width)*sinRotation + (dy + dstrec.height)*cosRotation;
+        }
+
+        rlSetTexture(texture.id);
+        rlBegin(RL_QUADS);
+
+            rlColor4ub(tint.r, tint.g, tint.b, tint.a);
+            rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
+
+            // Top-left corner for texture and quad
+            if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
+            else rlTexCoord2f(srcrec.x/width, srcrec.y/height);
+            rlVertex2f(topLeft.x, topLeft.y);
+
+            // Bottom-left corner for texture and quad
+            if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
+            else rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
+            rlVertex2f(bottomLeft.x, bottomLeft.y);
+
+            // Bottom-right corner for texture and quad
+            if (flipX) rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
+            else rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
+            rlVertex2f(bottomRight.x, bottomRight.y);
+
+            // Top-right corner for texture and quad
+            if (flipX) rlTexCoord2f(srcrec.x/width, srcrec.y/height);
+            else rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
+            rlVertex2f(topRight.x, topRight.y);
+
+        rlEnd();
+        rlSetTexture(0);
+
+        // NOTE: Vertex position can be transformed using matrices
+        // but the process is way more costly than calculating
+        // the vertex positions manually, like done above
+        // Old implementation is left here for educational purposes,
+        // in case someone wants to do some performance test
+        /*
+        rlSetTexture(texture.id);
+        rlPushMatrix();
+            rlTranslatef(dstrec.x, dstrec.y, 0.0f);
+            if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
+            rlTranslatef(-origin.x, -origin.y, 0.0f);
+
+            rlBegin(RL_QUADS);
+                rlColor4ub(tint.r, tint.g, tint.b, tint.a);
+                rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
+
+                // Bottom-left corner for texture and quad
+                if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
+                else rlTexCoord2f(srcrec.x/width, srcrec.y/height);
+                rlVertex2f(0.0f, 0.0f);
+
+                // Bottom-right corner for texture and quad
+                if (flipX) rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
+                else rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
+                rlVertex2f(0.0f, dstrec.height);
+
+                // Top-right corner for texture and quad
+                if (flipX) rlTexCoord2f(srcrec.x/width, (srcrec.y + srcrec.height)/height);
+                else rlTexCoord2f((srcrec.x + srcrec.width)/width, (srcrec.y + srcrec.height)/height);
+                rlVertex2f(dstrec.width, dstrec.height);
+
+                // Top-left corner for texture and quad
+                if (flipX) rlTexCoord2f(srcrec.x/width, srcrec.y/height);
+                else rlTexCoord2f((srcrec.x + srcrec.width)/width, srcrec.y/height);
+                rlVertex2f(dstrec.width, 0.0f);
+            rlEnd();
+        rlPopMatrix();
+        rlSetTexture(0);
+        */
+    }
+}
+
+// Draw a texture (or part of it) that stretches or shrinks nicely using n-patch info
+void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dstrec, Vector2 origin, float rotation, Color tint)
+{
+    if (texture.id > 0)
+    {
+        float width = (float)texture.width;
+        float height = (float)texture.height;
+
+        float patchWidth = ((int)dstrec.width <= 0)? 0.0f : dstrec.width;
+        float patchHeight = ((int)dstrec.height <= 0)? 0.0f : dstrec.height;
+
+        if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width;
+        if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height;
+        if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL) patchHeight = nPatchInfo.source.height;
+        if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL) patchWidth = nPatchInfo.source.width;
+
+        bool drawCenter = true;
+        bool drawMiddle = true;
+        float leftBorder = (float)nPatchInfo.left;
+        float topBorder = (float)nPatchInfo.top;
+        float rightBorder = (float)nPatchInfo.right;
+        float bottomBorder = (float)nPatchInfo.bottom;
+
+        // Adjust the lateral (left and right) border widths in case patchWidth < texture.width
+        if (patchWidth <= (leftBorder + rightBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_VERTICAL)
+        {
+            drawCenter = false;
+            leftBorder = (leftBorder/(leftBorder + rightBorder))*patchWidth;
+            rightBorder = patchWidth - leftBorder;
+        }
+
+        // Adjust the lateral (top and bottom) border heights in case patchHeight < texture.height
+        if (patchHeight <= (topBorder + bottomBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_HORIZONTAL)
+        {
+            drawMiddle = false;
+            topBorder = (topBorder/(topBorder + bottomBorder))*patchHeight;
+            bottomBorder = patchHeight - topBorder;
+        }
+
+        Vector2 vertA = { 0 };
+        Vector2 vertB = { 0 };
+        Vector2 vertC = { 0 };
+        Vector2 vertD = { 0 };
+        vertA.x = 0.0f;                             // Outer left
+        vertA.y = 0.0f;                             // Outer top
+        vertB.x = leftBorder;                       // Inner left
+        vertB.y = topBorder;                        // Inner top
+        vertC.x = patchWidth  - rightBorder;        // Inner right
+        vertC.y = patchHeight - bottomBorder;       // Inner bottom
+        vertD.x = patchWidth;                       // Outer right
+        vertD.y = patchHeight;                      // Outer bottom
+
+        Vector2 coordA = { 0 };
+        Vector2 coordB = { 0 };
+        Vector2 coordC = { 0 };
+        Vector2 coordD = { 0 };
+        coordA.x = nPatchInfo.source.x/width;
+        coordA.y = nPatchInfo.source.y/height;
+        coordB.x = (nPatchInfo.source.x + leftBorder)/width;
+        coordB.y = (nPatchInfo.source.y + topBorder)/height;
+        coordC.x = (nPatchInfo.source.x + nPatchInfo.source.width  - rightBorder)/width;
+        coordC.y = (nPatchInfo.source.y + nPatchInfo.source.height - bottomBorder)/height;
+        coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width;
+        coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height;
+
+        rlSetTexture(texture.id);
+
+        rlPushMatrix();
+            rlTranslatef(dstrec.x, dstrec.y, 0.0f);
+            rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
+            rlTranslatef(-origin.x, -origin.y, 0.0f);
+
+            rlBegin(RL_QUADS);
+                rlColor4ub(tint.r, tint.g, tint.b, tint.a);
+                rlNormal3f(0.0f, 0.0f, 1.0f);               // Normal vector pointing towards viewer
+
+                if (nPatchInfo.layout == NPATCH_NINE_PATCH)
+                {
+                    // ------------------------------------------------------------
+                    // TOP-LEFT QUAD
+                    rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
+                    if (drawCenter)
+                    {
+                        // TOP-CENTER QUAD
+                        rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
+                    }
+                    // TOP-RIGHT QUAD
+                    rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
+                    if (drawMiddle)
+                    {
+                        // ------------------------------------------------------------
+                        // MIDDLE-LEFT QUAD
+                        rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
+                        if (drawCenter)
+                        {
+                            // MIDDLE-CENTER QUAD
+                            rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Bottom-left corner for texture and quad
+                            rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-right corner for texture and quad
+                            rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-right corner for texture and quad
+                            rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y);  // Top-left corner for texture and quad
+                        }
+
+                        // MIDDLE-RIGHT QUAD
+                        rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y);  // Top-left corner for texture and quad
+                    }
+
+                    // ------------------------------------------------------------
+                    // BOTTOM-LEFT QUAD
+                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
+                    if (drawCenter)
+                    {
+                        // BOTTOM-CENTER QUAD
+                        rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y);  // Top-left corner for texture and quad
+                    }
+
+                    // BOTTOM-RIGHT QUAD
+                    rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y);  // Top-left corner for texture and quad
+                }
+                else if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL)
+                {
+                    // TOP QUAD
+                    // -----------------------------------------------------------
+                    // Texture coords                 Vertices
+                    rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
+                    if (drawCenter)
+                    {
+                        // MIDDLE QUAD
+                        // -----------------------------------------------------------
+                        // Texture coords                 Vertices
+                        rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y);  // Top-left corner for texture and quad
+                    }
+                    // BOTTOM QUAD
+                    // -----------------------------------------------------------
+                    // Texture coords                 Vertices
+                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y);  // Top-left corner for texture and quad
+                }
+                else if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL)
+                {
+                    // LEFT QUAD
+                    // -----------------------------------------------------------
+                    // Texture coords                 Vertices
+                    rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y);  // Top-left corner for texture and quad
+                    if (drawCenter)
+                    {
+                        // CENTER QUAD
+                        // -----------------------------------------------------------
+                        // Texture coords                 Vertices
+                        rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y);  // Bottom-left corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-right corner for texture and quad
+                        rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-right corner for texture and quad
+                        rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y);  // Top-left corner for texture and quad
+                    }
+                    // RIGHT QUAD
+                    // -----------------------------------------------------------
+                    // Texture coords                 Vertices
+                    rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y);  // Bottom-left corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y);  // Bottom-right corner for texture and quad
+                    rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y);  // Top-right corner for texture and quad
+                    rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y);  // Top-left corner for texture and quad
+                }
+            rlEnd();
+        rlPopMatrix();
+
+        rlSetTexture(0);
+    }
+}
+
+// Check if two colors are equal
+bool ColorIsEqual(Color col1, Color col2)
+{
+    bool result = false;
+
+    if ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) result = true;
+
+    return result;
+}
+
+// Get color with alpha applied, alpha goes from 0.0f to 1.0f
+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;
+}
+
+// Get hexadecimal value for a Color
+int ColorToInt(Color color)
+{
+    int result = 0;
+
+    result = (int)(((unsigned int)color.r << 24) |
+                   ((unsigned int)color.g << 16) |
+                   ((unsigned int)color.b << 8) |
+                    (unsigned int)color.a);
+
+    return result;
+}
+
+// Get color normalized as float [0..1]
+Vector4 ColorNormalize(Color color)
+{
+    Vector4 result;
+
+    result.x = (float)color.r/255.0f;
+    result.y = (float)color.g/255.0f;
+    result.z = (float)color.b/255.0f;
+    result.w = (float)color.a/255.0f;
+
+    return result;
+}
+
+// Get color from normalized values [0..1]
+Color ColorFromNormalized(Vector4 normalized)
+{
+    Color result;
+
+    result.r = (unsigned char)(normalized.x*255.0f);
+    result.g = (unsigned char)(normalized.y*255.0f);
+    result.b = (unsigned char)(normalized.z*255.0f);
+    result.a = (unsigned char)(normalized.w*255.0f);
+
+    return result;
+}
+
+// Get HSV values for a Color
+// NOTE: Hue is returned as degrees [0..360]
+Vector3 ColorToHSV(Color color)
+{
+    Vector3 hsv = { 0 };
+    Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+    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 = NAN; // Undefined
+        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;
+}
+
+// Get a Color from HSV values
+// Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion
+// NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors
+// Hue is provided in degrees: [0..360]
+// Saturation/Value are provided normalized: [0.0f..1.0f]
+Color ColorFromHSV(float hue, float saturation, float value)
+{
+    Color color = { 0, 0, 0, 255 };
+
+    // Red channel
+    float k = fmodf((5.0f + hue/60.0f), 6);
+    float t = 4.0f - k;
+    k = (t < k)? t : k;
+    k = (k < 1)? k : 1;
+    k = (k > 0)? k : 0;
+    color.r = (unsigned char)((value - value*saturation*k)*255.0f);
+
+    // Green channel
+    k = fmodf((3.0f + hue/60.0f), 6);
+    t = 4.0f - k;
+    k = (t < k)? t : k;
+    k = (k < 1)? k : 1;
+    k = (k > 0)? k : 0;
+    color.g = (unsigned char)((value - value*saturation*k)*255.0f);
+
+    // Blue channel
+    k = fmodf((1.0f + hue/60.0f), 6);
+    t = 4.0f - k;
+    k = (t < k)? t : k;
+    k = (k < 1)? k : 1;
+    k = (k > 0)? k : 0;
+    color.b = (unsigned char)((value - value*saturation*k)*255.0f);
+
+    return color;
+}
+
+// Get color multiplied with another color
+Color ColorTint(Color color, Color tint)
+{
+    Color result = color;
+
+    unsigned char r = (unsigned char)(((int)color.r*(int)tint.r)/255);
+    unsigned char g = (unsigned char)(((int)color.g*(int)tint.g)/255);
+    unsigned char b = (unsigned char)(((int)color.b*(int)tint.b)/255);
+    unsigned char a = (unsigned char)(((int)color.a*(int)tint.a)/255);
+
+    result.r = r;
+    result.g = g;
+    result.b = b;
+    result.a = a;
+
+    return result;
+}
+
+// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
+Color ColorBrightness(Color color, float factor)
+{
+    Color result = color;
+
+    if (factor > 1.0f) factor = 1.0f;
+    else if (factor < -1.0f) factor = -1.0f;
+
+    float red = (float)color.r;
+    float green = (float)color.g;
+    float blue = (float)color.b;
+
+    if (factor < 0.0f)
+    {
+        factor = 1.0f + factor;
+        red *= factor;
+        green *= factor;
+        blue *= factor;
+    }
+    else
+    {
+        red = (255 - red)*factor + red;
+        green = (255 - green)*factor + green;
+        blue = (255 - blue)*factor + blue;
+    }
+
+    result.r = (unsigned char)red;
+    result.g = (unsigned char)green;
+    result.b = (unsigned char)blue;
+
+    return result;
+}
+
+// Get color with contrast correction
+// NOTE: Contrast values between -1.0f and 1.0f
+Color ColorContrast(Color color, float contrast)
+{
+    Color result = color;
+
+    if (contrast < -1.0f) contrast = -1.0f;
+    else if (contrast > 1.0f) contrast = 1.0f;
+
+    contrast = (1.0f + contrast);
+    contrast *= contrast;
+
+    float pR = (float)color.r/255.0f;
+    pR -= 0.5f;
+    pR *= contrast;
+    pR += 0.5f;
+    pR *= 255;
+    if (pR < 0) pR = 0;
+    else if (pR > 255) pR = 255;
+
+    float pG = (float)color.g/255.0f;
+    pG -= 0.5f;
+    pG *= contrast;
+    pG += 0.5f;
+    pG *= 255;
+    if (pG < 0) pG = 0;
+    else if (pG > 255) pG = 255;
+
+    float pB = (float)color.b/255.0f;
+    pB -= 0.5f;
+    pB *= contrast;
+    pB += 0.5f;
+    pB *= 255;
+    if (pB < 0) pB = 0;
+    else if (pB > 255) pB = 255;
+
+    result.r = (unsigned char)pR;
+    result.g = (unsigned char)pG;
+    result.b = (unsigned char)pB;
+
+    return result;
+}
+
+// Get color with alpha applied, alpha goes from 0.0f to 1.0f
+Color ColorAlpha(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;
+}
+
+// Get src alpha-blended into dst color with tint
+Color ColorAlphaBlend(Color dst, Color src, Color tint)
+{
+    Color result = WHITE;
+
+    // Apply color tint to source color
+    src.r = (unsigned char)(((unsigned int)src.r*((unsigned int)tint.r+1)) >> 8);
+    src.g = (unsigned char)(((unsigned int)src.g*((unsigned int)tint.g+1)) >> 8);
+    src.b = (unsigned char)(((unsigned int)src.b*((unsigned int)tint.b+1)) >> 8);
+    src.a = (unsigned char)(((unsigned int)src.a*((unsigned int)tint.a+1)) >> 8);
+
+//#define COLORALPHABLEND_FLOAT
+#define COLORALPHABLEND_INTEGERS
+#if defined(COLORALPHABLEND_INTEGERS)
+    if (src.a == 0) result = dst;
+    else if (src.a == 255) result = src;
+    else
+    {
+        unsigned int alpha = (unsigned int)src.a + 1; // Shifting by 8 (dividing by 256), so need to take that excess into account
+        result.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8);
+
+        if (result.a > 0)
+        {
+            result.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
+            result.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
+            result.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/result.a) >> 8);
+        }
+    }
+#endif
+#if defined(COLORALPHABLEND_FLOAT)
+    if (src.a == 0) result = dst;
+    else if (src.a == 255) result = src;
+    else
+    {
+        Vector4 fdst = ColorNormalize(dst);
+        Vector4 fsrc = ColorNormalize(src);
+        Vector4 ftint = ColorNormalize(tint);
+        Vector4 fout = { 0 };
+
+        fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w);
+
+        if (fout.w > 0.0f)
+        {
+            fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w;
+            fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w;
+            fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w;
+        }
+
+        result = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) };
+    }
+#endif
+
+    return result;
+}
+
+// Get color lerp interpolation between two colors, factor [0.0f..1.0f]
+Color ColorLerp(Color color1, Color color2, float factor)
+{
+    Color color = { 0 };
+
+    if (factor < 0.0f) factor = 0.0f;
+    else if (factor > 1.0f) factor = 1.0f;
+
+    color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r);
+    color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g);
+    color.b = (unsigned char)((1.0f - factor)*color1.b + factor*color2.b);
+    color.a = (unsigned char)((1.0f - factor)*color1.a + factor*color2.a);
+
+    return color;
+}
+
+// Get a Color struct from hexadecimal value
+Color GetColor(unsigned 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 from a pixel from certain format
+Color GetPixelColor(const void *srcPtr, int format)
+{
+    Color color = { 0 };
+
+    switch (format)
+    {
+        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], 255 }; break;
+        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1] }; break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+        {
+            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
+            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 5) & 0b0000000000111111)*255/63);
+            color.b = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000011111)*255/31);
+            color.a = 255;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+        {
+            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 11)*255/31);
+            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 6) & 0b0000000000011111)*255/31);
+            color.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 1) & 0b0000000000011111)*255/31);
+            color.a = (((unsigned short *)srcPtr)[0] & 0b0000000000000001)? 255 : 0;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+        {
+            color.r = (unsigned char)((((unsigned short *)srcPtr)[0] >> 12)*255/15);
+            color.g = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 8) & 0b0000000000001111)*255/15);
+            color.b = (unsigned char)(((((unsigned short *)srcPtr)[0] >> 4) & 0b0000000000001111)*255/15);
+            color.a = (unsigned char)((((unsigned short *)srcPtr)[0] & 0b0000000000001111)*255/15);
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], ((unsigned char *)srcPtr)[3] }; break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8: color = (Color){ ((unsigned char *)srcPtr)[0], ((unsigned char *)srcPtr)[1], ((unsigned char *)srcPtr)[2], 255 }; break;
+        case PIXELFORMAT_UNCOMPRESSED_R32:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
+            color.g = (unsigned char)(((float *)srcPtr)[0]*255.0f);
+            color.b = (unsigned char)(((float *)srcPtr)[0]*255.0f);
+            color.a = 255;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
+            color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f);
+            color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f);
+            color.a = 255;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(((float *)srcPtr)[0]*255.0f);
+            color.g = (unsigned char)(((float *)srcPtr)[1]*255.0f);
+            color.b = (unsigned char)(((float *)srcPtr)[2]*255.0f);
+            color.a = (unsigned char)(((float *)srcPtr)[3]*255.0f);
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
+            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
+            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
+            color.a = 255;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
+            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f);
+            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f);
+            color.a = 255;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+        {
+            // NOTE: Pixel normalized float value is converted to [0..255]
+            color.r = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[0])*255.0f);
+            color.g = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[1])*255.0f);
+            color.b = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[2])*255.0f);
+            color.a = (unsigned char)(HalfToFloat(((unsigned short *)srcPtr)[3])*255.0f);
+
+        } break;
+        default: break;
+    }
+
+    return color;
+}
+
+// Set pixel color formatted into destination pointer
+void SetPixelColor(void *dstPtr, Color color, int format)
+{
+    switch (format)
+    {
+        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+        {
+            // NOTE: Calculate grayscale equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
+
+            ((unsigned char *)dstPtr)[0] = gray;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+        {
+            // NOTE: Calculate grayscale equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+            unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f);
+
+            ((unsigned char *)dstPtr)[0] = gray;
+            ((unsigned char *)dstPtr)[1] = color.a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+        {
+            // NOTE: Calculate R5G6B5 equivalent color
+            Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*31.0f));
+            unsigned char g = (unsigned char)(round(coln.y*63.0f));
+            unsigned char b = (unsigned char)(round(coln.z*31.0f));
+
+            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+        {
+            // NOTE: Calculate R5G5B5A1 equivalent color
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*31.0f));
+            unsigned char g = (unsigned char)(round(coln.y*31.0f));
+            unsigned char b = (unsigned char)(round(coln.z*31.0f));
+            unsigned char a = (coln.w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0;
+
+            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+        {
+            // NOTE: Calculate R5G5B5A1 equivalent color
+            Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f };
+
+            unsigned char r = (unsigned char)(round(coln.x*15.0f));
+            unsigned char g = (unsigned char)(round(coln.y*15.0f));
+            unsigned char b = (unsigned char)(round(coln.z*15.0f));
+            unsigned char a = (unsigned char)(round(coln.w*15.0f));
+
+            ((unsigned short *)dstPtr)[0] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+        {
+            ((unsigned char *)dstPtr)[0] = color.r;
+            ((unsigned char *)dstPtr)[1] = color.g;
+            ((unsigned char *)dstPtr)[2] = color.b;
+
+        } break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+        {
+            ((unsigned char *)dstPtr)[0] = color.r;
+            ((unsigned char *)dstPtr)[1] = color.g;
+            ((unsigned char *)dstPtr)[2] = color.b;
+            ((unsigned char *)dstPtr)[3] = color.a;
+
+        } break;
+        default: break;
+    }
+}
+
+// Get pixel data size in bytes for certain format
+// NOTE: Size can be requested for Image or Texture data
+int GetPixelDataSize(int width, int height, int format)
+{
+    int dataSize = 0;       // Size in bytes
+    int bpp = 0;            // Bits per pixel
+
+    switch (format)
+    {
+        case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
+        case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+        case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+        case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+        case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
+        case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
+        case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
+        case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
+        case PIXELFORMAT_UNCOMPRESSED_R16: bpp = 16; break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 16*3; break;
+        case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 16*4; break;
+        case PIXELFORMAT_COMPRESSED_DXT1_RGB:
+        case PIXELFORMAT_COMPRESSED_DXT1_RGBA:
+        case PIXELFORMAT_COMPRESSED_ETC1_RGB:
+        case PIXELFORMAT_COMPRESSED_ETC2_RGB:
+        case PIXELFORMAT_COMPRESSED_PVRT_RGB:
+        case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
+        case PIXELFORMAT_COMPRESSED_DXT3_RGBA:
+        case PIXELFORMAT_COMPRESSED_DXT5_RGBA:
+        case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
+        case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
+        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)
+    {
+        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;
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+// Convert half-float (stored as unsigned short) to float
+// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
+static float HalfToFloat(unsigned short x)
+{
+    float result = 0.0f;
+
+    union {
+        float fm;
+        unsigned int ui;
+    } uni;
+
+    const unsigned int e = (x & 0x7c00) >> 10; // Exponent
+    const unsigned int m = (x & 0x03ff) << 13; // Mantissa
+    uni.fm = (float)m;
+    const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
+    uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
+
+    result = uni.fm;
+
+    return result;
+}
+
+// Convert float to half-float (stored as unsigned short)
+static unsigned short FloatToHalf(float x)
+{
+    unsigned short result = 0;
+
+    union {
+        float fm;
+        unsigned int ui;
+    } uni;
+    uni.fm = x;
+
+    const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
+    const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
+    const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
+
+    result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
+
+    return result;
+}
+
+// Get pixel data from image as Vector4 array (float normalized)
+static Vector4 *LoadImageDataNormalized(Image image)
+{
+    Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4));
+
+    if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
+    else
+    {
+        for (int i = 0, k = 0; i < image.width*image.height; i++)
+        {
+            switch (image.format)
+            {
+                case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+                {
+                    pixels[i].x = (float)((unsigned char *)image.data)[i]/255.0f;
+                    pixels[i].y = (float)((unsigned char *)image.data)[i]/255.0f;
+                    pixels[i].z = (float)((unsigned char *)image.data)[i]/255.0f;
+                    pixels[i].w = 1.0f;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+                {
+                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
+                    pixels[i].y = (float)((unsigned char *)image.data)[k]/255.0f;
+                    pixels[i].z = (float)((unsigned char *)image.data)[k]/255.0f;
+                    pixels[i].w = (float)((unsigned char *)image.data)[k + 1]/255.0f;
+
+                    k += 2;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
+                    pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
+                    pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
+                    pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
+                    pixels[i].y = (float)((pixel & 0b0000011111100000) >> 5)*(1.0f/63);
+                    pixels[i].z = (float)(pixel & 0b0000000000011111)*(1.0f/31);
+                    pixels[i].w = 1.0f;
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+                {
+                    unsigned short pixel = ((unsigned short *)image.data)[i];
+
+                    pixels[i].x = (float)((pixel & 0b1111000000000000) >> 12)*(1.0f/15);
+                    pixels[i].y = (float)((pixel & 0b0000111100000000) >> 8)*(1.0f/15);
+                    pixels[i].z = (float)((pixel & 0b0000000011110000) >> 4)*(1.0f/15);
+                    pixels[i].w = (float)(pixel & 0b0000000000001111)*(1.0f/15);
+
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+                {
+                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
+                    pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
+                    pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
+                    pixels[i].w = (float)((unsigned char *)image.data)[k + 3]/255.0f;
+
+                    k += 4;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+                {
+                    pixels[i].x = (float)((unsigned char *)image.data)[k]/255.0f;
+                    pixels[i].y = (float)((unsigned char *)image.data)[k + 1]/255.0f;
+                    pixels[i].z = (float)((unsigned char *)image.data)[k + 2]/255.0f;
+                    pixels[i].w = 1.0f;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32:
+                {
+                    pixels[i].x = ((float *)image.data)[k];
+                    pixels[i].y = 0.0f;
+                    pixels[i].z = 0.0f;
+                    pixels[i].w = 1.0f;
+
+                    k += 1;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+                {
+                    pixels[i].x = ((float *)image.data)[k];
+                    pixels[i].y = ((float *)image.data)[k + 1];
+                    pixels[i].z = ((float *)image.data)[k + 2];
+                    pixels[i].w = 1.0f;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+                {
+                    pixels[i].x = ((float *)image.data)[k];
+                    pixels[i].y = ((float *)image.data)[k + 1];
+                    pixels[i].z = ((float *)image.data)[k + 2];
+                    pixels[i].w = ((float *)image.data)[k + 3];
+
+                    k += 4;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16:
+                {
+                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
+                    pixels[i].y = 0.0f;
+                    pixels[i].z = 0.0f;
+                    pixels[i].w = 1.0f;
+
+                    k += 1;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+                {
+                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
+                    pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]);
+                    pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]);
+                    pixels[i].w = 1.0f;
+
+                    k += 3;
+                } break;
+                case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+                {
+                    pixels[i].x = HalfToFloat(((unsigned short *)image.data)[k]);
+                    pixels[i].y = HalfToFloat(((unsigned short *)image.data)[k + 1]);
+                    pixels[i].z = HalfToFloat(((unsigned short *)image.data)[k + 2]);
+                    pixels[i].w = HalfToFloat(((unsigned short *)image.data)[k + 3]);
+
+                    k += 4;
+                } break;
+                default: break;
+            }
+        }
+    }
+
+    return pixels;
+}
+
+#endif // SUPPORT_MODULE_RTEXTURES
diff --git a/raylib/tools/rexm/rexm.c b/raylib/tools/rexm/rexm.c
--- a/raylib/tools/rexm/rexm.c
+++ b/raylib/tools/rexm/rexm.c
@@ -63,11 +63,12 @@
 #endif
 
 #define REXM_MAX_EXAMPLES               512
-#define REXM_MAX_EXAMPLE_CATEGORIES     8
+#define REXM_MAX_EXAMPLE_CATEGORIES     7
 
 #define REXM_MAX_BUFFER_SIZE            (2*1024*1024)      // 2MB
 
 #define REXM_MAX_RESOURCE_PATHS         256
+#define REXM_MAX_RESOURCE_PATH_LENGTH   256
 
 // Create local commit with changes on example renaming
 //#define RENAME_AUTO_COMMIT_CREATION
@@ -83,7 +84,7 @@
 //----------------------------------------------------------------------------------
 // raylib example info struct
 typedef struct {
-    char category[16];      // Example category: core, shapes, textures, text, models, shaders, audio, [others]
+    char category[16];      // Example category: core, shapes, textures, text, models, shaders, audio
     char name[128];         // Example name: <category>_name_part
     int stars;              // Example stars count: ★☆☆☆
     char verCreated[12];    // Example raylib creation version
@@ -132,7 +133,7 @@
     TESTING_FAIL_ASSETS         = 1 << 2,   // Assets loading (WARNING: FILE:)  -> "WARNING: FILEIO:"
     TESTING_FAIL_RLGL           = 1 << 3,   // OpenGL-wrapped initialization    -> "INFO: RLGL: Default OpenGL state initialized successfully"
     TESTING_FAIL_PLATFORM       = 1 << 4,   // Platform initialization          -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
-    TESTING_FAIL_FONT           = 1 << 5,   // Font deefault initialization     -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
+    TESTING_FAIL_FONT           = 1 << 5,   // Font default initialization      -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
     TESTING_FAIL_TIMER          = 1 << 6,   // Timer initialization             -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
     TESTING_FAIL_OTHER          = 1 << 7,   // Other types of warnings (WARNING:)
 } rlExampleTestingStatus;
@@ -149,9 +150,10 @@
     OP_BUILD    = 7,        // Build example(s) for desktop and web, copy web output - Multiple examples supported
     OP_TEST     = 8,        // Test example(s), checking output log "WARNING" - Multiple examples supported
     OP_TESTLOG  = 9,        // Process available examples logs to generate report
+    OP_CLEAN    = 10,       // Delete files generated during other commands, excluding reports
 } rlExampleOperation;
 
-static const char *exCategories[REXM_MAX_EXAMPLE_CATEGORIES] = { "core", "shapes", "textures", "text", "models", "shaders", "audio", "others" };
+static const char *exCategories[REXM_MAX_EXAMPLE_CATEGORIES] = { "core", "shapes", "textures", "text", "models", "shaders", "audio" };
 
 // Paths required for examples management
 // NOTE: Paths can be provided with environment variables
@@ -170,7 +172,7 @@
 static int UpdateRequiredFiles(void);
 
 // Load examples collection information
-// NOTE 1: Load by category: "ALL", "core", "shapes", "textures", "text", "models", "shaders", others"
+// NOTE 1: Load by category: "ALL", "core", "shapes", "textures", "text", "models", "shaders", audio"
 // NOTE 2: Sort examples list on request flag
 static rlExampleInfo *LoadExampleData(const char *filter, bool sort, int *exCount);
 static void UnloadExampleData(rlExampleInfo *exInfo);
@@ -242,6 +244,38 @@
     if (!exVSProjectSolutionFile) exVSProjectSolutionFile = "../../projects/VS2022/raylib.sln";
 #endif
 
+    // Make sure required paths exist
+    if (!DirectoryExists(exBasePath))
+    {
+        LOG("ERROR: Could not find raylib examples directory (hint: environment variable 'REXM_EXAMPLES_BASE_PATH')\n");
+        return 1;
+    }
+    if (!DirectoryExists(exWebPath))
+    {
+        LOG("ERROR: Could not find raylib.com examples directory (hint: environment variable 'REXM_EXAMPLES_WEB_PATH')\n");
+        return 1;
+    }
+    if (!FileExists(exTemplateFilePath))
+    {
+        LOG("ERROR: Could not find examples template file (hint: environment variable 'REXM_EXAMPLES_TEMPLATE_FILE_PATH')\n");
+        return 1;
+    }
+    if (!FileExists(exTemplateScreenshot))
+    {
+        LOG("ERROR: Could not find examples template screenshot (hint: environment variable 'REXM_EXAMPLES_TEMPLATE_SCREENSHOT_PATH')\n");
+        return 1;
+    }
+    if (!FileExists(exCollectionFilePath))
+    {
+        LOG("ERROR: Could not find examples collection file (hint: environment variable 'REXM_EXAMPLES_COLLECTION_FILE_PATH')\n");
+        return 1;
+    }
+    if (!FileExists(exVSProjectSolutionFile))
+    {
+        LOG("ERROR: Could not find VS solution file (hint: environment variable 'REXM_EXAMPLES_VS2022_SLN_FILE')\n");
+        return 1;
+    }
+
     char inFileName[1024] = { 0 };  // Example input filename (to be added)
 
     char exName[64] = { 0 };        // Example name, without extension: core_basic_window
@@ -446,7 +480,13 @@
                 }
             }
         }
+        else if (strcmp(argv[1], "clean") == 0)
+        {
+            // Delete files generated during other commands, excluding reports
 
+            opCode = OP_CLEAN;
+        }
+
         // Process command line options arguments
         for (int i = 1; i < argc; i++)
         {
@@ -469,12 +509,12 @@
             int exIndex = TextFindIndex(exText, "/****************");
 
             // Update required info with some defaults
-            exTextUpdated[0] = TextReplace(exText + exIndex, "<module>", exCategory);
-            exTextUpdated[1] = TextReplace(exTextUpdated[0], "<name>", exName + strlen(exCategory) + 1);
-            //TextReplace(newExample, "<user_name>", "Ray");
-            //TextReplace(newExample, "@<user_github>", "@raysan5");
-            //TextReplace(newExample, "<year_created>", 2025);
-            //TextReplace(newExample, "<year_updated>", 2025);
+            exTextUpdated[0] = TextReplaceAlloc(exText + exIndex, "<module>", exCategory);
+            exTextUpdated[1] = TextReplaceAlloc(exTextUpdated[0], "<name>", exName + strlen(exCategory) + 1);
+            //TextReplaceAlloc(newExample, "<user_name>", "Ray");
+            //TextReplaceAlloc(newExample, "@<user_github>", "@raysan5");
+            //TextReplaceAlloc(newExample, "<year_created>", 2026);
+            //TextReplaceAlloc(newExample, "<year_updated>", 2026);
 
             SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), exTextUpdated[1]);
             for (int i = 0; i < 6; i++) { MemFree(exTextUpdated[i]); exTextUpdated[i] = NULL; }
@@ -541,8 +581,6 @@
                                 else LOG("WARNING: Example resource must be placed in 'resources' directory next to .c file\n");
                             }
                             else LOG("WARNING: Example resource can not be found in: %s\n", TextFormat("%s/%s", GetDirectoryPath(inFileName), resPathUpdated));
-
-                            RL_FREE(resPathUpdated);
                         }
                     }
                     else
@@ -589,8 +627,7 @@
                 else if (TextIsEqual(exCategory, "text")) nextCategoryIndex = 4;
                 else if (TextIsEqual(exCategory, "models")) nextCategoryIndex = 5;
                 else if (TextIsEqual(exCategory, "shaders")) nextCategoryIndex = 6;
-                else if (TextIsEqual(exCategory, "audio")) nextCategoryIndex = 7;
-                else if (TextIsEqual(exCategory, "others")) nextCategoryIndex = -1; // Add to EOF
+                else if (TextIsEqual(exCategory, "audio")) nextCategoryIndex = -1; // EOF, "audio" is the last category, avoid out-of-bounds exCategories[7] access
 
                 // Get required example info from example file header (if provided)
 
@@ -623,7 +660,13 @@
                 else
                 {
                     // Add example to collection, at the end of the category list
-                    int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]);
+                    // NOTE: Search is anchored to "\n<category>;" (not just "<category>") to avoid
+                    // false-positive matches when one category name is a text-prefix of another
+                    // (e.g. "text" is a prefix of "textures", so a bare search for "text" matches
+                    // inside "core_render_texture" or at the start of the "textures" block instead
+                    // of the actual "text" category boundary, corrupting the collection list)
+                    int categoryIndex = TextFindIndex(exCollectionList, TextFormat("\n%s;", exCategories[nextCategoryIndex])) + 1;
+                    if (categoryIndex == 0) categoryIndex = (int)strlen(exCollectionList); // Category not found, fallback to EOF
                     memcpy(exCollectionListUpdated, exCollectionList, categoryIndex);
                     int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
                         exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub));
@@ -660,14 +703,14 @@
             // we must store provided file paths because pointers will be overwriten
             // TODO: It seems projects are added to solution BUT not to required solution folder,
             // that process still requires to be done manually
-            LOG("INFO: [%s] Adding project to raylib solution (.sln)\n", 
+            LOG("INFO: [%s] Adding project to raylib solution (.sln)\n",
                 TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
             AddVSProjectToSolution(exVSProjectSolutionFile,
                 TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), exCategory);
             //------------------------------------------------------------------------------------------------
 
             // Recompile example (on raylib side)
-            // NOTE: Tools requirements: emscripten, w64devkit
+            // NOTE: Tools requirements: emscripten, make
             // Compile to: raylib.com/examples/<category>/<category>_example_name.html
             // Compile to: raylib.com/examples/<category>/<category>_example_name.data
             // Compile to: raylib.com/examples/<category>/<category>_example_name.wasm
@@ -677,13 +720,11 @@
             // WARNING 2: raylib.a and raylib.web.a must be available when compiling locally
 #if defined(_WIN32)
             LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", GetFileNameWithoutExt(inFileName));
-            //putenv("RAYLIB_DIR=C:\\GitHub\\raylib");
-            _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-            system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
 #else
             LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName));
-            system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
 #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),
@@ -778,12 +819,8 @@
 
             // Recompile example (on raylib side)
             // WARNING: EMSDK_PATH must be set to proper location when calling from GitHub Actions
-#if defined(_WIN32)
-            _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-            system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
-#else
             system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
-#endif
+
             // Update generated .html metadata
             UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exRename),
                 TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename));
@@ -800,14 +837,13 @@
 
 #if defined(RENAME_AUTO_COMMIT_CREATION)
             // Create GitHub commit with changes (local)
-            putenv("PATH=%PATH%;C:\\Program Files\\Git\\bin");
-            ChangeDirectory("C:\\GitHub\\raylib");
+            ChangeDirectory(TextFormat("%s/..", exBasePath));
             system("git --version");
             system("git status");
             system("git add -A");
             int result = system(TextFormat("git commit -m \"REXM: RENAME: example: `%s` --> `%s`\"", exName, exRename)); // Commit changes (only tracked files)
             if (result != 0) LOG("WARNING: Error committing changes\n");
-            ChangeDirectory("C:/GitHub/raylib.com");
+            ChangeDirectory(TextFormat("%s/..", exWebPath));
             system("git add -A");
             result = system(TextFormat("git commit -m \"REXM: RENAME: example: `%s` --> `%s`\"", exName, exRename)); // Commit changes (only tracked files)
             if (result != 0) LOG("WARNING: Error committing changes\n");
@@ -864,9 +900,7 @@
 
                         for (int v = 0; v < 3; v++)
                         {
-                            char *resPathUpdated = TextReplace(resPaths[r], "glsl%i", TextFormat("glsl%i", glslVer[v]));
-                            FileRemove(TextFormat("%s/%s/%s", exBasePath, exCategory, resPathUpdated));
-                            RL_FREE(resPathUpdated);
+                            FileRemove(TextFormat("%s/%s/%s", exBasePath, exCategory, TextReplace(resPaths[r], "glsl%i", TextFormat("glsl%i", glslVer[v]))));
                         }
                     }
                     else FileRemove(TextFormat("%s/%s/%s", exBasePath, exCategory, resPaths[r]));
@@ -917,13 +951,6 @@
             LOG("INFO: Command requested: BUILD\n");
             LOG("INFO: Example(s) to be built: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
 
-#if defined(_WIN32)
-            // Set required environment variables
-            //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
-            _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-            //putenv("MAKE=mingw32-make");
-            //ChangeDirectory(exBasePath);
-#endif
             for (int i = 0; i < exBuildListCount; i++)
             {
                 // Get example name and category
@@ -937,7 +964,7 @@
                 // Build example for PLATFORM_DESKTOP
 #if defined(_WIN32)
                 LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
-                system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
+                system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
 #elif defined(PLATFORM_DRM)
                 LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);
                 system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DRM -B > %s/%s/logs/%s.build.log 2>&1",
@@ -953,13 +980,9 @@
                 // Build: raylib.com/examples/<category>/<category>_example_name.data
                 // Build: raylib.com/examples/<category>/<category>_example_name.wasm
                 // Build: raylib.com/examples/<category>/<category>_example_name.js
-    #if defined(_WIN32)
-                LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
-                system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
-    #else
-                LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
+                LOG("INFO: [%s] Building example for PLATFORM_WEB\n", exName);
                 system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
-    #endif
+
                 // Update generated .html metadata
                 LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
                 UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
@@ -1039,9 +1062,17 @@
                         if (nextCatIndex > (REXM_MAX_EXAMPLE_CATEGORIES - 1)) nextCatIndex = -1; // EOF
 
                         // Find position to add new example on list, just before the following category
-                        // Category order: core, shapes, textures, text, models, shaders, audio, [others]
+                        // Category order: core, shapes, textures, text, models, shaders, audio
+                        // NOTE: Search is anchored to "\n<category>;" (not just "\n<category>") to avoid
+                        // false-positive matches when one category name is a text-prefix of another
+                        // (e.g. "text" is a prefix of "textures", so a bare "\ntext" search matches the
+                        // START of the "textures" block instead of the actual "text" category boundary).
                         int exListNextCatIndex = -1;
-                        if (nextCatIndex != -1) exListNextCatIndex = TextFindIndex(exList, exCategories[nextCatIndex]);
+                        if (nextCatIndex != -1)
+                        {
+                            exListNextCatIndex = TextFindIndex(exList, TextFormat("\n%s;", exCategories[nextCatIndex])) + 1;
+                            if (exListNextCatIndex == 0) exListNextCatIndex = exListLen; // Category not found, fallback to EOF
+                        }
                         else exListNextCatIndex = exListLen; // EOF
 
                         strncpy(exListUpdated, exList, exListNextCatIndex);
@@ -1165,7 +1196,6 @@
                                     // Logging missing resources for convenience
                                     LOG("WARNING: [%s] Missing resource: %s\n", exInfo->name, resPathUpdated);
                                 }
-                                RL_FREE(resPathUpdated);
                             }
                         }
                         else
@@ -1255,7 +1285,7 @@
                     exCollection[i].status &= ~VALID_NOT_IN_README;
                     exCollection[i].status &= ~VALID_NOT_IN_JS;
                 }
-                
+
                 // Check examples "status" information
                 for (int i = 0; i < exCollectionCount; i++)
                 {
@@ -1273,8 +1303,7 @@
 
                         // NOTE: Some examples should be excluded from VS2022 solution because
                         // they have specific platform/linkage requirements:
-                        if ((strcmp(exInfo->name, "web_basic_window") == 0) ||
-                            (strcmp(exInfo->name, "raylib_opengl_interop") == 0)) continue;
+                        if (strcmp(exInfo->name, "raylib_opengl_interop") == 0) continue;
 
                         // Review: Add: raylib/projects/VS2022/examples/<category>_example_name.vcxproj
                         // Review: Add: raylib/projects/VS2022/raylib.sln
@@ -1317,12 +1346,10 @@
                             // Build example for PLATFORM_WEB
                         #if defined(_WIN32)
                             LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exInfo->name);
-                            _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-                            system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
                         #else
                             LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
-                            system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
                         #endif
+                            system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
 
                             // Update generated .html metadata
                             LOG("INFO: [%s.html] Updating HTML Metadata...\n", exInfo->name);
@@ -1497,21 +1524,6 @@
             LOG("INFO: Command requested: TEST\n");
             LOG("INFO: Example(s) to be build and tested: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
 
-#if defined(_WIN32)
-            // Set required environment variables
-            //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
-            //_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-            //putenv("MAKE=mingw32-make");
-            //ChangeDirectory(exBasePath);
-            //_putenv("MAKE_PATH=C:\\raylib\\w64devkit\\bin");
-            //_putenv("EMSDK_PATH = C:\\raylib\\emsdk");
-            //_putenv("PYTHON_PATH=$(EMSDK_PATH)\\python\\3.9.2-nuget_64bit");
-            //_putenv("NODE_PATH=$(EMSDK_PATH)\\node\\20.18.0_64bit\\bin");
-            //_putenv("PATH=%PATH%;$(MAKE_PATH);$(EMSDK_PATH);$(NODE_PATH);$(PYTHON_PATH)");
-
-            _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin;C:\\raylib\\emsdk\\python\\3.9.2-nuget_64bit;C:\\raylib\\emsdk\\node\\20.18.0_64bit\\bin");
-#endif
-
             for (int i = 0; i < exBuildListCount; i++)
             {
                 // Get example name and category
@@ -1556,7 +1568,7 @@
                     "#include <string.h>\n"
                     "#include <stdlib.h>\n"
                     "#include <emscripten/emscripten.h>\n\n"
-                    "static char logText[4096] = {0};\n"
+                    "static char logText[4096] = { 0 };\n"
                     "static int logTextOffset = 0;\n\n"
                     "void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n"
                     "    if (logTextOffset < 3800)\n    {\n"
@@ -1578,13 +1590,13 @@
                     "    SaveFileText(\"outputLogFileName\", logText);\n"
                     "    emscripten_run_script(\"saveFileFromMEMFSToDisk('outputLogFileName','outputLogFileName')\");\n\n"
                     "    return 0";
-                char *returnReplaceTextUpdated = TextReplace(returnReplaceText, "outputLogFileName", TextFormat("%s.log", exName));
+                char *returnReplaceTextUpdated = TextReplaceAlloc(returnReplaceText, "outputLogFileName", TextFormat("%s.log", exName));
 
                 char *srcTextUpdated[4] = { 0 };
-                srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
-                srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
-                srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
-                srcTextUpdated[3] = TextReplace(srcTextUpdated[2], "    return 0", returnReplaceTextUpdated);
+                srcTextUpdated[0] = TextReplaceAlloc(srcText, "int main(void)\n{", mainReplaceText);
+                srcTextUpdated[1] = TextReplaceAlloc(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
+                srcTextUpdated[2] = TextReplaceAlloc(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
+                srcTextUpdated[3] = TextReplaceAlloc(srcTextUpdated[2], "    return 0", returnReplaceTextUpdated);
                 MemFree(returnReplaceTextUpdated);
                 UnloadFileText(srcText);
 
@@ -1598,7 +1610,7 @@
                 // Build: raylib.com/examples/<category>/<category>_example_name.js
     #if defined(_WIN32)
                 LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
-                system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1",
+                system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1",
                     exBasePath, exCategory, exName, exBasePath, exCategory, exName));
     #else
                 LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
@@ -1617,8 +1629,8 @@
                     // WARNING: Example download is asynchronous so reading fails on next step
                     // when looking for a file that could not have been downloaded yet
                     ChangeDirectory(TextFormat("%s", exBasePath));
-                    if (i == 0) system("start python -m http.server 8080"); // Init localhost just once
-                    system(TextFormat("start explorer \"http:\\localhost:8080/%s/%s.html", exCategory, exName));
+                    if (i == 0) system("start python -m http.server 38080"); // Init localhost just once
+                    system(TextFormat("start explorer \"http:\\localhost:38080/%s/%s.html", exCategory, exName));
                 }
 
                 // NOTE: Example .log is automatically downloaded into system Downloads directory on browser-example exectution
@@ -1634,26 +1646,19 @@
                     "    if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
 
                 char *srcTextUpdated[3] = { 0 };
-                srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
-                srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
-                srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
+                srcTextUpdated[0] = TextReplaceAlloc(srcText, "int main(void)\n{", mainReplaceText);
+                srcTextUpdated[1] = TextReplaceAlloc(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
+                srcTextUpdated[2] = TextReplaceAlloc(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
                 UnloadFileText(srcText);
 
                 SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[2]);
                 for (int i = 0; i < 3; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
 
                 // STEP 2: Build example for DESKTOP platform
-    #if defined(_WIN32)
-                // Set required environment variables
-                //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
-                _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
-                //putenv("MAKE=mingw32-make");
-                //ChangeDirectory(exBasePath);
-    #endif
                 // Build example for PLATFORM_DESKTOP
     #if defined(_WIN32)
                 LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
-                system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1",
+                system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1",
                     exBasePath, exCategory, exName, exBasePath, exCategory, exName));
     #elif defined(PLATFORM_DRM)
                 LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);
@@ -1670,7 +1675,7 @@
                 FileRemove(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
 
                 // STEP 3: Run example with required arguments
-                // NOTE: Not easy to retrieve process return value from system(), it's platform dependant
+                // NOTE: Not easy to retrieve process return value from system(), it's platform dependent
                 ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory));
 
     #if defined(_WIN32)
@@ -1866,6 +1871,56 @@
             //-----------------------------------------------------------------------------------------------------
 
         } break;
+        case OP_CLEAN:  // Clean
+        {
+            LOG("INFO: Command requested: CLEAN\n");
+
+            int filesDeleted = 0;
+
+            for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
+            {
+                FilePathList pathList = LoadDirectoryFiles(TextFormat("%s/%s", exBasePath, exCategories[i]));
+
+                for (int i = 0; i < pathList.count; i++)
+                {
+                    const char *path = pathList.paths[i];
+
+                    if (IsPathFile(path))
+                    {
+                        const char *extension = GetFileExtension(path);
+                        if ((strcmp(extension, ".exe") == 0) ||     // Windows executable
+                            (extension == NULL) ||                  // Executable for non-Windows platforms
+                            (strcmp(extension, ".html") == 0) ||    // Web build output
+                            (strcmp(extension, ".js") == 0) ||      // Web build output
+                            (strcmp(extension, ".wasm") == 0) ||    // Web build output
+                            (strcmp(extension, ".data") == 0))      // Web build output
+                        {
+                            LOG("INFO: Deleting file [%s]\n", path);
+                            FileRemove(path);
+                            filesDeleted += 1;
+                        }
+                    }
+                }
+
+                UnloadDirectoryFiles(pathList);
+
+                // OP_TEST creates a 'logs' directory inside of example category directories
+                // Raylib currently has no way of deleting directories...
+                // We can at least delete the files
+                FilePathList logsPathList = LoadDirectoryFiles(TextFormat("%s/%s/logs", exBasePath, exCategories[i]));
+                for (int i = 0; i < logsPathList.count; i++)
+                {
+                    const char *logPath = logsPathList.paths[i];
+                    LOG("INFO: Deleting file [%s]\n", logPath);
+                    FileRemove(logPath);
+                    filesDeleted += 1;
+                }
+
+                UnloadDirectoryFiles(logsPathList);
+            }
+
+            LOG("INFO: Deleted %d files\n", filesDeleted);
+        } break;
         default:    // Help
         {
             // Supported commands:
@@ -1880,7 +1935,7 @@
             printf("\n////////////////////////////////////////////////////////////////////////////////////////////\n");
             printf("//                                                                                        //\n");
             printf("// rexm [raylib examples manager] - A simple command-line tool to manage raylib examples  //\n");
-            printf("// powered by raylib v5.6-dev                                                             //\n");
+            printf("// powered by raylib v6.0                                                                 //\n");
             printf("//                                                                                        //\n");
             printf("// Copyright (c) 2025-2026 Ramon Santamaria (@raysan5)                                    //\n");
             printf("//                                                                                        //\n");
@@ -1896,12 +1951,16 @@
             printf("    rename <old_examples_name> <new_example_name> : Rename an existing example\n");
             printf("    remove <example_name>         : Remove an existing example\n");
             printf("    build <example_name>          : Build example for Desktop and Web platforms\n");
-            printf("    test <example_name>           : Build and Test example for Desktop and Web platforms\n");
+            printf("    test <example_name>           : Build and test example for Desktop and Web platforms\n");
+            printf("    testlog <example_name>        : Validate test logs, generates report\n");
             printf("    validate                      : Validate examples collection, generates report\n");
-            printf("    update                        : Validate and update examples collection, generates report\n\n");
+            printf("    update                        : Validate and update examples collection, generates report\n");
+            printf("    clean                         : Delete files generated during other commands, excluding reports\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 <shapes_custom_stars>\n\n");
@@ -1972,7 +2031,6 @@
     //------------------------------------------------------------------------------------------------
 
     // Edit: raylib/examples/Makefile.Web --> Update from collection
-    // NOTE: We avoid the "others" category on web building
     //------------------------------------------------------------------------------------------------
     LOG("INFO: Updating raylib/examples/Makefile.Web\n");
     char *mkwText = LoadFileText(TextFormat("%s/Makefile.Web", exBasePath));
@@ -1985,8 +2043,7 @@
     memcpy(mkwTextUpdated, mkwText, mkwListStartIndex);
     mkwIndex = sprintf(mkwTextUpdated + mkwListStartIndex, "#EXAMPLES_LIST_START\n");
 
-    // NOTE: We avoid the "others" category on web building
-    for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++)
+    for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
     {
         mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("%s = \\\n", TextToUpper(exCategories[i])));
 
@@ -2011,8 +2068,7 @@
     mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, "shaders: $(SHADERS)\n");
     mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, "audio: $(AUDIO)\n\n");
 
-    // NOTE: We avoid the "others" category on web building
-    for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++)
+    for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
     {
         mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("# Compile %s examples\n", TextToUpper(exCategories[i])));
 
@@ -2046,7 +2102,7 @@
                     // In this case, we focus on web building for: glsl100
                     if (TextFindIndex(resPaths[r], "glsl%i") > -1)
                     {
-                        char *resPathUpdated = TextReplace(resPaths[r], "glsl%i", "glsl100");
+                        char *resPathUpdated = TextReplaceAlloc(resPaths[r], "glsl%i", "glsl100");
                         memset(resPaths[r], 0, 256);
                         strcpy(resPaths[r], resPathUpdated);
                         RL_FREE(resPathUpdated);
@@ -2151,7 +2207,7 @@
         {
             mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, TextFormat("\n### category: shaders [%i]\n\n", exCollectionCount));
             mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
-                "Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.\n\n");
+                "Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.h) module.\n\n");
         }
         else if (i == 6)    // "audio"
         {
@@ -2159,12 +2215,6 @@
             mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
                 "Examples using raylib audio functionality, including sound/music loading and playing. This functionality is provided by raylib [raudio](../src/raudio.c) module. Note this module can be used standalone independently of raylib.\n\n");
         }
-        else if (i == 7)    // "others"
-        {
-            mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, TextFormat("\n### category: others [%i]\n\n", exCollectionCount));
-            mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
-                "Examples showing raylib misc functionality that does not fit in other categories, like standalone modules usage or examples integrating external libraries.\n\n");
-        }
 
         // Table header required
         mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, "|  example  | image  | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |\n");
@@ -2227,8 +2277,7 @@
 
             char starsText[16] = { 0 };
 
-            // NOTE: We avoid "others" category
-            for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++)
+            for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
             {
                 int exCollectionCount = 0;
                 rlExampleInfo *exCollection = LoadExampleData(exCategories[i], false, &exCollectionCount);
@@ -2295,8 +2344,7 @@
                  (lines[i][0] == 's') ||      // shapes, shaders
                  (lines[i][0] == 't') ||      // textures, text
                  (lines[i][0] == 'm') ||      // models
-                 (lines[i][0] == 'a') ||      // audio
-                 (lines[i][0] == 'o')))       // TODO: Get others category?
+                 (lines[i][0] == 'a')))       // audio
             {
                 rlExampleInfo info = { 0 };
                 int result = ParseExampleInfoLine(lines[i], &info);
@@ -2353,7 +2401,7 @@
         // 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);
@@ -2399,7 +2447,7 @@
         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);
@@ -2447,7 +2495,7 @@
     #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;
@@ -2510,25 +2558,21 @@
     qsort(items, count, sizeof(rlExampleInfo), rlExampleInfoCompare);
 }
 
-// Scan resource paths in example file
-// WARNING: Supported resource file extensions is hardcoded by used file types
-// but new examples could require other file extensions to be added,
-// maybe it should look for '.xxx")' patterns instead
-// TODO: WARNING: Some resources could require linked resources: .fnt --> .png, .mtl --> .png, .gltf --> .png, ...
-static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount)
+// Scan asset paths from a source code file (raylib)
+// WARNING: Supported asset file extensions are hardcoded by used file types
+// but new examples could require other file extensions to be added
+static char **LoadExampleResourcePaths(const char *srcFilePath, int *resPathCount)
 {
-    #define REXM_MAX_RESOURCE_PATH_LEN    256
-
     char **paths = (char **)RL_CALLOC(REXM_MAX_RESOURCE_PATHS, sizeof(char **));
-    for (int i = 0; i < REXM_MAX_RESOURCE_PATHS; i++) paths[i] = (char *)RL_CALLOC(REXM_MAX_RESOURCE_PATH_LEN, sizeof(char));
+    for (int i = 0; i < REXM_MAX_RESOURCE_PATHS; i++) paths[i] = (char *)RL_CALLOC(REXM_MAX_RESOURCE_PATH_LENGTH, sizeof(char));
 
     int resCounter = 0;
-    char *code = LoadFileText(filePath);
+    char *code = LoadFileText(srcFilePath);
 
     if (code != NULL)
     {
         // Resources extensions to check
-        const char *exts[] = { ".png", ".bmp", ".jpg", ".qoi", ".gif", ".raw", ".hdr", ".ttf", ".fnt", ".wav", ".ogg", ".mp3", ".flac", ".mod", ".qoa", ".obj", ".iqm", ".glb", ".m3d", ".vox", ".vs", ".fs", ".txt" };
+        const char *exts[] = { ".png", ".bmp", ".jpg", ".qoi", ".gif", ".raw", ".hdr", ".ttf", ".fnt", ".wav", ".ogg", ".mp3", ".flac", ".mod", ".xm", ".qoa", ".obj", ".iqm", ".glb", ".m3d", ".vox", ".vs", ".fs", ".txt" };
         const int extCount = sizeof(exts)/sizeof(char *);
 
         char *ptr = code;
@@ -2554,9 +2598,9 @@
                 !((functionIndex05 != -1) && (functionIndex05 < 40)))    // Not found SaveFileText() before ""
             {
                 int len = (int)(end - start);
-                if ((len > 0) && (len < REXM_MAX_RESOURCE_PATH_LEN))
+                if ((len > 0) && (len < REXM_MAX_RESOURCE_PATH_LENGTH))
                 {
-                    char buffer[REXM_MAX_RESOURCE_PATH_LEN] = { 0 };
+                    char buffer[REXM_MAX_RESOURCE_PATH_LENGTH] = { 0 };
                     strncpy(buffer, start, len);
                     buffer[len] = '\0';
 
@@ -2592,6 +2636,29 @@
         UnloadFileText(code);
     }
 
+    /*
+    // WARNING: Some resources could require linked resources: .fnt --> .png, .mtl --> .png, .gltf --> .png
+    // So doing a recursive pass to scan possible files with second resources
+    int currentAssetCounter = resCounter;
+    for (int i = 0; i < currentAssetCounter; i++)
+    {
+        if (IsFileExtension(paths[i], ".fnt;.gltf"))
+        {
+            int assetCount2 = 0;
+            // ERROR: srcFilePath changes on rcursive call and TextFormat() static arrays are override
+            char **assetPaths2 = LoadExampleResourcePaths(TextFormat("%s/%s", GetDirectoryPath(srcFilePath), paths[i]), &assetCount2);
+
+            for (int j = 0; j < assetCount2; j++)
+            {
+                strcpy(paths[resCounter], TextFormat("%s/%s", GetDirectoryPath(paths[i]) + 2, assetPaths2[j]));
+                resCounter++;
+            }
+
+            UnloadExampleResourcePaths(assetPaths2);
+        }
+    }
+    */
+
     *resPathCount = resCounter;
     return paths;
 }
@@ -2698,21 +2765,21 @@
 
     // Add project folder line
     // NOTE: Folder uuid depends on category
-    if (strcmp(category, "core") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    if (strcmp(category, "core") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}\n", uuid));
-    else if (strcmp(category, "shapes") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "shapes") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {278D8859-20B1-428F-8448-064F46E1F021}\n", uuid));
-    else if (strcmp(category, "textures") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "textures") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}\n", uuid));
-    else if (strcmp(category, "text") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "text") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}\n", uuid));
-    else if (strcmp(category, "models") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "models") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}\n", uuid));
-    else if (strcmp(category, "shaders") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "shaders") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}\n", uuid));
-    else if (strcmp(category, "audio") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "audio") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}\n", uuid));
-    else if (strcmp(category, "other") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, 
+    else if (strcmp(category, "other") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
         TextFormat("\t\t{%s} = {E9D708A5-9C1F-4B84-A795-C5F191801762}\n", uuid));
     else LOG("WARNING: Provided category is not valid: %s\n", category);
     //----------------------------------------------------------------------------------------
@@ -2827,7 +2894,7 @@
 
         // Update example header title (line #3 - ALWAYS)
         // String: "*   raylib [shaders] example - texture drawing"
-        exTextUpdated[0] = TextReplaceBetween(exTextUpdatedPtr, "*   raylib [", "\n",
+        exTextUpdated[0] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "*   raylib [", "\n",
             TextFormat("%s] example - %s", info->category, exNameFormated));
         if (exTextUpdated[0] != NULL) exTextUpdatedPtr = exTextUpdated[0];
 
@@ -2841,13 +2908,13 @@
             if (i < info->stars) strcpy(starsText + 3*i, "★");
             else strcpy(starsText + 3*i, "☆");
         }
-        exTextUpdated[1] = TextReplaceBetween(exTextUpdatedPtr, "*   Example complexity rating: [", "/4\n",
+        exTextUpdated[1] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "*   Example complexity rating: [", "/4\n",
             TextFormat("%s] %i", starsText, info->stars));
         if (exTextUpdated[1] != NULL) exTextUpdatedPtr = exTextUpdated[1];
 
         // Update example creation/update raylib versions
         // String: "*   Example originally created with raylib 2.0, last time updated with raylib 3.7
-        exTextUpdated[2] = TextReplaceBetween(exTextUpdatedPtr, "*   Example originally created with raylib ", "\n",
+        exTextUpdated[2] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "*   Example originally created with raylib ", "\n",
             TextFormat("%s, last time updated with raylib %s", info->verCreated, info->verUpdated));
         if (exTextUpdated[2] != NULL) exTextUpdatedPtr = exTextUpdated[2];
 
@@ -2855,27 +2922,27 @@
         // String: "*   Copyright (c) 2019-2026 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)"
         if (info->yearCreated == info->yearReviewed)
         {
-            exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")",
+            exTextUpdated[3] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "Copyright (c) ", ")",
                 TextFormat("%i %s (@%s", info->yearCreated, info->author, info->authorGitHub));
             if (exTextUpdated[3] != NULL) exTextUpdatedPtr = exTextUpdated[3];
         }
         else
         {
-            exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")",
+            exTextUpdated[3] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "Copyright (c) ", ")",
                 TextFormat("%i-%i %s (@%s", info->yearCreated, info->yearReviewed, info->author, info->authorGitHub));
             if (exTextUpdated[3] != NULL) exTextUpdatedPtr = exTextUpdated[3];
         }
 
         // Update window title
         // String: "InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture drawing");"
-        exTextUpdated[4] = TextReplaceBetween(exTextUpdated[3], "InitWindow(screenWidth, screenHeight, \"", "\");",
+        exTextUpdated[4] = TextReplaceBetweenAlloc(exTextUpdated[3], "InitWindow(screenWidth, screenHeight, \"", "\");",
             TextFormat("raylib [%s] example - %s", info->category, exNameFormated));
         if (exTextUpdated[4] != NULL) exTextUpdatedPtr = exTextUpdated[4];
 
         // Update contributors names
         // String: "*   Example contributed by Contributor Name (@github_user) and reviewed by Ramon Santamaria (@raysan5)"
         // WARNING: Not all examples are contributed by someone, so the result of this replace can be NULL (string not found)
-        exTextUpdated[5] = TextReplaceBetween(exTextUpdatedPtr, "*   Example contributed by ", ")",
+        exTextUpdated[5] = TextReplaceBetweenAlloc(exTextUpdatedPtr, "*   Example contributed by ", ")",
             TextFormat("%s (@%s", info->author, info->authorGitHub));
         if (exTextUpdated[5] != NULL) exTextUpdatedPtr = exTextUpdated[5];
 
@@ -2905,7 +2972,7 @@
         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] = ' '; }
 
@@ -2922,14 +2989,14 @@
         UnloadFileText(exText);
 
         // Update example.html required text
-        exHtmlTextUpdated[0] = TextReplace(exHtmlText, "raylib web game", exTitle);
-        exHtmlTextUpdated[1] = TextReplace(exHtmlTextUpdated[0], "New raylib web videogame, developed using raylib videogames library", exDescription);
-        exHtmlTextUpdated[2] = TextReplace(exHtmlTextUpdated[1], "https://www.raylib.com/common/raylib_logo.png",
+        exHtmlTextUpdated[0] = TextReplaceAlloc(exHtmlText, "raylib web game", exTitle);
+        exHtmlTextUpdated[1] = TextReplaceAlloc(exHtmlTextUpdated[0], "New raylib web videogame, developed using raylib videogames library", exDescription);
+        exHtmlTextUpdated[2] = TextReplaceAlloc(exHtmlTextUpdated[1], "https://www.raylib.com/common/raylib_logo.png",
             TextFormat("https://raw.githubusercontent.com/raysan5/raylib/master/examples/%s/%s.png", exCategory, exName));
-        exHtmlTextUpdated[3] = TextReplace(exHtmlTextUpdated[2], "https://www.raylib.com/games.html",
+        exHtmlTextUpdated[3] = TextReplaceAlloc(exHtmlTextUpdated[2], "https://www.raylib.com/games.html",
             TextFormat("https://www.raylib.com/examples/%s/%s.html", exCategory, exName));
-        exHtmlTextUpdated[4] = TextReplace(exHtmlTextUpdated[3], "raylib - example", TextFormat("raylib - %s", exName)); // og:site_name
-        exHtmlTextUpdated[5] = TextReplace(exHtmlTextUpdated[4], "https://github.com/raysan5/raylib",
+        exHtmlTextUpdated[4] = TextReplaceAlloc(exHtmlTextUpdated[3], "raylib - example", TextFormat("raylib - %s", exName)); // og:site_name
+        exHtmlTextUpdated[5] = TextReplaceAlloc(exHtmlTextUpdated[4], "https://github.com/raysan5/raylib",
             TextFormat("https://github.com/raysan5/raylib/blob/master/examples/%s/%s.c", exCategory, exName));
 
         SaveFileText(exHtmlPathCopy, exHtmlTextUpdated[5]);
diff --git a/raylib/tools/rlparser/rlparser.c b/raylib/tools/rlparser/rlparser.c
--- a/raylib/tools/rlparser/rlparser.c
+++ b/raylib/tools/rlparser/rlparser.c
@@ -9,10 +9,10 @@
      - struct AliasInfo
      - struct EnumInfo
      - struct FunctionInfo
-     
+
     WARNING: This parser is specifically designed to work with raylib.h, and has some contraints
     in that regards. Still, it can also work with other header files that follow same file structure
-    conventions as raylib.h: rlgl.h, raymath.h, raygui.h, reasings.h 
+    conventions as raylib.h: rlgl.h, raymath.h, raygui.h, reasings.h
 
     CONSTRAINTS:
     This parser is specifically designed to work with raylib.h, so, it has some constraints:
@@ -146,7 +146,7 @@
 } 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
@@ -198,11 +198,11 @@
 //----------------------------------------------------------------------------------
 // Program main entry point
 //----------------------------------------------------------------------------------
-int main(int argc, char* argv[])
+int main(int argc, char *argv[])
 {
     if (argc > 1) ProcessCommandLine(argc, argv);
 
-    const char *raylibhPath = "../src/raylib.h\0";
+    const char *raylibhPath = "../../src/raylib.h\0";
     const char *raylibapiPath = "raylib_api.txt\0";
     const char *rlapiPath = "RLAPI\0";
     if (inFileName[0] == '\0') MemoryCopy(inFileName, raylibhPath, TextLength(raylibhPath) + 1);
@@ -260,8 +260,9 @@
     for (int i = 0; i < lineCount; i++)
     {
         int j = 0;
-        while ((lines[i][j] == ' ') || (lines[i][j] == '\t')) j++; // skip spaces and tabs in the begining
-        // Read define line
+        while ((lines[i][j] == ' ') || (lines[i][j] == '\t')) j++; // Skip spaces and tabs in the beginning
+
+        // Read one define line
         if (IsTextEqual(lines[i]+j, "#define ", 8))
         {
             // Keep the line position in the array of lines,
@@ -289,8 +290,10 @@
                     if (v == '{') validStruct = true;
                     if ((v == '{') || (v == ';') || (v == '\0')) break;
                 }
+
+                continue;
             }
-            if (!validStruct) continue;
+
             structLines[structCount] = i;
             while (lines[i][0] != '}') i++;
             while (lines[i][0] != '\0') i++;
@@ -314,7 +317,9 @@
                 if ((v == ';') && (spaceCount == 2)) validAlias = true;
                 if ((v == ';') || (v == '(') || (v == '\0')) break;
             }
+
             if (!validAlias) continue;
+
             aliasLines[aliasCount] = i;
             aliasCount++;
         }
@@ -385,7 +390,7 @@
         char *linePtr = lines[defineLines[i]];
         int j = 0;
 
-        while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs in the begining
+        while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs in the beginning
         j += 8;                                                  // Skip "#define "
         while ((linePtr[j] == ' ') || (linePtr[j] == '\t')) j++; // Skip spaces and tabs after "#define "
 
@@ -444,6 +449,7 @@
                       (ch == '-'))) isNumber = false;
                 j++;
             }
+
             if (isNumber)
             {
                 if (isFloat)
@@ -600,6 +606,7 @@
 
         defineIndex++;
     }
+
     defineCount = defineIndex;
     free(defineLines);
 
@@ -614,7 +621,7 @@
         GetDescription(linesPtr[-1], structs[i].desc);
 
         // Get struct name: typedef struct name {
-        const int TDS_LEN = 15; // length of "typedef struct "
+        const int TDS_LEN = 15; // Length of "typedef struct "
         for (int c = TDS_LEN; c < 64 + TDS_LEN; c++)
         {
             if ((linesPtr[0][c] == '{') || (linesPtr[0][c] == ' '))
@@ -640,8 +647,6 @@
 
                 if ((fieldLine[0] != '/') && !IsTextEqual(fieldLine, "struct", 6)) // Field line is not a comment and not a struct declaration
                 {
-                    //printf("Struct field: %s_\n", fieldLine);     // OK!
-
                     // Get struct field type and name
                     GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
 
@@ -721,7 +726,8 @@
                             char v = structs[i].fieldType[originalIndex][k];
                             if ((v == '*') || (v == ' ') || (v == ','))
                             {
-                                if (nameEnd != -1) {
+                                if (nameEnd != -1)
+                                {
                                     // Don't copy to last additional field
                                     if (fieldsRemaining != additionalFields)
                                     {
@@ -773,15 +779,23 @@
         // Skip "typedef "
         int c = 8;
 
-        // Type
+        // Type word part
         int typeStart = c;
         while(linePtr[c] != ' ') c++;
         int typeLen = c - typeStart;
-        MemoryCopy(aliases[i].type, &linePtr[typeStart], typeLen);
 
         // Skip space
         c++;
 
+        // Maybe type pointer part
+        if (linePtr[c] == '*')
+        {
+            while(linePtr[c] == '*') c++;
+            typeLen = c - typeStart;
+        }
+
+        MemoryCopy(aliases[i].type, &linePtr[typeStart], typeLen);
+
         // Name
         int nameStart = c;
         while(linePtr[c] != ';') c++;
@@ -1011,9 +1025,7 @@
                     ((linePtr[c - 4] == 'v') &&
                      (linePtr[c - 3] == 'o') &&
                      (linePtr[c - 2] == 'i') &&
-                     (linePtr[c - 1] == 'd'))) {
-                  break;
-                }
+                     (linePtr[c - 1] == 'd'))) break;
 
                 // Get parameter type + name, extract info
                 char funcParamTypeName[128] = { 0 };
@@ -1060,6 +1072,7 @@
     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);
@@ -1096,10 +1109,10 @@
     printf("    -i, --input <filename.h>        : Define input header file to parse.\n");
     printf("                                      NOTE: If not specified, defaults to: raylib.h\n\n");
     printf("    -o, --output <filename.ext>     : 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 <type>             : 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 <DEF>              : 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 <after>          : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n");
@@ -1152,7 +1165,8 @@
                 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], "CODE\0", 4)) outputFormat = CODE;
+                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");
         }
@@ -2005,6 +2019,131 @@
             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;
     }
diff --git a/src/Raylib/Core.hs b/src/Raylib/Core.hs
--- a/src/Raylib/Core.hs
+++ b/src/Raylib/Core.hs
@@ -132,7 +132,9 @@
     fileExists,
     directoryExists,
     isFileExtension,
+    isFileHidden,
     getFileLength,
+    getFileModTime,
     getFileExtension,
     getFileName,
     getFileNameWithoutExt,
@@ -148,7 +150,8 @@
     loadDirectoryFilesEx,
     isFileDropped,
     loadDroppedFiles,
-    getFileModTime,
+    getDirectoryFileCount,
+    getDirectoryFileCountEx,
     compressData,
     decompressData,
     encodeDataBase64,
@@ -156,6 +159,7 @@
     computeCRC32,
     computeMD5,
     computeSHA1,
+    computeSHA256,
     loadAutomationEventList,
     newAutomationEventList,
     exportAutomationEventList,
@@ -344,7 +348,9 @@
     c'fileTextFindIndex,
     c'directoryExists,
     c'isFileExtension,
+    c'isFileHidden,
     c'getFileLength,
+    c'getFileModTime,
     c'getFileExtension,
     c'getFileName,
     c'getFileNameWithoutExt,
@@ -361,8 +367,9 @@
     c'unloadDirectoryFiles,
     c'isFileDropped,
     c'loadDroppedFiles,
+    c'getDirectoryFileCount,
+    c'getDirectoryFileCountEx,
     c'unloadDroppedFiles,
-    c'getFileModTime,
     c'compressData,
     c'decompressData,
     c'encodeDataBase64,
@@ -370,6 +377,7 @@
     c'computeCRC32,
     c'computeMD5,
     c'computeSHA1,
+    c'computeSHA256,
     c'loadAutomationEventList,
     c'exportAutomationEventList,
     c'setAutomationEventList,
@@ -619,8 +627,8 @@
        ("c'setConfigFlags", "SetConfigFlags_", "rl_bindings.h", [t|CUInt -> IO ()|]),
        ("c'traceLog", "TraceLog_", "rl_bindings.h", [t|CInt -> CString -> IO ()|]), -- Uses varags, can't implement complete functionality
        ("c'setTraceLogLevel", "SetTraceLogLevel_", "rl_bindings.h", [t|CInt -> IO ()|]),
-       ("c'memAlloc", "MemAlloc_", "rl_bindings.h", [t|CInt -> IO (Ptr ())|]),
-       ("c'memRealloc", "MemRealloc_", "rl_bindings.h", [t|Ptr () -> CInt -> IO (Ptr ())|]),
+       ("c'memAlloc", "MemAlloc_", "rl_bindings.h", [t|CUInt -> IO (Ptr ())|]),
+       ("c'memRealloc", "MemRealloc_", "rl_bindings.h", [t|Ptr () -> CUInt -> IO (Ptr ())|]),
        ("c'memFree", "MemFree_", "rl_bindings.h", [t|Ptr () -> IO ()|]),
        ("c'openURL", "OpenURL_", "rl_bindings.h", [t|CString -> IO ()|]),
        ("c'setTraceLogCallback", "SetTraceLogCallback_", "rl_bindings.h", [t|C'TraceLogCallback -> IO ()|]),
@@ -644,7 +652,9 @@
        ("c'fileTextFindIndex", "FileTextFindIndex_", "rl_bindings.h", [t|CString -> CString -> IO CInt|]),
        ("c'directoryExists", "DirectoryExists_", "rl_bindings.h", [t|CString -> IO CBool|]),
        ("c'isFileExtension", "IsFileExtension_", "rl_bindings.h", [t|CString -> CString -> IO CBool|]),
-       ("c'getFileLength", "GetFileLength_", "rl_bindings.h", [t|CString -> IO CBool|]),
+       ("c'isFileHidden", "IsFileHidden_", "rl_bindings.h", [t|CString -> IO CBool|]),
+       ("c'getFileLength", "GetFileLength_", "rl_bindings.h", [t|CString -> IO CInt|]),
+       ("c'getFileModTime", "GetFileModTime_", "rl_bindings.h", [t|CString -> IO CLong|]),
        ("c'getFileExtension", "GetFileExtension_", "rl_bindings.h", [t|CString -> IO CString|]),
        ("c'getFileName", "GetFileName_", "rl_bindings.h", [t|CString -> IO CString|]),
        ("c'getFileNameWithoutExt", "GetFileNameWithoutExt_", "rl_bindings.h", [t|CString -> IO CString|]),
@@ -653,7 +663,7 @@
        ("c'getWorkingDirectory", "GetWorkingDirectory_", "rl_bindings.h", [t|IO CString|]),
        ("c'getApplicationDirectory", "GetApplicationDirectory_", "rl_bindings.h", [t|IO CString|]),
        ("c'makeDirectory", "MakeDirectory_", "rl_bindings.h", [t|CString -> IO CInt|]),
-       ("c'changeDirectory", "ChangeDirectory_", "rl_bindings.h", [t|CString -> IO CBool|]),
+       ("c'changeDirectory", "ChangeDirectory_", "rl_bindings.h", [t|CString -> IO CInt|]),
        ("c'isPathFile", "IsPathFile_", "rl_bindings.h", [t|CString -> IO CBool|]),
        ("c'isFileNameValid", "IsFileNameValid_", "rl_bindings.h", [t|CString -> IO CBool|]),
        ("c'loadDirectoryFiles", "LoadDirectoryFiles_", "rl_bindings.h", [t|CString -> IO (Ptr FilePathList)|]),
@@ -662,7 +672,8 @@
        ("c'isFileDropped", "IsFileDropped_", "rl_bindings.h", [t|IO CBool|]),
        ("c'loadDroppedFiles", "LoadDroppedFiles_", "rl_bindings.h", [t|IO (Ptr FilePathList)|]),
        ("c'unloadDroppedFiles", "UnloadDroppedFiles_", "rl_bindings.h", [t|Ptr FilePathList -> IO ()|]),
-       ("c'getFileModTime", "GetFileModTime_", "rl_bindings.h", [t|CString -> IO CLong|]),
+       ("c'getDirectoryFileCount", "GetDirectoryFileCount_", "rl_bindings.h", [t|CString -> IO CUInt|]),
+       ("c'getDirectoryFileCountEx", "GetDirectoryFileCountEx_", "rl_bindings.h", [t|CString -> CString -> CBool -> IO CUInt|]),
        ("c'compressData", "CompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|]),
        ("c'decompressData", "DecompressData_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO (Ptr CUChar)|]),
        ("c'encodeDataBase64", "EncodeDataBase64_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> Ptr CInt -> IO CString|]),
@@ -670,13 +681,14 @@
        ("c'computeCRC32", "ComputeCRC32_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> IO CUInt|]),
        ("c'computeMD5", "ComputeMD5_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> IO (Ptr CUInt)|]),
        ("c'computeSHA1", "ComputeSHA1_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> IO (Ptr CUInt)|]),
+       ("c'computeSHA256", "ComputeSHA256_", "rl_bindings.h", [t|Ptr CUChar -> CInt -> IO (Ptr CUInt)|]),
        ("c'loadAutomationEventList", "LoadAutomationEventList_", "rl_bindings.h", [t|CString -> IO (Ptr AutomationEventList)|]),
        ("c'exportAutomationEventList", "ExportAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> CString -> IO CBool|]),
        ("c'setAutomationEventList", "SetAutomationEventList_", "rl_bindings.h", [t|Ptr AutomationEventList -> IO ()|]),
        ("c'setAutomationEventBaseFrame", "SetAutomationEventBaseFrame_", "rl_bindings.h", [t|CInt -> IO ()|]),
        ("c'startAutomationEventRecording", "StartAutomationEventRecording_", "rl_bindings.h", [t|IO ()|]),
        ("c'stopAutomationEventRecording", "StopAutomationEventRecording_", "rl_bindings.h", [t|IO ()|]),
-       ("c'playAutomationEvent", "PlayAutomationEvent", "rl_bindings.h", [t|Ptr AutomationEvent -> IO ()|]),
+       ("c'playAutomationEvent", "PlayAutomationEvent_", "rl_bindings.h", [t|Ptr AutomationEvent -> IO ()|]),
        ("c'isKeyPressed", "IsKeyPressed_", "rl_bindings.h", [t|CInt -> IO CBool|]),
        ("c'isKeyPressedRepeat", "IsKeyPressedRepeat_", "rl_bindings.h", [t|CInt -> IO CBool|]),
        ("c'isKeyDown", "IsKeyDown_", "rl_bindings.h", [t|CInt -> IO CBool|]),
@@ -1179,9 +1191,15 @@
 isFileExtension :: String -> String -> IO Bool
 isFileExtension fileName ext = toBool <$> withCString fileName (withCString ext . c'isFileExtension)
 
-getFileLength :: String -> IO Bool
-getFileLength fileName = toBool <$> withCString fileName c'getFileLength
+isFileHidden :: String -> IO Bool
+isFileHidden fileName = toBool <$> withCString fileName c'isFileHidden
 
+getFileLength :: String -> IO Int
+getFileLength fileName = fromIntegral <$> withCString fileName c'getFileLength
+
+getFileModTime :: String -> IO Integer
+getFileModTime fileName = fromIntegral <$> withCString fileName c'getFileModTime
+
 getFileExtension :: String -> IO String
 getFileExtension fileName = withCString fileName c'getFileExtension >>= peekCString
 
@@ -1206,8 +1224,8 @@
 makeDirectory :: String -> IO Bool
 makeDirectory dirPath = (== 0) <$> withCString dirPath c'makeDirectory
 
-changeDirectory :: String -> IO Bool
-changeDirectory dir = toBool <$> withCString dir c'changeDirectory
+changeDirectory :: String -> IO Int
+changeDirectory dir = fromIntegral <$> withCString dir c'changeDirectory
 
 isPathFile :: String -> IO Bool
 isPathFile path = toBool <$> withCString path c'isPathFile
@@ -1232,9 +1250,12 @@
   c'unloadDroppedFiles ptr
   return val
 
-getFileModTime :: String -> IO Integer
-getFileModTime fileName = fromIntegral <$> withCString fileName c'getFileModTime
+getDirectoryFileCount :: String -> IO Integer
+getDirectoryFileCount dirPath = fromIntegral <$> withCString dirPath c'getDirectoryFileCount
 
+getDirectoryFileCountEx :: String -> String -> Bool -> IO Integer
+getDirectoryFileCountEx basePath filter scanSubdirs = fromIntegral <$> withCString basePath (\b -> withCString filter (\f -> c'getDirectoryFileCountEx b f (fromBool scanSubdirs)))
+
 compressData :: [Integer] -> IO [Integer]
 compressData contents = do
   withFreeableArrayLen
@@ -1321,6 +1342,16 @@
         return $ map fromIntegral arr
     )
 
+computeSHA256 :: [Integer] -> IO [Integer]
+computeSHA256 contents = do
+  withFreeableArrayLen
+    (map fromIntegral contents)
+    ( \size c -> do
+        encoded <- c'computeSHA256 c (fromIntegral $ size * sizeOf (0 :: CUChar))
+        arr <- peekArray 8 encoded
+        return $ map fromIntegral arr
+    )
+
 loadAutomationEventList :: String -> IO AutomationEventList
 loadAutomationEventList fileName = withCString fileName c'loadAutomationEventList >>= pop
 
@@ -1500,11 +1531,11 @@
 
 foreign import ccall unsafe "wrapper"
   mk'loadFileDataCallback ::
-    (CString -> Ptr CUInt -> IO (Ptr CUChar)) -> IO C'LoadFileDataCallback
+    (CString -> Ptr CInt -> IO (Ptr CUChar)) -> IO C'LoadFileDataCallback
 
 foreign import ccall unsafe "wrapper"
   mk'saveFileDataCallback ::
-    (CString -> Ptr () -> CUInt -> IO CInt) -> IO C'SaveFileDataCallback
+    (CString -> Ptr () -> CInt -> IO CBool) -> IO C'SaveFileDataCallback
 
 foreign import ccall unsafe "wrapper"
   mk'loadFileTextCallback ::
@@ -1512,7 +1543,7 @@
 
 foreign import ccall unsafe "wrapper"
   mk'saveFileTextCallback ::
-    (CString -> CString -> IO CInt) -> IO C'SaveFileTextCallback
+    (CString -> CString -> IO CBool) -> IO C'SaveFileTextCallback
 
 createTraceLogCallback :: TraceLogCallback -> IO C'TraceLogCallback
 createTraceLogCallback callback =
@@ -1530,7 +1561,7 @@
         do
           fn <- peekCString fileName
           arr <- callback fn
-          poke dataSize (fromIntegral (length arr) :: CUInt)
+          poke dataSize (fromIntegral (length arr) :: CInt)
           newArray (map fromIntegral arr :: [CUChar])
     )
 
diff --git a/src/Raylib/Core/Models.hs b/src/Raylib/Core/Models.hs
--- a/src/Raylib/Core/Models.hs
+++ b/src/Raylib/Core/Models.hs
@@ -34,8 +34,6 @@
     drawModelEx,
     drawModelWires,
     drawModelWiresEx,
-    drawModelPoints,
-    drawModelPointsEx,
     drawBoundingBox,
     drawBillboard,
     drawBillboardRec,
@@ -68,8 +66,8 @@
     setModelMeshMaterial,
     loadModelAnimations,
     updateModelAnimation,
+    updateModelAnimationEx,
     isModelAnimationValid,
-    updateModelAnimationBones,
     checkCollisionSpheres,
     checkCollisionBoxes,
     checkCollisionBoxSphere,
@@ -110,8 +108,6 @@
     c'drawModelEx,
     c'drawModelWires,
     c'drawModelWiresEx,
-    c'drawModelPoints,
-    c'drawModelPointsEx,
     c'drawBoundingBox,
     c'drawBillboard,
     c'drawBillboardRec,
@@ -144,10 +140,9 @@
     c'setModelMeshMaterial,
     c'loadModelAnimations,
     c'updateModelAnimation,
-    c'unloadModelAnimation,
+    c'updateModelAnimationEx,
     c'unloadModelAnimations,
     c'isModelAnimationValid,
-    c'updateModelAnimationBones,
     c'checkCollisionSpheres,
     c'checkCollisionBoxes,
     c'checkCollisionBoxSphere,
@@ -229,13 +224,11 @@
        ("c'drawModelEx", "DrawModelEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),
        ("c'drawModelWires", "DrawModelWires_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawModelWiresEx", "DrawModelWiresEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),
-       ("c'drawModelPoints", "DrawModelPoints_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),
-       ("c'drawModelPointsEx", "DrawModelPointsEx_", "rl_bindings.h", [t|Ptr Model -> Ptr Vector3 -> Ptr Vector3 -> CFloat -> Ptr Vector3 -> Ptr Color -> IO ()|]),
        ("c'drawBoundingBox", "DrawBoundingBox_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Color -> IO ()|]),
        ("c'drawBillboard", "DrawBillboard_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Vector3 -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawBillboardRec", "DrawBillboardRec_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
        ("c'drawBillboardPro", "DrawBillboardPro_", "rl_bindings.h", [t|Ptr Camera3D -> Ptr Texture -> Ptr Rectangle -> Ptr Vector3 -> Ptr Vector3 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
-       ("c'uploadMesh", "UploadMesh_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> IO ()|]),
+       ("c'uploadMesh", "UploadMesh_", "rl_bindings.h", [t|Ptr Mesh -> CBool -> IO ()|]),
        ("c'updateMeshBuffer", "UpdateMeshBuffer_", "rl_bindings.h", [t|Ptr Mesh -> CInt -> Ptr () -> CInt -> CInt -> IO ()|]),
        ("c'unloadMesh", "UnloadMesh_", "rl_bindings.h", [t|Ptr Mesh -> IO ()|]),
        ("c'drawMesh", "DrawMesh_", "rl_bindings.h", [t|Ptr Mesh -> Ptr Material -> Ptr Matrix -> IO ()|]),
@@ -262,11 +255,10 @@
        ("c'setMaterialTexture", "SetMaterialTexture_", "rl_bindings.h", [t|Ptr Material -> CInt -> Ptr Texture -> IO ()|]),
        ("c'setModelMeshMaterial", "SetModelMeshMaterial_", "rl_bindings.h", [t|Ptr Model -> CInt -> CInt -> IO ()|]),
        ("c'loadModelAnimations", "LoadModelAnimations_", "rl_bindings.h", [t|CString -> Ptr CInt -> IO (Ptr ModelAnimation)|]),
-       ("c'updateModelAnimation", "UpdateModelAnimation_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()|]),
-       ("c'unloadModelAnimation", "UnloadModelAnimation_", "rl_bindings.h", [t|Ptr ModelAnimation -> IO ()|]),
+       ("c'updateModelAnimation", "UpdateModelAnimation_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CFloat -> IO ()|]),
+       ("c'updateModelAnimationEx", "UpdateModelAnimationEx_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CFloat -> Ptr ModelAnimation -> CFloat -> CFloat -> IO ()|]),
        ("c'unloadModelAnimations", "UnloadModelAnimations_", "rl_bindings.h", [t|Ptr ModelAnimation -> CInt -> IO ()|]),
        ("c'isModelAnimationValid", "IsModelAnimationValid_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> IO CBool|]),
-       ("c'updateModelAnimationBones", "UpdateModelAnimationBones_", "rl_bindings.h", [t|Ptr Model -> Ptr ModelAnimation -> CInt -> IO ()|]),
        ("c'checkCollisionSpheres", "CheckCollisionSpheres_", "rl_bindings.h", [t|Ptr Vector3 -> CFloat -> Ptr Vector3 -> CFloat -> IO CBool|]),
        ("c'checkCollisionBoxes", "CheckCollisionBoxes_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr BoundingBox -> IO CBool|]),
        ("c'checkCollisionBoxSphere", "CheckCollisionBoxSphere_", "rl_bindings.h", [t|Ptr BoundingBox -> Ptr Vector3 -> CFloat -> IO CBool|]),
@@ -327,10 +319,10 @@
 drawCylinderWiresEx start end startRadius endRadius sides color = withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'drawCylinderWiresEx s e (realToFrac startRadius) (realToFrac endRadius) (fromIntegral sides))))
 
 drawCapsule :: Vector3 -> Vector3 -> Float -> Int -> Int -> Color -> IO ()
-drawCapsule start end radius slices rings color = withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'drawCapsule s e (realToFrac radius) (fromIntegral slices) (fromIntegral rings))))
+drawCapsule start end radius rings slices color = withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'drawCapsule s e (realToFrac radius) (fromIntegral rings) (fromIntegral slices))))
 
 drawCapsuleWires :: Vector3 -> Vector3 -> Float -> Int -> Int -> Color -> IO ()
-drawCapsuleWires start end radius slices rings color = withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'drawCapsuleWires s e (realToFrac radius) (fromIntegral slices) (fromIntegral rings))))
+drawCapsuleWires start end radius rings slices color = withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'drawCapsuleWires s e (realToFrac radius) (fromIntegral rings) (fromIntegral slices))))
 
 drawPlane :: Vector3 -> Vector2 -> Color -> IO ()
 drawPlane center size color = withFreeable center (\c -> withFreeable size (withFreeable color . c'drawPlane c))
@@ -378,12 +370,6 @@
 drawModelWiresEx :: Model -> Vector3 -> Vector3 -> Float -> Vector3 -> Color -> IO ()
 drawModelWiresEx model position rotationAxis rotationAngle scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable rotationAxis (\r -> withFreeable scale (withFreeable tint . c'drawModelWiresEx m p r (realToFrac rotationAngle)))))
 
-drawModelPoints :: Model -> Vector3 -> Float -> Color -> IO ()
-drawModelPoints model position scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable tint (c'drawModelPoints m p (realToFrac scale))))
-
-drawModelPointsEx :: Model -> Vector3 -> Vector3 -> Float -> Vector3 -> Color -> IO ()
-drawModelPointsEx model position rotationAxis rotationAngle scale tint = withFreeable model (\m -> withFreeable position (\p -> withFreeable rotationAxis (\r -> withFreeable scale (withFreeable tint . c'drawModelPointsEx m p r (realToFrac rotationAngle)))))
-
 drawBoundingBox :: BoundingBox -> Color -> IO ()
 drawBoundingBox box color = withFreeable box (withFreeable color . c'drawBoundingBox)
 
@@ -508,14 +494,14 @@
           )
     )
 
-updateModelAnimation :: Model -> ModelAnimation -> Int -> IO ()
-updateModelAnimation model animation frame = withFreeable model (\m -> withFreeable animation (\a -> c'updateModelAnimation m a (fromIntegral frame)))
+updateModelAnimation :: Model -> ModelAnimation -> Float -> IO ()
+updateModelAnimation model animation frame = withFreeable model (\m -> withFreeable animation (\a -> c'updateModelAnimation m a (realToFrac frame)))
 
+updateModelAnimationEx :: Model -> ModelAnimation -> Float -> ModelAnimation -> Float -> Float -> IO ()
+updateModelAnimationEx model animA frameA animB frameB blend = withFreeable model (\m -> withFreeable animA (\aa -> withFreeable animB (\ab -> c'updateModelAnimationEx m aa (realToFrac frameA) ab (realToFrac frameB) (realToFrac blend))))
+
 isModelAnimationValid :: Model -> ModelAnimation -> IO Bool
 isModelAnimationValid model animation = toBool <$> withFreeable model (withFreeable animation . c'isModelAnimationValid)
-
-updateModelAnimationBones :: Model -> ModelAnimation -> Int -> IO ()
-updateModelAnimationBones model animation frame = withFreeable model (\m -> withFreeable animation (\a -> c'updateModelAnimationBones m a (fromIntegral frame)))
 
 checkCollisionSpheres :: Vector3 -> Float -> Vector3 -> Float -> Bool
 checkCollisionSpheres center1 radius1 center2 radius2 = toBool $ unsafePerformIO (withFreeable center1 (\c1 -> withFreeable center2 (\c2 -> c'checkCollisionSpheres c1 (realToFrac radius1) c2 (realToFrac radius2))))
diff --git a/src/Raylib/Core/Shapes.hs b/src/Raylib/Core/Shapes.hs
--- a/src/Raylib/Core/Shapes.hs
+++ b/src/Raylib/Core/Shapes.hs
@@ -18,16 +18,19 @@
     drawCircle,
     drawCircleSector,
     drawCircleSectorLines,
+    drawCircleSectorLinesEx,
     drawCircleGradient,
     drawCircleV,
     drawCircleLines,
     drawCircleLinesV,
+    drawCircleLinesEx,
     drawEllipse,
     drawEllipseV,
     drawEllipseLines,
     drawEllipseLinesV,
     drawRing,
     drawRingLines,
+    drawRingLinesEx,
     drawRectangle,
     drawRectangleV,
     drawRectangleRec,
@@ -41,7 +44,9 @@
     drawRectangleRoundedLines,
     drawRectangleRoundedLinesEx,
     drawTriangle,
+    drawTriangleGradient,
     drawTriangleLines,
+    drawTriangleLinesEx,
     drawTriangleFan,
     drawTriangleStrip,
     drawPoly,
@@ -60,7 +65,7 @@
     getSplinePointLinear,
     getSplinePointBasis,
     getSplinePointCatmullRom,
-    getSplinePointBezierQuad,
+    getSplinePointBezierQuadratic,
     getSplinePointBezierCubic,
     checkCollisionRecs,
     checkCollisionCircles,
@@ -89,16 +94,19 @@
     c'drawCircle,
     c'drawCircleSector,
     c'drawCircleSectorLines,
+    c'drawCircleSectorLinesEx,
     c'drawCircleGradient,
     c'drawCircleV,
     c'drawCircleLines,
     c'drawCircleLinesV,
+    c'drawCircleLinesEx,
     c'drawEllipse,
     c'drawEllipseV,
     c'drawEllipseLines,
     c'drawEllipseLinesV,
     c'drawRing,
     c'drawRingLines,
+    c'drawRingLinesEx,
     c'drawRectangle,
     c'drawRectangleV,
     c'drawRectangleRec,
@@ -112,7 +120,9 @@
     c'drawRectangleRoundedLines,
     c'drawRectangleRoundedLinesEx,
     c'drawTriangle,
+    c'drawTriangleGradient,
     c'drawTriangleLines,
+    c'drawTriangleLinesEx,
     c'drawTriangleFan,
     c'drawTriangleStrip,
     c'drawPoly,
@@ -131,7 +141,7 @@
     c'getSplinePointLinear,
     c'getSplinePointBasis,
     c'getSplinePointCatmullRom,
-    c'getSplinePointBezierQuad,
+    c'getSplinePointBezierQuadratic,
     c'getSplinePointBezierCubic,
     c'checkCollisionRecs,
     c'checkCollisionCircles,
@@ -174,16 +184,19 @@
        ("c'drawCircle", "DrawCircle_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawCircleSector", "DrawCircleSector_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawCircleSectorLines", "DrawCircleSectorLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),
-       ("c'drawCircleGradient", "DrawCircleGradient_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> Ptr Color -> IO ()|]),
+       ("c'drawCircleSectorLinesEx", "DrawCircleSectorLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CInt -> CFloat -> Ptr Color -> IO ()|]),
+       ("c'drawCircleGradient", "DrawCircleGradient_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> Ptr Color -> IO ()|]),
        ("c'drawCircleV", "DrawCircleV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawCircleLines", "DrawCircleLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawCircleLinesV", "DrawCircleLinesV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
+       ("c'drawCircleLinesEx", "DrawCircleLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawEllipse", "DrawEllipse_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawEllipseV", "DrawEllipseV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawEllipseLines", "DrawEllipseLines_", "rl_bindings.h", [t|CInt -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawEllipseLinesV", "DrawEllipseLinesV_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawRing", "DrawRing_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawRingLines", "DrawRingLines_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> Ptr Color -> IO ()|]),
+       ("c'drawRingLinesEx", "DrawRingLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> CFloat -> CFloat -> CFloat -> CInt -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawRectangle", "DrawRectangle_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawRectangleV", "DrawRectangleV_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
        ("c'drawRectangleRec", "DrawRectangleRec_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Color -> IO ()|]),
@@ -197,7 +210,9 @@
        ("c'drawRectangleRoundedLines", "DrawRectangleRoundedLines_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawRectangleRoundedLinesEx", "DrawRectangleRoundedLinesEx_", "rl_bindings.h", [t|Ptr Rectangle -> CFloat -> CInt -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawTriangle", "DrawTriangle_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
+       ("c'drawTriangleGradient", "DrawTriangleGradient_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),
        ("c'drawTriangleLines", "DrawTriangleLines_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
+       ("c'drawTriangleLinesEx", "DrawTriangleLinesEx_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
        ("c'drawTriangleFan", "DrawTriangleFan_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawTriangleStrip", "DrawTriangleStrip_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
        ("c'drawPoly", "DrawPoly_", "rl_bindings.h", [t|Ptr Vector2 -> CInt -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
@@ -216,7 +231,7 @@
        ("c'getSplinePointLinear", "GetSplinePointLinear_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
        ("c'getSplinePointBasis", "GetSplinePointBasis_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
        ("c'getSplinePointCatmullRom", "GetSplinePointCatmullRom_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
-       ("c'getSplinePointBezierQuad", "GetSplinePointBezierQuad_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
+       ("c'getSplinePointBezierQuadratic", "GetSplinePointBezierQuadratic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
        ("c'getSplinePointBezierCubic", "GetSplinePointBezierCubic_", "rl_bindings.h", [t|Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> IO (Ptr Vector2)|]),
        ("c'checkCollisionRecs", "CheckCollisionRecs_", "rl_bindings.h", [t|Ptr Rectangle -> Ptr Rectangle -> IO CBool|]),
        ("c'checkCollisionCircles", "CheckCollisionCircles_", "rl_bindings.h", [t|Ptr Vector2 -> CFloat -> Ptr Vector2 -> CFloat -> IO CBool|]),
@@ -294,10 +309,21 @@
           )
     )
 
-drawCircleGradient :: Int -> Int -> Float -> Color -> Color -> IO ()
-drawCircleGradient centerX centerY radius inner outer =
-  withFreeable inner (withFreeable outer . c'drawCircleGradient (fromIntegral centerX) (fromIntegral centerY) (realToFrac radius))
+drawCircleSectorLinesEx :: Vector2 -> Float -> Float -> Float -> Int -> Float -> Color -> IO ()
+drawCircleSectorLinesEx center radius startAngle endAngle segments thick color =
+  withFreeable
+    center
+    ( \c ->
+        withFreeable
+          color
+          ( c'drawCircleSectorLinesEx c (realToFrac radius) (realToFrac startAngle) (realToFrac endAngle) (fromIntegral segments) (realToFrac thick)
+          )
+    )
 
+drawCircleGradient :: Vector2 -> Float -> Color -> Color -> IO ()
+drawCircleGradient center radius inner outer =
+  withFreeable center (\c -> withFreeable inner (withFreeable outer . c'drawCircleGradient c (realToFrac radius)))
+
 drawCircleV :: Vector2 -> Float -> Color -> IO ()
 drawCircleV center radius color =
   withFreeable center (\c -> withFreeable color (c'drawCircleV c (realToFrac radius)))
@@ -310,6 +336,10 @@
 drawCircleLinesV center radius color =
   withFreeable center (\c -> withFreeable color (c'drawCircleLinesV c (realToFrac radius)))
 
+drawCircleLinesEx :: Vector2 -> Float -> Float -> Color -> IO ()
+drawCircleLinesEx center radius thick color =
+  withFreeable center (\c -> withFreeable color (c'drawCircleLinesEx c (realToFrac radius) (realToFrac thick)))
+
 drawEllipse :: Int -> Int -> Float -> Float -> Color -> IO ()
 drawEllipse centerX centerY radiusH radiusV color =
   withFreeable color (c'drawEllipse (fromIntegral centerX) (fromIntegral centerY) (realToFrac radiusH) (realToFrac radiusV))
@@ -360,6 +390,24 @@
           )
     )
 
+drawRingLinesEx :: Vector2 -> Float -> Float -> Float -> Float -> Int -> Float -> Color -> IO ()
+drawRingLinesEx center innerRadius outerRadius startAngle endAngle segments thick color =
+  withFreeable
+    center
+    ( \c ->
+        withFreeable
+          color
+          ( c'drawRingLinesEx
+              c
+              (realToFrac innerRadius)
+              (realToFrac outerRadius)
+              (realToFrac startAngle)
+              (realToFrac endAngle)
+              (fromIntegral segments)
+              (realToFrac thick)
+          )
+    )
+
 drawRectangle :: Int -> Int -> Int -> Int -> Color -> IO ()
 drawRectangle posX posY width height color =
   withFreeable color (c'drawRectangle (fromIntegral posX) (fromIntegral posY) (fromIntegral width) (fromIntegral height))
@@ -445,6 +493,34 @@
           )
     )
 
+drawTriangleGradient :: Vector2 -> Vector2 -> Vector2 -> Color -> Color -> Color -> IO ()
+drawTriangleGradient v1 v2 v3 c1 c2 c3 =
+  withFreeable
+    v1
+    ( \p1 ->
+        withFreeable
+          v2
+          ( \p2 ->
+              withFreeable
+                v3
+                ( \p3 ->
+                    withFreeable
+                      c1
+                      ( \q1 ->
+                          withFreeable
+                            c2
+                            ( \q2 ->
+                                withFreeable
+                                  c3
+                                  ( \q3 ->
+                                    c'drawTriangleGradient p1 p2 p3 q1 q2 q3
+                                  )
+                            )
+                      )
+                )
+          )
+    )
+
 drawTriangleLines :: Vector2 -> Vector2 -> Vector2 -> Color -> IO ()
 drawTriangleLines v1 v2 v3 color =
   withFreeable
@@ -456,6 +532,22 @@
           )
     )
 
+drawTriangleLinesEx :: Vector2 -> Vector2 -> Vector2 -> Float -> Color -> IO ()
+drawTriangleLinesEx v1 v2 v3 thick color =
+  withFreeable
+    v1
+    ( \p1 ->
+        withFreeable
+          v2
+          ( \p2 ->
+              withFreeable
+                v3
+                ( \p3 ->
+                    withFreeable color (c'drawTriangleLinesEx p1 p2 p3 (realToFrac thick))
+                )
+          )
+    )
+
 drawTriangleFan :: [Vector2] -> Color -> IO ()
 drawTriangleFan points color = withFreeableArray points (\p -> withFreeable color $ c'drawTriangleFan p (genericLength points))
 
@@ -524,8 +616,8 @@
 getSplinePointCatmullRom :: Vector2 -> Vector2 -> Vector2 -> Vector2 -> Float -> Vector2
 getSplinePointCatmullRom p1 p2 p3 p4 t = unsafePerformIO $ withFreeable p1 (\q1 -> withFreeable p2 (\q2 -> withFreeable p3 (\q3 -> withFreeable p4 (\q4 -> c'getSplinePointCatmullRom q1 q2 q3 q4 (realToFrac t))))) >>= pop
 
-getSplinePointBezierQuad :: Vector2 -> Vector2 -> Vector2 -> Float -> Vector2
-getSplinePointBezierQuad p1 p2 p3 t = unsafePerformIO $ withFreeable p1 (\q1 -> withFreeable p2 (\q2 -> withFreeable p3 (\q3 -> c'getSplinePointBezierQuad q1 q2 q3 (realToFrac t)))) >>= pop
+getSplinePointBezierQuadratic :: Vector2 -> Vector2 -> Vector2 -> Float -> Vector2
+getSplinePointBezierQuadratic p1 p2 p3 t = unsafePerformIO $ withFreeable p1 (\q1 -> withFreeable p2 (\q2 -> withFreeable p3 (\q3 -> c'getSplinePointBezierQuadratic q1 q2 q3 (realToFrac t)))) >>= pop
 
 getSplinePointBezierCubic :: Vector2 -> Vector2 -> Vector2 -> Vector2 -> Float -> Vector2
 getSplinePointBezierCubic p1 p2 p3 p4 t = unsafePerformIO $ withFreeable p1 (\q1 -> withFreeable p2 (\q2 -> withFreeable p3 (\q3 -> withFreeable p4 (\q4 -> c'getSplinePointBezierCubic q1 q2 q3 q4 (realToFrac t))))) >>= pop
diff --git a/src/Raylib/Core/Text.hs b/src/Raylib/Core/Text.hs
--- a/src/Raylib/Core/Text.hs
+++ b/src/Raylib/Core/Text.hs
@@ -22,6 +22,7 @@
     setTextLineSpacing,
     measureText,
     measureTextEx,
+    measureTextCodepoints,
     getGlyphIndex,
     getGlyphInfo,
     getGlyphAtlasRec,
@@ -53,6 +54,7 @@
     c'setTextLineSpacing,
     c'measureText,
     c'measureTextEx,
+    c'measureTextCodepoints,
     c'getGlyphIndex,
     c'getGlyphInfo,
     c'getGlyphAtlasRec,
@@ -88,7 +90,7 @@
 import Raylib.Internal.TH (genNative)
 import Raylib.Types
   ( Color,
-    Font (font'texture),
+    Font (font'texture, font'glyphs),
     FontType,
     GlyphInfo,
     Image,
@@ -118,6 +120,7 @@
        ("c'setTextLineSpacing", "SetTextLineSpacing_", "rl_bindings.h", [t|CInt -> IO ()|]),
        ("c'measureText", "MeasureText_", "rl_bindings.h", [t|CString -> CInt -> IO CInt|]),
        ("c'measureTextEx", "MeasureTextEx_", "rl_bindings.h", [t|Ptr Font -> CString -> CFloat -> CFloat -> IO (Ptr Vector2)|]),
+       ("c'measureTextCodepoints", "MeasureTextCodepoints_", "rl_bindings.h", [t|Ptr Font -> Ptr CInt -> CInt -> CFloat -> CFloat -> IO (Ptr Vector2)|]),
        ("c'getGlyphIndex", "GetGlyphIndex_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO CInt|]),
        ("c'getGlyphInfo", "GetGlyphInfo_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr GlyphInfo)|]),
        ("c'getGlyphAtlasRec", "GetGlyphAtlasRec_", "rl_bindings.h", [t|Ptr Font -> CInt -> IO (Ptr Rectangle)|]),
@@ -231,11 +234,14 @@
 measureTextEx :: Font -> String -> Float -> Float -> IO Vector2
 measureTextEx font text fontSize spacing = withFreeable font (\f -> withCString text (\t -> c'measureTextEx f t (realToFrac fontSize) (realToFrac spacing))) >>= pop
 
+measureTextCodepoints :: Font -> [Int] -> Float -> Float -> IO Vector2
+measureTextCodepoints font codepoints fontSize spacing = withFreeable font (\f -> withFreeableArrayLen (map fromIntegral codepoints) (\l c -> c'measureTextCodepoints f c (fromIntegral l) (realToFrac fontSize) (realToFrac spacing))) >>= pop
+
 getGlyphIndex :: Font -> Int -> IO Int
 getGlyphIndex font codepoint = fromIntegral <$> withFreeable font (\f -> c'getGlyphIndex f (fromIntegral codepoint))
 
 getGlyphInfo :: Font -> Int -> IO GlyphInfo
-getGlyphInfo font codepoint = withFreeable font (\f -> c'getGlyphInfo f (fromIntegral codepoint)) >>= pop
+getGlyphInfo font codepoint = ((font'glyphs font) !!) <$> getGlyphIndex font codepoint
 
 getGlyphAtlasRec :: Font -> Int -> IO Rectangle
 getGlyphAtlasRec font codepoint = withFreeable font (\f -> c'getGlyphAtlasRec f (fromIntegral codepoint)) >>= pop
diff --git a/src/Raylib/Core/Textures.hs b/src/Raylib/Core/Textures.hs
--- a/src/Raylib/Core/Textures.hs
+++ b/src/Raylib/Core/Textures.hs
@@ -61,26 +61,37 @@
     imageDrawPixelV,
     imageDrawLine,
     imageDrawLineV,
+    imageDrawLineEx,
+    imageDrawLineStrip,
     imageDrawCircle,
     imageDrawCircleV,
     imageDrawCircleLines,
     imageDrawCircleLinesV,
+    imageDrawCircleGradient,
+    imageDrawImage,
+    imageDrawImageEx,
+    imageDrawImageRec,
+    imageDrawImagePro,
     imageDrawRectangle,
     imageDrawRectangleV,
     imageDrawRectangleRec,
+    imageDrawRectanglePro,
     imageDrawRectangleLines,
+    imageDrawRectangleLinesEx,
+    imageDrawRectangleGradientEx,
     imageDrawTriangle,
-    imageDrawTriangleEx,
+    imageDrawTriangleGradient,
     imageDrawTriangleLines,
     imageDrawTriangleFan,
     imageDrawTriangleStrip,
-    imageDraw,
     imageDrawText,
     imageDrawTextEx,
+    imageDrawTextPro,
     loadTexture,
     loadTextureFromImage,
     loadTextureCubemap,
     loadRenderTexture,
+    loadRenderTextureEx,
     isTextureValid,
     isRenderTextureValid,
     unloadTexture,
@@ -174,26 +185,37 @@
     c'imageDrawPixelV,
     c'imageDrawLine,
     c'imageDrawLineV,
+    c'imageDrawLineEx,
+    c'imageDrawLineStrip,
     c'imageDrawCircle,
     c'imageDrawCircleV,
     c'imageDrawCircleLines,
     c'imageDrawCircleLinesV,
+    c'imageDrawCircleGradient,
+    c'imageDrawImage,
+    c'imageDrawImageEx,
+    c'imageDrawImageRec,
+    c'imageDrawImagePro,
     c'imageDrawRectangle,
     c'imageDrawRectangleV,
     c'imageDrawRectangleRec,
+    c'imageDrawRectanglePro,
     c'imageDrawRectangleLines,
+    c'imageDrawRectangleLinesEx,
+    c'imageDrawRectangleGradientEx,
     c'imageDrawTriangle,
-    c'imageDrawTriangleEx,
+    c'imageDrawTriangleGradient,
     c'imageDrawTriangleLines,
     c'imageDrawTriangleFan,
     c'imageDrawTriangleStrip,
-    c'imageDraw,
     c'imageDrawText,
     c'imageDrawTextEx,
+    c'imageDrawTextPro,
     c'loadTexture,
     c'loadTextureFromImage,
     c'loadTextureCubemap,
     c'loadRenderTexture,
+    c'loadRenderTextureEx,
     c'isTextureValid,
     c'unloadTexture,
     c'isRenderTextureValid,
@@ -320,7 +342,7 @@
        ("c'imageColorTint", "ImageColorTint_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> IO ()|]),
        ("c'imageColorInvert", "ImageColorInvert_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),
        ("c'imageColorGrayscale", "ImageColorGrayscale_", "rl_bindings.h", [t|Ptr Image -> IO ()|]),
-       ("c'imageColorContrast", "ImageColorContrast_", "rl_bindings.h", [t|Ptr Image -> CFloat -> IO ()|]),
+       ("c'imageColorContrast", "ImageColorContrast_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),
        ("c'imageColorBrightness", "ImageColorBrightness_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO ()|]),
        ("c'imageColorReplace", "ImageColorReplace_", "rl_bindings.h", [t|Ptr Image -> Ptr Color -> Ptr Color -> IO ()|]),
        ("c'loadImageColors", "LoadImageColors_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Color)|]),
@@ -332,26 +354,37 @@
        ("c'imageDrawPixelV", "ImageDrawPixelV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Color -> IO ()|]),
        ("c'imageDrawLine", "ImageDrawLine_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawLineV", "ImageDrawLineV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
+       ("c'imageDrawLineEx", "ImageDrawLineEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawLineStrip", "ImageDrawLineStrip_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawCircle", "ImageDrawCircle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawCircleV", "ImageDrawCircleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawCircleLines", "ImageDrawCircleLines_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawCircleLinesV", "ImageDrawCircleLinesV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawCircleGradient", "ImageDrawCircleGradient_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CFloat -> Ptr Color -> Ptr Color -> IO ()|]),
+       ("c'imageDrawImage", "ImageDrawImage_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> CInt -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawImageEx", "ImageDrawImageEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
+       ("c'imageDrawImageRec", "ImageDrawImageRec_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Rectangle -> Ptr Vector2 -> Ptr Color -> IO ()|]),
+       ("c'imageDrawImagePro", "ImageDrawImagePro_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Rectangle -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
        ("c'imageDrawRectangle", "ImageDrawRectangle_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawRectangleV", "ImageDrawRectangleV_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
        ("c'imageDrawRectangleRec", "ImageDrawRectangleRec_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> Ptr Color -> IO ()|]),
-       ("c'imageDrawRectangleLines", "ImageDrawRectangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawRectanglePro", "ImageDrawRectanglePro_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> Ptr Vector2 -> CFloat -> Ptr Color -> IO ()|]),
+       ("c'imageDrawRectangleLines", "ImageDrawRectangleLines_", "rl_bindings.h", [t|Ptr Image -> CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawRectangleLinesEx", "ImageDrawRectangleLinesEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> CInt -> Ptr Color -> IO ()|]),
+       ("c'imageDrawRectangleGradientEx", "ImageDrawRectangleGradientEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Rectangle -> Ptr Color -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),
        ("c'imageDrawTriangle", "ImageDrawTriangle_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
-       ("c'imageDrawTriangleEx", "ImageDrawTriangleEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),
+       ("c'imageDrawTriangleGradient", "ImageDrawTriangleGradient_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> Ptr Color -> Ptr Color -> IO ()|]),
        ("c'imageDrawTriangleLines", "ImageDrawTriangleLines_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> Ptr Vector2 -> Ptr Vector2 -> Ptr Color -> IO ()|]),
        ("c'imageDrawTriangleFan", "ImageDrawTriangleFan_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawTriangleStrip", "ImageDrawTriangleStrip_", "rl_bindings.h", [t|Ptr Image -> Ptr Vector2 -> CInt -> Ptr Color -> IO ()|]),
-       ("c'imageDraw", "ImageDraw_", "rl_bindings.h", [t|Ptr Image -> Ptr Image -> Ptr Rectangle -> Ptr Rectangle -> Ptr Color -> IO ()|]),
        ("c'imageDrawText", "ImageDrawText_", "rl_bindings.h", [t|Ptr Image -> CString -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'imageDrawTextEx", "ImageDrawTextEx_", "rl_bindings.h", [t|Ptr Image -> Ptr Font -> CString -> Ptr Vector2 -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
+       ("c'imageDrawTextPro", "ImageDrawTextPro_", "rl_bindings.h", [t|Ptr Image -> Ptr Font -> CString -> Ptr Vector2 -> Ptr Vector2 -> CFloat -> CFloat -> CFloat -> Ptr Color -> IO ()|]),
        ("c'loadTexture", "LoadTexture_", "rl_bindings.h", [t|CString -> IO (Ptr Texture)|]),
        ("c'loadTextureFromImage", "LoadTextureFromImage_", "rl_bindings.h", [t|Ptr Image -> IO (Ptr Texture)|]),
        ("c'loadTextureCubemap", "LoadTextureCubemap_", "rl_bindings.h", [t|Ptr Image -> CInt -> IO (Ptr Texture)|]),
        ("c'loadRenderTexture", "LoadRenderTexture_", "rl_bindings.h", [t|CInt -> CInt -> IO (Ptr RenderTexture)|]),
+       ("c'loadRenderTextureEx", "LoadRenderTextureEx_", "rl_bindings.h", [t|CInt -> CInt -> CInt -> IO (Ptr RenderTexture)|]),
        ("c'isTextureValid", "IsTextureValid_", "rl_bindings.h", [t|Ptr Texture -> IO CBool|]),
        ("c'unloadTexture", "UnloadTexture_", "rl_bindings.h", [t|Ptr Texture -> IO ()|]),
        ("c'isRenderTextureValid", "IsRenderTextureValid_", "rl_bindings.h", [t|Ptr RenderTexture -> IO CBool|]),
@@ -579,8 +612,8 @@
 imageColorGrayscale :: Image -> IO Image
 imageColorGrayscale image = withFreeable image (\i -> c'imageColorGrayscale i >> peek i)
 
-imageColorContrast :: Image -> Float -> IO Image
-imageColorContrast image contrast = withFreeable image (\i -> c'imageColorContrast i (realToFrac contrast) >> peek i)
+imageColorContrast :: Image -> Int -> IO Image
+imageColorContrast image contrast = withFreeable image (\i -> c'imageColorContrast i (fromIntegral contrast) >> peek i)
 
 imageColorBrightness :: Image -> Int -> IO Image
 imageColorBrightness image brightness = withFreeable image (\i -> c'imageColorBrightness i (fromIntegral brightness) >> peek i)
@@ -631,6 +664,12 @@
 imageDrawLineV :: Image -> Vector2 -> Vector2 -> Color -> IO Image
 imageDrawLineV image start end color = withFreeable image (\i -> withFreeable start (\s -> withFreeable end (withFreeable color . c'imageDrawLineV i s)) >> peek i)
 
+imageDrawLineEx :: Image -> Vector2 -> Vector2 -> CInt -> Color -> IO Image
+imageDrawLineEx image start end thick color = withFreeable image (\i -> withFreeable start (\s -> withFreeable end (\e -> withFreeable color (c'imageDrawLineEx i s e (fromIntegral thick)))) >> peek i)
+
+imageDrawLineStrip :: Image -> [Vector2] -> Color -> IO Image
+imageDrawLineStrip image points color = withFreeable image (\i -> withFreeableArrayLen points (\l p -> withFreeable color (c'imageDrawLineStrip i p (fromIntegral l))) >> peek i)
+
 imageDrawCircle :: Image -> Int -> Int -> Int -> Color -> IO Image
 imageDrawCircle image centerX centerY radius color = withFreeable image (\i -> withFreeable color (c'imageDrawCircle i (fromIntegral centerX) (fromIntegral centerY) (fromIntegral radius)) >> peek i)
 
@@ -643,6 +682,21 @@
 imageDrawCircleLinesV :: Image -> Vector2 -> Int -> Color -> IO Image
 imageDrawCircleLinesV image center radius color = withFreeable image (\i -> withFreeable center (\c -> withFreeable color (c'imageDrawCircleLinesV i c (fromIntegral radius))) >> peek i)
 
+imageDrawCircleGradient :: Image -> Vector2 -> Float -> Color -> Color -> IO Image
+imageDrawCircleGradient image center radius inner outer = withFreeable image (\i -> withFreeable center (\c -> withFreeable inner (\c1 -> (withFreeable outer (\c2 -> c'imageDrawCircleGradient i c (realToFrac radius) c1 c2)))) >> peek i)
+
+imageDrawImage :: Image -> Image -> Int -> Int -> Color -> IO Image
+imageDrawImage image src posX posY tint = withFreeable image (\i -> withFreeable src (\s -> withFreeable tint (c'imageDrawImage i s (fromIntegral posX) (fromIntegral posY))) >> peek i)
+
+imageDrawImageEx :: Image -> Image -> Vector2 -> Float -> Float -> Color -> IO Image
+imageDrawImageEx image src position rotation scale tint = withFreeable image (\i -> withFreeable src (\s -> withFreeable position (\p -> withFreeable tint (c'imageDrawImageEx i s p (realToFrac rotation) (realToFrac scale)))) >> peek i)
+
+imageDrawImageRec :: Image -> Image -> Rectangle -> Vector2 -> Color -> IO Image
+imageDrawImageRec image src srcRec position tint = withFreeable image (\i -> withFreeable src (\s -> withFreeable srcRec (\r -> withFreeable position (\p -> withFreeable tint (c'imageDrawImageRec i s r p)))) >> peek i)
+
+imageDrawImagePro :: Image -> Image -> Rectangle -> Rectangle -> Vector2 -> Float -> Color -> IO Image
+imageDrawImagePro image src srcRec dstRec origin rotation tint = withFreeable image (\i -> withFreeable src (\s -> withFreeable srcRec (\sr -> withFreeable dstRec (\dr -> withFreeable origin (\o -> withFreeable tint (c'imageDrawImagePro i s sr dr o (realToFrac rotation)))))) >> peek i)
+
 imageDrawRectangle :: Image -> Int -> Int -> Int -> Int -> Color -> IO Image
 imageDrawRectangle image posX posY width height color = withFreeable image (\i -> withFreeable color (c'imageDrawRectangle i (fromIntegral posX) (fromIntegral posY) (fromIntegral width) (fromIntegral height)) >> peek i)
 
@@ -652,14 +706,48 @@
 imageDrawRectangleRec :: Image -> Rectangle -> Color -> IO Image
 imageDrawRectangleRec image rectangle color = withFreeable image (\i -> withFreeable rectangle (withFreeable color . c'imageDrawRectangleRec i) >> peek i)
 
-imageDrawRectangleLines :: Image -> Rectangle -> Int -> Color -> IO Image
-imageDrawRectangleLines image rectangle thickness color = withFreeable image (\i -> withFreeable rectangle (\r -> withFreeable color (c'imageDrawRectangleLines i r (fromIntegral thickness))) >> peek i)
+imageDrawRectanglePro :: Image -> Rectangle -> Vector2 -> Float -> Color -> IO Image
+imageDrawRectanglePro image rectangle origin rotation color = withFreeable image (\i -> withFreeable rectangle (\r -> withFreeable origin (\o -> withFreeable color (c'imageDrawRectanglePro i r o (realToFrac rotation)))) >> peek i)
 
+imageDrawRectangleLines :: Image -> Int -> Int -> Int -> Int -> Color -> IO Image
+imageDrawRectangleLines image posX posY width height color = withFreeable image (\i -> withFreeable color (c'imageDrawRectangleLines i (fromIntegral posX) (fromIntegral posY) (fromIntegral width) (fromIntegral height)) >> peek i)
+
+imageDrawRectangleLinesEx :: Image -> Rectangle -> Int -> Color -> IO Image
+imageDrawRectangleLinesEx image rectangle thickness color = withFreeable image (\i -> withFreeable rectangle (\r -> withFreeable color (c'imageDrawRectangleLinesEx i r (fromIntegral thickness))) >> peek i)
+
+imageDrawRectangleGradientEx :: Image -> Rectangle -> Color -> Color -> Color -> Color -> IO Image
+imageDrawRectangleGradientEx image rectangle col1 col2 col3 col4 = withFreeable image (\i -> withFreeable rectangle (\r -> withFreeable col1 (\c1 -> withFreeable col2 (\c2 -> withFreeable col3 (\c3 -> withFreeable col4 (\c4 -> c'imageDrawRectangleGradientEx i r c1 c2 c3 c4))))) >> peek i)
+
 imageDrawTriangle :: Image -> Vector2 -> Vector2 -> Vector2 -> Color -> IO Image
 imageDrawTriangle image v1 v2 v3 color = withFreeable image (\i -> withFreeable v1 (\p1 -> withFreeable v2 (\p2 -> withFreeable v3 (\p3 -> withFreeable color (\c -> c'imageDrawTriangle i p1 p2 p3 c)))) >> peek i)
 
-imageDrawTriangleEx :: Image -> Vector2 -> Vector2 -> Vector2 -> Color -> Color -> Color -> IO Image
-imageDrawTriangleEx image v1 v2 v3 c1 c2 c3 = withFreeable image (\i -> withFreeable v1 (\p1 -> withFreeable v2 (\p2 -> withFreeable v3 (\p3 -> withFreeable c1 (\q1 -> withFreeable c2 (\q2 -> withFreeable c3 (\q3 -> c'imageDrawTriangleEx i p1 p2 p3 q1 q2 q3)))))) >> peek i)
+imageDrawTriangleGradient :: Image -> Vector2 -> Vector2 -> Vector2 -> Color -> Color -> Color -> IO Image
+imageDrawTriangleGradient image v1 v2 v3 c1 c2 c3 = withFreeable
+      image
+      ( \i ->
+          withFreeable
+            v1
+            ( \p1 ->
+                withFreeable
+                  v2
+                  ( \p2 ->
+                      withFreeable
+                        v3
+                        ( \p3 ->
+                            withFreeable
+                              c1
+                              ( \q1 ->
+                                  withFreeable
+                                    c2
+                                    ( \q2 ->
+                                      withFreeable
+                                        c3
+                                        ( \q3 -> c'imageDrawTriangleGradient i p1 p2 p3 q1 q2 q3 )
+                                    )
+                              )
+                        )
+                  )
+            ) >> peek i)
 
 imageDrawTriangleLines :: Image -> Vector2 -> Vector2 -> Vector2 -> Color -> IO Image
 imageDrawTriangleLines image v1 v2 v3 color = withFreeable image (\i -> withFreeable v1 (\p1 -> withFreeable v2 (\p2 -> withFreeable v3 (\p3 -> withFreeable color (\c -> c'imageDrawTriangleLines i p1 p2 p3 c)))) >> peek i)
@@ -670,15 +758,15 @@
 imageDrawTriangleStrip :: Image -> [Vector2] -> Color -> IO Image
 imageDrawTriangleStrip image points color = withFreeable image (\i -> withFreeableArrayLen points (\l p -> withFreeable color (c'imageDrawTriangleStrip i p (fromIntegral l))) >> peek i)
 
-imageDraw :: Image -> Image -> Rectangle -> Rectangle -> Color -> IO Image
-imageDraw image source srcRec dstRec tint = withFreeable image (\i -> withFreeable source (\s -> withFreeable srcRec (\sr -> withFreeable dstRec (withFreeable tint . c'imageDraw i s sr))) >> peek i)
-
 imageDrawText :: Image -> String -> Int -> Int -> Int -> Color -> IO Image
 imageDrawText image text x y fontSize color = withFreeable image (\i -> withCString text (\t -> withFreeable color (c'imageDrawText i t (fromIntegral x) (fromIntegral y) (fromIntegral fontSize))) >> peek i)
 
 imageDrawTextEx :: Image -> Font -> String -> Vector2 -> Float -> Float -> Color -> IO Image
 imageDrawTextEx image font text position fontSize spacing tint = withFreeable image (\i -> withFreeable font (\f -> withCString text (\t -> withFreeable position (\p -> withFreeable tint (c'imageDrawTextEx i f t p (realToFrac fontSize) (realToFrac spacing))))) >> peek i)
 
+imageDrawTextPro :: Image -> Font -> String -> Vector2 -> Vector2 -> Float -> Float -> Float -> Color -> IO Image
+imageDrawTextPro image font text position origin rotation fontSize spacing tint = withFreeable image (\i -> withFreeable font (\f -> withCString text (\t -> withFreeable position (\p -> withFreeable origin (\o -> withFreeable tint (c'imageDrawTextPro i f t p o (realToFrac rotation) (realToFrac fontSize) (realToFrac spacing)))))) >> peek i)
+
 loadTexture :: String -> IO Texture
 loadTexture fileName = withCString fileName c'loadTexture >>= pop
 
@@ -690,6 +778,9 @@
 
 loadRenderTexture :: Int -> Int -> IO RenderTexture
 loadRenderTexture width height = c'loadRenderTexture (fromIntegral width) (fromIntegral height) >>= pop
+
+loadRenderTextureEx :: Int -> Int -> PixelFormat -> IO RenderTexture
+loadRenderTextureEx width height format = c'loadRenderTextureEx (fromIntegral width) (fromIntegral height) (fromIntegral $ fromEnum format) >>= pop
 
 isTextureValid :: Texture -> IO Bool
 isTextureValid texture = toBool <$> withFreeable texture c'isTextureValid
diff --git a/src/Raylib/Types/Core.hs b/src/Raylib/Types/Core.hs
--- a/src/Raylib/Types/Core.hs
+++ b/src/Raylib/Types/Core.hs
@@ -96,7 +96,6 @@
     p'vrStereoConfig'rightScreenCenter,
     p'vrStereoConfig'scale,
     p'vrStereoConfig'scaleIn,
-    p'filePathList'capacity,
     p'filePathList'count,
     p'filePathList'paths,
     p'automationEvent'frame,
@@ -133,7 +132,8 @@
     pokeArray,
   )
 import Foreign.C
-  ( CFloat,
+  ( CBool,
+    CFloat,
     CInt (..),
     CString,
     CUChar,
@@ -1124,33 +1124,27 @@
 p'vrStereoConfig'scaleIn = (`plusPtr` 296)
 
 data FilePathList = FilePathList
-  { filePathList'capacity :: Integer,
-    filePathList'paths :: [String]
+  { filePathList'paths :: [String]
   }
   deriving (Eq, Show, Read)
 
 instance Storable FilePathList where
   sizeOf _ = 16
-  alignment _ = 4
+  alignment _ = 8
   peek _p = do
-    capacity <- fromIntegral <$> peek (p'filePathList'capacity _p)
     count <- fromIntegral <$> peek (p'filePathList'count _p)
     pathsPtr <- peek (p'filePathList'paths _p)
     pathsCStrings <- peekArray count pathsPtr
     paths <- mapM peekCString pathsCStrings
-    return $ FilePathList capacity paths
-  poke _p (FilePathList capacity paths) = do
-    poke (p'filePathList'capacity _p) (fromIntegral capacity)
+    return $ FilePathList paths
+  poke _p (FilePathList paths) = do
     poke (p'filePathList'count _p) (fromIntegral (length paths))
     pathsCStrings <- mapM newCString paths
     poke (p'filePathList'paths _p) =<< newArray pathsCStrings
     return ()
 
-p'filePathList'capacity :: Ptr FilePathList -> Ptr CUInt
-p'filePathList'capacity = (`plusPtr` 0)
-
 p'filePathList'count :: Ptr FilePathList -> Ptr CUInt
-p'filePathList'count = (`plusPtr` 4)
+p'filePathList'count = (`plusPtr` 0)
 
 -- array (filePathList'count)
 p'filePathList'paths :: Ptr FilePathList -> Ptr (Ptr CString)
@@ -1244,7 +1238,7 @@
 
 type LoadFileDataCallback = String -> IO [Integer]
 
-type SaveFileDataCallback a = String -> Ptr a -> Integer -> IO Bool
+type SaveFileDataCallback a = String -> Ptr a -> Int -> IO Bool
 
 type LoadFileTextCallback = String -> IO String
 
@@ -1252,10 +1246,10 @@
 
 type C'TraceLogCallback = FunPtr (CInt -> CString -> IO ())
 
-type C'LoadFileDataCallback = FunPtr (CString -> Ptr CUInt -> IO (Ptr CUChar))
+type C'LoadFileDataCallback = FunPtr (CString -> Ptr CInt -> IO (Ptr CUChar))
 
-type C'SaveFileDataCallback = FunPtr (CString -> Ptr () -> CUInt -> IO CInt)
+type C'SaveFileDataCallback = FunPtr (CString -> Ptr () -> CInt -> IO CBool)
 
 type C'LoadFileTextCallback = FunPtr (CString -> IO CString)
 
-type C'SaveFileTextCallback = FunPtr (CString -> CString -> IO CInt)
+type C'SaveFileTextCallback = FunPtr (CString -> CString -> IO CBool)
diff --git a/src/Raylib/Types/Core/Models.hs b/src/Raylib/Types/Core/Models.hs
--- a/src/Raylib/Types/Core/Models.hs
+++ b/src/Raylib/Types/Core/Models.hs
@@ -20,7 +20,9 @@
     MaterialMap (..),
     Material (..),
     Transform (..),
+    ModelAnimPose,
     BoneInfo (..),
+    ModelSkeleton (..),
     Model (..),
     ModelAnimation (..),
     Ray (..),
@@ -37,10 +39,11 @@
     p'mesh'tangents,
     p'mesh'colors,
     p'mesh'indices,
+    p'mesh'boneCount,
+    p'mesh'boneIndices,
+    p'mesh'boneWeights,
     p'mesh'animVertices,
     p'mesh'animNormals,
-    p'mesh'boneIds,
-    p'mesh'boneWeights,
     p'mesh'vaoId,
     p'mesh'vboId,
     p'shader'id,
@@ -62,14 +65,13 @@
     p'model'meshes,
     p'model'materials,
     p'model'meshMaterial,
-    p'model'boneCount,
-    p'model'bones,
-    p'model'bindPose,
-    p'modelAnimation'boneCount,
-    p'modelAnimation'frameCount,
-    p'modelAnimation'bones,
-    p'modelAnimation'framePoses,
+    p'model'skeleton,
+    p'model'currentPose,
+    p'model'boneMatrices,
     p'modelAnimation'name,
+    p'modelAnimation'boneCount,
+    p'modelAnimation'keyframeCount,
+    p'modelAnimation'keyframePoses,
     p'ray'position,
     p'ray'direction,
     p'rayCollision'hit,
@@ -175,8 +177,8 @@
   | ShaderLocMapBrdf
   | ShaderLocVertexBoneIds
   | ShaderLocVertexBoneWeights
-  | ShaderLocBoneMatrices
-  | ShaderLocVertexInstanceTx
+  | ShaderLocBoneWeights
+  | ShaderLocVertexInstanceTransform
   deriving (Eq, Show, Read, Enum)
 
 data ShaderUniformDataType
@@ -341,12 +343,11 @@
     mesh'tangents :: Maybe [Vector4],
     mesh'colors :: Maybe [Color],
     mesh'indices :: Maybe [Word16],
+    mesh'boneCount :: Int,
+    mesh'boneIndices :: Maybe [Word8],
+    mesh'boneWeights :: Maybe [CFloat],
     mesh'animVertices :: Maybe [Vector3],
     mesh'animNormals :: Maybe [Vector3],
-    mesh'boneIds :: Maybe [Word8],
-    mesh'boneWeights :: Maybe [Float],
-    mesh'boneMatrices :: Maybe [Matrix],
-    mesh'boneCount :: Int,
     mesh'vaoId :: Integer,
     -- | Use `toEnum` on `DefaultShaderAttributeLocation` for indices
     mesh'vboId :: Maybe [Integer]
@@ -366,16 +367,15 @@
     tangents <- peekMaybeArray vertexCount =<< peek (p'mesh'tangents _p)
     colors <- peekMaybeArray vertexCount =<< peek (p'mesh'colors _p)
     indices <- (map fromIntegral <$>) <$> (peekMaybeArray vertexCount =<< peek (p'mesh'indices _p))
-    animVertices <- peekMaybeArray vertexCount =<< peek (p'mesh'animVertices _p)
-    animNormals <- peekMaybeArray vertexCount =<< peek (p'mesh'animNormals _p)
     boneCount <- fromIntegral <$> peek (p'mesh'boneCount _p)
-    boneIds <- (map fromIntegral <$>) <$> (peekMaybeArray (4 * vertexCount) =<< peek (p'mesh'boneIds _p))
+    boneIndices <- (map fromIntegral <$>) <$> (peekMaybeArray (4 * vertexCount) =<< peek (p'mesh'boneIndices _p))
     boneWeights <- (map realToFrac <$>) <$> (peekMaybeArray (4 * vertexCount) =<< peek (p'mesh'boneWeights _p))
-    boneMatrices <- peekMaybeArray boneCount =<< peek (p'mesh'boneMatrices _p)
+    animVertices <- peekMaybeArray vertexCount =<< peek (p'mesh'animVertices _p)
+    animNormals <- peekMaybeArray vertexCount =<< peek (p'mesh'animNormals _p)
     vaoId <- fromIntegral <$> peek (p'mesh'vaoId _p)
     vboId <- (map fromIntegral <$>) <$> (peekMaybeArray 9 =<< peek (p'mesh'vboId _p))
-    return $ Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights boneMatrices boneCount vaoId vboId
-  poke _p (Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices animVertices animNormals boneIds boneWeights boneMatrices boneCount vaoId vboId) = do
+    return $ Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices boneCount boneIndices boneWeights animVertices animNormals vaoId vboId
+  poke _p (Mesh vertexCount triangleCount vertices texcoords texcoords2 normals tangents colors indices boneCount boneIndices boneWeights animVertices animNormals vaoId vboId) = do
     poke (p'mesh'vertexCount _p) (fromIntegral vertexCount)
     poke (p'mesh'triangleCount _p) (fromIntegral triangleCount)
     poke (p'mesh'vertices _p) =<< newArray vertices
@@ -385,12 +385,11 @@
     poke (p'mesh'tangents _p) =<< newMaybeArray tangents
     poke (p'mesh'colors _p) =<< newMaybeArray colors
     poke (p'mesh'indices _p) =<< newMaybeArray (map fromIntegral <$> indices)
+    poke (p'mesh'boneCount _p) (fromIntegral boneCount)
+    poke (p'mesh'boneIndices _p) =<< newMaybeArray (map fromIntegral <$> boneIndices)
+    poke (p'mesh'boneWeights _p) =<< newMaybeArray (map realToFrac <$> boneWeights)
     poke (p'mesh'animVertices _p) =<< newMaybeArray animVertices
     poke (p'mesh'animNormals _p) =<< newMaybeArray animNormals
-    poke (p'mesh'boneIds _p) =<< newMaybeArray (map fromIntegral <$> boneIds)
-    poke (p'mesh'boneWeights _p) =<< newMaybeArray (map realToFrac <$> boneWeights)
-    poke (p'mesh'boneMatrices _p) =<< newMaybeArray boneMatrices
-    poke (p'mesh'boneCount _p) (fromIntegral boneCount)
     poke (p'mesh'vaoId _p) (fromIntegral vaoId)
     poke (p'mesh'vboId _p) =<< newMaybeArray (map fromIntegral <$> vboId)
     return ()
@@ -439,31 +438,27 @@
 p'mesh'indices :: Ptr Mesh -> Ptr (Ptr CUShort)
 p'mesh'indices = (`plusPtr` 56)
 
--- maybe array (mesh'vertexCount)
-p'mesh'animVertices :: Ptr Mesh -> Ptr (Ptr Vector3)
-p'mesh'animVertices = (`plusPtr` 64)
-
--- maybe array (mesh'vertexCount)
-p'mesh'animNormals :: Ptr Mesh -> Ptr (Ptr Vector3)
-p'mesh'animNormals = (`plusPtr` 72)
+p'mesh'boneCount :: Ptr Mesh -> Ptr CInt
+p'mesh'boneCount = (`plusPtr` 64)
 
--- maybe array (mesh'boneCount)
-p'mesh'boneIds :: Ptr Mesh -> Ptr (Ptr CUChar)
-p'mesh'boneIds = (`plusPtr` 80)
+-- maybe array (4 * mesh'vertexCount)
+p'mesh'boneIndices :: Ptr Mesh -> Ptr (Ptr CUChar)
+p'mesh'boneIndices = (`plusPtr` 72)
 
--- maybe array (mesh'boneCount)
+-- maybe array (4 * mesh'vertexCount)
 p'mesh'boneWeights :: Ptr Mesh -> Ptr (Ptr CFloat)
-p'mesh'boneWeights = (`plusPtr` 88)
+p'mesh'boneWeights = (`plusPtr` 80)
 
--- maybe array (mesh'boneCount)
-p'mesh'boneMatrices :: Ptr Mesh -> Ptr (Ptr Matrix)
-p'mesh'boneMatrices = (`plusPtr` 96)
+-- maybe array (mesh'vertexCount)
+p'mesh'animVertices :: Ptr Mesh -> Ptr (Ptr Vector3)
+p'mesh'animVertices = (`plusPtr` 88)
 
-p'mesh'boneCount :: Ptr Mesh -> Ptr CInt
-p'mesh'boneCount = (`plusPtr` 104)
+-- maybe array (mesh'vertexCount)
+p'mesh'animNormals :: Ptr Mesh -> Ptr (Ptr Vector3)
+p'mesh'animNormals = (`plusPtr` 96)
 
 p'mesh'vaoId :: Ptr Mesh -> Ptr CUInt
-p'mesh'vaoId = (`plusPtr` 108)
+p'mesh'vaoId = (`plusPtr` 104)
 
 -- maybe array (9)
 p'mesh'vboId :: Ptr Mesh -> Ptr (Ptr CUInt)
@@ -484,15 +479,15 @@
     colorsPtr <- peek (p'mesh'colors ptr)
     freeMaybePtr $ castPtr colorsPtr
     indicesPtr <- peek (p'mesh'indices ptr)
+    boneIndicesPtr <- peek (p'mesh'boneIndices ptr)
+    freeMaybePtr $ castPtr boneIndicesPtr
+    boneWeightsPtr <- peek (p'mesh'boneWeights ptr)
+    freeMaybePtr $ castPtr boneWeightsPtr
     freeMaybePtr $ castPtr indicesPtr
     animVerticesPtr <- peek (p'mesh'animVertices ptr)
     freeMaybePtr $ castPtr animVerticesPtr
     animNormalsPtr <- peek (p'mesh'animNormals ptr)
     freeMaybePtr $ castPtr animNormalsPtr
-    boneIdsPtr <- peek (p'mesh'boneIds ptr)
-    freeMaybePtr $ castPtr boneIdsPtr
-    boneWeightsPtr <- peek (p'mesh'boneWeights ptr)
-    freeMaybePtr $ castPtr boneWeightsPtr
     vboIdPtr <- peek (p'mesh'vboId ptr)
     c'free $ castPtr vboIdPtr
 
@@ -654,6 +649,8 @@
 p'transform'scale :: Ptr Transform -> Ptr Vector3
 p'transform'scale = (`plusPtr` 28)
 
+type ModelAnimPose = [Transform]
+
 data BoneInfo = BoneInfo
   { boneInfo'name :: String,
     boneInfo'parent :: Int
@@ -679,20 +676,57 @@
 p'boneInfo'parent :: Ptr BoneInfo -> Ptr CInt
 p'boneInfo'parent = (`plusPtr` 32)
 
+data ModelSkeleton = ModelSkeleton
+  { modelSkeleton'boneCount :: Int,
+    modelSkeleton'bones :: [BoneInfo],
+    modelSkeleton'bindPose :: ModelAnimPose
+  }
+  deriving (Eq, Show, Read)
+
+instance Storable ModelSkeleton where
+  sizeOf _ = 24
+  alignment _ = 8
+  peek _p = do
+    boneCount <- fromIntegral <$> peek (p'modelSkeleton'boneCount _p)
+    bones <- peekArray boneCount =<< peek (p'modelSkeleton'bones _p)
+    bindPose <- peekArray boneCount =<< peek (p'modelSkeleton'bindPose _p)
+    return $ ModelSkeleton boneCount bones bindPose
+  poke _p (ModelSkeleton boneCount bones bindPose) = do
+    poke (p'modelSkeleton'boneCount _p) (fromIntegral boneCount)
+    poke (p'modelSkeleton'bones _p) =<< newArray bones
+    poke (p'modelSkeleton'bindPose _p) =<< newArray bindPose
+    return ()
+
+p'modelSkeleton'boneCount :: Ptr ModelSkeleton -> Ptr CUInt
+p'modelSkeleton'boneCount = (`plusPtr` 0)
+
+-- array (modelSkeleton'boneCount)
+p'modelSkeleton'bones :: Ptr ModelSkeleton -> Ptr (Ptr BoneInfo)
+p'modelSkeleton'bones = (`plusPtr` 8)
+
+-- array (modelSkeleton'boneCount)
+p'modelSkeleton'bindPose :: Ptr ModelSkeleton -> Ptr (Ptr Transform)
+p'modelSkeleton'bindPose = (`plusPtr` 16)
+
+instance Freeable ModelSkeleton where
+  rlFreeDependents _ ptr = do
+    (c'free . castPtr) =<< peek (p'modelSkeleton'bones ptr)
+    (c'free . castPtr) =<< peek (p'modelSkeleton'bindPose ptr)
+
 data Model = Model
   { model'transform :: Matrix,
     model'meshes :: [Mesh],
     model'materials :: [Material],
     model'meshMaterial :: [Int],
-    model'boneCount :: Int,
-    model'bones :: Maybe [BoneInfo],
-    model'bindPose :: Maybe [Transform]
+    model'skeleton :: ModelSkeleton,
+    model'currentPose :: Maybe ModelAnimPose,
+    model'boneMatrices :: Maybe [Matrix]
   }
   deriving (Eq, Show, Read)
 
 instance Storable Model where
-  sizeOf _ = 120
-  alignment _ = 4
+  sizeOf _ = 136
+  alignment _ = 8
   peek _p = do
     transform <- peek (p'model'transform _p)
     meshCount <- fromIntegral <$> peek (p'model'meshCount _p)
@@ -700,20 +734,21 @@
     meshes <- peekArray meshCount =<< peek (p'model'meshes _p)
     materials <- peekArray materialCount =<< peek (p'model'materials _p)
     meshMaterial <- map fromIntegral <$> (peekArray meshCount =<< peek (p'model'meshMaterial _p))
-    boneCount <- fromIntegral <$> peek (p'model'boneCount _p)
-    bones <- peekMaybeArray boneCount =<< peek (p'model'bones _p)
-    bindPose <- peekMaybeArray boneCount =<< peek (p'model'bindPose _p)
-    return $ Model transform meshes materials meshMaterial boneCount bones bindPose
-  poke _p (Model transform meshes materials meshMaterial boneCount bones bindPose) = do
+    skeleton <- peek (p'model'skeleton _p)
+    let boneCount = modelSkeleton'boneCount skeleton
+    currentPose <- peekMaybeArray boneCount =<< peek (p'model'currentPose _p)
+    boneMatrices <- peekMaybeArray boneCount =<< peek (p'model'boneMatrices _p)
+    return $ Model transform meshes materials meshMaterial skeleton currentPose boneMatrices
+  poke _p (Model transform meshes materials meshMaterial skeleton currentPose boneMatrices) = do
     poke (p'model'transform _p) transform
     poke (p'model'meshCount _p) (fromIntegral (length meshes))
     poke (p'model'materialCount _p) (fromIntegral (length materials))
     poke (p'model'meshes _p) =<< newArray meshes
     poke (p'model'materials _p) =<< newArray materials
     poke (p'model'meshMaterial _p) =<< newArray (map fromIntegral meshMaterial)
-    poke (p'model'boneCount _p) (fromIntegral boneCount)
-    poke (p'model'bones _p) =<< newMaybeArray bones
-    poke (p'model'bindPose _p) =<< newMaybeArray bindPose
+    poke (p'model'skeleton _p) skeleton
+    poke (p'model'currentPose _p) =<< newMaybeArray currentPose
+    poke (p'model'boneMatrices _p) =<< newMaybeArray boneMatrices
     return ()
 
 instance Closeable Model where
@@ -745,79 +780,71 @@
 p'model'meshMaterial :: Ptr Model -> Ptr (Ptr CInt)
 p'model'meshMaterial = (`plusPtr` 88)
 
-p'model'boneCount :: Ptr Model -> Ptr CInt
-p'model'boneCount = (`plusPtr` 96)
+p'model'skeleton :: Ptr Model -> Ptr ModelSkeleton
+p'model'skeleton = (`plusPtr` 96)
 
--- maybe array (model'boneCount)
-p'model'bones :: Ptr Model -> Ptr (Ptr BoneInfo)
-p'model'bones = (`plusPtr` 104)
+-- maybe array (modelSkeleton'boneCount . model'skeleton)
+p'model'currentPose :: Ptr Model -> Ptr (Ptr Transform)
+p'model'currentPose = (`plusPtr` 120)
 
--- maybe array (model'boneCount)
-p'model'bindPose :: Ptr Model -> Ptr (Ptr Transform)
-p'model'bindPose = (`plusPtr` 112)
+-- maybe array (modelSkeleton'boneCount . model'skeleton)
+p'model'boneMatrices :: Ptr Model -> Ptr (Ptr Matrix)
+p'model'boneMatrices = (`plusPtr` 128)
 
 instance Freeable Model where
   rlFreeDependents val ptr = do
     rlFree (model'meshes val) . castPtr =<< peek (p'model'meshes ptr)
     rlFree (model'materials val) . castPtr =<< peek (p'model'materials ptr)
     c'free . castPtr =<< peek (p'model'meshMaterial ptr)
-    freeMaybePtr . castPtr =<< peek (p'model'bones ptr)
-    freeMaybePtr . castPtr =<< peek (p'model'bindPose ptr)
+    rlFreeMaybeArray (model'currentPose val) =<< peek (p'model'currentPose ptr)
+    rlFreeMaybeArray (model'boneMatrices val) =<< peek (p'model'boneMatrices ptr)
+    rlFreeDependents (model'skeleton val) (p'model'skeleton ptr)
 
 data ModelAnimation = ModelAnimation
-  { modelAnimation'boneCount :: Int,
-    modelAnimation'frameCount :: Int,
-    modelAnimation'bones :: [BoneInfo],
-    modelAnimation'framePoses :: [[Transform]],
-    modelAnimation'name :: String
+  { modelAnimation'name :: String,
+    modelAnimation'boneCount :: Int,
+    modelAnimation'keyframeCount :: Int,
+    modelAnimation'keyframePoses :: [ModelAnimPose]
   }
   deriving (Eq, Show, Read)
 
 instance Storable ModelAnimation where
-  sizeOf _ = 56
-  alignment _ = 4
+  sizeOf _ = 48
+  alignment _ = 8
   peek _p = do
-    boneCount <- fromIntegral <$> peek (p'modelAnimation'boneCount _p)
-    frameCount <- fromIntegral <$> peek (p'modelAnimation'frameCount _p)
-    bones <- peekArray boneCount =<< peek (p'modelAnimation'bones _p)
-    framePosesPtr <- peek (p'modelAnimation'framePoses _p)
-    framePosesPtrArr <- peekArray frameCount framePosesPtr
-    framePoses <- mapM (peekArray boneCount) framePosesPtrArr
     name <- peekCString (p'modelAnimation'name _p)
-    return $ ModelAnimation boneCount frameCount bones framePoses name
-  poke _p (ModelAnimation boneCount frameCount bones framePoses name) = do
-    poke (p'modelAnimation'boneCount _p) (fromIntegral boneCount)
-    poke (p'modelAnimation'frameCount _p) (fromIntegral frameCount)
-    poke (p'modelAnimation'bones _p) =<< newArray bones
-    poke (p'modelAnimation'framePoses _p) =<< newArray =<< mapM newArray framePoses
+    boneCount <- fromIntegral <$> peek (p'modelAnimation'boneCount _p)
+    keyframeCount <- fromIntegral <$> peek (p'modelAnimation'keyframeCount _p)
+    keyframePosesPtrs <- peekArray keyframeCount =<< peek (p'modelAnimation'keyframePoses _p)
+    keyframePoses <- mapM (peekArray boneCount) keyframePosesPtrs
+    return $ ModelAnimation name boneCount keyframeCount keyframePoses
+  poke _p (ModelAnimation name boneCount keyframeCount keyframePoses) = do
     pokeStaticArray (p'modelAnimation'name _p) (rightPad 32 0 $ map castCharToCChar name)
+    poke (p'modelAnimation'boneCount _p) (fromIntegral boneCount)
+    poke (p'modelAnimation'keyframeCount _p) (fromIntegral keyframeCount)
+    poke (p'modelAnimation'keyframePoses _p) =<< newArray =<< mapM newArray keyframePoses
     return ()
 
-p'modelAnimation'boneCount :: Ptr ModelAnimation -> Ptr CInt
-p'modelAnimation'boneCount = (`plusPtr` 0)
+-- static string (32)
+p'modelAnimation'name :: Ptr ModelAnimation -> Ptr CChar
+p'modelAnimation'name = (`plusPtr` 0)
 
-p'modelAnimation'frameCount :: Ptr ModelAnimation -> Ptr CInt
-p'modelAnimation'frameCount = (`plusPtr` 4)
+p'modelAnimation'boneCount :: Ptr ModelAnimation -> Ptr CUInt
+p'modelAnimation'boneCount = (`plusPtr` 32)
 
--- array (modelAnimation'boneCount)
-p'modelAnimation'bones :: Ptr ModelAnimation -> Ptr (Ptr BoneInfo)
-p'modelAnimation'bones = (`plusPtr` 8)
+p'modelAnimation'keyframeCount :: Ptr ModelAnimation -> Ptr CInt
+p'modelAnimation'keyframeCount = (`plusPtr` 36)
 
 -- array 2d (rows: modelAnimation'frameCount, cols: modelAnimation'boneCount)
-p'modelAnimation'framePoses :: Ptr ModelAnimation -> Ptr (Ptr (Ptr Transform))
-p'modelAnimation'framePoses = (`plusPtr` 16)
-
--- static string (32)
-p'modelAnimation'name :: Ptr ModelAnimation -> Ptr CChar
-p'modelAnimation'name = (`plusPtr` 24)
+p'modelAnimation'keyframePoses :: Ptr ModelAnimation -> Ptr (Ptr (Ptr Transform))
+p'modelAnimation'keyframePoses = (`plusPtr` 40)
 
 instance Freeable ModelAnimation where
   rlFreeDependents val ptr = do
-    c'free . castPtr =<< peek (p'modelAnimation'bones ptr)
-    framePosesPtr <- peek (p'modelAnimation'framePoses ptr)
-    framePosesPtrArr <- peekArray (modelAnimation'frameCount val) framePosesPtr
-    forM_ framePosesPtrArr (c'free . castPtr)
-    c'free $ castPtr framePosesPtr
+    keyframePosesPtr <- peek (p'modelAnimation'keyframePoses ptr)
+    keyframePosesPtrArr <- peekArray (modelAnimation'keyframeCount val) keyframePosesPtr
+    forM_ keyframePosesPtrArr (c'free . castPtr)
+    c'free $ castPtr keyframePosesPtr
 
 data Ray = Ray
   { ray'position :: Vector3,
diff --git a/src/Raylib/Types/Util/GUI.hs b/src/Raylib/Types/Util/GUI.hs
--- a/src/Raylib/Types/Util/GUI.hs
+++ b/src/Raylib/Types/Util/GUI.hs
@@ -19,6 +19,7 @@
     GuiDropdownBoxProperty (..),
     GuiTextBoxProperty (..),
     GuiValueBoxProperty (..),
+    GuiTabBarProperty (..),
     GuiListViewProperty (..),
     GuiColorPickerProperty (..),
     GuiIconName (..),
@@ -258,6 +259,8 @@
     TextPadding
   | -- | Control text horizontal alignment inside control text bound (after border and padding)
     TextAlignment
+  | -- | Not used yet...
+    BaseProp16
   deriving (Eq, Show, Read)
 
 instance Enum GuiControlProperty where
@@ -277,6 +280,7 @@
     BorderWidth -> 12
     TextPadding -> 13
     TextAlignment -> 14
+    BaseProp16 -> 15
   toEnum x = case x of
     0 -> BorderColorNormal
     1 -> BaseColorNormal
@@ -293,6 +297,7 @@
     12 -> BorderWidth
     13 -> TextPadding
     14 -> TextAlignment
+    15 -> BaseProp16
     n -> error $ "(GuiControlProperty.toEnum) Invalid value: " ++ show n
 
 instance Storable GuiControlProperty where
@@ -319,6 +324,8 @@
     TextAlignmentVertical
   | -- | Text wrap-mode inside text bounds
     TextWrapMode
+  | -- | Not used yet...
+    ExtProp08
   deriving (Eq, Show, Read)
 
 instance Enum GuiDefaultProperty where
@@ -330,6 +337,7 @@
     TextLineSpacing -> 20
     TextAlignmentVertical -> 21
     TextWrapMode -> 22
+    ExtProp08 -> 23
   toEnum x = case x of
     16 -> TextSize
     17 -> TextSpacing
@@ -338,6 +346,7 @@
     20 -> TextLineSpacing
     21 -> TextAlignmentVertical
     22 -> TextWrapMode
+    23 -> ExtProp08
     n -> error $ "(GuiDefaultProperty.toEnum) Invalid value: " ++ show n
 
 instance Storable GuiDefaultProperty where
@@ -352,13 +361,17 @@
 data GuiToggleProperty
   = -- | ToggleGroup separation between toggles
     GroupPadding
+  | -- | ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width
+    GroupWidthFull
   deriving (Eq, Show, Read)
 
 instance Enum GuiToggleProperty where
   fromEnum x = case x of
     GroupPadding -> 16
+    GroupWidthFull -> 17
   toEnum x = case x of
     16 -> GroupPadding
+    17 -> GroupWidthFull
     n -> error $ "(GuiToggleProperty.toEnum) Invalid value: " ++ show n
 
 instance Storable GuiToggleProperty where
@@ -398,13 +411,17 @@
 data GuiProgressBarProperty
   = -- | ProgressBar internal padding
     ProgressPadding
+  | -- | ProgressBar increment side: 0-Left->Right, 1-Right->Left
+    ProgressSide
   deriving (Eq, Show, Read)
 
 instance Enum GuiProgressBarProperty where
   fromEnum x = case x of
     ProgressPadding -> 16
+    ProgressSide -> 17
   toEnum x = case x of
     16 -> ProgressPadding
+    17 -> ProgressSide
     n -> error $ "(GuiProgressBarProperty.toEnum) Invalid value: " ++ show n
 
 instance Storable GuiProgressBarProperty where
@@ -581,6 +598,35 @@
     return $ toEnum $ fromEnum (val :: CInt)
   poke ptr v = poke (castPtr ptr) (fromIntegral (fromEnum v) :: CInt)
 
+-- | TabBar
+data GuiTabBarProperty
+  = -- | TabBar tab items width
+    TabItemsWidth
+  | -- | TabBar tab close button: 0-Not shown, 1-Shown
+    TabCloseButton
+  | -- | TabBar tabs side: 0-Bottom, 1-Top
+    TabLineSide
+  deriving (Eq, Show, Read)
+
+instance Enum GuiTabBarProperty where
+  fromEnum x = case x of
+    TabItemsWidth -> 16
+    TabCloseButton -> 17
+    TabLineSide -> 17
+  toEnum x = case x of
+    16 -> TabItemsWidth
+    17 -> TabCloseButton
+    18 -> TabLineSide
+    n -> error $ "(GuiTabBarProperty.toEnum) Invalid value: " ++ show n
+
+instance Storable GuiTabBarProperty where
+  sizeOf _ = 4
+  alignment _ = 4
+  peek ptr = do
+    val <- peek (castPtr ptr)
+    return $ toEnum $ fromEnum (val :: CInt)
+  poke ptr v = poke (castPtr ptr) (fromIntegral (fromEnum v) :: CInt)
+
 -- | ListView
 data GuiListViewProperty
   = -- | ListView items height
@@ -909,12 +955,13 @@
   | IconCone
   | IconEllipsoid
   | IconCapsule
-  | Icon250
-  | Icon251
-  | Icon252
-  | Icon253
-  | Icon254
-  | Icon255
+  | IconFiletypeFont
+  | IconFiletype3D
+  | IconFiletypeCodeXML
+  | IconFiletypeCodeC
+  | IconFiletypeCodePython
+  | IconFiletypeCodeJS
+  | IconFiletypeIcon
   deriving (Eq, Show, Read)
 
 instance Enum GuiIconName where
@@ -1169,12 +1216,13 @@
     IconCone -> 247
     IconEllipsoid -> 248
     IconCapsule -> 249
-    Icon250 -> 250
-    Icon251 -> 251
-    Icon252 -> 252
-    Icon253 -> 253
-    Icon254 -> 254
-    Icon255 -> 255
+    IconFiletypeFont -> 250
+    IconFiletype3D -> 251
+    IconFiletypeCodeXML -> 252
+    IconFiletypeCodeC -> 253
+    IconFiletypeCodePython -> 254
+    IconFiletypeCodeJS -> 255
+    IconFiletypeIcon -> 256
   toEnum x = case x of
     0 -> IconNone
     1 -> IconFolderFileOpen
@@ -1426,12 +1474,13 @@
     247 -> IconCone
     248 -> IconEllipsoid
     249 -> IconCapsule
-    250 -> Icon250
-    251 -> Icon251
-    252 -> Icon252
-    253 -> Icon253
-    254 -> Icon254
-    255 -> Icon255
+    250 -> IconFiletypeFont
+    251 -> IconFiletype3D
+    252 -> IconFiletypeCodeXML
+    253 -> IconFiletypeCodeC
+    254 -> IconFiletypeCodePython
+    255 -> IconFiletypeCodeJS
+    256 -> IconFiletypeIcon
     n -> error $ "(GuiIconName.toEnum) Invalid value: " ++ show n
 
 instance Storable GuiIconName where
diff --git a/src/Raylib/Types/Util/RLGL.hs b/src/Raylib/Types/Util/RLGL.hs
--- a/src/Raylib/Types/Util/RLGL.hs
+++ b/src/Raylib/Types/Util/RLGL.hs
@@ -69,7 +69,9 @@
 
 -- | OpenGL version
 data RLGLVersion
-  = -- | OpenGL 1.1
+  = -- | Software rendering
+    RLOpenGLSoftware
+  | -- | OpenGL 1.1
     RLOpenGL11
   | -- | OpenGL 2.1 (GLSL 120)
     RLOpenGL21
@@ -83,17 +85,19 @@
 
 instance Enum RLGLVersion where
   fromEnum n = case n of
-    RLOpenGL11 -> 0
-    RLOpenGL21 -> 1
-    RLOpenGL33 -> 2
-    RLOpenGL43 -> 3
-    RLOpenGLES20 -> 4
+    RLOpenGLSoftware -> 0
+    RLOpenGL11 -> 1
+    RLOpenGL21 -> 2
+    RLOpenGL33 -> 3
+    RLOpenGL43 -> 4
+    RLOpenGLES20 -> 5
   toEnum n = case n of
-    0 -> RLOpenGL11
-    1 -> RLOpenGL21
-    2 -> RLOpenGL33
-    3 -> RLOpenGL43
-    4 -> RLOpenGLES20
+    0 -> RLOpenGLSoftware
+    1 -> RLOpenGL11
+    2 -> RLOpenGL21
+    3 -> RLOpenGL33
+    4 -> RLOpenGL43
+    5 -> RLOpenGLES20
     _ -> error $ "(RLGLVersion.toEnum) Invalid value: " ++ show n
 
 instance Storable RLGLVersion where
diff --git a/src/Raylib/Util/GUI.hs b/src/Raylib/Util/GUI.hs
--- a/src/Raylib/Util/GUI.hs
+++ b/src/Raylib/Util/GUI.hs
@@ -100,6 +100,7 @@
 
     -- ** Styles loading functions
     guiLoadStyle,
+    guiLoadStyleFromMemory,
     guiLoadStyleDefault,
 
     -- ** Tooltips management functions
@@ -112,6 +113,7 @@
     guiSetIconScale,
     guiGetIcons,
     guiLoadIcons,
+    guiLoadIconsFromMemory,
     guiDrawIcon,
 
     -- ** Utility functions
@@ -124,7 +126,6 @@
     guiGroupBox,
     guiLine,
     guiPanel,
-    guiTabBar,
     guiScrollPanel,
 
     -- *** Basic controls set
@@ -151,6 +152,8 @@
     -- *** Advanced controls set
     guiListView,
     guiListViewEx,
+    guiTabBar,
+    guiTabBarEx,
     guiMessageBox,
     guiTextInputBox,
     guiColorPicker,
@@ -174,6 +177,7 @@
     c'guiSetStyle,
     c'guiGetStyle,
     c'guiLoadStyle,
+    c'guiLoadStyleFromMemory,
     c'guiLoadStyleDefault,
     c'guiEnableTooltip,
     c'guiDisableTooltip,
@@ -182,13 +186,13 @@
     c'guiSetIconScale,
     c'guiGetIcons,
     c'guiLoadIcons,
+    c'guiLoadIconsFromMemory,
     c'guiDrawIcon,
     c'guiGetTextWidth,
     c'guiWindowBox,
     c'guiGroupBox,
     c'guiLine,
     c'guiPanel,
-    c'guiTabBar,
     c'guiScrollPanel,
     c'guiLabel,
     c'guiButton,
@@ -211,6 +215,8 @@
     c'guiGrid,
     c'guiListView,
     c'guiListViewEx,
+    c'guiTabBar,
+    c'guiTabBarEx,
     c'guiMessageBox,
     c'guiTextInputBox,
     c'guiColorPicker,
@@ -230,6 +236,7 @@
     CFloat (..),
     CInt (..),
     CString,
+    CUChar,
     CUInt (..),
     newCString,
     peekCString,
@@ -253,6 +260,7 @@
        ("c'guiSetStyle", "GuiSetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> IO ()|]),
        ("c'guiGetStyle", "GuiGetStyle_", "rgui_bindings.h", [t|CInt -> CInt -> IO CInt|]),
        ("c'guiLoadStyle", "GuiLoadStyle_", "rgui_bindings.h", [t|CString -> IO ()|]),
+       ("c'guiLoadStyleFromMemory", "GuiLoadStyleFromMemory_", "rgui_bindings.h", [t|Ptr CUChar -> CInt -> IO ()|]),
        ("c'guiLoadStyleDefault", "GuiLoadStyleDefault_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiEnableTooltip", "GuiEnableTooltip_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiDisableTooltip", "GuiDisableTooltip_", "rgui_bindings.h", [t|IO ()|]),
@@ -261,13 +269,13 @@
        ("c'guiSetIconScale", "GuiSetIconScale_", "rgui_bindings.h", [t|CInt -> IO ()|]),
        ("c'guiGetIcons", "GuiGetIcons_", "rgui_bindings.h", [t|IO (Ptr CUInt)|]),
        ("c'guiLoadIcons", "GuiLoadIcons_", "rgui_bindings.h", [t|CString -> CBool -> IO (Ptr CString)|]),
+       ("c'guiLoadIconsFromMemory", "GuiLoadIconsFromMemory_", "rgui_bindings.h", [t|Ptr CUChar -> CInt -> CBool -> IO (Ptr CString)|]),
        ("c'guiDrawIcon", "GuiDrawIcon_", "rgui_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> Ptr Color -> IO ()|]),
        ("c'guiGetTextWidth", "GuiGetTextWidth_", "rgui_bindings.h", [t|CString -> IO CInt|]),
        ("c'guiWindowBox", "GuiWindowBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
        ("c'guiGroupBox", "GuiGroupBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
        ("c'guiLine", "GuiLine_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
        ("c'guiPanel", "GuiPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
-       ("c'guiTabBar", "GuiTabBar_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> IO CInt|]),
        ("c'guiScrollPanel", "GuiScrollPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Rectangle -> Ptr Vector2 -> Ptr Rectangle -> IO CInt|]),
        ("c'guiLabel", "GuiLabel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
        ("c'guiButton", "GuiButton_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> IO CInt|]),
@@ -290,8 +298,10 @@
        ("c'guiGrid", "GuiGrid_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CFloat -> CInt -> Ptr Vector2 -> IO CInt|]),
        ("c'guiListView", "GuiListView_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> Ptr CInt -> IO CInt|]),
        ("c'guiListViewEx", "GuiListViewEx_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt|]),
-       ("c'guiMessageBox", "GuiMessageBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> IO CInt|]),
-       ("c'guiTextInputBox", "GuiTextInputBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> CString -> CInt -> Ptr CBool -> IO CInt|]),
+       ("c'guiTabBar", "GuiTabBar_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CInt -> Ptr CInt -> IO CInt|]),
+       ("c'guiTabBarEx", "GuiTabBarEx_", "rgui_bindings.h", [t|Ptr Rectangle -> Ptr CString -> CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt|]),
+       ("c'guiMessageBox", "GuiMessageBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> Ptr CInt -> IO CInt|]),
+       ("c'guiTextInputBox", "GuiTextInputBox_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> CString -> CString -> CInt -> CString -> Ptr CInt -> Ptr CBool -> IO CInt|]),
        ("c'guiColorPicker", "GuiColorPicker_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|]),
        ("c'guiColorPanel", "GuiColorPanel_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr Color -> IO CInt|]),
        ("c'guiColorBarAlpha", "GuiColorBarAlpha_", "rgui_bindings.h", [t|Ptr Rectangle -> CString -> Ptr CFloat -> IO CInt|]),
@@ -589,6 +599,10 @@
 guiLoadStyle :: String -> IO ()
 guiLoadStyle fileName = withCString fileName c'guiLoadStyle
 
+-- | Load style from memory (binary only)
+guiLoadStyleFromMemory :: [Integer] -> IO ()
+guiLoadStyleFromMemory fileData = withFreeableArrayLen (map fromIntegral fileData) (\l f -> c'guiLoadStyleFromMemory f (fromIntegral l))
+
 -- | Load style default over global style
 guiLoadStyleDefault :: IO ()
 guiLoadStyleDefault = c'guiLoadStyleDefault
@@ -629,6 +643,18 @@
   cStrings <- popCArray count raw
   mapM popCString cStrings
 
+-- | Load raygui icons file (.rgi) from memory into internal icons data
+guiLoadIconsFromMemory ::
+  [Integer] ->
+  Bool ->
+  -- | The number of icons in the file
+  Int ->
+  IO [String]
+guiLoadIconsFromMemory fileData loadIconsName count = do
+  raw <- withFreeableArrayLen (map fromIntegral fileData) (\l f -> c'guiLoadIconsFromMemory f (fromIntegral l) (fromBool loadIconsName))
+  cStrings <- popCArray count raw
+  mapM popCString cStrings
+
 -- | Draw icon using pixel size at specified position
 guiDrawIcon :: GuiIconName -> Int -> Int -> Int -> Color -> IO ()
 guiDrawIcon icon posX posY pixelSize color = withFreeable color (c'guiDrawIcon (fromIntegral (fromEnum icon)) (fromIntegral posX) (fromIntegral posY) (fromIntegral pixelSize))
@@ -657,34 +683,6 @@
 guiPanel :: Rectangle -> Maybe String -> IO ()
 guiPanel bounds text = void (withFreeable bounds (withMaybeCString text . c'guiPanel))
 
--- | Tab Bar control
-guiTabBar ::
-  Rectangle ->
-  [String] ->
-  -- | The currently active tab's index, use `Nothing` if creating the tab bar
-  --   for the first time
-  Maybe Int ->
-  -- | A tuple, the first element is the index of the active tab, the second
-  --   element is the tab whose close button is pressed (if any)
-  IO (Int, Maybe Int)
-guiTabBar bounds tabNames active = do
-  cStrings <- mapM newCString tabNames
-  withFreeable
-    bounds
-    ( \b ->
-        withFreeableArrayLen
-          cStrings
-          ( \l t ->
-              withFreeable
-                (fromIntegral (fromMaybe 0 active))
-                ( \a -> do
-                    close <- c'guiTabBar b t (fromIntegral l) a
-                    active' <- peek a
-                    return (fromIntegral active', if close == (-1) then Nothing else Just (fromIntegral close))
-                )
-          )
-    )
-
 -- | Scroll Panel control
 guiScrollPanel ::
   Rectangle ->
@@ -1165,6 +1163,61 @@
           )
     )
 
+-- | Tab Bar control
+guiTabBar ::
+  Rectangle ->
+  String ->
+  -- | The currently active tab's index, use `Nothing` if creating the tab bar
+  --   for the first time
+  Maybe Int ->
+  -- | A tuple, the first element is the index of the active tab, the second
+  --   element is the tab whose close button is pressed (if any)
+  IO (Int, Maybe Int)
+guiTabBar bounds text active = do
+  withFreeable
+    bounds
+    ( \b ->
+        withCString
+          text
+          ( \t ->
+              withFreeable
+                (fromIntegral (fromMaybe 0 active))
+                ( \a -> do
+                    close <- c'guiTabBar b t nullPtr a
+                    active' <- peek a
+                    return (fromIntegral active', if close == (-1) then Nothing else Just (fromIntegral close))
+                )
+          )
+    )
+
+-- | Tab Bar control, using text entries list an returning focus entry
+guiTabBarEx ::
+  Rectangle ->
+  [String] ->
+  -- | The currently active tab's index, use `Nothing` if creating the tab bar
+  --   for the first time
+  Maybe Int ->
+  -- | A tuple, the first element is the index of the active tab, the second
+  --   element is the tab whose close button is pressed (if any)
+  IO (Int, Maybe Int)
+guiTabBarEx bounds text active = do
+  cStrings <- mapM newCString text
+  withFreeable
+    bounds
+    ( \b ->
+        withFreeableArrayLen
+          cStrings
+          ( \l t ->
+              withFreeable
+                (fromIntegral (fromMaybe 0 active))
+                ( \a -> do
+                    close <- c'guiTabBarEx b t (fromIntegral l) nullPtr a nullPtr
+                    active' <- peek a
+                    return (fromIntegral active', if close == (-1) then Nothing else Just (fromIntegral close))
+                )
+          )
+    )
+
 -- | Message Box control, displays a message
 guiMessageBox ::
   Rectangle ->
@@ -1172,10 +1225,12 @@
   String ->
   -- | Button labels separated by semicolons
   String ->
-  -- | The index of the clicked button, if any (0 = close message box,
-  --   1,2,... = custom button)
-  IO (Maybe Int)
-guiMessageBox bounds title message buttons =
+  -- | The currently active button's index, use `Nothing` if creating the
+  -- message box for the first time
+  Maybe Int ->
+  -- | The index of the active button and whether it is clicked
+  IO (Maybe Int, Bool)
+guiMessageBox bounds title message btnText btnActive =
   withFreeable
     bounds
     ( \b ->
@@ -1186,10 +1241,15 @@
                 message
                 ( \m ->
                     withCString
-                      buttons
-                      ( \bu -> do
-                          res <- c'guiMessageBox b t m bu
-                          if res == (-1) then return Nothing else return (Just (fromIntegral res))
+                      btnText
+                      ( \bu ->
+                          withFreeable
+                            (fromIntegral (fromMaybe 0 btnActive))
+                            ( \a -> do
+                                res <- c'guiMessageBox b t m bu a
+                                a' <- fromIntegral <$> peek a
+                                return (Just a', toBool res)
+                            )
                       )
                 )
           )
@@ -1200,24 +1260,23 @@
   Rectangle ->
   Maybe String ->
   String ->
-  -- | Button names, separated by semicolons
-  String ->
   -- | Current text box value
   String ->
-  -- | Text box buffer size; if `Nothing`, then it will automatically allocate
-  --   a buffer large enough to fit the text
   Maybe Int ->
+  String ->
+  -- | The currently active button's index, use `Nothing` if creating the
+  -- text input box for the first time
+  Maybe Int ->
   -- | Secret (password) mode; `Just True` if the value should be censored;
   --   `Just False` if it should not be censored but there should still be a
   --   button to hide it; `Nothing` if the value should not be censored at all
   Maybe Bool ->
   -- | A tuple, the first element is the updated secret mode, the second
   --   element is the updated text box value, the third element is the index
-  --   of the clicked button, if any (0 = close input box, 1,2,... = custom
-  --   button)
-  IO (Maybe Bool, String, Maybe Int)
-guiTextInputBox bounds title message buttons value bufferSize secret = do
-  ((clicked, secret'), value') <-
+  --   of the active button, the fourth element is whether it is clicked
+  IO (Maybe Bool, String, Maybe Int, Bool)
+guiTextInputBox bounds title message value textSize btnText btnActive secret = do
+  ((clicked, secret', active'), value') <-
     withFreeable
       bounds
       ( \b ->
@@ -1227,42 +1286,51 @@
                 withCString
                   message
                   ( \m ->
-                      withCString
-                        buttons
-                        ( \bu ->
-                            withCStringBuffer
-                              value
-                              bufferSize
-                              ( \s te ->
-                                  withMaybe
-                                    (fromBool <$> secret)
-                                    ( \sec -> do
-                                        clicked <- c'guiTextInputBox b t m bu te (fromIntegral s) sec
-                                        secret' <- if sec == nullPtr then return Nothing else Just . toBool <$> peek sec
-                                        return (if clicked == (-1) then Nothing else Just (fromIntegral clicked), secret')
+                      withCStringBuffer
+                        value
+                        textSize
+                        ( \s te ->
+                            withCString
+                              btnText
+                              ( \bu ->
+                                  withFreeable
+                                    (fromIntegral (fromMaybe 0 btnActive))
+                                    ( \a -> do
+                                        withMaybe
+                                          (fromBool <$> secret)
+                                          ( \sec -> do
+                                              clicked <- toBool <$> c'guiTextInputBox b t m te (fromIntegral s) bu a sec
+                                              secret' <- if sec == nullPtr then return Nothing else Just . toBool <$> peek sec
+                                              active' <- Just . fromIntegral <$> peek a
+                                              return (clicked, secret', active')
+                                          )
                                     )
                               )
                         )
                   )
             )
       )
-  return (secret', value', clicked)
+  return (secret', value', active', clicked)
 
 -- | Color Picker control (multiple color controls)
 guiColorPicker ::
   Rectangle ->
+  Maybe String ->
   -- | Currently selected color, use `Nothing` if creating the color picker for
   --   the first time
   Maybe Color ->
   -- | Updated color
   IO Color
-guiColorPicker bounds color =
+guiColorPicker bounds text color =
   withFreeable
     bounds
     ( \b ->
-        withFreeable
-          (fromMaybe (Color 200 0 0 255) color)
-          ( \c -> c'guiColorPicker b nullPtr c >> peek c
+        withMaybeCString
+          text
+          ( \t ->
+              withFreeable
+                (fromMaybe (Color 200 0 0 255) color)
+                (\c -> c'guiColorPicker b t c >> peek c)
           )
     )
 
diff --git a/src/Raylib/Util/GUI/Styles.hs b/src/Raylib/Util/GUI/Styles.hs
--- a/src/Raylib/Util/GUI/Styles.hs
+++ b/src/Raylib/Util/GUI/Styles.hs
@@ -4,39 +4,56 @@
 --   will activate that style. To return to the default style, simply call
 --   `Raylib.Util.GUI.guiLoadStyleDefault`.
 module Raylib.Util.GUI.Styles
-  ( guiLoadStyleAmber,
+  ( guiLoadStyleAdvance,
+    guiLoadStyleAmber,
     guiLoadStyleAshes,
     guiLoadStyleBluish,
+    guiLoadStyleBrick,
     guiLoadStyleCandy,
     guiLoadStyleCherry,
     guiLoadStyleCyber,
     guiLoadStyleDark,
     guiLoadStyleEnefete,
+    guiLoadStyleGenesis,
     guiLoadStyleJungle,
     guiLoadStyleLavanda,
+    guiLoadStylePocket,
+    guiLoadStyleRLTech,
     guiLoadStyleSunny,
     guiLoadStyleTerminal,
+    guiLoadStyleTurbo,
+    guiLoadStyleWisteria,
   )
 where
 
 import Raylib.Internal.TH (genNative)
 
 $( genNative
-     [ ("c'guiLoadStyleAmber", "GuiLoadStyleAmber_", "rgui_bindings.h", [t|IO ()|]),
+     [ ("c'guiLoadStyleAdvance", "GuiLoadStyleAdvance_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleAmber", "GuiLoadStyleAmber_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleAshes", "GuiLoadStyleAshes_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleBluish", "GuiLoadStyleBluish_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleBrick", "GuiLoadStyleBrick_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleCandy", "GuiLoadStyleCandy_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleCherry", "GuiLoadStyleCherry_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleCyber", "GuiLoadStyleCyber_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleDark", "GuiLoadStyleDark_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleEnefete", "GuiLoadStyleEnefete_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleGenesis", "GuiLoadStyleGenesis_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleJungle", "GuiLoadStyleJungle_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleLavanda", "GuiLoadStyleLavanda_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStylePocket", "GuiLoadStylePocket_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleRLTech", "GuiLoadStyleRLTech_", "rgui_bindings.h", [t|IO ()|]),
        ("c'guiLoadStyleSunny", "GuiLoadStyleSunny_", "rgui_bindings.h", [t|IO ()|]),
-       ("c'guiLoadStyleTerminal", "GuiLoadStyleTerminal_", "rgui_bindings.h", [t|IO ()|])
+       ("c'guiLoadStyleTerminal", "GuiLoadStyleTerminal_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleTurbo", "GuiLoadStyleTurbo_", "rgui_bindings.h", [t|IO ()|]),
+       ("c'guiLoadStyleWisteria", "GuiLoadStyleWisteria_", "rgui_bindings.h", [t|IO ()|])
      ]
  )
 
+guiLoadStyleAdvance :: IO ()
+guiLoadStyleAdvance = c'guiLoadStyleAdvance
+
 guiLoadStyleAmber :: IO ()
 guiLoadStyleAmber = c'guiLoadStyleAmber
 
@@ -46,6 +63,9 @@
 guiLoadStyleBluish :: IO ()
 guiLoadStyleBluish = c'guiLoadStyleBluish
 
+guiLoadStyleBrick :: IO ()
+guiLoadStyleBrick = c'guiLoadStyleBrick
+
 guiLoadStyleCandy :: IO ()
 guiLoadStyleCandy = c'guiLoadStyleCandy
 
@@ -61,14 +81,29 @@
 guiLoadStyleEnefete :: IO ()
 guiLoadStyleEnefete = c'guiLoadStyleEnefete
 
+guiLoadStyleGenesis :: IO ()
+guiLoadStyleGenesis = c'guiLoadStyleGenesis
+
 guiLoadStyleJungle :: IO ()
 guiLoadStyleJungle = c'guiLoadStyleJungle
 
 guiLoadStyleLavanda :: IO ()
 guiLoadStyleLavanda = c'guiLoadStyleLavanda
 
+guiLoadStylePocket :: IO ()
+guiLoadStylePocket = c'guiLoadStylePocket
+
+guiLoadStyleRLTech :: IO ()
+guiLoadStyleRLTech = c'guiLoadStyleRLTech
+
 guiLoadStyleSunny :: IO ()
 guiLoadStyleSunny = c'guiLoadStyleSunny
 
 guiLoadStyleTerminal :: IO ()
 guiLoadStyleTerminal = c'guiLoadStyleTerminal
+
+guiLoadStyleTurbo :: IO ()
+guiLoadStyleTurbo = c'guiLoadStyleTurbo
+
+guiLoadStyleWisteria :: IO ()
+guiLoadStyleWisteria = c'guiLoadStyleWisteria
diff --git a/src/Raylib/Util/Lenses.hs b/src/Raylib/Util/Lenses.hs
--- a/src/Raylib/Util/Lenses.hs
+++ b/src/Raylib/Util/Lenses.hs
@@ -35,6 +35,7 @@
        ''RL.Material,
        ''RL.Transform,
        ''RL.BoneInfo,
+       ''RL.ModelSkeleton,
        ''RL.Model,
        ''RL.ModelAnimation,
        ''RL.Ray,
diff --git a/src/Raylib/Util/Math.hs b/src/Raylib/Util/Math.hs
--- a/src/Raylib/Util/Math.hs
+++ b/src/Raylib/Util/Math.hs
@@ -63,6 +63,8 @@
     (/-/),
     matrixMultiply,
     (/*/),
+    matrixMultiplyValue,
+    (/*),
     matrixTranslate,
     matrixRotate,
     matrixRotateX,
@@ -750,6 +752,16 @@
 -- | Alias for 'matrixMultiply'
 (/*/) :: Matrix -> Matrix -> Matrix
 (/*/) = matrixMultiply
+
+-- | Multiply matrix components by value
+matrixMultiplyValue :: Matrix -> Float -> Matrix
+matrixMultiplyValue
+  (Matrix m0 m4 m8 m12 m1 m5 m9 m13 m2 m6 m10 m14 m3 m7 m11 m15) value =
+  (Matrix (value * m0) (value * m4) (value * m8) (value * m12) (value * m1) (value * m5) (value * m9) (value * m13) (value * m2) (value * m6) (value * m10) (value * m14) (value * m3) (value * m7) (value * m11) (value * m15))
+
+-- | Alias for 'matrixMultiplyValue'
+(/*) :: Matrix -> Float -> Matrix
+(/*) = matrixMultiplyValue
 
 -- | Translation matrix
 matrixTranslate ::
diff --git a/src/Raylib/Util/RLGL.hs b/src/Raylib/Util/RLGL.hs
--- a/src/Raylib/Util/RLGL.hs
+++ b/src/Raylib/Util/RLGL.hs
@@ -167,9 +167,11 @@
     rlUnloadFramebuffer,
 
     -- *** Shaders management
-    rlLoadShaderCode,
-    rlCompileShader,
+    rlLoadShader,
     rlLoadShaderProgram,
+    rlLoadShaderProgramEx,
+    rlLoadShaderProgramCompute,
+    rlUnloadShader,
     rlUnloadShaderProgram,
     rlGetLocationUniform,
     rlGetLocationAttrib,
@@ -180,7 +182,6 @@
     rlSetShader,
 
     -- *** Compute shader management
-    rlLoadComputeShaderProgram,
     rlComputeShaderDispatch,
 
     -- *** Shader buffer storage object management (ssbo)
@@ -302,9 +303,11 @@
     c'rlCopyFramebuffer,
     c'rlResizeFramebuffer,
     c'rlUnloadFramebuffer,
-    c'rlLoadShaderCode,
-    c'rlCompileShader,
+    c'rlLoadShader,
     c'rlLoadShaderProgram,
+    c'rlLoadShaderProgramEx,
+    c'rlLoadShaderProgramCompute,
+    c'rlUnloadShader,
     c'rlUnloadShaderProgram,
     c'rlGetLocationUniform,
     c'rlGetLocationAttrib,
@@ -313,7 +316,6 @@
     c'rlSetUniformMatrices,
     c'rlSetUniformSampler,
     c'rlSetShader,
-    c'rlLoadComputeShaderProgram,
     c'rlComputeShaderDispatch,
     c'rlLoadShaderBuffer,
     c'rlUnloadShaderBuffer,
@@ -518,9 +520,11 @@
        ("c'rlCopyFramebuffer", "rlCopyFramebuffer_", "rlgl_bindings.h", [t|CInt -> CInt -> CInt -> CInt -> CInt -> Ptr CUChar -> IO ()|]),
        ("c'rlResizeFramebuffer", "rlResizeFramebuffer_", "rlgl_bindings.h", [t|CInt -> CInt -> IO ()|]),
        ("c'rlUnloadFramebuffer", "rlUnloadFramebuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),
-       ("c'rlLoadShaderCode", "rlLoadShaderCode_", "rlgl_bindings.h", [t|CString -> CString -> IO CUInt|]),
-       ("c'rlCompileShader", "rlCompileShader_", "rlgl_bindings.h", [t|CString -> CInt -> IO CUInt|]),
-       ("c'rlLoadShaderProgram", "rlLoadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO CUInt|]),
+       ("c'rlLoadShader", "rlLoadShader_", "rlgl_bindings.h", [t|CString -> CInt -> IO CUInt|]),
+       ("c'rlLoadShaderProgram", "rlLoadShaderProgram_", "rlgl_bindings.h", [t|CString -> CString -> IO CUInt|]),
+       ("c'rlLoadShaderProgramEx", "rlLoadShaderProgramEx_", "rlgl_bindings.h", [t|CUInt -> CUInt -> IO CUInt|]),
+       ("c'rlLoadShaderProgramCompute", "rlLoadShaderProgramCompute_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|]),
+       ("c'rlUnloadShader", "rlUnloadShader_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),
        ("c'rlUnloadShaderProgram", "rlUnloadShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),
        ("c'rlGetLocationUniform", "rlGetLocationUniform_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|]),
        ("c'rlGetLocationAttrib", "rlGetLocationAttrib_", "rlgl_bindings.h", [t|CUInt -> CString -> IO CInt|]),
@@ -529,7 +533,6 @@
        ("c'rlSetUniformMatrices", "rlSetUniformMatrices_", "rlgl_bindings.h", [t|CInt -> Ptr Matrix -> CInt -> IO ()|]),
        ("c'rlSetUniformSampler", "rlSetUniformSampler_", "rlgl_bindings.h", [t|CInt -> CUInt -> IO ()|]),
        ("c'rlSetShader", "rlSetShader_", "rlgl_bindings.h", [t|CUInt -> Ptr CInt -> IO ()|]),
-       ("c'rlLoadComputeShaderProgram", "rlLoadComputeShaderProgram_", "rlgl_bindings.h", [t|CUInt -> IO CUInt|]),
        ("c'rlComputeShaderDispatch", "rlComputeShaderDispatch_", "rlgl_bindings.h", [t|CUInt -> CUInt -> CUInt -> IO ()|]),
        ("c'rlLoadShaderBuffer", "rlLoadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> Ptr () -> CInt -> IO CUInt|]),
        ("c'rlUnloadShaderBuffer", "rlUnloadShaderBuffer_", "rlgl_bindings.h", [t|CUInt -> IO ()|]),
@@ -1197,21 +1200,30 @@
 rlUnloadFramebuffer :: Integer -> IO ()
 rlUnloadFramebuffer fboId = c'rlUnloadFramebuffer (fromIntegral fboId)
 
+-- | Load (compile) shader and return shader id
+rlLoadShader :: String -> RLShaderType -> IO Integer
+rlLoadShader shaderCode shaderType =
+  fromIntegral <$> withCString shaderCode (\s -> c'rlLoadShader s (fromIntegral $ fromEnum shaderType))
+
 -- | Load shader from code strings
-rlLoadShaderCode :: String -> String -> IO Integer
-rlLoadShaderCode vsCode fsCode =
-  fromIntegral <$> withCString vsCode (withCString fsCode . c'rlLoadShaderCode)
+rlLoadShaderProgram :: String -> String -> IO Integer
+rlLoadShaderProgram vsCode fsCode =
+  fromIntegral <$> withCString vsCode (withCString fsCode . c'rlLoadShaderProgram)
 
--- | Compile custom shader and return shader id
-rlCompileShader :: String -> RLShaderType -> IO Integer
-rlCompileShader shaderCode shaderType =
-  fromIntegral <$> withCString shaderCode (\s -> c'rlCompileShader s (fromIntegral $ fromEnum shaderType))
+-- | Load shader program, using already loaded shader ids
+rlLoadShaderProgramEx :: Integer -> Integer -> IO Integer
+rlLoadShaderProgramEx vsShaderId fsShaderId =
+  fromIntegral <$> c'rlLoadShaderProgramEx (fromIntegral vsShaderId) (fromIntegral fsShaderId)
 
--- | Load custom shader program
-rlLoadShaderProgram :: Integer -> Integer -> IO Integer
-rlLoadShaderProgram vsShaderId fsShaderId =
-  fromIntegral <$> c'rlLoadShaderProgram (fromIntegral vsShaderId) (fromIntegral fsShaderId)
+-- | Load compute shader program
+rlLoadShaderProgramCompute :: Integer -> IO Integer
+rlLoadShaderProgramCompute csId =
+  fromIntegral <$> c'rlLoadShaderProgramCompute (fromIntegral csId)
 
+-- | Unload shader, loaded with rlLoadShader
+rlUnloadShader :: Integer -> IO ()
+rlUnloadShader shaderId = c'rlUnloadShader (fromIntegral shaderId)
+
 -- | Unload shader program
 rlUnloadShaderProgram :: Integer -> IO ()
 rlUnloadShaderProgram shaderId = c'rlUnloadShaderProgram (fromIntegral shaderId)
@@ -1248,10 +1260,6 @@
 -- | Set shader currently active (id and locations)
 rlSetShader :: Integer -> [Int] -> IO ()
 rlSetShader shaderId locs = withFreeableArray (map fromIntegral locs :: [CInt]) (c'rlSetShader (fromIntegral shaderId))
-
--- | Load compute shader program
-rlLoadComputeShaderProgram :: Integer -> IO Integer
-rlLoadComputeShaderProgram shaderId = fromIntegral <$> c'rlLoadComputeShaderProgram (fromIntegral shaderId)
 
 -- | Dispatch compute shader (equivalent to *draw* for graphics pipeline)
 rlComputeShaderDispatch :: Integer -> Integer -> Integer -> IO ()
