shithub: mp3dec

Download patch

ref: 84bd920604b9b2c0fad2e8ed18c51ba0e944cced
parent: 863d526efec9afd8091a5b37d8b64e2cb0c2e773
parent: d80b7edcd358f2159238f84b5efcc064b9a650c4
author: Lion <lieff@users.noreply.github.com>
date: Sun Sep 2 20:23:57 EDT 2018

Merge pull request #36 from FWGS/master


--- a/.travis.yml
+++ b/.travis.yml
@@ -25,6 +25,7 @@
 
 script:
     - scripts/build.sh
+    - (pushd player/; ./build.sh linux; popd)
 
 after_success:
     - bash <(curl -s https://codecov.io/bash)
--- a/minimp3.h
+++ b/minimp3.h
@@ -24,22 +24,24 @@
 
 #ifdef __cplusplus
 extern "C" {
-#endif
+#endif /* __cplusplus */
 
 void mp3dec_init(mp3dec_t *dec);
 #ifndef MINIMP3_FLOAT_OUTPUT
 typedef int16_t mp3d_sample_t;
-#else
+#else /* MINIMP3_FLOAT_OUTPUT */
 typedef float mp3d_sample_t;
 void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples);
-#endif
+#endif /* MINIMP3_FLOAT_OUTPUT */
 int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info);
 
 #ifdef __cplusplus
 }
-#endif
+#endif /* __cplusplus */
 
-#ifdef MINIMP3_IMPLEMENTATION
+#endif /* MINIMP3_H */
+#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD)
+#define _MINIMP3_IMPLEMENTATION_GUARD
 
 #include <stdlib.h>
 #include <string.h>
@@ -85,12 +87,12 @@
 #if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(_M_ARM64) || defined(__x86_64__) || defined(__aarch64__))
 /* x64 always have SSE2, arm64 always have neon, no need for generic code */
 #define MINIMP3_ONLY_SIMD
-#endif
+#endif /* SIMD checks... */
 
 #if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__))
 #if defined(_MSC_VER)
 #include <intrin.h>
-#endif
+#endif /* defined(_MSC_VER) */
 #include <immintrin.h>
 #define HAVE_SSE 1
 #define HAVE_SIMD 1
@@ -107,7 +109,7 @@
 typedef __m128 f4;
 #if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD)
 #define minimp3_cpuid __cpuid
-#else
+#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */
 static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType)
 {
 #if defined(__PIC__)
@@ -117,26 +119,26 @@
         "cpuid\n"
         "xchgl %%ebx, %1\n"
         "pop  %%rbx\n"
-#else
+#else /* defined(__x86_64__) */
         "xchgl %%ebx, %1\n"
         "cpuid\n"
         "xchgl %%ebx, %1\n"
-#endif
+#endif /* defined(__x86_64__) */
         : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
         : "a" (InfoType));
-#else
+#else /* defined(__PIC__) */
     __asm__ __volatile__(
         "cpuid"
         : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
         : "a" (InfoType));
-#endif
+#endif /* defined(__PIC__)*/
 }
-#endif
+#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */
 static int have_simd()
 {
 #ifdef MINIMP3_ONLY_SIMD
     return 1;
-#else
+#else /* MINIMP3_ONLY_SIMD */
     static int g_have_simd;
     int CPUInfo[4];
 #ifdef MINIMP3_TEST
@@ -143,7 +145,7 @@
     static int g_counter;
     if (g_counter++ > 100)
         return 0;
-#endif
+#endif /* MINIMP3_TEST */
     if (g_have_simd)
         goto end;
     minimp3_cpuid(CPUInfo, 0);
@@ -155,7 +157,7 @@
     }
 end:
     return g_have_simd - 1;
-#endif
+#endif /* MINIMP3_ONLY_SIMD */
 }
 #elif defined(__ARM_NEON) || defined(__aarch64__)
 #include <arm_neon.h>
@@ -175,19 +177,16 @@
 {   /* TODO: detect neon for !MINIMP3_ONLY_SIMD */
     return 1;
 }
-#else
+#else /* SIMD checks... */
 #define HAVE_SIMD 0
 #ifdef MINIMP3_ONLY_SIMD
 #error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled
-#endif
-#endif
-
-#else
-
+#endif /* MINIMP3_ONLY_SIMD */
+#endif /* SIMD checks... */
+#else /* !defined(MINIMP3_NO_SIMD) */
 #define HAVE_SIMD 0
+#endif /* !defined(MINIMP3_NO_SIMD) */
 
-#endif
-
 typedef struct
 {
     const uint8_t *buf;
@@ -464,7 +463,7 @@
         }
     }
 }
-#endif
+#endif /* MINIMP3_ONLY_MP3 */
 
 static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr)
 {
@@ -842,7 +841,7 @@
         VSTORE(left + i, VADD(vl, vr));
         VSTORE(right + i, VSUB(vl, vr));
     }
-#endif
+#endif /* HAVE_SIMD */
     for (; i < n; i++)
     {
         float a = left[i];
@@ -975,7 +974,7 @@
             vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0));
             VSTORE(grbuf + 14 - i, VREV(vd));
         }
-#endif
+#endif /* HAVE_SIMD */
 #ifndef MINIMP3_ONLY_SIMD
         for(; i < 8; i++)
         {
@@ -984,7 +983,7 @@
             grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i];
             grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i];
         }
-#endif
+#endif /* MINIMP3_ONLY_SIMD */
     }
 }
 
@@ -1073,7 +1072,7 @@
             vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0));
             VSTORE(grbuf + 14 - i, VREV(vsum));
         }
