From 9c6410cc3a43d9d1e01f853cb5a8d0f8a6d93b45 Mon Sep 17 00:00:00 2001
From: gramanas <anastasis.gramm2@gmail.com>
Date: Tue, 18 Apr 2023 16:31:25 +0300
Subject: autotools initial...

---
 src/Makefile.am    |   33 +
 src/filter.c       |  562 +++++++
 src/filter.h       |  160 ++
 src/lowpass.c      |  371 +++++
 src/lowpass.h      |   46 +
 src/notes.h        |   51 +
 src/raygui.h       | 4647 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/synth.c        |  114 ++
 src/synth_engine.c |  332 ++++
 src/synth_engine.h |   77 +
 src/synth_gui.c    |  173 ++
 src/synth_gui.h    |   10 +
 src/synth_math.h   |   22 +
 13 files changed, 6598 insertions(+)
 create mode 100644 src/Makefile.am
 create mode 100644 src/filter.c
 create mode 100644 src/filter.h
 create mode 100644 src/lowpass.c
 create mode 100644 src/lowpass.h
 create mode 100644 src/notes.h
 create mode 100644 src/raygui.h
 create mode 100644 src/synth.c
 create mode 100644 src/synth_engine.c
 create mode 100644 src/synth_engine.h
 create mode 100644 src/synth_gui.c
 create mode 100644 src/synth_gui.h
 create mode 100644 src/synth_math.h

(limited to 'src')

diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..91e1be5
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,33 @@
+#bin_PROGRAMS = food cookbook cook synth
+bin_PROGRAMS = synth
+
+common_sources = filter.c \
+                 filter.h \
+                 lowpass.c \
+                 lowpass.h \
+                 Makefile.am \
+                 notes.h \
+                 raygui.h \
+                 synth_engine.c \
+                 synth_engine.h \
+                 synth_gui.c \
+                 synth_gui.h \
+                 synth_math.h
+
+# -fwhole-program allows cross-file inlining, but only works when you put all
+# the source files on one gcc command-line. -flto is another way to get the
+# same effect. (Link-Time Optimization). clang supports -flto but not
+# -fwhole-program.
+
+# If your program doesn't depend on strict FP rounding
+# behaviour, use -ffast-math. If it does, you can usually still use
+# -fno-math-errno and stuff like that, without enabling
+# -funsafe-math-optimizations. Some FP code can get big speedups from
+# fast-math, like auto-vectorization.
+AM_CFLAGS = -O3 -march=native -fno-math-errno -funroll-loops -flto
+
+synth_SOURCES = synth.c $(common_sources)
+synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib
+#cookbook_SOURCES = cookbook.c $(common_sources)
+#cookbook_SOURCES = cookbook.c $(common_sources)
+#cook_SOURCES = cook.c $(common_sources)
diff --git a/src/filter.c b/src/filter.c
new file mode 100644
index 0000000..69d7bb6
--- /dev/null
+++ b/src/filter.c
@@ -0,0 +1,562 @@
+/*
+ * filter.c
+ *
+ * Copyright (c) 2018 Disi A
+ * 
+ * Author: Disi A
+ * Email: adis@live.cn
+ *  https://www.mathworks.com/matlabcentral/profile/authors/3734620-disi-a
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "filter.h"
+#include <stddef.h>
+
+#if DOUBLE_PRECISION
+#define COS cos
+#define SIN sin
+#define TAN tan
+#define COSH cosh
+#define SINH sinh
+#define SQRT sqrt
+#define LOG log
+#else
+#define COS cosf
+#define SIN sinf
+#define TAN tanf
+#define COSH coshf
+#define SINH sinhf
+#define SQRT sqrtf
+#define LOG logf
+#endif
+
+void update_bw_low_pass_filter(BWLowPass* filter, FTR_PRECISION s, FTR_PRECISION f, FTR_PRECISION q)
+{
+    FTR_PRECISION a = TAN((FTR_PRECISION)(M_PI * f / s));
+    FTR_PRECISION a2 = a * a;
+    FTR_PRECISION r;
+    
+    int i;
+    
+    for(i=0; i < filter -> n; ++i){
+      r = SIN((FTR_PRECISION)(M_PI * (2.0 * i + 1.0) / (4.0 * filter->n)));
+      s = (FTR_PRECISION) (a2 + 2.0 * a * r + 1.0);
+      filter->A[i] = a2 / s;
+      filter->d1[i] = (FTR_PRECISION) (2.0 * (1 - a2) / s);
+      filter->d2[i] = (FTR_PRECISION)(-(a2 - 2.0 * a * r + 1.0) / s);
+    }
+}
+
+BWLowPass* create_bw_low_pass_filter(int order, FTR_PRECISION s, FTR_PRECISION f) {
+    BWLowPass* filter = (BWLowPass *) malloc(sizeof(BWLowPass));
+    filter -> n = order/2;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    
+    if (filter->d2 == NULL)
+    {
+        free_bw_low_pass(filter);
+        return NULL;
+    }
+
+    FTR_PRECISION a = TAN((FTR_PRECISION)(M_PI * f / s));
+    FTR_PRECISION a2 = a * a;
+    FTR_PRECISION r;
+    
+    int i;
+    
+    for(i=0; i < filter -> n; ++i){
+        r = SIN((FTR_PRECISION)(M_PI * (2.0 * i + 1.0) / (4.0 * filter->n)));
+        s = (FTR_PRECISION) (a2 + 2.0 * a * r + 1.0);
+        filter->A[i] = a2 / s;
+        filter->d1[i] = (FTR_PRECISION) (2.0 * (1 - a2) / s);
+        filter->d2[i] = (FTR_PRECISION)(-(a2 - 2.0 * a * r + 1.0) / s);
+    }
+    return filter;
+}
+
+BWHighPass* create_bw_high_pass_filter(int order, FTR_PRECISION s, FTR_PRECISION f){
+    BWHighPass* filter = (BWHighPass *) malloc(sizeof(BWHighPass));
+    filter -> n = order/2;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+
+    if (filter->d2 == NULL)
+    {
+        free_bw_high_pass(filter);
+        return NULL;
+    }
+
+    FTR_PRECISION a = TAN((FTR_PRECISION) (M_PI * f/s));
+    FTR_PRECISION a2 = a * a;
+    FTR_PRECISION r;
+    
+    int i;
+
+    for(i=0; i < filter -> n; ++i){
+        r = SIN((FTR_PRECISION)(M_PI * (2.0 * i + 1.0) / ( 4.0 * filter->n)));
+        s = (FTR_PRECISION) (a2 + 2.0 * a * r + 1.0);
+        filter -> A[i] = (FTR_PRECISION) (1.0 / s);
+        filter -> d1[i] = (FTR_PRECISION) (2.0 * (1 - a2) / s);
+        filter -> d2[i] = (FTR_PRECISION) (- (a2 - 2.0 * a * r + 1.0) / s);
+    }
+    return filter;
+}
+
+BWBandPass* create_bw_band_pass_filter(int order, FTR_PRECISION s, FTR_PRECISION fl, FTR_PRECISION fu){
+    if(fu <= fl){
+        printf("ERROR:Lower half-power frequency is smaller than higher half-power frequency");
+        return NULL;
+    }
+    BWBandPass* filter = (BWBandPass *) malloc(sizeof(BWBandPass));
+    filter -> n = order/4;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d3 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d4 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w3 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w4 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+
+  
+    FTR_PRECISION a = COS(M_PI*(fu+fl)/s)/COS(M_PI*(fu-fl)/s);
+    FTR_PRECISION a2 = a*a;
+    FTR_PRECISION b = TAN(M_PI*(fu-fl)/s);
+    FTR_PRECISION b2 = b*b;
+    FTR_PRECISION r;
+    int i;
+    for(i=0; i<filter->n; ++i){
+        r = SIN( (FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / (4.0 * filter->n)));
+        s = (FTR_PRECISION)(b2 + 2.0 * b * r + 1.0);
+        filter->A[i] = b2/s;
+        filter->d1[i] = (FTR_PRECISION) (4.0 * a * (1.0 + b * r) / s);
+        filter->d2[i] = (FTR_PRECISION) (2.0 * (b2 - 2.0 * a2 - 1.0)/ s);
+        filter->d3[i] = (FTR_PRECISION) (4.0 * a * (1.0 - b * r ) / s);
+        filter->d4[i] = (FTR_PRECISION) (- (b2 - 2.0 * b * r + 1.0) / s);
+    }
+    return filter;
+}
+
+BWBandStop* create_bw_band_stop_filter(int order, FTR_PRECISION s, FTR_PRECISION fl, FTR_PRECISION fu){
+    if(fu <= fl){
+        printf("ERROR:Lower half-power frequency is smaller than higher half-power frequency");
+        return NULL;
+    }
+
+    BWBandStop* filter = (BWBandStop *) malloc(sizeof(BWBandStop));
+    filter -> n = order/4;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d3 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+    filter -> d4 = (FTR_PRECISION *)malloc(filter -> n*sizeof(FTR_PRECISION));
+
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w3 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+    filter -> w4 = (FTR_PRECISION *)calloc(filter -> n, sizeof(FTR_PRECISION));
+
+    FTR_PRECISION a = COS(M_PI*(fu+fl)/s)/COS(M_PI*(fu-fl)/s);
+    FTR_PRECISION a2 = a*a;
+    FTR_PRECISION b = TAN(M_PI*(fu-fl)/s);
+    FTR_PRECISION b2 = b*b;
+    FTR_PRECISION r;
+
+    int i;
+    for(i=0; i<filter->n; ++i){
+        r = SIN((FTR_PRECISION) (M_PI * (2.0 * i + 1.0 ) / ( 4.0 * filter->n)));
+        s = (FTR_PRECISION) (b2 + 2.0 * b * r + 1.0);
+        filter->A[i] = (FTR_PRECISION) (1.0 / s);
+        filter->d1[i] = (FTR_PRECISION) (4.0 * a * (1.0 + b * r ) / s);
+        filter->d2[i] = (FTR_PRECISION) (2.0 * (b2 - 2.0 * a2- 1.0) / s);
+        filter->d3[i] = (FTR_PRECISION) (4.0 * a * (1.0 - b * r) / s);
+        filter->d4[i] = (FTR_PRECISION) (- (b2 - 2.0 * b * r + 1.0) / s);
+    }
+    filter->r = (FTR_PRECISION) (4.0 * a);
+    filter->s = (FTR_PRECISION) (4.0 * a2 + 2.0);
+    return filter;
+}
+
+CHELowPass* create_che_low_pass_filter(int n, FTR_PRECISION epsilon, FTR_PRECISION s, FTR_PRECISION f){
+    CHELowPass* filter = (CHELowPass *) malloc(sizeof(CHELowPass));
+    filter -> m = n/2;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+
+    if (filter->d2 == NULL)
+    {
+        free_che_low_pass(filter);
+        return NULL;
+    }
+
+    FTR_PRECISION a = TAN((FTR_PRECISION) (M_PI * f/ s));
+    FTR_PRECISION a2 = a * a;
+    
+    FTR_PRECISION u = LOG((FTR_PRECISION) (1.0 + SQRT((FTR_PRECISION) (1.0 + epsilon * epsilon)) / epsilon));
+    FTR_PRECISION su = SINH(u/(FTR_PRECISION)n);
+    FTR_PRECISION cu = COSH(u/(FTR_PRECISION)n);
+    FTR_PRECISION b,c;
+    
+    int i;
+    for(i=0; i<filter->m; ++i){
+        b = SIN((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / (2.0 * n))) * su;
+        c = COS((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / (2.0 * n))) * cu;
+        c = b*b + c*c;
+        s = (FTR_PRECISION) (a2 * c + 2.0 * a * b + 1.0);
+        filter->A[i] = (FTR_PRECISION) (a2 / (4.0 * s));
+        filter->d1[i] = (FTR_PRECISION) (2.0 * (1 - a2 * c) / s);
+        filter->d2[i] = (FTR_PRECISION) (- (a2 * c - 2.0 * a * b + 1.0) / s);
+    }
+    filter->ep = (FTR_PRECISION) (2.0 / epsilon);  // used to normalize
+    
+    return filter;
+}
+
+CHEHighPass* create_che_high_pass_filter(int n, FTR_PRECISION epsilon, FTR_PRECISION s, FTR_PRECISION f){
+    CHEHighPass* filter = (CHELowPass *) malloc(sizeof(CHEHighPass));
+    filter -> m = n/2;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+
+    if (filter->d2 == NULL)
+    {
+        free_che_high_pass(filter);
+        return NULL;
+    }
+
+    FTR_PRECISION a = TAN((FTR_PRECISION) (M_PI * f/ s));
+    FTR_PRECISION a2 = a * a;
+
+    FTR_PRECISION u = LOG((FTR_PRECISION) (1.0 + SQRT((FTR_PRECISION) (1.0 + epsilon*epsilon))) / epsilon);
+    FTR_PRECISION su = SINH(u/(FTR_PRECISION)n);
+    FTR_PRECISION cu = COSH(u/(FTR_PRECISION)n);
+    FTR_PRECISION b,c;
+    
+    int i;
+    for(i=0; i<filter->m; ++i){
+        b = SIN((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / (2.0 * n))) * su;
+        c = COS((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / (2.0 * n))) * cu;
+        c = b*b + c*c;
+        s = (FTR_PRECISION) (a2 + 2.0 * a * b + c);
+        filter->A[i] = (FTR_PRECISION) (1.0 / (4.0 * s));
+        filter->d1[i] = (FTR_PRECISION) (2.0 * (c - a2)/s);
+        filter->d2[i] = (FTR_PRECISION) (- (a2 - 2.0 * a * b + c) / s);
+    }
+
+    filter->ep = (FTR_PRECISION) (2.0 / epsilon); // used to normalize
+    return filter;
+}
+
+CHEBandPass* create_che_band_pass_filter(int n, FTR_PRECISION epsilon, FTR_PRECISION s, FTR_PRECISION f_lower, FTR_PRECISION f_upper){
+    CHEBandPass* filter = (CHEBandPass *) malloc(sizeof(CHEBandPass));
+    filter -> m = n/4;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d3 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d4 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w3 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w4 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+
+    FTR_PRECISION a = COS(M_PI*(f_lower+f_upper)/s)/COS(M_PI*(f_upper-f_lower)/s);
+    FTR_PRECISION a2 = a*a;
+    FTR_PRECISION b = TAN(M_PI*(f_upper-f_lower)/s);
+    FTR_PRECISION b2 = b*b;
+    FTR_PRECISION u = LOG((FTR_PRECISION) (1.0 + SQRT((FTR_PRECISION) (1.0 + epsilon * epsilon))) / epsilon);
+    FTR_PRECISION su = SINH((FTR_PRECISION) (2.0 * u / (FTR_PRECISION)n));
+    FTR_PRECISION cu = COSH((FTR_PRECISION) (2.0 * u / (FTR_PRECISION)n));
+    FTR_PRECISION r,c;
+
+    int i;
+    for(i=0; i < filter->m; ++i){
+        r = SIN((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / n)) * su;
+        c = COS((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / n)) * cu;
+        c = r*r + c*c;
+        s = (FTR_PRECISION) (b2 * c + 2.0 * b * r + 1.0);
+        filter->A[i] = (FTR_PRECISION) (b2 / (4.0 * s));
+        filter->d1[i] = (FTR_PRECISION) (4.0 * a * (1.0 + b * r) / s);
+        filter->d2[i] = (FTR_PRECISION) (2.0 * (b2 * c - 2.0 * a2 - 1.0) / s);
+        filter->d3[i] = (FTR_PRECISION) (4.0 * a * (1.0 - b * r) / s);
+        filter->d4[i] = (FTR_PRECISION) (- (b2 * c - 2.0 * b * r + 1.0) / s);
+    }
+    filter->ep = (FTR_PRECISION) (2.0 / epsilon);  // used to normalize
+    return filter;
+}
+
+CHEBandStop* create_che_band_stop_filter(int n, FTR_PRECISION epsilon, FTR_PRECISION s, FTR_PRECISION f_lower, FTR_PRECISION f_upper){
+    CHEBandStop* filter = (CHEBandStop *) malloc(sizeof(CHEBandStop));
+    filter -> m = n/4;
+    filter -> A = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d1 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d2 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d3 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> d4 = (FTR_PRECISION *)malloc(filter -> m*sizeof(FTR_PRECISION));
+    filter -> w0 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w1 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w2 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w3 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+    filter -> w4 = (FTR_PRECISION *)calloc(filter -> m, sizeof(FTR_PRECISION));
+
+    FTR_PRECISION a = COS(M_PI*(f_lower+f_upper)/s)/COS(M_PI*(f_upper-f_lower)/s);
+    FTR_PRECISION a2 = a*a;
+    FTR_PRECISION b = TAN(M_PI*(f_upper-f_lower)/s);
+    FTR_PRECISION b2 = b*b;
+    FTR_PRECISION u = LOG((FTR_PRECISION) (1.0 + SQRT((FTR_PRECISION) (1.0 + epsilon * epsilon))) / epsilon);
+    FTR_PRECISION su = SINH((FTR_PRECISION) (2.0*u/(FTR_PRECISION)n));
+    FTR_PRECISION cu = COSH((FTR_PRECISION) (2.0*u/(FTR_PRECISION)n));
+    FTR_PRECISION r,c;
+    int i;
+    for(i=0; i < filter->m; ++i){
+        r = SIN((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / n)) * su;
+        c = COS((FTR_PRECISION) (M_PI * (2.0 * i + 1.0) / n))*cu;
+        c = r*r + c*c;
+        s = (FTR_PRECISION) (b2 + 2.0 * b * r + c);
+        filter->A[i] = (FTR_PRECISION) (1.0 / (4.0 * s));
+        filter->d1[i] = (FTR_PRECISION) (4.0 * a * (c + b * r)/s);
+        filter->d2[i] = (FTR_PRECISION) (2.0 * (b2 - 2.0 * a2 * c - c) / s);
+        filter->d3[i] = (FTR_PRECISION) (4.0 * a * (c - b * r ) / s);
+        filter->d4[i] = (FTR_PRECISION) (- (b2 - 2.0 * b * r + c) / s);
+    }
+    filter->r = (FTR_PRECISION) (4.0 * a);
+    filter->s = (FTR_PRECISION) (4.0 * a2 + 2.0);
+    filter->ep = (FTR_PRECISION) (2.0 / epsilon);  // used to normalize
+    return filter;
+}
+
+void free_bw_low_pass(BWLowPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter);
+}
+void free_bw_high_pass(BWHighPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter);
+}
+void free_bw_band_pass(BWBandPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> d3);
+    free(filter -> d4);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter -> w3);
+    free(filter -> w4);
+    free(filter);
+}
+void free_bw_band_stop(BWBandStop* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> d3);
+    free(filter -> d4);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter -> w3);
+    free(filter -> w4);
+    free(filter);
+}
+
+void free_che_low_pass(CHELowPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter);
+}
+
+void free_che_high_pass(CHEHighPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter);
+}
+void free_che_band_pass(CHEBandPass* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> d3);
+    free(filter -> d4);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter -> w3);
+    free(filter -> w4);
+    free(filter);
+}
+void free_che_band_stop(CHEBandStop* filter){
+    free(filter -> A);
+    free(filter -> d1);
+    free(filter -> d2);
+    free(filter -> d3);
+    free(filter -> d4);
+    free(filter -> w0);
+    free(filter -> w1);
+    free(filter -> w2);
+    free(filter -> w3);
+    free(filter -> w4);
+    free(filter);
+}
+
+FTR_PRECISION bw_low_pass(BWLowPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->n; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i] + x;
+        x = filter->A[i] * (filter->w0[i] + 2.0f * filter->w1[i] + filter->w2[i]);
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x;
+}
+FTR_PRECISION bw_high_pass(BWHighPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->n; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i] + x;
+        x = filter->A[i] * (filter->w0[i] - 2.0f * filter->w1[i] + filter->w2[i]);
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x;
+}
+FTR_PRECISION bw_band_pass(BWBandPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->n; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i]+ filter->d3[i]*filter->w3[i]+ filter->d4[i]*filter->w4[i] + x;
+        x = filter->A[i] * (filter->w0[i] - 2.0f * filter->w2[i] + filter->w4[i]);
+        filter->w4[i] = filter->w3[i];
+        filter->w3[i] = filter->w2[i];
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x;
+}
+FTR_PRECISION bw_band_stop(BWBandStop* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->n; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i]+ filter->d3[i]*filter->w3[i]+ filter->d4[i]*filter->w4[i] + x;
+        x = filter->A[i]*(filter->w0[i] - filter->r*filter->w1[i] + filter->s*filter->w2[i]- filter->r*filter->w3[i] + filter->w4[i]);
+        filter->w4[i] = filter->w3[i];
+        filter->w3[i] = filter->w2[i];
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x;
+}
+
+FTR_PRECISION che_low_pass(CHELowPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->m; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i] + x;
+        x = filter->A[i] * (filter->w0[i] + 2.0f * filter->w1[i] + filter->w2[i]);
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x * filter->ep;
+}
+FTR_PRECISION che_high_pass(CHEHighPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->m; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i] + x;
+        x = filter->A[i] * (filter->w0[i] - 2.0f * filter->w1[i] + filter->w2[i]);
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x * filter->ep;
+}
+
+FTR_PRECISION che_band_pass(CHEBandPass* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->m; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i]+ filter->d3[i]*filter->w3[i]+ filter->d4[i]*filter->w4[i] + x;
+        x = filter->A[i] * (filter->w0[i] - 2.0f * filter->w2[i] + filter->w4[i]);
+        filter->w4[i] = filter->w3[i];
+        filter->w3[i] = filter->w2[i];
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x * filter->ep;
+}
+
+FTR_PRECISION che_band_stop(CHEBandStop* filter, FTR_PRECISION x){
+    int i;
+    for(i=0; i<filter->m; ++i){
+        filter->w0[i] = filter->d1[i]*filter->w1[i] + filter->d2[i]*filter->w2[i]+ filter->d3[i]*filter->w3[i]+ filter->d4[i]*filter->w4[i] + x;
+        x = filter->A[i]*(filter->w0[i] - filter->r*filter->w1[i] + filter->s*filter->w2[i]- filter->r*filter->w3[i] + filter->w4[i]);
+        filter->w4[i] = filter->w3[i];
+        filter->w3[i] = filter->w2[i];
+        filter->w2[i] = filter->w1[i];
+        filter->w1[i] = filter->w0[i];
+    }
+    return x * filter->ep;
+}
+
+FTR_PRECISION softmax(FTR_PRECISION* data, int size, int target_ind){
+    FTR_PRECISION sum = 0;
+    for(int i = 0; i < size; i++) sum += data[i];
+    return data[target_ind]/sum;
+}
+
+static const FTR_PRECISION SPIKE_KERNEL[] = {-1.0, 2.0, -1.0};
+void spike_filter_upward(FTR_PRECISION * input, int size, FTR_PRECISION * output, FTR_PRECISION strength){
+    FTR_PRECISION mean = 0.0;
+    FTR_PRECISION std = 0.0;
+    FTR_PRECISION diff = 0.0;
+    for(int i=0; i < size; i++) mean += input[i];
+    mean /= size;
+
+    for(int i=0; i < size; i++){
+        diff = input[i] - mean;
+        std += diff * diff;
+    }
+    std = SQRT(std/size);
+      
+    output[0] = 0.0;
+    output[size - 1] = 0.0;
+    for(int i=1; i<size-1; i++){
+        FTR_PRECISION val = input[i-1] * SPIKE_KERNEL[0] + input[i] * SPIKE_KERNEL[1] + input[i+1] * SPIKE_KERNEL[2];
+        if(val < strength * std) output[i] = 0.0;
+        else output[i] = val;
+    }
+}
diff --git a/src/filter.h b/src/filter.h
new file mode 100644
index 0000000..e72d384
--- /dev/null
+++ b/src/filter.h
@@ -0,0 +1,160 @@
+/*
+ * filter.h
+ *
+ * Copyright (c) 2018 Disi A
+ * 
+ * Author: Disi A
+ * Email: adis@live.cn
+ *  https://www.mathworks.com/matlabcentral/profile/authors/3734620-disi-a
+ */
+#ifndef filter_h
+#define filter_h
+
+#if __cplusplus
+extern "C"{
+#endif
+
+#define DOUBLE_PRECISION 0
+
+#if DOUBLE_PRECISION
+#define FTR_PRECISION double
+#if defined(_WIN32) || defined(__ZEPHYR__)
+#define M_PI 3.141592653589793238462643383279502884197163993751
+#endif
+#else
+#define FTR_PRECISION float
+#if defined(_WIN32) || defined(__ZEPHYR__)
+#define M_PI 3.1415927f
+#endif
+#endif
+
+typedef struct {
+    int n;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+} BWLowPass;
+// BWHighPass uses exactly the same struct
+typedef BWLowPass BWHighPass;
+
+typedef struct {
+    int m;
+    FTR_PRECISION ep;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+} CHELowPass;
+typedef CHELowPass CHEHighPass;
+
+typedef struct {
+    int n;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *d3;
+    FTR_PRECISION *d4;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+    FTR_PRECISION *w3;
+    FTR_PRECISION *w4;
+} BWBandPass;
+
+typedef struct {
+    int m;
+    FTR_PRECISION ep;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *d3;
+    FTR_PRECISION *d4;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+    FTR_PRECISION *w3;
+    FTR_PRECISION *w4;
+} CHEBandPass;
+
+typedef struct {
+    int n;
+    FTR_PRECISION r;
+    FTR_PRECISION s;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *d3;
+    FTR_PRECISION *d4;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+    FTR_PRECISION *w3;
+    FTR_PRECISION *w4;
+} BWBandStop;
+
+typedef struct {
+    int m;
+    FTR_PRECISION ep;
+    FTR_PRECISION r;
+    FTR_PRECISION s;
+	FTR_PRECISION *A;
+    FTR_PRECISION *d1;
+    FTR_PRECISION *d2;
+    FTR_PRECISION *d3;
+    FTR_PRECISION *d4;
+    FTR_PRECISION *w0;
+    FTR_PRECISION *w1;
+    FTR_PRECISION *w2;
+    FTR_PRECISION *w3;
+    FTR_PRECISION *w4;
+} CHEBandStop;
+
+void update_bw_low_pass_filter(BWLowPass* filter, FTR_PRECISION s, FTR_PRECISION f, FTR_PRECISION q);
+  
+BWLowPass* create_bw_low_pass_filter(int order, FTR_PRECISION sampling_frequency, FTR_PRECISION half_power_frequency);
+BWHighPass* create_bw_high_pass_filter(int order, FTR_PRECISION sampling_frequency, FTR_PRECISION half_power_frequency);
+BWBandPass* create_bw_band_pass_filter(int order, FTR_PRECISION sampling_frequency, FTR_PRECISION lower_half_power_frequency, FTR_PRECISION upper_half_power_frequency);
+BWBandStop* create_bw_band_stop_filter(int order, FTR_PRECISION sampling_frequency, FTR_PRECISION lower_half_power_frequency, FTR_PRECISION upper_half_power_frequency);
+
+CHELowPass* create_che_low_pass_filter(int order, FTR_PRECISION epsilon, FTR_PRECISION sampling_frequency, FTR_PRECISION half_power_frequency);
+CHEHighPass* create_che_high_pass_filter(int order, FTR_PRECISION epsilon, FTR_PRECISION sampling_frequency, FTR_PRECISION half_power_frequency);
+CHEBandPass* create_che_band_pass_filter(int order, FTR_PRECISION epsilon, FTR_PRECISION sampling_frequency, FTR_PRECISION lower_half_power_frequency, FTR_PRECISION upper_half_power_frequency);
+CHEBandStop* create_che_band_stop_filter(int order, FTR_PRECISION epsilon, FTR_PRECISION sampling_frequency, FTR_PRECISION lower_half_power_frequency, FTR_PRECISION upper_half_power_frequency);
+
+
+void free_bw_low_pass(BWLowPass* filter);
+void free_bw_high_pass(BWHighPass* filter);
+void free_bw_band_pass(BWBandPass* filter);
+void free_bw_band_stop(BWBandStop* filter);
+
+void free_che_low_pass(CHELowPass* filter);
+void free_che_high_pass(CHEHighPass* filter);
+void free_che_band_pass(CHEBandPass* filter);
+void free_che_band_stop(CHEBandStop* filter);
+
+
+FTR_PRECISION bw_low_pass(BWLowPass* filter, FTR_PRECISION input);
+FTR_PRECISION bw_high_pass(BWHighPass* filter, FTR_PRECISION input);
+FTR_PRECISION bw_band_pass(BWBandPass* filter, FTR_PRECISION input);
+FTR_PRECISION bw_band_stop(BWBandStop* filter, FTR_PRECISION input);
+
+FTR_PRECISION che_low_pass(CHELowPass* filter, FTR_PRECISION input);
+FTR_PRECISION che_high_pass(CHEHighPass* filter, FTR_PRECISION input);
+FTR_PRECISION che_band_pass(CHEBandPass* filter, FTR_PRECISION input);
+FTR_PRECISION che_band_stop(CHEBandStop* filter, FTR_PRECISION input);
+
+FTR_PRECISION softmax(FTR_PRECISION* data, int size, int target_ind);
+
+// Output should be pre-allocated which has the same(or larger) size as the input.
+void spike_filter_upward(FTR_PRECISION * input, int size, FTR_PRECISION * output, FTR_PRECISION strength);
+
+#if __cplusplus
+}
+#endif
+
+#endif /* filter_h */
diff --git a/src/lowpass.c b/src/lowpass.c
new file mode 100644
index 0000000..304ad9f
--- /dev/null
+++ b/src/lowpass.c
@@ -0,0 +1,371 @@
+/*
+Resonant low pass filter source code.
+By baltrax@hotmail.com (Zxform)
+
+- little changes and optimizations by Brett Paterson for FMOD example.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "lowpass.h"
+
+/**************************************************************************
+
+FILTER.C - Source code for filter functions
+
+    iir_filter         IIR filter floats sample by sample (real time)
+
+*************************************************************************/
+
+FILTER   iir;
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * iir_filter - Perform IIR filtering sample by sample on floats
+ *
+ * Implements cascaded direct form II second order sections.
+ * Requires FILTER structure for history and coefficients.
+ * The length in the filter structure specifies the number of sections.
+ * The size of the history array is 2*iir.length.
+ * The size of the coefficient array is 4*iir.length + 1 because
+ * the first coefficient is the overall scale factor for the filter.
+ * Returns one output sample for each input sample.  Allocates history
+ * array if not previously allocated.
+ *
+ * float iir_filter(float input,FILTER *iir)
+ *
+ *     float input        new float input sample
+ *     FILTER *iir        pointer to FILTER structure
+ *
+ * Returns float value giving the current output.
+ *
+ * Allocation errors cause an error message and a call to exit.
+ * --------------------------------------------------------------------
+ */
+float LowPass_Filter(float input)
+{
+    unsigned int i;
+    float *hist1_ptr,*hist2_ptr,*coef_ptr;
+    float output,new_hist,history1,history2;
+    static float dc = (float)1E-25;
+    input += dc;
+    dc = -dc;
+
+	/* allocate history array if different size than last call */
+
+    coef_ptr = iir.coef;                /* coefficient pointer */
+
+    hist1_ptr = iir.history;            /* first history */
+    hist2_ptr = hist1_ptr + 1;           /* next history */
+
+    /* 1st number of coefficients array is overall input scale factor,
+     * or filter gain */
+    output = input * (*coef_ptr++);
+
+    for (i = 0 ; i < iir.length; i++)
+    {
+        history1 = *hist1_ptr;           /* history values */
+        history2 = *hist2_ptr;
+
+        output   = output - history1 * coef_ptr[0];
+        new_hist = output - history2 * coef_ptr[1];    /* poles */
+
+        output = new_hist + history1 * coef_ptr[2];
+        output = output   + history2 * coef_ptr[3];    /* zeros */
+
+        coef_ptr += 4;
+        *hist2_ptr++ = *hist1_ptr;
+        *hist1_ptr++ = new_hist;
+        hist1_ptr++;
+        hist2_ptr++;
+    }
+
+    return(output);
+}
+
+
+void LowPass_Update(float resonance, float cutoff, int samplerate)
+{
+    unsigned nInd;
+    double   a0, a1, a2, b0, b1, b2;
+    double   fs;    /* Sampling frequency, cutoff frequency */
+    double   k;           /* overall gain factor */
+    float    *coef;
+
+	k = 1.0;				/* Set overall filter gain */
+	coef = iir.coef + 1;		/* Skip k, or gain */
+	fs = (double)samplerate;    /* Sampling frequency (Hz) */
+
+/*
+ * Compute z-domain coefficients for each biquad section
+ * for new Cutoff Frequency and Resonance
+ */
+    for (nInd = 0; nInd < iir.length; nInd++)
+    {
+             a0 = ProtoCoef[nInd].a0;
+             a1 = ProtoCoef[nInd].a1;
+             a2 = ProtoCoef[nInd].a2;
+
+             b0 = ProtoCoef[nInd].b0;
+             b1 = ProtoCoef[nInd].b1 / resonance;      /* Divide by resonance or Q */
+             b2 = ProtoCoef[nInd].b2;
+             szxform(&a0, &a1, &a2, &b0, &b1, &b2, cutoff, fs, &k, coef);
+             coef += 4;                       /* Point to next filter section */
+    }
+
+    /* Update overall filter gain in coef array */
+    iir.coef[0] = (float)k;
+}
+
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * initn()
+ *
+ * Example main function to show how to update filter coefficients.
+ * We create a 4th order filter (24 db/oct roloff), consisting
+ * of two second order sections.
+ * --------------------------------------------------------------------
+ */
+signed char LowPass_Init()
+{
+
+/*
+ * Setup filter s-domain coefficients
+ */
+	/* Section 1 */
+	ProtoCoef[0].a0 = 1.0;
+	ProtoCoef[0].a1 = 0;
+	ProtoCoef[0].a2 = 0;
+	ProtoCoef[0].b0 = 1.0;
+	ProtoCoef[0].b1 = 0.765367;
+	ProtoCoef[0].b2 = 1.0;
+	
+	/* Section 2 */
+	ProtoCoef[1].a0 = 1.0;
+	ProtoCoef[1].a1 = 0;
+	ProtoCoef[1].a2 = 0;
+	ProtoCoef[1].b0 = 1.0;
+	ProtoCoef[1].b1 = 1.847759;
+	ProtoCoef[1].b2 = 1.0;
+
+	iir.length = FILTER_SECTIONS;         /* Number of filter sections */
+
+/*
+ * Allocate array of z-domain coefficients for each filter section
+ * plus filter gain variable
+ */
+	iir.coef = (float *) calloc(4 * iir.length + 1, sizeof(float));
+	if (!iir.coef)
+	{
+//		 printf("Unable to allocate coef array, exiting\n");
+		 return 0;
+	}
+
+	LowPass_Update(1.0, 5000.0, 44100);
+
+    /* Display filter coefficients */
+//    for (nInd = 0; nInd < (iir.length * 4 + 1); nInd++)
+//             printf("C[%d] = %15.10f\n", nInd, iir.coef[nInd]);
+/*
+ * To process audio samples, call function iir_filter()
+ * for each audio sample
+ */
+   return 1;
+}
+
+void LowPass_Close()
+{
+}
+
+
+/*
+ * ----------------------------------------------------------
+ *      bilinear.c
+ *
+ *      Perform bilinear transformation on s-domain coefficients
+ *      of 2nd order biquad section.
+ *      First design an analog filter and use s-domain coefficients
+ *      as input to szxform() to convert them to z-domain.
+ *
+ * Here's the butterworth polinomials for 2nd, 4th and 6th order sections.
+ *      When we construct a 24 db/oct filter, we take to 2nd order
+ *      sections and compute the coefficients separately for each section.
+ *
+ *      n       Polinomials
+ * --------------------------------------------------------------------
+ *      2       s^2 + 1.4142s +1
+ *      4       (s^2 + 0.765367s + 1) (s^2 + 1.847759s + 1)
+ *      6       (s^2 + 0.5176387s + 1) (s^2 + 1.414214 + 1) (s^2 + 1.931852s + 1)
+ *
+ *      Where n is a filter order.
+ *      For n=4, or two second order sections, we have following equasions for each
+ *      2nd order stage:
+ *
+ *      (1 / (s^2 + (1/Q) * 0.765367s + 1)) * (1 / (s^2 + (1/Q) * 1.847759s + 1))
+ *
+ *      Where Q is filter quality factor in the range of
+ *      1 to 1000. The overall filter Q is a product of all
+ *      2nd order stages. For example, the 6th order filter
+ *      (3 stages, or biquads) with individual Q of 2 will
+ *      have filter Q = 2 * 2 * 2 = 8.
+ *
+ *      The nominator part is just 1.
+ *      The denominator coefficients for stage 1 of filter are:
+ *      b2 = 1; b1 = 0.765367; b0 = 1;
+ *      numerator is
+ *      a2 = 0; a1 = 0; a0 = 1;
+ *
+ *      The denominator coefficients for stage 1 of filter are:
+ *      b2 = 1; b1 = 1.847759; b0 = 1;
+ *      numerator is
+ *      a2 = 0; a1 = 0; a0 = 1;
+ *
+ *      These coefficients are used directly by the szxform()
+ *      and bilinear() functions. For all stages the numerator
+ *      is the same and the only thing that is different between
+ *      different stages is 1st order coefficient. The rest of
+ *      coefficients are the same for any stage and equal to 1.
+ *
+ *      Any filter could be constructed using this approach.
+ *
+ *      References:
+ *             Van Valkenburg, "Analog Filter Design"
+ *             Oxford University Press 1982
+ *             ISBN 0-19-510734-9
+ *
+ *             C Language Algorithms for Digital Signal Processing
+ *             Paul Embree, Bruce Kimble
+ *             Prentice Hall, 1991
+ *             ISBN 0-13-133406-9
+ *
+ *             Digital Filter Designer's Handbook
+ *             With C++ Algorithms
+ *             Britton Rorabaugh
+ *             McGraw Hill, 1997
+ *             ISBN 0-07-053806-9
+ * ----------------------------------------------------------
+ */
+
+void prewarp(double *a0, double *a1, double *a2, double fc, double fs);
+void bilinear(
+    double a0, double a1, double a2,    /* numerator coefficients */
+    double b0, double b1, double b2,    /* denominator coefficients */
+    double *k,                                   /* overall gain factor */
+    double fs,                                   /* sampling rate */
+    float *coef);                         /* pointer to 4 iir coefficients */
+
+
+/*
+ * ----------------------------------------------------------
+ *      Pre-warp the coefficients of a numerator or denominator.
+ *      Note that a0 is assumed to be 1, so there is no wrapping
+ *      of it.
+ * ----------------------------------------------------------
+ */
+void prewarp(
+    double *a0, double *a1, double *a2,
+    double fc, double fs)
+{
+    double wp, pi;
+
+    pi = 4.0 * atan(1.0);
+    wp = 2.0 * fs * tan(pi * fc / fs);
+
+    *a2 = (*a2) / (wp * wp);
+    *a1 = (*a1) / wp;
+}
+
+
+/*
+ * ----------------------------------------------------------
+ * bilinear()
+ *
+ * Transform the numerator and denominator coefficients
+ * of s-domain biquad section into corresponding
+ * z-domain coefficients.
+ *
+ *      Store the 4 IIR coefficients in array pointed by coef
+ *      in following order:
+ *             beta1, beta2    (denominator)
+ *             alpha1, alpha2  (numerator)
+ *
+ * Arguments:
+ *             a0-a2   - s-domain numerator coefficients
+ *             b0-b2   - s-domain denominator coefficients
+ *             k               - filter gain factor. initially set to 1
+ *                                and modified by each biquad section in such
+ *                                a way, as to make it the coefficient by
+ *                                which to multiply the overall filter gain
+ *                                in order to achieve a desired overall filter gain,
+ *                                specified in initial value of k.
+ *             fs             - sampling rate (Hz)
+ *             coef    - array of z-domain coefficients to be filled in.
+ *
+ * Return:
+ *             On return, set coef z-domain coefficients
+ * ----------------------------------------------------------
+ */
+void bilinear(
+    double a0, double a1, double a2,	/* numerator coefficients */
+    double b0, double b1, double b2,	/* denominator coefficients */
+    double *k,							/* overall gain factor */
+    double fs,							/* sampling rate */
+    float *coef							/* pointer to 4 iir coefficients */
+)
+{
+    double ad, bd;
+
+	/* alpha (Numerator in s-domain) */
+    ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
+	/* beta (Denominator in s-domain) */
+    bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
+
+	/* update gain constant for this section */
+    *k *= ad/bd;
+
+	/* Denominator */
+    *coef++ = (float)((2. * b0 - 8. * b2 * fs * fs)           / bd); /* beta1 */
+    *coef++ = (float)((4. * b2 * fs * fs - 2. * b1 * fs + b0) / bd); /* beta2 */
+
+	/* Nominator */
+    *coef++ = (float)((2. * a0 - 8. * a2 * fs * fs) / ad);			 /* alpha1 */
+    *coef   = (float)((4. * a2 * fs * fs - 2. * a1 * fs + a0) / ad); /* alpha2 */
+}
+
+
+/*
+ * ----------------------------------------------------------
+ * Transform from s to z domain using bilinear transform
+ * with prewarp.
+ *
+ * Arguments:
+ *      For argument description look at bilinear()
+ *
+ *      coef - pointer to array of floating point coefficients,
+ *                     corresponding to output of bilinear transofrm
+ *                     (z domain).
+ *
+ * Note: frequencies are in Hz.
+ * ----------------------------------------------------------
+ */
+void szxform(
+    double *a0, double *a1, double *a2, /* numerator coefficients */
+    double *b0, double *b1, double *b2, /* denominator coefficients */
+    double fc,         /* Filter cutoff frequency */
+    double fs,         /* sampling rate */
+    double *k,         /* overall gain factor */
+    float *coef)         /* pointer to 4 iir coefficients */
+{
+                 /* Calculate a1 and a2 and overwrite the original values */
+        prewarp(a0, a1, a2, fc, fs);
+        prewarp(b0, b1, b2, fc, fs);
+        bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
+}
+
+
diff --git a/src/lowpass.h b/src/lowpass.h
new file mode 100644
index 0000000..6c99212
--- /dev/null
+++ b/src/lowpass.h
@@ -0,0 +1,46 @@
+#ifndef _LOWPASS_H
+#define _LOWPASS_H
+
+
+/* FILTER INFORMATION STRUCTURE FOR FILTER ROUTINES */
+
+#define FILTER_SECTIONS   2   /* 2 filter sections for 24 db/oct filter */
+
+typedef struct {
+    unsigned int length;       /* size of filter */
+    float history[2 * FILTER_SECTIONS];    /* history in filter */
+    float *coef;               /* pointer to coefficients of filter */
+} FILTER;
+
+typedef struct {
+        double a0, a1, a2;       /* numerator coefficients */
+        double b0, b1, b2;       /* denominator coefficients */
+} BIQUAD;
+
+static BIQUAD ProtoCoef[FILTER_SECTIONS];      /* Filter prototype coefficients,
+                                                     1 for each filter section */
+
+void szxform(
+    double *a0, double *a1, double *a2,     /* numerator coefficients */
+    double *b0, double *b1, double *b2,   /* denominator coefficients */
+    double fc,           /* Filter cutoff frequency */
+    double fs,           /* sampling rate */
+    double *k,           /* overall gain factor */
+    float *coef);         /* pointer to 4 iir coefficients */
+
+
+
+#ifdef __cplusplus
+	extern "C" {
+#endif
+
+	signed char LowPass_Init();
+	void		LowPass_Close();
+	float		LowPass_Filter(float input);
+	void		LowPass_Update(float resonance, float cutoff, int samplerate);
+
+#ifdef __cplusplus
+	}
+#endif
+
+#endif
diff --git a/src/notes.h b/src/notes.h
new file mode 100644
index 0000000..ed6b3e6
--- /dev/null
+++ b/src/notes.h
@@ -0,0 +1,51 @@
+#ifndef NOTES_H
+#define NOTES_H
+
+static float note_C[] = {16.35, 32.70, 65.41, 130.81, 261.63, 523.25, 1046.50, 2093.00, 4186.01};
+static float note_Db[] = {17.32, 34.65, 69.30, 138.59, 277.18, 554.37, 1108.73, 2217.46, 4434.92};
+static float note_D[] = {18.35, 36.71, 73.42, 146.83, 293.66, 587.33, 1174.66, 2349.32, 4698.64};
+static float note_Eb[] = {19.45, 38.89, 77.78, 155.56, 311.13, 622.25, 1244.51, 2489.02, 4978.03};
+static float note_E[] = {20.60, 41.20, 82.41, 164.81, 329.63, 659.26, 1318.51, 2637.02};
+static float note_F[] = {21.83, 43.65, 87.31, 174.61, 349.23, 698.46, 1396.91, 2793.83};
+static float note_Gb[] = {23.12, 46.25, 92.50, 185.00, 369.99, 739.99, 1479.98, 2959.96};
+static float note_G[] = {24.50, 49.00, 98.00, 196.00, 392.00, 783.99, 1567.98, 3135.96};
+static float note_Ab[] = {25.96, 51.91, 103.83, 207.65, 415.30, 830.61, 1661.22, 3322.44};
+static float note_A[] = {27.50, 55.00, 110.00, 220.00, 440.00, 880.00, 1760.00, 3520.00};
+static float note_Bb[] = {29.14, 58.27, 116.54, 233.08, 466.16, 932.33, 1864.66, 3729.31};
+static float note_B[] = {30.87, 61.74, 123.47, 246.94, 493.88, 987.77, 1975.53, 3951.0};
+
+static float *notes[12] = {note_C, note_Db, note_D, note_Eb, note_E, note_F, note_Gb, note_G, note_Ab, note_A, note_Bb, note_B };
+
+static char *
+int_to_note(int n)
+{
+  switch (n) {
+  case 0:
+    return "C";
+  case 1:
+    return "Db";
+  case 2:
+    return "D";
+  case 3:
+    return "Eb";
+  case 4:
+    return "E";
+  case 5:
+    return "F";
+  case 6:
+    return "Gb";
+  case 7:
+    return "G";
+  case 8:
+    return "Ab";
+  case 9:
+    return "A";
+  case 10:
+    return "Bb";
+  case 11:
+    return "B";
+  }
+  return "";
+}
+
+#endif /* NOTES_H */
diff --git a/src/raygui.h b/src/raygui.h
new file mode 100644
index 0000000..833725d
--- /dev/null
+++ b/src/raygui.h
@@ -0,0 +1,4647 @@
+/*******************************************************************************************
+*
+*   raygui v3.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.
+*
+*   Controls provided:
+*
+*   # Container/separators Controls
+*       - WindowBox     --> StatusBar, Panel
+*       - GroupBox      --> Line
+*       - Line
+*       - Panel         --> StatusBar
+*       - ScrollPanel   --> StatusBar
+*
+*   # Basic Controls
+*       - Label
+*       - Button
+*       - LabelButton   --> Label
+*       - Toggle
+*       - ToggleGroup   --> Toggle
+*       - CheckBox
+*       - ComboBox
+*       - DropdownBox
+*       - TextBox
+*       - TextBoxMulti
+*       - 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*4 = 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.
+*
+*
+*   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 raygui icons and create new ones.
+*
+*
+*   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
+*
+*
+*   VERSIONS HISTORY:
+*       3.5 (xx-xxx-2022) ADDED: Multiple new icons, useful for code editing tools
+*                         ADDED: GuiTabBar(), based on GuiToggle()
+*                         REMOVED: Unneeded icon editing functions
+*                         REDESIGNED: GuiDrawText() to divide drawing by lines
+*                         REMOVED: MeasureTextEx() dependency, logic directly implemented
+*                         REMOVED: DrawTextEx() dependency, logic directly implemented
+*                         ADDED: Helper functions to split text in separate 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.
+*
+*
+*   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-2023 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  "3.2"
+
+#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
+//----------------------------------------------------------------------------------
+// Allow custom memory allocators
+#ifndef RAYGUI_MALLOC
+    #define RAYGUI_MALLOC(sz)       malloc(sz)
+#endif
+#ifndef RAYGUI_CALLOC
+    #define RAYGUI_CALLOC(n,sz)     calloc(n,sz)
+#endif
+#ifndef RAYGUI_FREE
+    #define RAYGUI_FREE(p)          free(p)
+#endif
+
+// 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 Texture2D {
+        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)
+    } 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
+typedef struct GuiStyleProp {
+    unsigned short controlId;
+    unsigned short propertyId;
+    unsigned int propertyValue;
+} GuiStyleProp;
+
+// 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 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
+    PROGRESSBAR,
+    CHECKBOX,
+    COMBOBOX,
+    DROPDOWNBOX,
+    TEXTBOX,        // Used also for: TEXTBOXMULTI
+    VALUEBOX,
+    SPINNER,        // Uses: BUTTON, VALUEBOX
+    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,
+    BASE_COLOR_NORMAL,
+    TEXT_COLOR_NORMAL,
+    BORDER_COLOR_FOCUSED,
+    BASE_COLOR_FOCUSED,
+    TEXT_COLOR_FOCUSED,
+    BORDER_COLOR_PRESSED,
+    BASE_COLOR_PRESSED,
+    TEXT_COLOR_PRESSED,
+    BORDER_COLOR_DISABLED,
+    BASE_COLOR_DISABLED,
+    TEXT_COLOR_DISABLED,
+    BORDER_WIDTH,
+    TEXT_PADDING,
+    TEXT_ALIGNMENT,
+    RESERVED
+} GuiControlProperty;
+
+// Gui extended properties depend on control
+// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default 8 properties)
+//----------------------------------------------------------------------------------
+
+// DEFAULT extended properties
+// NOTE: Those properties are common to all controls or global
+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
+} GuiDefaultProperty;
+
+// 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,
+    ARROWS_VISIBLE,
+    SCROLL_SLIDER_PADDING,      // (SLIDERBAR, SLIDER_PADDING)
+    SCROLL_SLIDER_SIZE,
+    SCROLL_PADDING,
+    SCROLL_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
+} GuiDropdownBoxProperty;
+
+// TextBox/TextBoxMulti/ValueBox/Spinner
+typedef enum {
+    TEXT_INNER_PADDING = 16,    // TextBox/TextBoxMulti/ValueBox/Spinner inner text padding
+    TEXT_LINES_SPACING,         // TextBoxMulti lines separation
+} GuiTextBoxProperty;
+
+// Spinner
+typedef enum {
+    SPIN_BUTTON_WIDTH = 16,     // Spinner left/right buttons width
+    SPIN_BUTTON_SPACING,        // Spinner buttons separation
+} GuiSpinnerProperty;
+
+// 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-left, 1-right)
+} 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 GuiFade(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
+
+// Container/separator controls, useful for controls organization
+RAYGUIAPI bool GuiWindowBox(Rectangle bounds, const char *title);                                       // Window Box control, shows a window that can be closed
+RAYGUIAPI void GuiGroupBox(Rectangle bounds, const char *text);                                         // Group Box control with text name
+RAYGUIAPI void GuiLine(Rectangle bounds, const char *text);                                             // Line separator control, could contain text
+RAYGUIAPI void 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 Rectangle GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll); // Scroll Panel control
+
+// Basic controls set
+RAYGUIAPI void GuiLabel(Rectangle bounds, const char *text);                                            // Label control, shows text
+RAYGUIAPI bool GuiButton(Rectangle bounds, const char *text);                                           // Button control, returns true when clicked
+RAYGUIAPI bool GuiLabelButton(Rectangle bounds, const char *text);                                      // Label button control, show true when clicked
+RAYGUIAPI bool GuiToggle(Rectangle bounds, const char *text, bool active);                              // Toggle Button control, returns true when active
+RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int active);                           // Toggle Group control, returns active toggle index
+RAYGUIAPI bool 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, returns selected item index
+RAYGUIAPI bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode);          // Dropdown Box control, returns selected item
+RAYGUIAPI bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode);     // Spinner control, returns selected value
+RAYGUIAPI bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode);    // Value Box control, updates input text with numbers
+RAYGUIAPI bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode);                   // Text Box control, updates input text
+RAYGUIAPI bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode);              // Text Box control with multiple lines
+RAYGUIAPI float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue);       // Slider control, returns selected value
+RAYGUIAPI float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue);    // Slider Bar control, returns selected value
+RAYGUIAPI float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue);  // Progress Bar control, shows current progress value
+RAYGUIAPI void GuiStatusBar(Rectangle bounds, const char *text);                                        // Status Bar control, shows info text
+RAYGUIAPI void GuiDummyRec(Rectangle bounds, const char *text);                                         // Dummy control for placeholders
+RAYGUIAPI Vector2 GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs);              // Grid control, returns mouse cell position
+
+// Advance controls set
+RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active);            // List View control, returns selected list item index
+RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active);      // 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, int *secretViewActive);   // Text Input Box control, ask for text, supports secret
+RAYGUIAPI Color GuiColorPicker(Rectangle bounds, const char *text, Color color);                        // Color Picker control (multiple color controls)
+RAYGUIAPI Color GuiColorPanel(Rectangle bounds, const char *text, Color color);                         // Color Panel control
+RAYGUIAPI float GuiColorBarAlpha(Rectangle bounds, const char *text, float alpha);                      // Color Bar Alpha control
+RAYGUIAPI float GuiColorBarHue(Rectangle bounds, const char *text, float value);                        // Color Bar Hue control
+
+// 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 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);
+RAYGUIAPI void GuiSetIconScale(int scale);                      // Set icon drawing size
+
+#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_219                      = 219,
+    ICON_220                      = 220,
+    ICON_221                      = 221,
+    ICON_222                      = 222,
+    ICON_223                      = 223,
+    ICON_224                      = 224,
+    ICON_225                      = 225,
+    ICON_226                      = 226,
+    ICON_227                      = 227,
+    ICON_228                      = 228,
+    ICON_229                      = 229,
+    ICON_230                      = 230,
+    ICON_231                      = 231,
+    ICON_232                      = 232,
+    ICON_233                      = 233,
+    ICON_234                      = 234,
+    ICON_235                      = 235,
+    ICON_236                      = 236,
+    ICON_237                      = 237,
+    ICON_238                      = 238,
+    ICON_239                      = 239,
+    ICON_240                      = 240,
+    ICON_241                      = 241,
+    ICON_242                      = 242,
+    ICON_243                      = 243,
+    ICON_244                      = 244,
+    ICON_245                      = 245,
+    ICON_246                      = 246,
+    ICON_247                      = 247,
+    ICON_248                      = 248,
+    ICON_249                      = 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 <stdio.h>              // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include <stdlib.h>             // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+#include <string.h>             // Required for: strlen() [GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()], memset(), memcpy()
+#include <stdarg.h>             // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include <math.h>               // Required for: roundf() [GuiColorPicker()]
+
+#ifdef __cplusplus
+    #define RAYGUI_CLITERAL(name) name
+#else
+    #define RAYGUI_CLITERAL(name) (name)
+#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, 0x47fe483c, 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, 0x3ff27fe2, 0x0ffe1ffa, 0x000007fe,      // ICON_CUBE_FACE_BOTTOM
+    0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe,      // ICON_CUBE_FACE_RIGHT
+    0x7fe00000, 0x7fe87ff0, 0x7ffe7fe4, 0x7fe27fe2, 0x7fe27fe2, 0x24127fe2, 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
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_219
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_220
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_221
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_222
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_223
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_224
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_225
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_226
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_227
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_228
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_229
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_230
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_231
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_232
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_233
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_234
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_235
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_236
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_237
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_238
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_239
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_240
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_241
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_242
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_243
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_244
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_245
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_246
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_247
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_248
+    0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,      // ICON_249
+    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: We keep a pointer to the icons array, useful to point to other sets if required
+static unsigned int *guiIconsPtr = guiIcons;
+
+#endif      // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS
+
+#ifndef RAYGUI_ICON_SIZE
+    #define RAYGUI_ICON_SIZE             0
+#endif
+
+#define RAYGUI_MAX_CONTROLS             16      // Maximum number of standard controls
+#define RAYGUI_MAX_PROPS_BASE           16      // Maximum number of standard properties
+#define RAYGUI_MAX_PROPS_EXTENDED        8      // Maximum number of extended properties
+
+//----------------------------------------------------------------------------------
+// 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 element transpacency on drawing
+
+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)
+
+
+//----------------------------------------------------------------------------------
+// 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(), GuiTextBoxMulti(), GuiValueBox()
+//-------------------------------------------------------------------------------
+
+// Drawing required functions
+//-------------------------------------------------------------------------------
+static void DrawRectangle(int x, int y, int width, int height, Color color);        // -- GuiDrawRectangle(), GuiDrawIcon()
+
+static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
+//-------------------------------------------------------------------------------
+
+// Text required functions
+//-------------------------------------------------------------------------------
+static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // -- GuiLoadStyle()
+static Font GetFontDefault(void);                           // -- GuiLoadStyleDefault()
+static Texture2D LoadTextureFromImage(Image image);         // -- GuiLoadStyle()
+static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle()
+static char *LoadFileText(const char *fileName);            // -- GuiLoadStyle()
+static const char *GetDirectoryPath(const char *filePath);  // -- 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 Color Fade(Color color, float alpha);        // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
+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 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 specific Functions Declaration
+//----------------------------------------------------------------------------------
+static int GetTextWidth(const char *text);                      // Gui get text width using gui font and style
+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 bounds, 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
+
+
+//----------------------------------------------------------------------------------
+// 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 GuiFade(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;
+        GuiSetStyle(DEFAULT, TEXT_SIZE, font.baseSize);
+    }
+}
+
+// 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
+bool 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
+
+    //GuiState state = guiState;
+    bool clicked = false;
+
+    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;
+
+    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) - 20,
+                                 statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 };
+
+    // 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)
+    clicked = GuiButton(closeButtonRec, "x");
+#else
+    clicked = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL));
+#endif
+    GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
+    //--------------------------------------------------------------------
+
+    return clicked;
+}
+
+// Group Box control with text name
+void GuiGroupBox(Rectangle bounds, const char *text)
+{
+    #if !defined(RAYGUI_GROUPBOX_LINE_THICK)
+        #define RAYGUI_GROUPBOX_LINE_THICK     1
+    #endif
+
+    GuiState state = guiState;
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
+    GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
+    GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
+
+    GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text);
+    //--------------------------------------------------------------------
+}
+
+// Line control
+void GuiLine(Rectangle bounds, const char *text)
+{
+    #if !defined(RAYGUI_LINE_ORIGIN_SIZE)
+        #define RAYGUI_LINE_MARGIN_TEXT  12
+    #endif
+    #if !defined(RAYGUI_LINE_TEXT_PADDING)
+        #define RAYGUI_LINE_TEXT_PADDING  4
+    #endif
+
+    GuiState state = guiState;
+
+    Color color = Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha);
+
+    // 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)GetTextWidth(text);
+        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);
+    }
+    //--------------------------------------------------------------------
+}
+
+// Panel control
+void GuiPanel(Rectangle bounds, const char *text)
+{
+    #if !defined(RAYGUI_PANEL_BORDER_WIDTH)
+        #define RAYGUI_PANEL_BORDER_WIDTH   1
+    #endif
+
+    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, Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), guiAlpha),
+                     Fade(GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)), guiAlpha));
+    //--------------------------------------------------------------------
+}
+
+// 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    160
+
+    GuiState state = guiState;
+
+    int closing = -1;
+    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;
+
+    // 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) GuiToggle(tabBounds, GuiIconText(12, text[i]), true);
+            else if (GuiToggle(tabBounds, GuiIconText(12, text[i]), false) == true) *active = i;
+            GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
+            GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
+
+            // Draw tab close button
+            // NOTE: Only draw close button for curren tab: if (CheckCollisionPointRec(mousePoint, 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(closeButtonRec, "x")) closing = i;
+#else
+            if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) closing = 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 closing;     // Return closing tab requested
+}
+
+// Scroll Panel control
+Rectangle GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll)
+{
+    GuiState state = guiState;
+
+    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) };
+
+    // Calculate view area (area without the scrollbars)
+    Rectangle 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();
+
+            // Horizontal scroll (Shift + Mouse wheel)
+            if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_SHIFT))) scrollPos.x += wheelMove*20;
+            else scrollPos.y += wheelMove*20; // 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, Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), guiAlpha));        // 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, Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))), guiAlpha));
+    }
+
+    // Draw scrollbar lines depending on current state
+    GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), guiAlpha), BLANK);
+
+    // Set scrollbar slider size back to the way it was before
+    GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider);
+    //--------------------------------------------------------------------
+
+    if (scroll != NULL) *scroll = scrollPos;
+
+    return view;
+}
+
+// Label control
+void GuiLabel(Rectangle bounds, const char *text)
+{
+    GuiState state = guiState;
+
+    // Update control
+    //--------------------------------------------------------------------
+    //...
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    //--------------------------------------------------------------------
+}
+
+// Button control, returns true when clicked
+bool GuiButton(Rectangle bounds, const char *text)
+{
+    GuiState state = guiState;
+    bool pressed = false;
+
+    // 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 (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
+    GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
+
+    if (state == STATE_FOCUSED) GuiTooltip(bounds);
+    //------------------------------------------------------------------
+
+    return pressed;
+}
+
+// Label button control
+bool GuiLabelButton(Rectangle bounds, const char *text)
+{
+    GuiState state = guiState;
+    bool pressed = false;
+
+    // NOTE: We force bounds.width to be all text
+    float textWidth = (float)GetTextWidth(text);
+    if (bounds.width < textWidth) bounds.width = textWidth;
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        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), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return pressed;
+}
+
+// Toggle Button control, returns true when active
+bool GuiToggle(Rectangle bounds, const char *text, bool active)
+{
+    GuiState state = guiState;
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        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), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BORDER_COLOR_PRESSED : (BORDER + state*3)))), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BASE_COLOR_PRESSED : (BASE + state*3)))), guiAlpha));
+        GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, (active? TEXT_COLOR_PRESSED : (TEXT + state*3)))), guiAlpha));
+    }
+    else
+    {
+        GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, BASE + state*3)), guiAlpha));
+        GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)), guiAlpha));
+    }
+
+    if (state == STATE_FOCUSED) GuiTooltip(bounds);
+    //--------------------------------------------------------------------
+
+    return active;
+}
+
+// Toggle Group control, returns toggled button codepointIndex
+int GuiToggleGroup(Rectangle bounds, const char *text, int active)
+{
+    #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
+        #define RAYGUI_TOGGLEGROUP_MAX_ITEMS    32
+    #endif
+
+    float initBoundsX = bounds.x;
+
+    // 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) GuiToggle(bounds, items[i], true);
+        else if (GuiToggle(bounds, items[i], false) == true) active = i;
+
+        bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
+    }
+
+    return active;
+}
+
+// Check Box control, returns true when active
+bool GuiCheckBox(Rectangle bounds, const char *text, bool checked)
+{
+    GuiState state = guiState;
+
+    Rectangle textBounds = { 0 };
+
+    if (text != NULL)
+    {
+        textBounds.width = (float)GetTextWidth(text);
+        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)
+    {
+        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;
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), guiAlpha), 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, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
+    }
+
+    GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return checked;
+}
+
+// Combo Box control, returns selected item codepointIndex
+int GuiComboBox(Rectangle bounds, const char *text, int active)
+{
+    GuiState state = guiState;
+
+    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))
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (CheckCollisionPointRec(mousePoint, bounds) ||
+            CheckCollisionPointRec(mousePoint, selector))
+        {
+            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+            {
+                active += 1;
+                if (active >= itemCount) active = 0;
+            }
+
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+            else state = STATE_FOCUSED;
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    // Draw combo box main
+    GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))), guiAlpha));
+    GuiDrawText(items[active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))), guiAlpha));
+
+    // 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 active;
+}
+
+// Dropdown Box control
+// NOTE: Returns mouse click
+bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
+{
+    GuiState state = guiState;
+    int itemSelected = *active;
+    int itemFocused = -1;
+
+    // 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));
+
+    Rectangle itemBounds = bounds;
+
+    bool pressed = false;       // Check mouse button pressed
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1))
+    {
+        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)) pressed = true;
+            }
+
+            // Check if already selected item has been pressed again
+            if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
+
+            // Check focused and selected item
+            for (int i = 0; i < itemCount; i++)
+            {
+                // Update item rectangle y position for next item
+                itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+                if (CheckCollisionPointRec(mousePoint, itemBounds))
+                {
+                    itemFocused = i;
+                    if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+                    {
+                        itemSelected = i;
+                        pressed = true;     // Item selected, change to editMode = false
+                    }
+                    break;
+                }
+            }
+
+            itemBounds = bounds;
+        }
+        else
+        {
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+                {
+                    pressed = true;
+                    state = STATE_PRESSED;
+                }
+                else state = STATE_FOCUSED;
+            }
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    if (editMode) GuiPanel(boundsOpen, NULL);
+
+    GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)), guiAlpha));
+    GuiDrawText(items[itemSelected], GetTextBounds(DEFAULT, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)), guiAlpha));
+
+    if (editMode)
+    {
+        // Draw visible items
+        for (int i = 0; i < itemCount; i++)
+        {
+            // Update item rectangle y position for next item
+            itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+            if (i == itemSelected)
+            {
+                GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)), guiAlpha));
+                GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)), guiAlpha));
+            }
+            else if (i == itemFocused)
+            {
+                GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)), guiAlpha));
+                GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)), guiAlpha));
+            }
+            else GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)), guiAlpha));
+        }
+    }
+
+    // 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, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
+#else
+    GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
+                TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));   // ICON_ARROW_DOWN_FILL
+#endif
+    //--------------------------------------------------------------------
+
+    *active = itemSelected;
+    return pressed;
+}
+
+// Text Box control, updates input text
+// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
+bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+    GuiState state = guiState;
+    Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
+
+    bool pressed = false;
+    int textWidth = GetTextWidth(text);
+
+    Rectangle cursor = {
+        bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + textWidth + 2,
+        bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
+        4,
+        (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);
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+
+            int key = GetCharPressed();      // Returns codepoint as Unicode
+            int keyCount = (int)strlen(text);
+            int byteSize = 0;
+            const char *textUTF8 = CodepointToUTF8(key, &byteSize);
+
+            // Only allow keys in range [32..125]
+            if ((keyCount + byteSize) < textSize)
+            {
+                //float maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)*2));
+
+                if (key >= 32)
+                {
+                    for (int i = 0; i < byteSize; i++)
+                    {
+                        text[keyCount] = textUTF8[i];
+                        keyCount++;
+                    }
+
+                    text[keyCount] = '\0';
+                }
+            }
+
+            // Delete text
+            if (keyCount > 0)
+            {
+                if (IsKeyPressed(KEY_BACKSPACE))
+                {
+                    while ((keyCount > 0) && ((text[--keyCount] & 0xc0) == 0x80));
+                    text[keyCount] = '\0';
+                }
+            }
+
+            if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true;
+        }
+        else
+        {
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                state = STATE_FOCUSED;
+                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
+            }
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    if (state == STATE_PRESSED)
+    {
+        GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
+    }
+    else if (state == STATE_DISABLED)
+    {
+        GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha));
+    }
+    else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
+
+    if (editMode)
+    {
+        // In case we edit and text does not fit in the textbox,
+        // we move text pointer to a position it fits inside the text box
+        while ((textWidth >= textBounds.width) && (text[0] != '\0'))
+        {
+            int codepointSize = 0;
+            GetCodepointNext(text, &codepointSize);
+            text += codepointSize;
+            textWidth = GetTextWidth(text);
+            cursor.x = textBounds.x + textWidth + 2;
+        }
+    }
+
+    GuiDrawText(text, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
+
+    // Draw cursor
+    if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED) GuiTooltip(bounds);
+    //--------------------------------------------------------------------
+
+    return pressed;
+}
+
+// Spinner control, returns selected value
+bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
+{
+    GuiState state = guiState;
+
+    bool pressed = false;
+    int tempValue = *value;
+
+    Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
+                          bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
+    Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+    Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+
+    Rectangle textBounds = { 0 };
+    if (text != NULL)
+    {
+        textBounds.width = (float)GetTextWidth(text);
+        textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+        textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING);
+        textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+        if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING);
+    }
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        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
+    //--------------------------------------------------------------------
+    // TODO: Set Spinner properties for ValueBox
+    pressed = GuiValueBox(spinner, 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(SPINNER, 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(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    //--------------------------------------------------------------------
+
+    *value = tempValue;
+    return pressed;
+}
+
+// Value Box control, updates input text with numbers
+// NOTE: Requires static variables: frameCounter
+bool 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
+
+    GuiState state = guiState;
+    bool pressed = false;
+
+    char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
+    sprintf(textValue, "%i", *value);
+
+    Rectangle textBounds = { 0 };
+    if (text != NULL)
+    {
+        textBounds.width = (float)GetTextWidth(text);
+        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)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        bool valueHasChanged = false;
+
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+
+            int keyCount = (int)strlen(textValue);
+
+            // Only allow keys in range [48..57]
+            if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+            {
+                if (GetTextWidth(textValue) < bounds.width)
+                {
+                    int key = GetCharPressed();
+                    if ((key >= 48) && (key <= 57))
+                    {
+                        textValue[keyCount] = (char)key;
+                        keyCount++;
+                        valueHasChanged = true;
+                    }
+                }
+            }
+
+            // Delete text
+            if (keyCount > 0)
+            {
+                if (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) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true;
+        }
+        else
+        {
+            if (*value > maxValue) *value = maxValue;
+            else if (*value < minValue) *value = minValue;
+
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                state = STATE_FOCUSED;
+                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
+            }
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // 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));
+
+    // WARNING: BLANK color does not work properly with Fade()
+    GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor);
+    GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
+
+    // Draw cursor
+    if (editMode)
+    {
+        // NOTE: ValueBox internal text is always centered
+        Rectangle cursor = { bounds.x + GetTextWidth(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, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
+    }
+
+    // Draw text label if provided
+    GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return pressed;
+}
+
+// Text Box control with multiple lines
+bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+    GuiState state = guiState;
+    bool pressed = false;
+
+    Rectangle textAreaBounds = {
+        bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING),
+        bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING),
+        bounds.width - 2*(GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)),
+        bounds.height - 2*(GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING))
+    };
+
+    // Cursor position, [x, y] values should be updated
+    Rectangle cursor = { 0, -1, 4, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 };
+
+    float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;     // Character rectangle scaling factor
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (editMode)
+        {
+            state = STATE_PRESSED;
+
+            // We get an Unicode codepoint
+            int codepoint = GetCharPressed();
+            int textLength = (int)strlen(text);     // Length in bytes (UTF-8 string)
+            int byteSize = 0;
+            const char *textUTF8 = CodepointToUTF8(codepoint, &byteSize);
+
+            // Introduce characters
+            if ((textLength + byteSize) < textSize)
+            {
+                if (IsKeyPressed(KEY_ENTER))
+                {
+                    text[textLength] = '\n';
+                    textLength++;
+                }
+                else if (codepoint >= 32)
+                {
+                    // Supports Unicode inputs -> Encoded to UTF-8
+                    int charUTF8Length = 0;
+                    const char *charEncoded = CodepointToUTF8(codepoint, &charUTF8Length);
+                    memcpy(text + textLength, charEncoded, charUTF8Length);
+                    textLength += charUTF8Length;
+                }
+            }
+
+            // Delete characters
+            if (textLength > 0)
+            {
+                if (IsKeyPressed(KEY_BACKSPACE))
+                {
+                    if ((unsigned char)text[textLength - 1] < 127)
+                    {
+                        // Remove ASCII equivalent character (1 byte)
+                        textLength--;
+                        text[textLength] = '\0';
+                    }
+                    else
+                    {
+                        // Remove latest UTF-8 unicode character introduced (n bytes)
+                        int charUTF8Length = 0;
+                        while ((charUTF8Length < textLength) && ((unsigned char)text[textLength - 1 - charUTF8Length] & 0b01000000) == 0) charUTF8Length++;
+
+                        textLength -= (charUTF8Length + 1);
+                        text[textLength] = '\0';
+                    }
+                }
+            }
+
+            // Exit edit mode
+            if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
+        }
+        else
+        {
+            if (CheckCollisionPointRec(mousePoint, bounds))
+            {
+                state = STATE_FOCUSED;
+                if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
+            }
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    if (state == STATE_PRESSED)
+    {
+        GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
+    }
+    else if (state == STATE_DISABLED)
+    {
+        GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha));
+    }
+    else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
+
+    int wrapMode = 1;      // 0-No wrap, 1-Char wrap, 2-Word wrap
+    Vector2 cursorPos = { textAreaBounds.x, textAreaBounds.y };
+
+    //int lastSpacePos = 0;
+    //int lastSpaceWidth = 0;
+    //int lastSpaceCursorPos = 0;
+
+    for (int i = 0, codepointSize = 0; (text != NULL) && (text[i] != '\0'); i += codepointSize)
+    {
+        int codepoint = GetCodepointNext(text + i, &codepointSize);
+        int index = GetGlyphIndex(guiFont, codepoint);      // If requested codepoint is not found, we get '?' (0x3f)
+        Rectangle atlasRec = guiFont.recs[index];
+        GlyphInfo glyphInfo = guiFont.glyphs[index];        // Glyph measures
+
+        if ((codepointSize == 1) && (codepoint == '\n'))
+        {
+            cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_SPACING));   // Line feed
+            cursorPos.x = textAreaBounds.x;                 // Carriage return
+        }
+        else
+        {
+            if (wrapMode == 1)
+            {
+                int glyphWidth = 0;
+                if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
+                else glyphWidth += (int)(atlasRec.width + glyphInfo.offsetX);
+
+                // Jump line if the end of the text box area has been reached
+                if ((cursorPos.x + (glyphWidth*scaleFactor)) > (textAreaBounds.x + textAreaBounds.width))
+                {
+                    cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_SPACING));   // Line feed
+                    cursorPos.x = textAreaBounds.x;     // Carriage return
+                }
+            }
+            else if (wrapMode == 2)
+            {
+                /*
+                if ((codepointSize == 1) && (codepoint == ' '))
+                {
+                    lastSpacePos = i;
+                    lastSpaceWidth = 0;
+                    lastSpaceCursorPos = cursorPos.x;
+                }
+
+                // Jump line if last word reaches end of text box area
+                if ((lastSpaceCursorPos + lastSpaceWidth) > (textAreaBounds.x + textAreaBounds.width))
+                {
+                    cursorPos.y += 12;               // Line feed
+                    cursorPos.x = textAreaBounds.x;  // Carriage return
+                }
+                */
+            }
+
+            // Draw current character glyph
+            DrawTextCodepoint(guiFont, codepoint, cursorPos, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
+
+            int glyphWidth = 0;
+            if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
+            else glyphWidth += (int)(atlasRec.width + glyphInfo.offsetX);
+
+            cursorPos.x += (glyphWidth*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+            //if (i > lastSpacePos) lastSpaceWidth += (atlasRec.width + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+        }
+    }
+
+    cursor.x = cursorPos.x;
+    cursor.y = cursorPos.y;
+
+    // Draw cursor position considering text glyphs
+    if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return pressed;
+}
+
+// Slider control with pro parameters
+// NOTE: Other GuiSlider*() controls use this one
+float GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue, int sliderWidth)
+{
+    GuiState state = guiState;
+
+    int sliderValue = (int)(((value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_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) };
+
+    if (sliderWidth > 0)        // Slider
+    {
+        slider.x += (sliderValue - sliderWidth/2);
+        slider.width = (float)sliderWidth;
+    }
+    else if (sliderWidth == 0)  // SliderBar
+    {
+        slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
+        slider.width = (float)sliderValue;
+    }
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                state = STATE_PRESSED;
+
+                // Get equivalent value and slider position from mousePoint.x
+                value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
+
+                if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2;  // Slider
+                else if (sliderWidth == 0) slider.width = (float)sliderValue;          // SliderBar
+            }
+            else state = STATE_FOCUSED;
+        }
+
+        if (value > maxValue) value = maxValue;
+        else if (value < minValue) value = minValue;
+    }
+
+    // Bar limits check
+    if (sliderWidth > 0)        // Slider
+    {
+        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
+    {
+        if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)?  BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+
+    // Draw slider internal bar (depends on state)
+    if ((state == STATE_NORMAL) || (state == STATE_PRESSED)) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha));
+
+    // Draw left/right text if provided
+    if (textLeft != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(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, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+
+    if (textRight != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(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, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
+    }
+    //--------------------------------------------------------------------
+
+    return value;
+}
+
+// Slider control extended, returns selected value and has text
+float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue)
+{
+    return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
+}
+
+// Slider Bar control extended, returns selected value
+float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue)
+{
+    return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0);
+}
+
+// Progress Bar control extended, shows current progress value
+float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue)
+{
+    GuiState state = guiState;
+
+    Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
+                           bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
+                           bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) };
+
+    // Update control
+    //--------------------------------------------------------------------
+    if (value > maxValue) value = maxValue;
+
+    if (state != STATE_DISABLED) progress.width = ((float)(value/(maxValue - minValue))*(float)(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)));
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), guiAlpha), BLANK);
+
+    // Draw slider internal progress bar (depends on state)
+    if ((state == STATE_NORMAL) || (state == STATE_PRESSED)) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)), guiAlpha));
+    else if (state == STATE_FOCUSED) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT_COLOR_FOCUSED)), guiAlpha));
+
+    // Draw left/right text if provided
+    if (textLeft != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(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, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha));
+    }
+
+    if (textRight != NULL)
+    {
+        Rectangle textBounds = { 0 };
+        textBounds.width = (float)GetTextWidth(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, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha));
+    }
+    //--------------------------------------------------------------------
+
+    return value;
+}
+
+// Status Bar control
+void GuiStatusBar(Rectangle bounds, const char *text)
+{
+    GuiState state = guiState;
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha),
+                     Fade(GetColor(GuiGetStyle(STATUSBAR, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+    GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
+    //--------------------------------------------------------------------
+}
+
+// Dummy rectangle control, intended for placeholding
+void GuiDummyRec(Rectangle bounds, const char *text)
+{
+    GuiState state = guiState;
+
+    // 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;
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
+    GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
+    //------------------------------------------------------------------
+}
+
+// List View control
+int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active)
+{
+    int itemCount = 0;
+    const char **items = NULL;
+
+    if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+    return GuiListViewEx(bounds, items, itemCount, NULL, scrollIndex, active);
+}
+
+// List View control with extended parameters
+int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active)
+{
+    GuiState state = guiState;
+    int itemFocused = (focus == NULL)? -1 : *focus;
+    int itemSelected = 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)
+    {
+        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(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));     // Draw background
+
+    // Draw visible items
+    for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
+    {
+        if (state == STATE_DISABLED)
+        {
+            if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
+
+            GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha));
+        }
+        else
+        {
+            if ((startIndex + i) == itemSelected)
+            {
+                // Draw item selected
+                GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
+                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha));
+            }
+            else if ((startIndex + i) == itemFocused)
+            {
+                // Draw item focused
+                GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
+                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha));
+            }
+            else
+            {
+                // Draw item normal
+                GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha));
+            }
+        }
+
+        // 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 (focus != NULL) *focus = itemFocused;
+    if (scrollIndex != NULL) *scrollIndex = startIndex;
+
+    return itemSelected;
+}
+
+// Color Panel control
+Color GuiColorPanel(Rectangle bounds, const char *text, Color color)
+{
+    const Color colWhite = { 255, 255, 255, 255 };
+    const Color colBlack = { 0, 0, 0, 255 };
+
+    GuiState state = guiState;
+    Vector2 pickerSelector = { 0 };
+
+    Vector3 vcolor = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
+    Vector3 hsv = ConvertRGBtoHSV(vcolor);
+
+    pickerSelector.x = bounds.x + (float)hsv.y*bounds.width;            // HSV: Saturation
+    pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height;  // HSV: Value
+
+    float hue = -1.0f;
+    Vector3 maxHue = { hue >= 0.0f ? hue : hsv.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 (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                state = STATE_PRESSED;
+                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
+
+                hsv.y = colorPick.x;
+                hsv.z = 1.0f - colorPick.y;
+
+                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),
+                                 (unsigned char)(255.0f*(float)color.a/255.0f) };
+
+            }
+            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, Fade(colWhite, guiAlpha));
+    }
+    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), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK);
+    //--------------------------------------------------------------------
+
+    return color;
+}
+
+// Color Bar Alpha control
+// NOTE: Returns alpha value normalized [0..1]
+float GuiColorBarAlpha(Rectangle bounds, const char *text, float alpha)
+{
+    #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE)
+        #define RAYGUI_COLORBARALPHA_CHECKED_SIZE   10
+    #endif
+
+    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 (CheckCollisionPointRec(mousePoint, bounds) ||
+            CheckCollisionPointRec(mousePoint, selector))
+        {
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                state = STATE_PRESSED;
+
+                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(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f), guiAlpha) : Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f), guiAlpha));
+            }
+        }
+
+        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), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK);
+
+    // Draw alpha bar: selector
+    GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return alpha;
+}
+
+// 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]
+float GuiColorBarHue(Rectangle bounds, const char *text, float hue)
+{
+    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 (CheckCollisionPointRec(mousePoint, bounds) ||
+            CheckCollisionPointRec(mousePoint, selector))
+        {
+            if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                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 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
+        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), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK);
+
+    // Draw hue bar: selector
+    GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
+    //--------------------------------------------------------------------
+
+    return hue;
+}
+
+// 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
+Color GuiColorPicker(Rectangle bounds, const char *text, Color color)
+{
+    color = 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) };
+
+    Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ color.r/255.0f, color.g/255.0f, color.b/255.0f });
+    hsv.x = 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 color;
+}
+
+// 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 clicked = -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 = GetTextWidth(message);
+
+    Rectangle textBounds = { 0 };
+    textBounds.x = bounds.x + bounds.width/2 - textWidth/2;
+    textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+    textBounds.width = (float)textWidth;
+    textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
+
+    // Draw control
+    //--------------------------------------------------------------------
+    if (GuiWindowBox(bounds, title)) clicked = 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])) clicked = i + 1;
+        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+    }
+
+    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
+    //--------------------------------------------------------------------
+
+    return clicked;
+}
+
+// Text Input Box control, ask for text
+int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, int *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 btnIndex = -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 = GetTextWidth(message);
+
+        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)) btnIndex = 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;
+
+        *secretViewActive = 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])) btnIndex = i + 1;
+        buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+    }
+
+    GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
+    //--------------------------------------------------------------------
+
+    return btnIndex;
+}
+
+// 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
+Vector2 GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs)
+{
+    // Grid lines alpha amount
+    #if !defined(RAYGUI_GRID_ALPHA)
+        #define RAYGUI_GRID_ALPHA    0.15f
+    #endif
+
+    GuiState state = guiState;
+    Vector2 mousePoint = GetMousePosition();
+    Vector2 currentCell = { -1, -1 };
+
+    int linesV = ((int)(bounds.width/spacing))*subdivs + 1;
+    int linesH = ((int)(bounds.height/spacing))*subdivs + 1;
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            // NOTE: Cell values must be the upper left of the cell the mouse is in
+            currentCell.x = floorf((mousePoint.x - bounds.x)/spacing);
+            currentCell.y = floorf((mousePoint.y - bounds.y)/spacing);
+        }
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+
+    // TODO: Draw background panel?
+
+    switch (state)
+    {
+        case STATE_NORMAL:
+        {
+            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 };
+                    GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_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 };
+                    GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA));
+                }
+            }
+        } break;
+        default: break;
+    }
+
+    return currentCell;
+}
+
+//----------------------------------------------------------------------------------
+// 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;
+
+    // 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 };
+
+                        if (charmapFileName[0] != '0')
+                        {
+                            // Load characters from charmap file,
+                            // expected '\n' separated list of integer values
+                            char *charValues = LoadFileText(charmapFileName);
+                            if (charValues != NULL)
+                            {
+                                int glyphCount = 0;
+                                const char **chars = TextSplit(charValues, '\n', &glyphCount);
+
+                                int *values = (int *)RAYGUI_MALLOC(glyphCount*sizeof(int));
+                                for (int i = 0; i < glyphCount; i++) values[i] = TextToInteger(chars[i]);
+
+                                if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+                                font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, values, glyphCount);
+                                if (font.texture.id == 0) font = GetFontDefault();
+
+                                RAYGUI_FREE(values);
+                            }
+                        }
+                        else
+                        {
+                            if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+                            font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0);
+                            if (font.texture.id == 0) font = GetFontDefault();
+                        }
+
+                        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) return;
+
+        char signature[5] = { 0 };
+        short version = 0;
+        short reserved = 0;
+        int propertyCount = 0;
+
+        fread(signature, 1, 4, rgsFile);
+        fread(&version, sizeof(short), 1, rgsFile);
+        fread(&reserved, sizeof(short), 1, rgsFile);
+        fread(&propertyCount, sizeof(int), 1, rgsFile);
+
+        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++)
+            {
+                fread(&controlId, sizeof(short), 1, rgsFile);
+                fread(&propertyId, sizeof(short), 1, rgsFile);
+                fread(&propertyValue, sizeof(unsigned int), 1, rgsFile);
+
+                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 i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (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;
+            fread(&fontDataSize, sizeof(int), 1, rgsFile);
+
+            if (fontDataSize > 0)
+            {
+                Font font = { 0 };
+                int fontType = 0;   // 0-Normal, 1-SDF
+                Rectangle whiteRec = { 0 };
+
+                fread(&font.baseSize, sizeof(int), 1, rgsFile);
+                fread(&font.glyphCount, sizeof(int), 1, rgsFile);
+                fread(&fontType, sizeof(int), 1, rgsFile);
+
+                // Load font white rectangle
+                fread(&whiteRec, sizeof(Rectangle), 1, rgsFile);
+
+                // Load font image parameters
+                int fontImageUncompSize = 0;
+                int fontImageCompSize = 0;
+                fread(&fontImageUncompSize, sizeof(int), 1, rgsFile);
+                fread(&fontImageCompSize, sizeof(int), 1, rgsFile);
+
+                Image imFont = { 0 };
+                imFont.mipmaps = 1;
+                fread(&imFont.width, sizeof(int), 1, rgsFile);
+                fread(&imFont.height, sizeof(int), 1, rgsFile);
+                fread(&imFont.format, sizeof(int), 1, rgsFile);
+
+                if (fontImageCompSize < fontImageUncompSize)
+                {
+                    // Compressed font atlas image data (DEFLATE), it requires DecompressData()
+                    int dataUncompSize = 0;
+                    unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize);
+                    fread(compData, 1, fontImageCompSize, rgsFile);
+                    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_MALLOC(fontImageUncompSize);
+                    fread(imFont.data, 1, fontImageUncompSize, rgsFile);
+                }
+
+                if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+                font.texture = LoadTextureFromImage(imFont);
+                if (font.texture.id == 0) font = GetFontDefault();
+
+                RAYGUI_FREE(imFont.data);
+
+                // Load font recs data
+                font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+                for (int i = 0; i < font.glyphCount; i++) fread(&font.recs[i], sizeof(Rectangle), 1, rgsFile);
+
+                // Load font chars info data
+                font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+                for (int i = 0; i < font.glyphCount; i++)
+                {
+                    fread(&font.glyphs[i].value, sizeof(int), 1, rgsFile);
+                    fread(&font.glyphs[i].offsetX, sizeof(int), 1, rgsFile);
+                    fread(&font.glyphs[i].offsetY, sizeof(int), 1, rgsFile);
+                    fread(&font.glyphs[i].advanceX, sizeof(int), 1, rgsFile);
+                }
+
+                GuiSetFont(font);
+
+                // Set font texture source rectangle to be used as white texture to draw shapes
+                // NOTE: This way, all gui can be draw using a single draw call
+                if ((whiteRec.width != 0) && (whiteRec.height != 0)) SetShapesTexture(font.texture, whiteRec);
+            }
+#endif
+        }
+
+        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
+    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);                       // WARNING: Some controls use other values
+    GuiSetStyle(DEFAULT, TEXT_PADDING, 0);                       // WARNING: Some controls use other values
+    GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); // WARNING: Some controls use other values
+
+    // 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(CHECKBOX, TEXT_PADDING, 4);
+    GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
+    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(SPINNER, TEXT_PADDING, 0);
+    GuiSetStyle(SPINNER, 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(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(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(TEXTBOX, TEXT_LINES_SPACING, 4);
+    GuiSetStyle(TEXTBOX, TEXT_INNER_PADDING, 4);
+    GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24);
+    GuiSetStyle(SPINNER, SPIN_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, 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);
+
+        // Setup default raylib font
+        guiFont = GetFontDefault();
+
+        // Setup default raylib font rectangle
+        Rectangle whiteChar = { 41, 46, 2, 8 };
+        SetShapesTexture(guiFont.texture, whiteChar);
+    }
+}
+
+// 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[6] = { 0 };
+
+    if (text != NULL)
+    {
+        memset(buffer, 0, 1024);
+        sprintf(buffer, "#%03i#", iconId);
+
+        for (int i = 5; i < 1024; i++)
+        {
+            buffer[i] = text[i - 5];
+            if (text[i - 5] == '\0') break;
+        }
+
+        return buffer;
+    }
+    else
+    {
+        sprintf(iconBuffer, "#%03i#", iconId & 0x1ff);
+
+        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_MALLOC(iconCount*sizeof(char **));
+                for (int i = 0; i < iconCount; i++)
+                {
+                    guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH);
+                    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), iconCount*(iconSize*iconSize/32), rgiFile);
+        }
+
+        fclose(rgiFile);
+    }
+
+    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)
+                DrawRectangle(posX + (k%RAYGUI_ICON_SIZE)*pixelSize, posY + y*pixelSize, pixelSize, pixelSize, color);
+            #endif
+            }
+
+            if ((k == 15) || (k == 31)) y++;
+        }
+    }
+}
+
+// Set icon drawing size
+void GuiSetIconScale(int scale)
+{
+    if (scale >= 1) guiIconScale = scale;
+}
+
+#endif      // !RAYGUI_NO_ICONS
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Definition
+//----------------------------------------------------------------------------------
+// Gui get text width considering icon
+static int GetTextWidth(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; (text[i] != '\0') && (i < 5); 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 + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+                else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor + GuiGetStyle(DEFAULT, TEXT_SPACING));
+
+                textSize.x += glyphWidth;
+            }
+        }
+
+        if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE - 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);
+    textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING);
+    textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH);
+
+    // Consider TEXT_PADDING properly, depends on control type and TEXT_ALIGNMENT
+    switch (control)
+    {
+        case COMBOBOX: textBounds.width -= (GuiGetStyle(control, COMBO_BUTTON_WIDTH) + GuiGetStyle(control, COMBO_BUTTON_SPACING)); break;
+        //case VALUEBOX: break;   // NOTE: ValueBox text value always centered, text padding applies to label
+        default:
+        {
+            if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING);
+            else textBounds.x += GuiGetStyle(control, TEXT_PADDING);
+            textBounds.width -= 2 * GuiGetStyle(control, TEXT_PADDING);
+        }
+        break;
+    }
+
+    // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW (scrollbar?)
+    // More special cases (label on side): CHECKBOX, SLIDER, VALUEBOX, SPINNER
+
+    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')
+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;
+    int len = 0;
+    *count = 1;
+    int lineSize = 0;   // Stores current line size, not returned
+
+    for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
+    {
+        if (text[i] == '\n')
+        {
+            lineSize = len;
+            k++;
+            lines[k] = &text[i + 1];     // WARNING: next value is valid?
+            len = 0;
+            *count += 1;
+        }
+        else len++;
+    }
+
+    //lines[*count - 1].size = len;
+
+    return lines;
+}
+
+// Gui draw text using default font
+static void GuiDrawText(const char *text, Rectangle bounds, 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
+
+    // We process the text lines one by one
+    if ((text != NULL) && (text[0] != '\0'))
+    {
+        // Get text lines ('\n' delimiter) to process lines individually
+        // NOTE: We can't use GuiTextSplit() because it can be already use before calling
+        // GuiDrawText() and static buffer would be overriden :(
+        int lineCount = 0;
+        const char **lines = GetTextLines(text, &lineCount);
+
+        //Rectangle textBounds = GetTextBounds(LABEL, bounds);
+        float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
+        float posOffsetY = 0;
+
+        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 position = { bounds.x, bounds.y };
+
+            // TODO: We get text size after icon has been processed
+            // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
+            int textSizeX = GetTextWidth(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 ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
+            }
+
+            // Check guiTextAlign global variables
+            switch (alignment)
+            {
+                case TEXT_ALIGN_LEFT:
+                {
+                    position.x = bounds.x;
+                    position.y = bounds.y + posOffsetY + bounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height);
+                } break;
+                case TEXT_ALIGN_CENTER:
+                {
+                    position.x = bounds.x +  bounds.width/2 - textSizeX/2;
+                    position.y = bounds.y + posOffsetY + bounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height);
+                } break;
+                case TEXT_ALIGN_RIGHT:
+                {
+                    position.x = bounds.x + bounds.width - textSizeX;
+                    position.y = bounds.y + posOffsetY + bounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height);
+                } break;
+                default: break;
+            }
+
+            // NOTE: Make sure we get pixel-perfect coordinates,
+            // In case of decimals we got weird text positioning
+            position.x = (float)((int)position.x);
+            position.y = (float)((int)position.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)position.x, (int)(bounds.y + bounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height)), guiIconScale, tint);
+                position.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
+            }
+#endif
+            //DrawTextEx(guiFont, text, position, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), tint);
+
+            // Get size in bytes of text,
+            // considering end of line and line break
+            int size = 0;
+            for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n'); c++, size++){ }
+            float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
+
+            int textOffsetY = 0;
+            float textOffsetX = 0.0f;
+            for (int c = 0, codepointSize = 0; c < size; 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;
+
+                if (codepoint == '\n') break;   // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
+                else
+                {
+                    if ((codepoint != ' ') && (codepoint != '\t'))
+                    {
+                        // TODO: Draw only required text glyphs fitting the bounds.width, '...' can be appended at the end of the text
+                        if (textOffsetX < bounds.width)
+                        {
+                            DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ position.x + textOffsetX, position.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), tint);
+                        }
+                    }
+
+                    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));
+                }
+            }
+
+            posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*1.5f;    // TODO: GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)?
+            //---------------------------------------------------------------------------------
+        }
+    }
+}
+
+// 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, color);
+    }
+
+    if (borderWidth > 0)
+    {
+        // Draw rectangle border lines with color
+        DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, borderColor);
+        DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, borderColor);
+        DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, borderColor);
+        DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, borderColor);
+    }
+}
+
+// Draw tooltip using control bounds
+static void GuiTooltip(Rectangle controlRec)
+{
+    if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL))
+    {
+        Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, GuiGetStyle(DEFAULT, TEXT_SIZE), 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.f }, 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.f }, 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
+
+    // WARNING: HACK: TODO: Review!
+    // 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;
+
+    const int range = maxValue - minValue;
+    int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_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) };
+        sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize;     // Make sure the slider won't get outside of the scrollbar
+        slider = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)scrollbar.y + (int)(((float)(value - minValue)/range)*(scrollbar.height - sliderSize)), (float)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)) };
+        sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize;       // Make sure the slider won't get outside of the scrollbar
+        slider = RAYGUI_CLITERAL(Rectangle){ (float)scrollbar.x + (int)(((float)(value - minValue)/range)*(scrollbar.width - sliderSize)), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)sliderSize, (float)bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) };
+    }
+
+    // Update control
+    //--------------------------------------------------------------------
+    if ((state != STATE_DISABLED) && !guiLocked)
+    {
+        Vector2 mousePoint = GetMousePosition();
+
+        if (CheckCollisionPointRec(mousePoint, bounds))
+        {
+            state = STATE_FOCUSED;
+
+            // Handle mouse wheel
+            int wheel = (int)GetMouseWheelMove();
+            if (wheel != 0) value += wheel;
+
+            if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+            {
+                if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+                else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+
+                state = STATE_PRESSED;
+            }
+            else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+            {
+                if (!isVertical)
+                {
+                    Rectangle scrollArea = { arrowUpLeft.x + arrowUpLeft.width, arrowUpLeft.y, scrollbar.width, bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) };
+                    if (CheckCollisionPointRec(mousePoint, scrollArea)) value = (int)(((float)(mousePoint.x - scrollArea.x - slider.width/2)*range)/(scrollArea.width - slider.width) + minValue);
+                }
+                else
+                {
+                    Rectangle scrollArea = { arrowUpLeft.x, arrowUpLeft.y+arrowUpLeft.height, bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH),  scrollbar.height };
+                    if (CheckCollisionPointRec(mousePoint, scrollArea)) value = (int)(((float)(mousePoint.y - scrollArea.y - slider.height/2)*range)/(scrollArea.height - slider.height) + minValue);
+                }
+            }
+        }
+
+        // Normalize value
+        if (value > maxValue) value = maxValue;
+        if (value < minValue) value = minValue;
+    }
+    //--------------------------------------------------------------------
+
+    // Draw control
+    //--------------------------------------------------------------------
+    GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED)), guiAlpha));   // Draw the background
+
+    GuiDrawRectangle(scrollbar, 0, BLANK, Fade(GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL)), guiAlpha));     // Draw the scrollbar active area background
+    GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BORDER + state*3)), guiAlpha));         // 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, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
+        GuiDrawText(isVertical? "v" : ">",
+            RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+            TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
+#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, Fade(GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3)), guiAlpha));   // 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, Fade(GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3)), guiAlpha));   // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL
+#endif
+    }
+    //--------------------------------------------------------------------
+
+    return value;
+}
+
+#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;
+}
+
+// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
+static Color Fade(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)(255.0f*alpha) };
+
+    return result;
+}
+
+// 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);
+    vsprintf(buffer, 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;
+}
+
+// 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
+// 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 = 0;
+
+    // Get current codepoint and bytes processed
+    if (0xf0 == (0xf8 & ptr[0]))
+    {
+        // 4 byte UTF-8 codepoint
+        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 */
+        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
+        codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
+        *codepointSize = 2;
+    }
+    else
+    {
+        // 1 byte UTF-8 codepoint
+        codepoint = ptr[0];
+        *codepointSize = 1;
+    }
+
+    return codepoint;
+}
+#endif      // RAYGUI_STANDALONE
+
+#endif      // RAYGUI_IMPLEMENTATION
diff --git a/src/synth.c b/src/synth.c
new file mode 100644
index 0000000..5a08e4f
--- /dev/null
+++ b/src/synth.c
@@ -0,0 +1,114 @@
+/*
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ */
+
+/* audio */
+#include <string.h>
+#include <portaudio.h>
+
+/* graphics */
+
+/* synth */
+#include "synth_engine.h"
+#include "synth_gui.h"
+
+#define NUM_SECONDS   (1)
+
+#define WAVE_SIZE   (44100)
+
+static void
+StreamFinished( void* synthData )
+{
+  synth_t *synth = (synth_t *) synthData;
+  printf( "Stream Completed\n");
+}
+
+int
+main(void) {
+  PaStreamParameters outputParameters;
+  PaStream *stream;
+  PaError err;
+  int i;
+  synth_t synth;
+  init_synth(&synth);
+
+
+  err = Pa_Initialize();
+  if( err != paNoError ) goto error;
+
+  const   PaDeviceInfo *deviceInfo;
+  for( i=0; i< Pa_GetDeviceCount(); i++ ) {
+    deviceInfo = Pa_GetDeviceInfo( i );
+    //if (!strcmp("HyperX Cloud II Wireless: USB Audio (hw:0,0)", deviceInfo->name)) break;
+    if (!strcmp("HDA Intel PCH: ALC1220 Analog (hw:1,0)", deviceInfo->name)) break;
+    printf("dev: %s || %f\n", deviceInfo->name, deviceInfo->defaultSampleRate);
+  }
+
+
+  outputParameters.device = i; Pa_GetDefaultOutputDevice(); /* default output device */
+  printf("-------\nSelected device: %s\n-------\n", Pa_GetDeviceInfo(outputParameters.device)->name);
+  if (outputParameters.device == paNoDevice) {
+    fprintf(stderr,"Error: No default output device.\n");
+    goto error;
+  }
+  outputParameters.channelCount = 2;       /* stereo output */
+  outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+  outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+  outputParameters.hostApiSpecificStreamInfo = NULL;
+
+  err = Pa_OpenStream(&stream,
+                      NULL, /* no input */
+                      &outputParameters,
+                      SAMPLE_RATE,
+                      FRAMES_PER_BUFFER,
+                      paClipOff,      /* we won't output out of range samples so don't bother clipping them */
+                      sound_gen,
+                      &synth );
+  if( err != paNoError ) goto error;
+
+  err = Pa_SetStreamFinishedCallback( stream, &StreamFinished );
+  if( err != paNoError ) goto error;
+
+  err = Pa_StartStream( stream );
+  if( err != paNoError ) goto error;
+
+  rayrun(&synth, stream);
+
+  err = Pa_StopStream( stream );
+  if( err != paNoError ) goto error;
+
+  err = Pa_CloseStream( stream );
+  if( err != paNoError ) goto error;
+
+  Pa_Terminate();
+  printf("Test finished.\n");
+
+  return err;
+ error:
+  Pa_Terminate();
+  fprintf( stderr, "An error occurred while using the portaudio stream\n" );
+  fprintf( stderr, "Error number: %d\n", err );
+  fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+  return err;
+}
diff --git a/src/synth_engine.c b/src/synth_engine.c
new file mode 100644
index 0000000..57ec29b
--- /dev/null
+++ b/src/synth_engine.c
@@ -0,0 +1,332 @@
+#include "synth_engine.h"
+#include "lowpass.h"
+#include "filter.h"
+
+float
+adsr_amplitude(void *synthData, unsigned long long elapsed)
+{
+  synth_t *synth = (synth_t*)synthData;
+
+  float dAmplitude = 0.0;
+  float dReleaseAmplitude = 0.0;
+  float dStartAmplitude = 1.0;
+
+  float dLifeTime = (elapsed * (1.0 / (float)SAMPLE_RATE));
+
+  if (synth->n.noteOn != 0 && synth->n.noteOff == 0) {
+    if (dLifeTime <= synth->adsr.a)
+      dAmplitude = (dLifeTime / synth->adsr.a)*(dLifeTime / synth->adsr.a) * dStartAmplitude;
+
+    if (dLifeTime >  synth->adsr.a && dLifeTime <= ( synth->adsr.a +  synth->adsr.d))
+      dAmplitude = ((dLifeTime - synth->adsr.a) / synth->adsr.d) * (synth->adsr.s - dStartAmplitude) + dStartAmplitude;
+
+    if (dLifeTime > (synth->adsr.a + synth->adsr.d))
+      dAmplitude = synth->adsr.s;
+  }
+  else { // Note is off
+    if (dLifeTime <= synth->adsr.a)
+      dReleaseAmplitude = (dLifeTime / synth->adsr.a)*(dLifeTime / synth->adsr.a) * dStartAmplitude;
+
+    if (dLifeTime > synth->adsr.a && dLifeTime <= (synth->adsr.a + synth->adsr.d))
+      dReleaseAmplitude = ((dLifeTime - synth->adsr.a) / synth->adsr.d) * (synth->adsr.s - dStartAmplitude) + dStartAmplitude;
+
+    if (dLifeTime > (synth->adsr.a + synth->adsr.d))
+      dReleaseAmplitude = synth->adsr.s;
+
+    dAmplitude = (((synth->n.noteOn + dLifeTime) - synth->n.noteOff) / synth->adsr.r) * (0.0 - dReleaseAmplitude) + dReleaseAmplitude;
+
+    if (synth->adsr.r < 0) {
+      dAmplitude = synth->adsr.s;
+    }
+}
+  // Amplitude should not be negative
+  if (dAmplitude <= 0.000)
+    dAmplitude = 0.0;
+
+  return dAmplitude;
+}
+
+
+float
+sin_sample(float amp, float freq, unsigned long long phase, unsigned int sample_rate)
+{
+  return amp * sinf(2.0 * M_PI * freq * ((float)phase / (float)sample_rate));
+}
+
+float
+saw_sample(float amp, float freq, unsigned long long phase, unsigned int sample_rate)
+{
+  return amp * (0.17 * (1.0 - (2.0 * M_PI * freq * fmod((float)phase, (float)(sample_rate / (freq)))) / (float)sample_rate));
+}
+
+float
+sawX_sample(float amp, float freq, float sm, unsigned long long phase, unsigned int sample_rate)
+{
+  float dOutput = 0.0;
+  for (float n = 1.0; n < sm; n++)
+    dOutput += (sinf(n * 2.0 * M_PI * freq * ((float)phase / (float)sample_rate))) / n;
+  return 0.5 * amp * dOutput;
+}
+
+float
+sqr_sample(float amp, float freq, float duty_cycle, unsigned long long phase, unsigned int sample_rate)
+{
+  if (duty_cycle < 0.0001 || duty_cycle > 0.9999) {
+    duty_cycle = 0.5;
+  }
+
+  return (fmod((float)phase / (float)sample_rate, 1.0 / freq) < duty_cycle * (1.0 / freq)) ? amp : -amp;
+}
+
+float
+gen0(float f, unsigned long long phase, float x, unsigned int sample_rate)
+{
+  return sqr_sample(0.1, f,  0.3,             phase, sample_rate)
+    + sqr_sample(0.1, f * 3.0 / 2.0 , 0.5, phase, sample_rate)
+    + saw_sample(0.3, f,                   phase, sample_rate)
+    + sin_sample(0.1, f,                   phase, sample_rate)
+    + sin_sample(0.1, f * 5,               phase, sample_rate)
+    /* + sin_sample(0.1, freq * 50 * 1021,       phase, sample_rate) */
+    /* + sin_sample(0.1, freq * 50 * 3531021,    phase, sample_rate) */
+    + sin_sample(0.1, f * 7,               phase, sample_rate);
+}
+
+float
+gen1(float f, unsigned long long phase, float x, unsigned int sample_rate)
+{
+  return sawX_sample(0.5, f, 5, phase, sample_rate)
+    + saw_sample(0.3, 2 * f / 5, phase, sample_rate)
+    + sin_sample(0.2, f * 5.0 / 7.0 , phase, sample_rate);
+}
+
+float
+gen2(float f, unsigned long long phase, float x, unsigned int sample_rate)
+{
+  return sin_sample(0.5, f * sqrt(2) , phase, sample_rate)
+    + sin_sample(0.5, f, phase, sample_rate);
+
+  /* sawX_sample(1, synth->freq, 5, phase, sample_rate); */
+}
+
+float
+gen3(float f, unsigned long long phase, float x, unsigned int sample_rate)
+{
+  return sawX_sample(0.7, f, 5, phase, sample_rate)
+    + sin_sample(0.3, 4.0/17.0*f, phase, sample_rate);
+  /* return sawX_sample(0.5, f * (1 + sqrt(5)) / 2, 5, phase, sample_rate) */
+  /*   + sin_sample(0.3, f * x, phase, sample_rate) */
+  /*   + sqr_sample(0.2, f * x, 0.2 * x * x, phase, sample_rate); */
+}
+
+
+
+/* 1d convolution */
+void
+convole(float *signal, float *filter, size_t signal_size, size_t filter_size, float *out) {
+  for (size_t i = 0; i < filter_size + signal_size; i++) {
+    size_t kmin, kmax, k;
+    out[i] = 0;
+    /* find overlap */
+    kmin = (i >= filter_size - 1) ? i - (filter_size - 1) : 0;
+    kmax = (i < signal_size - 1) ? i : signal_size - 1;
+
+    /* Add the overlaping values */
+    for (k = kmin; k <= kmax; k++) {
+      out[i] += signal[k] * filter[i - k];
+    }
+  }
+}
+
+void
+low_pass_filter(float* signal, int length, float cutoff, float resonance, float* out) {
+    float c = 1.0f / tanf(M_PI * cutoff); // calculate filter constant
+    float a1 = 1.0f / (1.0f + resonance * c + c * c); // calculate filter coefficients
+    float a2 = 2.0f * a1;
+    float a3 = a1;
+    float b1 = 2.0f * (1.0f - c * c) * a1;
+    float b2 = (1.0f - resonance * c + c * c) * a1;
+    float prev_input = 0.0f, prev_output = 0.0f; // initialize previous input and output to zero
+    for (int i = 0; i < length; i++) {
+        float input = signal[i];
+        float output = a1 * input + a2 * prev_input + a3 * prev_output - (i >= 1 ? b1 * out[i-1] : 0.0f) - (i >= 2 ? b2 * out[i-2] : 0.0f);
+        out[i] = output;
+        prev_input = input;
+        prev_output = output;
+    }
+}
+
+
+float
+make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, int viz)
+{
+  synth_t *synth = (synth_t*)synthData;
+  float sample = 0;
+
+
+  int n = 1;
+  if (1 /* !synth->filter */) {
+    for (int i = 0; i < n; i++) {
+      sample += (1.0 / n) * synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase, synth->x, sample_rate);
+    }
+
+    if (!viz && synth->filter) {
+      // ALLL THE FILTERS
+      LowPass_Update(synth->resonance, (adsr_amplitude(synth, synth->adsr.elapsed) + 0.1) * synth->cutoff + 1, sample_rate);
+      sample = LowPass_Filter(sample);
+
+      update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, (adsr_amplitude(synth, synth->adsr.elapsed) + 0.1) * synth->cutoff, synth->resonance);
+      sample = bw_low_pass(synth->fff, sample);
+    }
+
+    sample = synth->gain * adsr_amplitude(synth, synth->adsr.elapsed) *
+      sample; //synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase, synth->x);
+    
+    if (synth->clamp && sample >= 1) sample = 0.99;
+    if (synth->clamp && sample <= -1) sample = -0.99;
+  } else {
+    // get sample array s[]
+    int samples = 30;
+    float s[samples];
+    
+    if (synth->adsr.elapsed < samples) {
+      for (int i = 0; i < samples; i++) {
+        s[i] = synth->gain * adsr_amplitude(synth, i) * synth->gen[synth->geni](synth->n.freq + synth->freq_offset, i, synth->x, sample_rate);
+      }
+    } else {
+      for (int i = 0; i < samples; i++) {
+        s[i] = synth->gain * adsr_amplitude(synth, synth->adsr.elapsed - 50 + i) * synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase - 50 + i, synth->x, sample_rate);
+      }
+    }
+
+    // process s[]
+
+
+    // return s[50]
+  }
+  
+  return sample;
+}
+
+int
+sound_gen(const void *inputBuffer, void *outputBuffer,
+          unsigned long framesPerBuffer,
+          const PaStreamCallbackTimeInfo* timeInfo,
+          PaStreamCallbackFlags statusFlags,
+          void *synthData)
+{
+  synth_t *synth = (synth_t*)synthData;
+  float *out = (float*)outputBuffer;
+
+  (void) timeInfo; /* Prevent unused variable warnings. */
+  (void) statusFlags;
+  (void) inputBuffer;
+
+  if (1) {
+    float s;
+    for( unsigned long i=0; i<framesPerBuffer; i++ ) {
+      //get_portaudio_frame(outputBuffer, synth);
+      s = make_sample(synth->n.elapsed, synth, SAMPLE_RATE, 0);
+      *out++ = s;
+      *out++ = s;
+      synth->adsr.elapsed++;
+      synth->n.elapsed++;
+      if (!synth->multi) {
+        if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0;
+      } else {
+      
+      }
+    }
+  } else {
+    float s[FRAMES_PER_BUFFER * 5];
+
+    if (synth->adsr.elapsed < framesPerBuffer * 5) {
+      for (unsigned long long i = 0; i < framesPerBuffer * 5; i++) {
+        s[i] = make_sample(i, synth, SAMPLE_RATE, 0);
+        synth->adsr.elapsed++;
+        synth->n.elapsed++;
+        if (!synth->multi) {
+          if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0;
+        } else {
+        }
+      }
+    } else {
+      for (unsigned long long i = 0; i < framesPerBuffer * 5; i++) {
+        s[i] = make_sample(synth->n.elapsed - framesPerBuffer * 2 + i, synth, SAMPLE_RATE, 0);
+        synth->adsr.elapsed++;
+        synth->n.elapsed++;
+        if (!synth->multi) {
+          if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0;
+        } else {
+        }
+      }
+    }
+
+    // filter
+
+    // output
+
+    if (synth->adsr.elapsed < framesPerBuffer * 5) {
+      for( unsigned long i=0; i<framesPerBuffer; i++ ) {
+        *out++ = s[i];
+        *out++ = s[i];
+      }
+    } else {
+      for( unsigned long i=0; i<framesPerBuffer; i++ ) {
+        *out++ = s[i + (2 * framesPerBuffer)];
+        *out++ = s[i + (2 * framesPerBuffer)];
+      }
+    }
+    synth->adsr.elapsed-= 4*framesPerBuffer;
+
+    if (!synth->multi) {
+      for (int i = 0; i < framesPerBuffer * 4; i++) {
+        synth->n.elapsed--;
+        if (synth->n.elapsed == 0) synth->n.elapsed = (int)(SAMPLE_RATE / synth->n.freq);
+      }
+    } else {
+      synth->n.elapsed-= 4*framesPerBuffer;
+    }
+  }
+
+  return paContinue;
+}
+
+void
+init_synth(synth_t * synth)
+{
+  synth->freq_offset = 0;
+  synth->gain = 1;
+  synth->x = 1;
+
+  synth->n.freq    = 0; 
+  synth->n.noteOn  = 0; 
+  synth->n.noteOff = 1; 
+  synth->n.key     = 0; 
+  synth->n.elapsed = 0; 
+
+
+  synth->adsr.a = 0.001;
+  synth->adsr.d = 0.3;
+  synth->adsr.s = 0.7;
+  synth->adsr.r = 0.4;
+  synth->adsr.elapsed = 0;
+
+  synth->octave = 3;
+
+  synth->multi = 0;
+  synth->filter = 0;
+  synth->cutoff = 22000.0f;
+  synth->resonance = 1.0f;
+  synth->clamp = 0;
+
+  synth->gen[0] = gen0;
+  synth->gen[1] = gen1;
+  synth->gen[2] = gen2;
+  synth->gen[3] = gen3;
+  synth->geni = 0;
+
+  synth->viz.sample_rate_divider = 1;
+
+  LowPass_Init();
+  synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400);
+}
diff --git a/src/synth_engine.h b/src/synth_engine.h
new file mode 100644
index 0000000..e35e8fb
--- /dev/null
+++ b/src/synth_engine.h
@@ -0,0 +1,77 @@
+#ifndef SYNTH_ENGINE_H
+#define SYNTH_ENGINE_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <portaudio.h>
+
+#include "notes.h"
+#include "filter.h"
+
+#define SAMPLE_RATE   (44100)
+//#define SAMPLE_RATE   (48000)
+#define FRAMES_PER_BUFFER  (210)
+
+#define WIDTH 1024
+#define HEIGHT 600
+
+#ifndef M_PI
+#define M_PI  (3.14159265)
+#endif
+
+
+typedef struct {
+  float a;
+  float d;
+  float s;
+  float r;
+  unsigned long long elapsed;
+} adsr_t;
+
+typedef struct {
+  float freq;
+  PaTime noteOn;
+  PaTime noteOff;
+  int key;
+  unsigned long long elapsed;
+} note_t;
+
+typedef struct {
+  int sample_rate_divider;
+} viz_t;
+
+typedef struct {
+  float freq_offset;
+  float gain;
+  float x;
+
+  note_t n;
+  adsr_t adsr;
+
+  int octave;
+
+  int multi;
+  int filter;
+  float cutoff;
+  float resonance;
+  int clamp;
+
+  float (*gen[4]) (float freq, unsigned long long phase, float x, unsigned int sample_rate);
+  int geni;
+
+  BWLowPass* fff;
+
+  viz_t viz;
+} synth_t;
+
+float adsr_amplitude(void *synthData, unsigned long long elapsed);
+float make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, int viz);
+void init_synth(synth_t * synth);
+int sound_gen(const void *inputBuffer, void *outputBuffer,
+              unsigned long framesPerBuffer,
+              const PaStreamCallbackTimeInfo* timeInfo,
+              PaStreamCallbackFlags statusFlags,
+              void *synthData);
+
+#endif /* SYNTH_ENGINE_H */
diff --git a/src/synth_gui.c b/src/synth_gui.c
new file mode 100644
index 0000000..3cfde6f
--- /dev/null
+++ b/src/synth_gui.c
@@ -0,0 +1,173 @@
+#include "synth_gui.h"
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+//#include "raylib.h"
+
+
+void
+set_note(void *synthData, float note, PaTime time, int key)
+{
+  synth_t * synth = (synth_t *)synthData;
+
+  synth->n.key = key;
+  synth->n.freq = note;
+  synth->n.noteOn = time;
+  synth->n.noteOff = 0;
+  synth->n.elapsed = 0;
+  synth->adsr.elapsed = 0;
+}
+
+
+void
+keyboard(void *synthData, PaStream *stream)
+{
+  synth_t * synth = (synth_t *)synthData;
+
+  int keys[] = {KEY_Q, KEY_TWO, KEY_W, KEY_THREE, KEY_E, KEY_R, KEY_FIVE, KEY_T, KEY_SIX, KEY_Y, KEY_SEVEN, KEY_U, KEY_I, KEY_NINE, KEY_O, KEY_ZERO, KEY_P, KEY_LEFT_BRACKET, KEY_EQUAL, KEY_RIGHT_BRACKET, 0};
+
+  float note;
+
+  for (int i = 0; keys[i]; i++) {
+    if (IsKeyPressed(keys[i])) {
+      note = notes[i % 12][(synth->octave + (i / 12)) % 8];
+      if (note) {
+        set_note(synth, note, Pa_GetStreamTime(stream), keys[i]);
+        printf("Note On : %s[%d]\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8);
+      }
+    }
+  }
+  for (int i = 0; keys[i]; i++) {
+    if (IsKeyReleased(keys[i])) {
+      if (synth->n.key == keys[i]) {
+        synth->n.noteOff = Pa_GetStreamTime(stream);
+        printf("Note Off: %s[%d]\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8);
+      }
+    }
+  }
+}
+
+void
+draw_adsr_sliders(synth_t * synth, int x, int y, int width, int height, int offset)
+{
+  char buf[64];
+  int count = 0;
+  
+  snprintf(buf, sizeof buf, "%.3f", synth->adsr.a);
+  synth->adsr.a = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "A: ", buf, synth->adsr.a , 0.001f, 2.0f);
+  snprintf(buf, sizeof buf, "%.3f", synth->adsr.d);
+  synth->adsr.d = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "D: ", buf, synth->adsr.d , 0.001f, 2.0f);
+  snprintf(buf, sizeof buf, "%.3f", synth->adsr.s);
+  synth->adsr.s = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "S: ", buf, synth->adsr.s , 0.0f, 1.0f);
+  snprintf(buf, sizeof buf, "%.3f", synth->adsr.r);
+  synth->adsr.r = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "R: ", buf, synth->adsr.r , -0.001f, 3.0f);
+  snprintf(buf, sizeof buf, "%.3f", synth->cutoff);
+  synth->cutoff = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fC: ", buf, synth->cutoff , 0.0f, 11000.0f);
+  snprintf(buf, sizeof buf, "%.3f", synth->resonance);
+  synth->resonance = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fR: ", buf, synth->resonance , 0.001f, 5.0f);
+}
+
+void
+draw_signals(synth_t * synth, int x, int y, int width, int height)
+{
+  DrawRectangleLines(x, y, width, height, BLACK);
+
+  int point_radius = 1.5;
+
+  GuiSpinner((Rectangle){ x+ 100, y - 24 - 6, 100, 24 }, "rate divider: ", &(synth->viz.sample_rate_divider), 1, 10, 0);
+  int period = (1 / (synth->n.freq + 1)) * SAMPLE_RATE / synth->viz.sample_rate_divider;
+
+  if (synth->multi) {
+    for (int i = x; i < WIDTH - x; i++) {
+      DrawCircle(i , y + height / 2 + floor(50 *  make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
+    }
+  } else {
+    for (int i = x; i < WIDTH - x; i++) {
+      //DrawCircle((WIDTH - (1 / (synth->n.freq + 1)) * SAMPLE_RATE) / 2 + i , (HEIGHT / 2) + floor(50 *  make_sample(i % period, synth, SAMPLE_RATE)), point_radius, RED);
+      DrawCircle(i , y + height / 2 + floor(50 *  make_sample((i - x) % period, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
+    }
+  }
+
+  for (int i = x; i < WIDTH - x; i++) {
+    DrawCircle(i , y + height - 1+ floor((WIDTH / 24) * - adsr_amplitude(synth, synth->adsr.elapsed)), point_radius, GREEN);
+  }
+  float adsr_duration = synth->adsr.a + synth->adsr.d + (synth->adsr.a + synth->adsr.d + synth->adsr.r) / 3.0 + synth->adsr.r;
+  for (int i = x; i < WIDTH - x; i++) {
+    DrawCircle(i , y + height - 1 + floor((WIDTH / 24) * - adsr_amplitude(synth, (i - x) * (adsr_duration * SAMPLE_RATE) / WIDTH)), point_radius, BLUE);
+  }
+}
+
+void
+rayrun(void *synthData, PaStream *stream)
+{
+  synth_t * synth = (synth_t *)synthData;
+  PaTime current_time = 0;
+  PaTime prev_time = 0;
+
+  InitWindow(WIDTH, HEIGHT, "Raylib synth");
+  SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+  while (!WindowShouldClose()) {
+
+    keyboard(synth, stream);
+    int prec = 100000;
+
+    if (IsKeyPressed(KEY_ENTER)) {
+      synth->multi = !synth->multi;
+    }
+
+    // Draw
+    //----------------------------------------------------------------------------------
+    BeginDrawing();
+    ClearBackground(RAYWHITE);
+
+    // GUI
+    char buf[64];
+
+    draw_adsr_sliders(synth, 30, 20, 256, 20, 4);
+
+
+    if ( GuiButton((Rectangle){ WIDTH / 2 - 108, 150 - 42 - 6 - 6, 216, 6 }, "")) {
+      synth->freq_offset = 0;
+    }
+    snprintf(buf, sizeof buf, "%.1f", synth->freq_offset);
+    synth->freq_offset = GuiSliderBar((Rectangle){ WIDTH / 2 - 108, 150 - 42, 216, 24 }, "fine", buf, synth->freq_offset , -20.0f, 20.0f);
+
+    if ( GuiButton((Rectangle){ WIDTH / 2 - 108, 150 - 6 - 6, 216, 6 }, "")) {
+      synth->gain = 1;
+    }
+    snprintf(buf, sizeof buf, "%.1f", synth->gain);
+    synth->gain = GuiSliderBar((Rectangle){ WIDTH / 2 - 108, 150, 216, 24 }, "gain", buf, synth->gain , 0.0f, 2.0f);
+
+    if ( GuiButton((Rectangle){ WIDTH / 2 - 108, 150 - 6 - 6 + 42, 216, 6 }, "")) {
+      synth->x = 1;
+    }
+    snprintf(buf, sizeof buf, "%.1f", synth->x);
+    synth->x = GuiSliderBar((Rectangle){ WIDTH / 2 - 108, 150 + 42, 216, 24 }, "x", buf, synth->x , 0.0f, 2.0f);
+
+    synth->multi = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 , 50, 100, 24 }, "!MULTI!", synth->multi);
+    synth->filter = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 , 50 + 24 + 6, 100, 24 }, "FILTER", synth->filter);
+
+    GuiSpinner((Rectangle){ WIDTH - 100 - 50 , 50, 100, 24 }, "oct: ", &(synth->octave), 0, 7, 0);
+    snprintf(buf, sizeof buf, "generator %d  --> ", synth->geni);
+    GuiSpinner((Rectangle){ WIDTH - 100 - 50 , 50 + 24 + 6, 100, 24 }, buf, &(synth->geni), 0, 3, 0);
+
+    synth->clamp = GuiToggle((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6, 100, 24 }, "clamp", synth->clamp);
+
+
+    // signals
+    draw_signals(synth, 20, 390, WIDTH - 2*20, 200);
+
+    DrawText("THE SYNTH!!!!!!!!!!!!!!!!!!1", WIDTH / 2 - 100, 50, 20, LIGHTGRAY);
+    DrawText("KEYBOARD: Q .. ]    TOGGLE MULTI: ENTER", WIDTH / 2 -300, HEIGHT - 20 - 50, 20, LIGHTGRAY);
+    snprintf(buf, sizeof buf, "time?: %lld adsr: %lld note: %lld", synth->adsr.elapsed / SAMPLE_RATE, synth->adsr.elapsed, synth->n.elapsed);
+    DrawText(buf, WIDTH / 2 -300, HEIGHT - 40 - 50, 20, LIGHTGRAY);
+
+    EndDrawing();
+    //----------------------------------------------------------------------------------
+
+    current_time = Pa_GetStreamTime(stream);
+    //printf("%f :: %ld\n", current_time - prev_time, phase);
+
+    prev_time = current_time;
+  }
+  CloseWindow();
+}
diff --git a/src/synth_gui.h b/src/synth_gui.h
new file mode 100644
index 0000000..73bdbdf
--- /dev/null
+++ b/src/synth_gui.h
@@ -0,0 +1,10 @@
+#ifndef SYNTH_GUI_H
+#define SYNTH_GUI_H
+
+#include <portaudio.h>
+
+#include "synth_engine.h"
+
+void rayrun(void *synthData, PaStream *stream);
+
+#endif /* SYNTH_GUI_H */
diff --git a/src/synth_math.h b/src/synth_math.h
new file mode 100644
index 0000000..de6fb26
--- /dev/null
+++ b/src/synth_math.h
@@ -0,0 +1,22 @@
+#ifndef SYNTH_MATH_H
+#define SYNTH_MATH_H
+
+extern long long
+gcd(long long int a, long long int b)
+{
+   long long rem;
+   rem=a-(a/b*b);
+   if(rem==0)
+      return b;
+   else
+      gcd(b,rem);
+}
+ 
+// Function to return LCM of two numbers
+extern long long
+lcm(long long a, long long b)
+{
+    return (a / gcd(a, b)) * b;
+}
+  
+#endif /* SYNTH_MATH_H */
-- 
cgit v1.2.3