-#endif
+#endif /* HAVE_SIMD */
         for (; i < 9; i++)
         {
             float ovl  = overlap[i];
@@ -1273,9 +1272,9 @@
         {
 #if HAVE_SSE
 #define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
-#else
+#else /* HAVE_SSE */
 #define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18],  vget_low_f32(v))
-#endif
+#endif /* HAVE_SSE */
             for (i = 0; i < 7; i++, y += 4*18)
             {
                 f4 s = VADD(t[3][i], t[3][i + 1]);
@@ -1305,10 +1304,10 @@
             VSAVE4(3, t[3][7]);
         }
     } else
-#endif
+#endif /* HAVE_SIMD */
 #ifdef MINIMP3_ONLY_SIMD
     {}
-#else
+#else /* MINIMP3_ONLY_SIMD */
     for (; k < n; k++)
     {
         float t[4][8], *x, *y = grbuf + k;
@@ -1367,7 +1366,7 @@
         y[2*18] = t[1][7];
         y[3*18] = t[3][7];
     }
-#endif
+#endif /* MINIMP3_ONLY_SIMD */
 }
 
 #ifndef MINIMP3_FLOAT_OUTPUT
@@ -1379,12 +1378,12 @@
     s -= (s < 0);   /* away from zero, to be compliant */
     return s;
 }
-#else
+#else /* MINIMP3_FLOAT_OUTPUT */
 static float mp3d_scale_pcm(float sample)
 {
     return sample*(1.f/32768.f);
 }
-#endif
+#endif /* MINIMP3_FLOAT_OUTPUT */
 
 static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z)
 {
@@ -1486,7 +1485,7 @@
             dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7);
             dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2);
             dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6);
-#else
+#else /* HAVE_SSE */
             int16x4_t pcma, pcmb;
             a = VADD(a, VSET(0.5f));
             b = VADD(b, VSET(0.5f));
@@ -1500,9 +1499,9 @@
             vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3);
             vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2);
             vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
-#endif
+#endif /* HAVE_SSE */
 
-#else
+#else /* MINIMP3_FLOAT_OUTPUT */
 
             static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
             a = VMUL(a, g_scale);
@@ -1516,7 +1515,7 @@
             _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3)));
             _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
             _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2)));
-#else
+#else /* HAVE_SSE */
             vst1q_lane_f32(dstr + (15 - i)*nch, a, 1);
             vst1q_lane_f32(dstr + (17 + i)*nch, b, 1);
             vst1q_lane_f32(dstl + (15 - i)*nch, a, 0);
@@ -1525,14 +1524,14 @@
             vst1q_lane_f32(dstr + (49 + i)*nch, b, 3);
             vst1q_lane_f32(dstl + (47 - i)*nch, a, 2);
             vst1q_lane_f32(dstl + (49 + i)*nch, b, 2);
-#endif
+#endif /* HAVE_SSE */
 #endif /* MINIMP3_FLOAT_OUTPUT */
         }
     } else
-#endif
+#endif /* HAVE_SIMD */
 #ifdef MINIMP3_ONLY_SIMD
     {}
-#else
+#else /* MINIMP3_ONLY_SIMD */
     for (i = 14; i >= 0; i--)
     {
 #define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64];
@@ -1561,7 +1560,7 @@
         dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]);
         dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]);
     }
-#endif
+#endif /* MINIMP3_ONLY_SIMD */
 }
 
 static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins)
@@ -1586,7 +1585,7 @@
             qmf_state[i] = lins[nbands*64 + i];
         }
     } else
-#endif
+#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */
     {
         memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64);
     }
@@ -1716,7 +1715,7 @@
     {
 #ifdef MINIMP3_ONLY_MP3
         return 0;
-#else
+#else /* MINIMP3_ONLY_MP3 */
         L12_scale_info sci[1];
         L12_read_scale_info(hdr, bs_frame, sci);
 
@@ -1737,7 +1736,7 @@
                 return 0;
             }
         }
-#endif
+#endif /* MINIMP3_ONLY_MP3 */
     }
     return success*hdr_frame_samples(dec->header);
 }
@@ -1769,7 +1768,7 @@
             out[i+5] = _mm_extract_epi16(pcm8, 5);
             out[i+6] = _mm_extract_epi16(pcm8, 6);
             out[i+7] = _mm_extract_epi16(pcm8, 7);
-#else
+#else /* HAVE_SSE */
             int16x4_t pcma, pcmb;
             a = VADD(a, VSET(0.5f));
             b = VADD(b, VSET(0.5f));
@@ -1783,9 +1782,9 @@
             vst1_lane_s16(out+i+5, pcmb, 1);
             vst1_lane_s16(out+i+6, pcmb, 2);
             vst1_lane_s16(out+i+7, pcmb, 3);
-#endif
+#endif /* HAVE_SSE */
         }
-#endif
+#endif /* HAVE_SIMD */
         for(; i < num_samples; i++)
         {
             float sample = in[i] * 32768.0f;
@@ -1802,7 +1801,5 @@
         }
     }
 }
-#endif
-
-#endif /*MINIMP3_IMPLEMENTATION*/
-#endif /*MINIMP3_H*/
+#endif /* MINIMP3_FLOAT_OUTPUT */
+#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */
--- /dev/null
+++ b/player/build-sdl.sh
@@ -1,0 +1,25 @@
+set -e
+
+SDL_VERSION=2.0.8
+
+if [ ! -d "SDL" ]; then
+  wget https://www.libsdl.org/release/SDL2-$SDL_VERSION.tar.gz
+  tar -xf SDL2-$SDL_VERSION.tar.gz
+  mv SDL2-$SDL_VERSION SDL
+  rm SDL2-$SDL_VERSION.tar.gz
+fi
+SDL_DIR=SDL/build-$1
+if [ "$1" = "win" ]; then
+  TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=../../windows/mingw64.cmake -DRENDER_D3D=OFF"
+fi
+if [ ! -d "$SDL_DIR" ]; then
+  mkdir $SDL_DIR
+  cd $SDL_DIR
+  cmake $TOOLCHAIN -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=TRUE -DVIDEO_OPENGLES=0 -DSDL_SHARED=OFF -DPTHREADS_SEM=OFF -DOSS=OFF -DSNDIO=OFF -DDISKAUDIO=OFF -DVIDEO_WAYLAND=OFF -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_C_FLAGS=-m32 ..
+  make -j4
+  cd ../../
+fi
+if [ ! -d "SDL/include/SDL2" ]; then
+  mkdir SDL/include/SDL2
+  cp SDL/include/*.h SDL/include/SDL2
+fi
--- a/player/build.sh
+++ b/player/build.sh
@@ -1,1 +1,3 @@
-gcc -O2 -o player *.cpp *.c -lstdc++ -lglfw -lGL -lpthread -lm -ldl -lSDL2
\ No newline at end of file
+./build-sdl.sh $1
+
+gcc -O2 -o player *.cpp *.c -lstdc++ -lGL -lpthread -lm -ldl -LSDL/build-$1 -ISDL/include -lSDL2
--- a/player/nuklear_glfw_gl3.h
+++ /dev/null
@@ -1,683 +1,0 @@
-/*
- * Nuklear - 1.32.0 - public domain
- * no warrenty implied; use at your own risk.
- * authored from 2015-2016 by Micha Mettke
- */
-/*
- * ==============================================================
- *
- *                              API
- *
- * ===============================================================
- */
-#ifndef NK_GLFW_GL3_H_
-#define NK_GLFW_GL3_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void GLvoid;
-typedef unsigned int GLuint;
-typedef unsigned int GLenum;
-typedef unsigned int GLbitfield;
-typedef int GLint;
-typedef int GLsizei;
-typedef float GLfloat;
-typedef float GLclampf;
-typedef char GLchar;
-typedef unsigned char GLboolean;
-typedef ptrdiff_t GLintptr;
-typedef ptrdiff_t GLsizeiptr;
-
-#define GL_FALSE 0
-#define GL_TRUE	1
-
-#define GL_FRAGMENT_SHADER                0x8B30
-#define GL_VERTEX_SHADER                  0x8B31
-#define GL_COMPILE_STATUS                 0x8B81
-#define GL_LINK_STATUS                    0x8B82
-#define GL_INFO_LOG_LENGTH                0x8B84
-
-#define GL_ARRAY_BUFFER                   0x8892
-#define GL_ELEMENT_ARRAY_BUFFER           0x8893
-
-#define GL_TEXTURE_2D				0x0DE1
-#define GL_TEXTURE_WRAP_S			0x2802
-#define GL_TEXTURE_WRAP_T			0x2803
-#define GL_TEXTURE_MAG_FILTER			0x2800
-#define GL_TEXTURE_MIN_FILTER			0x2801
-
-#define GL_NEAREST_MIPMAP_NEAREST		0x2700
-#define GL_NEAREST_MIPMAP_LINEAR		0x2702
-#define GL_LINEAR_MIPMAP_NEAREST		0x2701
-#define GL_LINEAR_MIPMAP_LINEAR			0x2703
-
-#define GL_LINEAR				0x2601
-#define GL_NEAREST				0x2600
-#define GL_REPEAT				0x2901
-#define GL_CLAMP				0x2900
-
-#define GL_FLOAT				0x1406
-#define GL_UNSIGNED_BYTE			0x1401
-#define GL_UNSIGNED_SHORT			0x1403
-#define GL_RGBA					0x1908
-
-#define GL_BLEND				0x0BE2
-#define GL_FUNC_ADD				0x8006
-#define GL_SRC_ALPHA				0x0302
-#define GL_ONE_MINUS_SRC_ALPHA			0x0303
-
-#define GL_CULL_FACE				0x0B44
-#define GL_DEPTH_TEST				0x0B71
-#define GL_SCISSOR_TEST				0x0C11
-
-#define GL_TEXTURE0				0x84C0
-
-#define GL_STREAM_DRAW                    0x88E0
-#define GL_WRITE_ONLY                     0x88B9
-
-#define GL_TRIANGLES				0x0004
-#define GL_TRIANGLE_STRIP			0x0005
-#define GL_TRIANGLE_FAN				0x0006
-
-#define GL_MAP_READ_BIT                   0x0001
-#define GL_MAP_WRITE_BIT                  0x0002
-#define GL_MAP_INVALIDATE_RANGE_BIT       0x0004
-#define GL_MAP_INVALIDATE_BUFFER_BIT      0x0008
-#define GL_MAP_FLUSH_EXPLICIT_BIT         0x0010
-#define GL_MAP_UNSYNCHRONIZED_BIT         0x0020
-
-/*GLuint glCreateProgram (void);
-void glDeleteProgram (GLuint program);
-void glGetProgramiv (GLuint program, GLenum pname, GLint *params);
-
-GLuint glCreateShader (GLenum type);
-void glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
-void glCompileShader (GLuint shader);
-void glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
-void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
-void glAttachShader (GLuint program, GLuint shader);
-void glLinkProgram (GLuint program);
-void glUseProgram (GLuint program);
-void glDeleteShader (GLuint shader);
-void glDetachShader (GLuint program, GLuint shader);
-
-GLint glGetUniformLocation (GLuint program, const GLchar *name);
-GLint glGetAttribLocation (GLuint program, const GLchar *name);
-
-void glGenBuffers (GLsizei n, GLuint *buffers);
-void glDeleteBuffers (GLsizei n, const GLuint *buffers);
-void glBindBuffer (GLenum target, GLuint buffer);
-
-void glGenVertexArrays (GLsizei n, GLuint *arrays);
-void glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
-void glBindVertexArray (GLuint array);
-
-void glDisableVertexAttribArray (GLuint index);
-void glEnableVertexAttribArray (GLuint index);
-void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
-
-void glGenTextures( GLsizei n, GLuint *textures );
-void glDeleteTextures( GLsizei n, const GLuint *textures);
-void glBindTexture( GLenum target, GLuint texture );
-void glTexParameteri( GLenum target, GLenum pname, GLint param );
-void glTexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
-                   GLint border, GLenum format, GLenum type, const GLvoid *pixels );
-void glActiveTexture( GLenum texture );
-
-void glEnable( GLenum cap );
-void glDisable( GLenum cap );
-
-void glAlphaFunc( GLenum func, GLclampf ref );
-void glBlendFunc( GLenum sfactor, GLenum dfactor );
-void glBlendEquation( GLenum mode );
-
-void glScissor( GLint x, GLint y, GLsizei width, GLsizei height);
-void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );
-
-void glUniform1f (GLint location, GLfloat v0);
-void glUniform2f (GLint location, GLfloat v0, GLfloat v1);
-void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
-void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
-void glUniform1i (GLint location, GLint v0);
-void glUniform2i (GLint location, GLint v0, GLint v1);
-void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2);
-void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
-void glUniform1fv (GLint location, GLsizei count, const GLfloat *value);
-void glUniform2fv (GLint location, GLsizei count, const GLfloat *value);
-void glUniform3fv (GLint location, GLsizei count, const GLfloat *value);
-void glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
-void glUniform1iv (GLint location, GLsizei count, const GLint *value);
-void glUniform2iv (GLint location, GLsizei count, const GLint *value);
-void glUniform3iv (GLint location, GLsizei count, const GLint *value);
-void glUniform4iv (GLint location, GLsizei count, const GLint *value);
-void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-
-void glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
-void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
-#ifndef EMSCRIPTEN
-void *glMapBuffer (GLenum target, GLenum access);
-#endif
-void *glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-GLboolean glUnmapBuffer (GLenum target);*/
-
-enum nk_glfw_init_state{
-    NK_GLFW3_DEFAULT=0,
-    NK_GLFW3_INSTALL_CALLBACKS
-};
-
-NK_API struct nk_context*   nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);
-NK_API void                 nk_glfw3_shutdown(void);
-NK_API void                 nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);
-NK_API void                 nk_glfw3_font_stash_end(void);
-NK_API void                 nk_glfw3_new_frame(void);
-NK_API void                 nk_glfw3_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
-
-NK_API void                 nk_glfw3_device_destroy(void);
-NK_API void                 nk_glfw3_device_create(void);
-
-NK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
-NK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
-NK_API void                 nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);
-
-#endif
-/*
- * ==============================================================
- *
- *                          IMPLEMENTATION
- *
- * ===============================================================
- */
-#ifdef NK_GLFW_GL3_IMPLEMENTATION
-
-#ifndef NK_GLFW_TEXT_MAX
-#define NK_GLFW_TEXT_MAX 256
-#endif
-#ifndef NK_GLFW_DOUBLE_CLICK_LO
-#define NK_GLFW_DOUBLE_CLICK_LO 0.02
-#endif
-#ifndef NK_GLFW_DOUBLE_CLICK_HI
-#define NK_GLFW_DOUBLE_CLICK_HI 0.2
-#endif
-
-struct nk_glfw_device {
-    struct nk_buffer cmds;
-    struct nk_draw_null_texture null;
-    GLuint vbo, vao, ebo;
-    GLuint prog;
-    GLuint vert_shdr;
-    GLuint frag_shdr;
-    GLint attrib_pos;
-    GLint attrib_uv;
-    GLint attrib_col;
-    GLint uniform_tex;
-    GLint uniform_proj;
-    GLuint font_tex;
-};
-
-struct nk_glfw_vertex {
-    float position[2];
-    float uv[2];
-    nk_byte col[4];
-};
-
-static struct nk_glfw {
-    GLFWwindow *win;
-    int width, height;
-    int display_width, display_height;
-    struct nk_glfw_device ogl;
-    struct nk_context ctx;
-    struct nk_font_atlas atlas;
-    struct nk_vec2 fb_scale;
-    unsigned int text[NK_GLFW_TEXT_MAX];
-    int text_len;
-    struct nk_vec2 scroll;
-    double last_button_click;
-} glfw;
-
-#if defined(USE_GLES3)
-#if defined(__APPLE__)
-#define NK_SHADER_VERSION "#version 150\n"
-#else
-#define NK_SHADER_VERSION "#version 300 es\n"
-#endif
-#define ATTR "in "
-#define VARYING "out "
-#define INVARYNG "in "
-#else
-#define NK_SHADER_VERSION ""
-#define ATTR "attribute "
-#define VARYING "varying "
-#define INVARYNG "varying "
-#endif
-
-static GLuint LoadShader(GLenum type, const char *shaderSrc)
-{
-    GLint compiled;
-    GLuint shader = glCreateShader(type);
-    if (shader == 0)
-        return 0;
-    glShaderSource(shader, 1, &shaderSrc, NULL);
-    glCompileShader(shader);
-    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
-    if (!compiled)
-    {
-       GLint infoLen = 0;
-       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-       if (infoLen > 1)
-       {
-           char *infoLog = (char*)malloc(sizeof(char)*infoLen);
-           glGetShaderInfoLog (shader, infoLen, NULL, infoLog);
-           printf("error: compiling shader failed:\n%s\n", infoLog);
-           free(infoLog);
-       }
-       glDeleteShader(shader);
-       return 0;
-    }
-    return shader;
-}
-
-NK_API void
-nk_glfw3_device_create(void)
-{
-    GLint status;
-    static const GLchar *vertex_shader =
-        NK_SHADER_VERSION
-        "uniform mat4 ProjMtx;\n"
-        ATTR "vec2 Position;\n"
-        ATTR "vec2 TexCoord;\n"
-        ATTR "vec4 Color;\n"
-        VARYING "vec2 Frag_UV;\n"
-        VARYING "vec4 Frag_Color;\n"
-        "void main() {\n"
-        "   Frag_UV = TexCoord;\n"
-        "   Frag_Color = Color;\n"
-        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
-        "}\n";
-    static const GLchar *fragment_shader =
-        NK_SHADER_VERSION
-#if defined(USE_GLES3)
-        "precision mediump float;\n"
-#endif
-        "uniform sampler2D Texture;\n"
-        INVARYNG "vec2 Frag_UV;\n"
-        INVARYNG "vec4 Frag_Color;\n"
-#if defined(USE_GLES3)
-        "out vec4 Out_Color;\n"
-#endif
-        "void main(){\n"
-#if defined(USE_GLES3)
-        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
-#else
-        "   gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
-#endif
-        "}\n";
-
-    struct nk_glfw_device *dev = &glfw.ogl;
-    nk_buffer_init_default(&dev->cmds);
-    dev->prog = glCreateProgram();
-    dev->vert_shdr = LoadShader(GL_VERTEX_SHADER, vertex_shader);
-    dev->frag_shdr = LoadShader(GL_FRAGMENT_SHADER, fragment_shader);
-    glAttachShader(dev->prog, dev->vert_shdr);
-    glAttachShader(dev->prog, dev->frag_shdr);
-    glLinkProgram(dev->prog);
-    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
-    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
-    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
-    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
-    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
-
-    {
-        /* buffer setup */
-        GLsizei vs = sizeof(struct nk_glfw_vertex);
-        size_t vp = offsetof(struct nk_glfw_vertex, position);
-        size_t vt = offsetof(struct nk_glfw_vertex, uv);
-        size_t vc = offsetof(struct nk_glfw_vertex, col);
-
-        glGenBuffers(1, &dev->vbo);
-        glGenBuffers(1, &dev->ebo);
-        glGenVertexArrays(1, &dev->vao);
-
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
-        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
-        glEnableVertexAttribArray((GLuint)dev->attrib_col);
-
-        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
-        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
-        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
-    }
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-}
-
-NK_INTERN void
-nk_glfw3_device_upload_atlas(const void *image, int width, int height)
-{
-    struct nk_glfw_device *dev = &glfw.ogl;
-    glGenTextures(1, &dev->font_tex);
-    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, image);
-}
-
-NK_API void
-nk_glfw3_device_destroy(void)
-{
-    struct nk_glfw_device *dev = &glfw.ogl;
-    glDetachShader(dev->prog, dev->vert_shdr);
-    glDetachShader(dev->prog, dev->frag_shdr);
-    glDeleteShader(dev->vert_shdr);
-    glDeleteShader(dev->frag_shdr);
-    glDeleteProgram(dev->prog);
-    glDeleteTextures(1, &dev->font_tex);
-    glDeleteBuffers(1, &dev->vbo);
-    glDeleteBuffers(1, &dev->ebo);
-    nk_buffer_free(&dev->cmds);
-}
-
-NK_API void
-nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
-{
-    struct nk_glfw_device *dev = &glfw.ogl;
-    struct nk_buffer vbuf, ebuf;
-    GLfloat ortho[4][4] = {
-        {2.0f, 0.0f, 0.0f, 0.0f},
-        {0.0f,-2.0f, 0.0f, 0.0f},
-        {0.0f, 0.0f,-1.0f, 0.0f},
-        {-1.0f,1.0f, 0.0f, 1.0f},
-    };
-    ortho[0][0] /= (GLfloat)glfw.width;
-    ortho[1][1] /= (GLfloat)glfw.height;
-
-    /* setup global state */
-    glEnable(GL_BLEND);
-    glBlendEquation(GL_FUNC_ADD);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-    glEnable(GL_SCISSOR_TEST);
-    glActiveTexture(GL_TEXTURE0);
-
-    /* setup program */
-    glUseProgram(dev->prog);
-    glUniform1i(dev->uniform_tex, 0);
-    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
-    //glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);
-    {
-        /* convert from command queue into draw list and draw to screen */
-        const struct nk_draw_command *cmd;
-        void *vertices, *elements;
-        const nk_draw_index *offset = NULL;
-
-        /* allocate vertex and element buffer */
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
-
-        /* load draw vertices & elements directly into vertex + element buffer */
-        //vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
-        //elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
-        vertices = glMapBufferRange(GL_ARRAY_BUFFER, 0, max_vertex_buffer, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
-        elements = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, max_element_buffer, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
-        {
-            /* fill convert configuration */
-            struct nk_convert_config config;
-            static const struct nk_draw_vertex_layout_element vertex_layout[] = {
-                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
-                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
-                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
-                {NK_VERTEX_LAYOUT_END}
-            };
-            NK_MEMSET(&config, 0, sizeof(config));
-            config.vertex_layout = vertex_layout;
-            config.vertex_size = sizeof(struct nk_glfw_vertex);
-            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
-            config.null = dev->null;
-            config.circle_segment_count = 22;
-            config.curve_segment_count = 22;
-            config.arc_segment_count = 22;
-            config.global_alpha = 1.0f;
-            config.shape_AA = AA;
-            config.line_AA = AA;
-
-            /* setup buffers to load vertices and elements */
-            nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
-            nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
-            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);
-        }
-        glUnmapBuffer(GL_ARRAY_BUFFER);
-        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-
-        /* iterate over and execute each draw command */
-        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)
-        {
-            if (!cmd->elem_count) continue;
-            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-            glScissor(
-                (GLint)(cmd->clip_rect.x * glfw.fb_scale.x),
-                (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),
-                (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),
-                (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));
-            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-            offset += cmd->elem_count;
-        }
-        nk_clear(&glfw.ctx);
-    }
-
-    /* default OpenGL state */
-    glUseProgram(0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-    glDisable(GL_BLEND);
-    glDisable(GL_SCISSOR_TEST);
-}
-
-NK_API void
-nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
-{
-    (void)win;
-    if (glfw.text_len < NK_GLFW_TEXT_MAX)
-        glfw.text[glfw.text_len++] = codepoint;
-}
-
-NK_API void
-nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
-{
-    (void)win; (void)xoff;
-    glfw.scroll.x += (float)xoff;
-    glfw.scroll.y += (float)yoff;
-}
-
-NK_API void
-nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
-{
-    double x, y;
-    if (button != GLFW_MOUSE_BUTTON_LEFT) return;
-    glfwGetCursorPos(window, &x, &y);
-    if (action == GLFW_PRESS)  {
-        double dt = glfwGetTime() - glfw.last_button_click;
-        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI)
-            nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true);
-        glfw.last_button_click = glfwGetTime();
-    } else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false);
-}
-
-NK_INTERN void
-nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
-{
-    const char *text = glfwGetClipboardString(glfw.win);
-    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
-    (void)usr;
-}
-
-NK_INTERN void
-nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
-{
-    char *str = 0;
-    (void)usr;
-    if (!len) return;
-    str = (char*)malloc((size_t)len+1);
-    if (!str) return;
-    memcpy(str, text, (size_t)len);
-    str[len] = '\0';
-    glfwSetClipboardString(glfw.win, str);
-    free(str);
-}
-
-NK_API struct nk_context*
-nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
-{
-    glfw.win = win;
-    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
-        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
-        glfwSetCharCallback(win, nk_glfw3_char_callback);
-        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);
-    }
-    nk_init_default(&glfw.ctx, 0);
-    glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
-    glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
-    glfw.ctx.clip.userdata = nk_handle_ptr(0);
-    glfw.last_button_click = 0;
-    nk_glfw3_device_create();
-    return &glfw.ctx;
-}
-
-NK_API void
-nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)
-{
-    nk_font_atlas_init_default(&glfw.atlas);
-    nk_font_atlas_begin(&glfw.atlas);
-    *atlas = &glfw.atlas;
-}
-
-NK_API void
-nk_glfw3_font_stash_end(void)
-{
-    const void *image; int w, h;
-    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
-    nk_glfw3_device_upload_atlas(image, w, h);
-    nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null);
-    if (glfw.atlas.default_font)
-        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);
-}
-
-NK_API void
-nk_glfw3_new_frame(void)
-{
-    int i;
-    double x, y;
-    struct nk_context *ctx = &glfw.ctx;
-    struct GLFWwindow *win = glfw.win;
-
-    /*glfw.width  = winWidth;
-    glfw.height = winHeight;
-    glfw.display_width = width;
-    glfw.display_height = height;*/
-    glfwGetWindowSize(win, &glfw.width, &glfw.height);
-    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);
-    glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;
-    glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;
-
-    nk_input_begin(ctx);
-    for (i = 0; i < glfw.text_len; ++i)
-        nk_input_unicode(ctx, glfw.text[i]);
-
-#if NK_GLFW_GL3_MOUSE_GRABBING
-    /* optional grabbing behavior */
-    if (ctx->input.mouse.grab)
-        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
-    else if (ctx->input.mouse.ungrab)
-        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
-#endif
-
-    nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS);
-    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
-                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
-
-    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
-        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
-        nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
-    } else {
-        nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
-        nk_input_key(ctx, NK_KEY_COPY, 0);
-        nk_input_key(ctx, NK_KEY_PASTE, 0);
-        nk_input_key(ctx, NK_KEY_CUT, 0);
-        nk_input_key(ctx, NK_KEY_SHIFT, 0);
-    }
-
-    glfwGetCursorPos(win, &x, &y);
-    //x = mx;
-    //y = my;
-    nk_input_motion(ctx, (int)x, (int)y);
-#if NK_GLFW_GL3_MOUSE_GRABBING
-    if (ctx->input.mouse.grabbed) {
-        glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
-        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
-        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
-    }
-#endif
-    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
-    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
-    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
-    /*nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, mkeys & 1);
-    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, mkeys & 2);
-    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, mkeys & 4);*/
-
-    nk_input_scroll(ctx, glfw.scroll);
-    nk_input_end(&glfw.ctx);
-    glfw.text_len = 0;
-    glfw.scroll = nk_vec2(0,0);
-}
-
-NK_API
-void nk_glfw3_shutdown(void)
-{
-    nk_font_atlas_clear(&glfw.atlas);
-    nk_free(&glfw.ctx);
-    nk_glfw3_device_destroy();
-    memset(&glfw, 0, sizeof(glfw));
-}
-
-#ifdef __cplusplus
-}
-#endif
-#endif
--- /dev/null
+++ b/player/nuklear_sdl_gl3.h
@@ -1,0 +1,442 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GL3_H_
+#define NK_SDL_GL3_H_
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+NK_API struct nk_context*   nk_sdl_init(SDL_Window *win);
+NK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void                 nk_sdl_font_stash_end(void);
+NK_API int                  nk_sdl_handle_event(SDL_Event *evt);
+NK_API void                 nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void                 nk_sdl_shutdown(void);
+NK_API void                 nk_sdl_device_destroy(void);
+NK_API void                 nk_sdl_device_create(void);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GL3_IMPLEMENTATION
+
+#include <string.h>
+
+struct nk_sdl_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+struct nk_sdl_vertex {
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+
+static struct nk_sdl {
+    SDL_Window *win;
+    struct nk_sdl_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+} sdl;
+
+#ifdef __APPLE__
+  #define NK_SHADER_VERSION "#version 150\n"
+#else
+  #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+NK_API void
+nk_sdl_device_create(void)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        NK_SHADER_VERSION
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        NK_SHADER_VERSION
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    struct nk_sdl_device *dev = &sdl.ogl;
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_sdl_vertex);
+        size_t vp = offsetof(struct nk_sdl_vertex, position);
+        size_t vt = offsetof(struct nk_sdl_vertex, uv);
+        size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sdl_device_destroy(void)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    int width, height;
+    int display_width, display_height;
+    struct nk_vec2 scale;
+    GLfloat ortho[4][4] = {
+        {2.0f, 0.0f, 0.0f, 0.0f},
+        {0.0f,-2.0f, 0.0f, 0.0f},
+        {0.0f, 0.0f,-1.0f, 0.0f},
+        {-1.0f,1.0f, 0.0f, 1.0f},
+    };
+    SDL_GetWindowSize(sdl.win, &width, &height);
+    SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    scale.x = (float)display_width/(float)width;
+    scale.y = (float)display_height/(float)height;
+
+    /* setup global state */
+    glViewport(0,0,display_width,display_height);
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+        struct nk_buffer vbuf, ebuf;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+        /* load vertices/elements directly into vertex/element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill convert configuration */
+            struct nk_convert_config config;
+            static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+                {NK_VERTEX_LAYOUT_END}
+            };
+            NK_MEMSET(&config, 0, sizeof(config));
+            config.vertex_layout = vertex_layout;
+            config.vertex_size = sizeof(struct nk_sdl_vertex);
+            config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+            config.null = dev->null;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+
+            /* setup buffers to load vertices and elements */
+            nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
+            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)(cmd->clip_rect.x * scale.x),
+                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+                (GLint)(cmd->clip_rect.w * scale.x),
+                (GLint)(cmd->clip_rect.h * scale.y));
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(&sdl.ctx);
+    }
+
+    glUseProgram(0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+    glDisable(GL_BLEND);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+static void
+nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    const char *text = SDL_GetClipboardText();
+    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+    (void)usr;
+}
+
+static void
+nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+    char *str = 0;
+    (void)usr;
+    if (!len) return;
+    str = (char*)malloc((size_t)len+1);
+    if (!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+    SDL_SetClipboardText(str);
+    free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+    sdl.win = win;
+    nk_init_default(&sdl.ctx, 0);
+    sdl.ctx.clip.copy = nk_sdl_clipbard_copy;
+    sdl.ctx.clip.paste = nk_sdl_clipbard_paste;
+    sdl.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_sdl_device_create();
+    return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&sdl.atlas);
+    nk_font_atlas_begin(&sdl.atlas);
+    *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+    const void *image; int w, h;
+    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sdl_device_upload_atlas(image, w, h);
+    nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null);
+    if (sdl.atlas.default_font)
+        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+
+}
+
+NK_API int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+    struct nk_context *ctx = &sdl.ctx;
+    if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) {
+        /* key events */
+        int down = evt->type == SDL_KEYDOWN;
+        const Uint8* state = SDL_GetKeyboardState(0);
+        SDL_Keycode sym = evt->key.keysym.sym;
+        if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
+            nk_input_key(ctx, NK_KEY_SHIFT, down);
+        else if (sym == SDLK_DELETE)
+            nk_input_key(ctx, NK_KEY_DEL, down);
+        else if (sym == SDLK_RETURN)
+            nk_input_key(ctx, NK_KEY_ENTER, down);
+        else if (sym == SDLK_TAB)
+            nk_input_key(ctx, NK_KEY_TAB, down);
+        else if (sym == SDLK_BACKSPACE)
+            nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+        else if (sym == SDLK_HOME) {
+            nk_input_key(ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+        } else if (sym == SDLK_END) {
+            nk_input_key(ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+        } else if (sym == SDLK_PAGEDOWN) {
+            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+        } else if (sym == SDLK_PAGEUP) {
+            nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+        } else if (sym == SDLK_z)
+            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_r)
+            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_c)
+            nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_v)
+            nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_x)
+            nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_b)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_e)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_UP)
+            nk_input_key(ctx, NK_KEY_UP, down);
+        else if (sym == SDLK_DOWN)
+            nk_input_key(ctx, NK_KEY_DOWN, down);
+        else if (sym == SDLK_LEFT) {
+            if (state[SDL_SCANCODE_LCTRL])
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else nk_input_key(ctx, NK_KEY_LEFT, down);
+        } else if (sym == SDLK_RIGHT) {
+            if (state[SDL_SCANCODE_LCTRL])
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else nk_input_key(ctx, NK_KEY_RIGHT, down);
+        } else return 0;
+        return 1;
+    } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
+        /* mouse button */
+        int down = evt->type == SDL_MOUSEBUTTONDOWN;
+        const int x = evt->button.x, y = evt->button.y;
+        if (evt->button.button == SDL_BUTTON_LEFT) {
+            if (evt->button.clicks > 1)
+                nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
+            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        } else if (evt->button.button == SDL_BUTTON_MIDDLE)
+            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+        else if (evt->button.button == SDL_BUTTON_RIGHT)
+            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+        return 1;
+    } else if (evt->type == SDL_MOUSEMOTION) {
+        /* mouse motion */
+        if (ctx->input.mouse.grabbed) {
+            int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+            nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+        } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+        return 1;
+    } else if (evt->type == SDL_TEXTINPUT) {
+        /* text input */
+        nk_glyph glyph;
+        memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+        nk_input_glyph(ctx, glyph);
+        return 1;
+    } else if (evt->type == SDL_MOUSEWHEEL) {
+        /* mouse wheel */
+        nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
+        return 1;
+    }
+    return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+    nk_font_atlas_clear(&sdl.atlas);
+    nk_free(&sdl.ctx);
+    nk_sdl_device_destroy();
+    memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif
--- a/player/player.cpp
+++ b/player/player.cpp
@@ -3,8 +3,8 @@
 #include <string>
 #include <map>
 #include <vector>
+#include <SDL2/SDL.h>
 #include "glad.h"
-#include <GLFW/glfw3.h>
 #if defined(__APPLE__)
 #define USE_GLES3
 #include <OpenGL/gl3.h>
@@ -23,9 +23,9 @@
 #define NK_INCLUDE_FONT_BAKING
 #define NK_INCLUDE_DEFAULT_FONT
 #define NK_IMPLEMENTATION
-#define NK_GLFW_GL3_IMPLEMENTATION
+#define NK_SDL_GL3_IMPLEMENTATION
 #include "nuklear.h"
-#include "nuklear_glfw_gl3.h"
+#include "nuklear_sdl_gl3.h"
 #include "style.h"
 
 #define MAX_VERTEX_BUFFER  512 * 1024
@@ -35,10 +35,12 @@
 static PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
 #endif
 static void       *_ctx;
-static GLFWwindow *_mainWindow;
+static SDL_Window *_mainWindow;
+static SDL_GLContext _mainContext;
 static std::map<std::string, int> _previews;
 static std::vector<std::string> _playlist;
 static void *_render;
+static bool _closeNextFrame;
 decoder _dec;
 
 static int load_image(const stbi_uc *data, int len)
@@ -66,69 +68,88 @@
 
 static void close()
 {
-    glfwMakeContextCurrent(_mainWindow);
+    nk_sdl_shutdown();
+    SDL_GL_MakeCurrent(_mainWindow, _mainContext);
     for (auto it = _previews.begin(); it != _previews.end(); it++)
     {
         GLuint tex = it->second;
         glDeleteTextures(1, &tex);
     }
-    glfwDestroyWindow(_mainWindow);
-    glfwTerminate();
+    SDL_GL_DeleteContext(_mainContext);
+    SDL_DestroyWindow(_mainWindow);
+    SDL_Quit();
 }
 
 static int init()
 {
-    if (!glfwInit())
+    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+    if (!SDL_Init(SDL_INIT_VIDEO) < 0)
     {
-        printf("error: glfw init failed\n");
+        printf("error: sdl2 video init failed %s\n", SDL_GetError());
         return false;
     }
 #ifdef USE_GLES3
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+    // SDL_GL_SetAttribute(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
 #else
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
 #endif
-    glfwWindowHint(GLFW_RESIZABLE, 1);
-    _mainWindow = glfwCreateWindow(400, 600, "Lion Audio Player", NULL, NULL);
+    _mainWindow = SDL_CreateWindow("Lion Audio Player", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 600, SDL_WINDOW_RESIZABLE|SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);
     if (!_mainWindow)
     {
-        printf("error: create window failed\n"); fflush(stdout);
+        printf("error: create window failed: %s\n", SDL_GetError()); 
+        fflush(stdout);
         exit(1);
     }
-    glfwMakeContextCurrent(_mainWindow);
+    if((_mainContext = SDL_GL_CreateContext(_mainWindow)) == NULL)
+    {
+        printf("error: create context failed: %s\n", SDL_GetError()); 
+        fflush(stdout);
+        exit(1);
+    }
+    SDL_GL_MakeCurrent(_mainWindow, _mainContext);
+    
 #ifdef USE_GLES3
-    glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)glfwGetProcAddress("glGenerateMipmap");
+    glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)SDL_GL_GetProcAddress("glGenerateMipmap");
 #endif
-    glfwSetInputMode(_mainWindow, GLFW_STICKY_MOUSE_BUTTONS, 1);
 
     gladLoadGL();
-    _ctx = (void*)nk_glfw3_init(_mainWindow, NK_GLFW3_INSTALL_CALLBACKS);
+    _ctx = (void*)nk_sdl_init(_mainWindow);
     struct nk_font_atlas *atlas;
     struct nk_font_config fconfig = nk_font_config(20);
     fconfig.range = nk_font_cyrillic_glyph_ranges();
-    nk_glfw3_font_stash_begin(&atlas);
+    nk_sdl_font_stash_begin(&atlas);
     atlas->default_font = nk_font_atlas_add_from_memory(atlas, FreeSans, FreeSansLen, 20, &fconfig);;
-    nk_glfw3_font_stash_end();
+    nk_sdl_font_stash_end();
 }
 
 static void tick()
 {
-    //glfwMakeContextCurrent(_mainWindow);
+    nk_context *ctx = (nk_context *)_ctx;
+    
     float bg[4];
     nk_color_fv(bg, nk_rgb(28,48,62));
     int width, height, i;
-    glfwGetWindowSize(_mainWindow, &width, &height);
+    SDL_GL_GetDrawableSize(_mainWindow, &width, &height);
     glViewport(0, 0, width, height);
     glClearColor(bg[0], bg[1], bg[2], bg[3]);
     glClear(GL_COLOR_BUFFER_BIT);
-    glfwPollEvents();
+    
+    // Run events
+    SDL_Event event;
+    nk_input_begin(ctx);
+    while(SDL_PollEvent(&event))
+    {
+        nk_sdl_handle_event(&event);
+        
+        if(event.type == SDL_QUIT)
+            _closeNextFrame = true;
+    }
+    nk_input_end(ctx);
 
-    nk_context *ctx = (nk_context *)_ctx;
-    nk_glfw3_new_frame();
     if (nk_begin(ctx, "Player", nk_rect(0, 0, width, height), 0))
     {
         nk_layout_row_dynamic(ctx, 25, 2);
@@ -196,18 +217,18 @@
         }
     }
     nk_end(ctx);
-    nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
-    glfwSwapBuffers(_mainWindow);
-    //glfwMakeContextCurrent(0);
+    nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+    SDL_GL_SwapWindow(_mainWindow);
 }
 
 int main(int argc, char *argv[])
 {
+    _closeNextFrame = false;
     sdl_audio_init(&_render, 44100, 2, 0, 0);
     init();
     for (int i = 1; i < argc; i++)
         _playlist.push_back(argv[i]);
-    while (!glfwWindowShouldClose(_mainWindow))
+    while (!_closeNextFrame)
     {
         tick();
     }