ecere/gfx/drivers/OpenGL: Fixed mipmapping
[sdk] / ecere / src / gfx / drivers / OpenGLDisplayDriver.ec
index 2f4d8b0..7c79ca4 100644 (file)
@@ -4,26 +4,83 @@
 namespace gfx::drivers;
 
 // OpenGL Extensions
-#if defined(__unix__)
+#if defined(__unix__) || defined(__APPLE__)
 
 #if !defined(__MINGW32__)
-#define GL_GLEXT_PROTOTYPES
+   #define GL_GLEXT_PROTOTYPES
 #endif
 
+#define pointer _pointer
+
 #ifdef ECERE_MINIGLX
 
 //#include <GL/miniglx.h>
 
 #else
 
-#if defined(__ANDROID__)
+   #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
+
+      #define property _property
+      #define new _new
+      #define class _class
+
+      #define Window    X11Window
+      #define Cursor    X11Cursor
+      #define Font      X11Font
+      #define Display   X11Display
+      #define Time      X11Time
+      #define KeyCode   X11KeyCode
+      #define Picture   X11Picture
+      #define uint _uint
+
+      #include <X11/Xlib.h>
+      #include <X11/Xutil.h>
+      #include <GL/glx.h>
+      #include <X11/extensions/XShm.h>
+      #include <sys/ipc.h>
+      #include <sys/shm.h>
+      #include <X11/extensions/Xrender.h>
+      #include <X11/extensions/shape.h>
+
+      #undef Window
+      #undef Cursor
+      #undef Font
+      #undef Display
+      #undef Time
+      #undef KeyCode
+      #undef Picture
+      #undef uint
+      #undef new
+      #undef property
+      #undef class
 
-#else
+   #endif
+
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+#include <OpenGl/gl.h>
+#endif
+
+#if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
+
+#if defined(__WIN32__)
+   #define WIN32_LEAN_AND_MEAN
+   #undef _WIN32_WINNT
+   #define _WIN32_WINNT 0x0502
+   #define String Sting_
+   #include <windows.h>
+   #undef String
+#endif
 
+#if defined(__ANDROID__) || defined(__ODROID__)
+
+#define uint _uint
 #define property _property
 #define new _new
 #define class _class
-
 #define Window    X11Window
 #define Cursor    X11Cursor
 #define Font      X11Font
@@ -31,69 +88,86 @@ namespace gfx::drivers;
 #define Time      X11Time
 #define KeyCode   X11KeyCode
 #define Picture   X11Picture
-#define uint _uint
+#define Bool      X11Bool
 
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <GL/glx.h>
-#include <X11/extensions/XShm.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <X11/extensions/Xrender.h>
-#include <X11/extensions/shape.h>
+   #include <GLES/gl.h>
+   #include <EGL/egl.h>
 
+#undef Bool
+#undef Picture
 #undef Window
 #undef Cursor
 #undef Font
 #undef Display
 #undef Time
 #undef KeyCode
-#undef Picture
 #undef uint
 #undef new
 #undef property
 #undef class
 
-#endif
+#elif defined(__EMSCRIPTEN__)
 
-#endif
+   #define property _property
+   #define uint _uint
 
-#endif
+   #include <GL/gl.h>
 
-#if defined(__APPLE__)
-#include <OpenGl/gl.h>
-#endif
+   //#include <GLES/gl.h>
+   //#include <EGL/egl.h>
 
-#if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
+   //#include <GLES2/gl.h>
+   //#include <EGL/egl.h>
 
-#if defined(__WIN32__)
-#define WIN32_LEAN_AND_MEAN
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#endif
+   //#include <GLES2/gl2.h>
+   #include <GL/glfw.h>
+   #include <emscripten/emscripten.h>
 
-#if defined(__ANDROID__)
-
-#include <GLES/gl.h>
-#include <EGL/egl.h>
+   #undef property
+   #undef uint
 
 #else
 
-#include <GL/gl.h>
-#include <GL/glext.h>
+   #include <GL/gl.h>
+   #include <GL/glext.h>
+
+#endif
+
+#if defined(__ODROID__) && !defined(_GLES)
+#define _GLES
+#endif
 
+#if defined(__EMSCRIPTEN__)
+#define EM_MODE
+// #define _GLES
 #endif
 
+//#define EM_MODE
+
+#undef pointer
+
 import "Display"
 
-#if defined(__unix__)
+#if defined(__unix__) || defined(__APPLE__)
 
-#ifndef __ANDROID__
-import "XInterface"
-#endif
+   #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
+   import "XInterface"
+   #endif
 
 #endif
 
+static double nearPlane = 1;
+
+public double glesGetNearPlane()
+{
+   return nearPlane;
+}
+
+public void glesSetNearPlane(double value)
+{
+   nearPlane = value;
+}
+
 #define glLoadMatrix glLoadMatrixd
 #define glMultMatrix glMultMatrixd
 #define glGetMatrix  glGetDoublev
@@ -141,386 +215,481 @@ import "XInterface"
 
 #if defined(__WIN32__)
 
-#define WGL_SAMPLE_BUFFERS_ARB              0x2041
-#define WGL_SAMPLES_ARB                     0x2042
-
-#define  WGL_WGLEXT_VERSION   1 
-#define  WGL_FRONT_COLOR_BUFFER_BIT_ARB   0x00000001 
-#define  WGL_BACK_COLOR_BUFFER_BIT_ARB   0x00000002 
-#define  WGL_DEPTH_BUFFER_BIT_ARB   0x00000004 
-#define  WGL_STENCIL_BUFFER_BIT_ARB   0x00000008 
-#define  WGL_NUMBER_PIXEL_FORMATS_ARB   0x2000 
-#define  WGL_DRAW_TO_WINDOW_ARB   0x2001 
-#define  WGL_DRAW_TO_BITMAP_ARB   0x2002 
-#define  WGL_ACCELERATION_ARB   0x2003 
-#define  WGL_NEED_PALETTE_ARB   0x2004 
-#define  WGL_NEED_SYSTEM_PALETTE_ARB   0x2005 
-#define  WGL_SWAP_LAYER_BUFFERS_ARB   0x2006 
-#define  WGL_SWAP_METHOD_ARB   0x2007 
-#define  WGL_NUMBER_OVERLAYS_ARB   0x2008 
-#define  WGL_NUMBER_UNDERLAYS_ARB   0x2009 
-#define  WGL_TRANSPARENT_ARB   0x200A 
-#define  WGL_TRANSPARENT_RED_VALUE_ARB   0x2037 
-#define  WGL_TRANSPARENT_GREEN_VALUE_ARB   0x2038 
-#define  WGL_TRANSPARENT_BLUE_VALUE_ARB   0x2039 
-#define  WGL_TRANSPARENT_ALPHA_VALUE_ARB   0x203A 
-#define  WGL_TRANSPARENT_INDEX_VALUE_ARB   0x203B 
-#define  WGL_SHARE_DEPTH_ARB   0x200C 
-#define  WGL_SHARE_STENCIL_ARB   0x200D 
-#define  WGL_SHARE_ACCUM_ARB   0x200E 
-#define  WGL_SUPPORT_GDI_ARB   0x200F 
-#define  WGL_SUPPORT_OPENGL_ARB   0x2010 
-#define  WGL_DOUBLE_BUFFER_ARB   0x2011 
-#define  WGL_STEREO_ARB   0x2012 
-#define  WGL_PIXEL_TYPE_ARB   0x2013 
-#define  WGL_COLOR_BITS_ARB   0x2014 
-#define  WGL_RED_BITS_ARB   0x2015 
-#define  WGL_RED_SHIFT_ARB   0x2016 
-#define  WGL_GREEN_BITS_ARB   0x2017 
-#define  WGL_GREEN_SHIFT_ARB   0x2018 
-#define  WGL_BLUE_BITS_ARB   0x2019 
-#define  WGL_BLUE_SHIFT_ARB   0x201A 
-#define  WGL_ALPHA_BITS_ARB   0x201B 
-#define  WGL_ALPHA_SHIFT_ARB   0x201C 
-#define  WGL_ACCUM_BITS_ARB   0x201D 
-#define  WGL_ACCUM_RED_BITS_ARB   0x201E 
-#define  WGL_ACCUM_GREEN_BITS_ARB   0x201F 
-#define  WGL_ACCUM_BLUE_BITS_ARB   0x2020 
-#define  WGL_ACCUM_ALPHA_BITS_ARB   0x2021 
-#define  WGL_DEPTH_BITS_ARB   0x2022 
-#define  WGL_STENCIL_BITS_ARB   0x2023 
-#define  WGL_AUX_BUFFERS_ARB   0x2024 
-#define  WGL_NO_ACCELERATION_ARB   0x2025 
-#define  WGL_GENERIC_ACCELERATION_ARB   0x2026 
-#define  WGL_FULL_ACCELERATION_ARB   0x2027 
-#define  WGL_SWAP_EXCHANGE_ARB   0x2028 
-#define  WGL_SWAP_COPY_ARB   0x2029 
-#define  WGL_SWAP_UNDEFINED_ARB   0x202A 
-#define  WGL_TYPE_RGBA_ARB   0x202B 
-#define  WGL_TYPE_COLORINDEX_ARB   0x202C 
-#define  ERROR_INVALID_PIXEL_TYPE_ARB   0x2043 
-#define  ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB   0x2054 
-#define  WGL_DRAW_TO_PBUFFER_ARB   0x202D 
-#define  WGL_MAX_PBUFFER_PIXELS_ARB   0x202E 
-#define  WGL_MAX_PBUFFER_WIDTH_ARB   0x202F 
-#define  WGL_MAX_PBUFFER_HEIGHT_ARB   0x2030 
-#define  WGL_PBUFFER_LARGEST_ARB   0x2033 
-#define  WGL_PBUFFER_WIDTH_ARB   0x2034 
-#define  WGL_PBUFFER_HEIGHT_ARB   0x2035 
-#define  WGL_PBUFFER_LOST_ARB   0x2036 
-#define  ERROR_INVALID_PIXEL_TYPE_EXT   0x2043 
-#define  WGL_NUMBER_PIXEL_FORMATS_EXT   0x2000 
-#define  WGL_DRAW_TO_WINDOW_EXT   0x2001 
-#define  WGL_DRAW_TO_BITMAP_EXT   0x2002 
-#define  WGL_ACCELERATION_EXT   0x2003 
-#define  WGL_NEED_PALETTE_EXT   0x2004 
-#define  WGL_NEED_SYSTEM_PALETTE_EXT   0x2005 
-#define  WGL_SWAP_LAYER_BUFFERS_EXT   0x2006 
-#define  WGL_SWAP_METHOD_EXT   0x2007 
-#define  WGL_NUMBER_OVERLAYS_EXT   0x2008 
-#define  WGL_NUMBER_UNDERLAYS_EXT   0x2009 
-#define  WGL_TRANSPARENT_EXT   0x200A 
-#define  WGL_TRANSPARENT_VALUE_EXT   0x200B 
-#define  WGL_SHARE_DEPTH_EXT   0x200C 
-#define  WGL_SHARE_STENCIL_EXT   0x200D 
-#define  WGL_SHARE_ACCUM_EXT   0x200E 
-#define  WGL_SUPPORT_GDI_EXT   0x200F 
-#define  WGL_SUPPORT_OPENGL_EXT   0x2010 
-#define  WGL_DOUBLE_BUFFER_EXT   0x2011 
-#define  WGL_STEREO_EXT   0x2012 
-#define  WGL_PIXEL_TYPE_EXT   0x2013 
-#define  WGL_COLOR_BITS_EXT   0x2014 
-#define  WGL_RED_BITS_EXT   0x2015 
-#define  WGL_RED_SHIFT_EXT   0x2016 
-#define  WGL_GREEN_BITS_EXT   0x2017 
-#define  WGL_GREEN_SHIFT_EXT   0x2018 
-#define  WGL_BLUE_BITS_EXT   0x2019 
-#define  WGL_BLUE_SHIFT_EXT   0x201A 
-#define  WGL_ALPHA_BITS_EXT   0x201B 
-#define  WGL_ALPHA_SHIFT_EXT   0x201C 
-#define  WGL_ACCUM_BITS_EXT   0x201D 
-#define  WGL_ACCUM_RED_BITS_EXT   0x201E 
-#define  WGL_ACCUM_GREEN_BITS_EXT   0x201F 
-#define  WGL_ACCUM_BLUE_BITS_EXT   0x2020 
-#define  WGL_ACCUM_ALPHA_BITS_EXT   0x2021 
-#define  WGL_DEPTH_BITS_EXT   0x2022 
-#define  WGL_STENCIL_BITS_EXT   0x2023 
-#define  WGL_AUX_BUFFERS_EXT   0x2024 
-#define  WGL_NO_ACCELERATION_EXT   0x2025 
-#define  WGL_GENERIC_ACCELERATION_EXT   0x2026 
-#define  WGL_FULL_ACCELERATION_EXT   0x2027 
-#define  WGL_SWAP_EXCHANGE_EXT   0x2028 
-#define  WGL_SWAP_COPY_EXT   0x2029 
-#define  WGL_SWAP_UNDEFINED_EXT   0x202A 
-#define  WGL_TYPE_RGBA_EXT   0x202B 
-#define  WGL_TYPE_COLORINDEX_EXT   0x202C 
-#define  WGL_DRAW_TO_PBUFFER_EXT   0x202D 
-#define  WGL_MAX_PBUFFER_PIXELS_EXT   0x202E 
-#define  WGL_MAX_PBUFFER_WIDTH_EXT   0x202F 
-#define  WGL_MAX_PBUFFER_HEIGHT_EXT   0x2030 
-#define  WGL_OPTIMAL_PBUFFER_WIDTH_EXT   0x2031 
-#define  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT   0x2032 
-#define  WGL_PBUFFER_LARGEST_EXT   0x2033 
-#define  WGL_PBUFFER_WIDTH_EXT   0x2034 
-#define  WGL_PBUFFER_HEIGHT_EXT   0x2035 
-#define  WGL_DEPTH_FLOAT_EXT   0x2040 
-#define  WGL_SAMPLE_BUFFERS_3DFX   0x2060 
-#define  WGL_SAMPLES_3DFX   0x2061 
-#define  WGL_SAMPLE_BUFFERS_EXT   0x2041 
-#define  WGL_SAMPLES_EXT   0x2042 
-#define  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D   0x2044 
-#define  WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D   0x2045 
-#define  WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D   0x2046 
-#define  WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D   0x2047 
-#define  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D   0x2048 
-#define  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D   0x2049 
-#define  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D   0x204A 
-#define  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D   0x204B 
-#define  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D   0x204C 
-#define  WGL_GAMMA_TABLE_SIZE_I3D   0x204E 
-#define  WGL_GAMMA_EXCLUDE_DESKTOP_I3D   0x204F 
-#define  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D   0x2050 
-#define  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D   0x2051 
-#define  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D   0x2052 
-#define  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D   0x2053 
-#define  WGL_ARB_buffer_region   1 
-#define  WGL_ARB_extensions_string   1 
-#define  WGL_ARB_pixel_format   1 
-#define  WGL_ARB_make_current_read   1 
-#define  WGL_ARB_pbuffer   1 
-#define  WGL_EXT_display_color_table   1 
-#define  WGL_EXT_extensions_string   1 
-#define  WGL_EXT_make_current_read   1 
-#define  WGL_EXT_pbuffer   1 
-#define  WGL_EXT_pixel_format   1 
-#define  WGL_EXT_swap_control   1 
-#define  WGL_WGL_EXT_depth_float   1 
-#define  WGL_WGL_3DFX_multisample   1 
-#define  WGL_WGL_EXT_multisample   1 
-#define  WGL_NV_allocate_memory   1 
+   #define WGL_SAMPLE_BUFFERS_ARB              0x2041
+   #define WGL_SAMPLES_ARB                     0x2042
+
+   #define  WGL_WGLEXT_VERSION   1
+   #define  WGL_FRONT_COLOR_BUFFER_BIT_ARB   0x00000001
+   #define  WGL_BACK_COLOR_BUFFER_BIT_ARB   0x00000002
+   #define  WGL_DEPTH_BUFFER_BIT_ARB   0x00000004
+   #define  WGL_STENCIL_BUFFER_BIT_ARB   0x00000008
+   #define  WGL_NUMBER_PIXEL_FORMATS_ARB   0x2000
+   #define  WGL_DRAW_TO_WINDOW_ARB   0x2001
+   #define  WGL_DRAW_TO_BITMAP_ARB   0x2002
+   #define  WGL_ACCELERATION_ARB   0x2003
+   #define  WGL_NEED_PALETTE_ARB   0x2004
+   #define  WGL_NEED_SYSTEM_PALETTE_ARB   0x2005
+   #define  WGL_SWAP_LAYER_BUFFERS_ARB   0x2006
+   #define  WGL_SWAP_METHOD_ARB   0x2007
+   #define  WGL_NUMBER_OVERLAYS_ARB   0x2008
+   #define  WGL_NUMBER_UNDERLAYS_ARB   0x2009
+   #define  WGL_TRANSPARENT_ARB   0x200A
+   #define  WGL_TRANSPARENT_RED_VALUE_ARB   0x2037
+   #define  WGL_TRANSPARENT_GREEN_VALUE_ARB   0x2038
+   #define  WGL_TRANSPARENT_BLUE_VALUE_ARB   0x2039
+   #define  WGL_TRANSPARENT_ALPHA_VALUE_ARB   0x203A
+   #define  WGL_TRANSPARENT_INDEX_VALUE_ARB   0x203B
+   #define  WGL_SHARE_DEPTH_ARB   0x200C
+   #define  WGL_SHARE_STENCIL_ARB   0x200D
+   #define  WGL_SHARE_ACCUM_ARB   0x200E
+   #define  WGL_SUPPORT_GDI_ARB   0x200F
+   #define  WGL_SUPPORT_OPENGL_ARB   0x2010
+   #define  WGL_DOUBLE_BUFFER_ARB   0x2011
+   #define  WGL_STEREO_ARB   0x2012
+   #define  WGL_PIXEL_TYPE_ARB   0x2013
+   #define  WGL_COLOR_BITS_ARB   0x2014
+   #define  WGL_RED_BITS_ARB   0x2015
+   #define  WGL_RED_SHIFT_ARB   0x2016
+   #define  WGL_GREEN_BITS_ARB   0x2017
+   #define  WGL_GREEN_SHIFT_ARB   0x2018
+   #define  WGL_BLUE_BITS_ARB   0x2019
+   #define  WGL_BLUE_SHIFT_ARB   0x201A
+   #define  WGL_ALPHA_BITS_ARB   0x201B
+   #define  WGL_ALPHA_SHIFT_ARB   0x201C
+   #define  WGL_ACCUM_BITS_ARB   0x201D
+   #define  WGL_ACCUM_RED_BITS_ARB   0x201E
+   #define  WGL_ACCUM_GREEN_BITS_ARB   0x201F
+   #define  WGL_ACCUM_BLUE_BITS_ARB   0x2020
+   #define  WGL_ACCUM_ALPHA_BITS_ARB   0x2021
+   #define  WGL_DEPTH_BITS_ARB   0x2022
+   #define  WGL_STENCIL_BITS_ARB   0x2023
+   #define  WGL_AUX_BUFFERS_ARB   0x2024
+   #define  WGL_NO_ACCELERATION_ARB   0x2025
+   #define  WGL_GENERIC_ACCELERATION_ARB   0x2026
+   #define  WGL_FULL_ACCELERATION_ARB   0x2027
+   #define  WGL_SWAP_EXCHANGE_ARB   0x2028
+   #define  WGL_SWAP_COPY_ARB   0x2029
+   #define  WGL_SWAP_UNDEFINED_ARB   0x202A
+   #define  WGL_TYPE_RGBA_ARB   0x202B
+   #define  WGL_TYPE_COLORINDEX_ARB   0x202C
+   #define  ERROR_INVALID_PIXEL_TYPE_ARB   0x2043
+   #define  ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB   0x2054
+   #define  WGL_DRAW_TO_PBUFFER_ARB   0x202D
+   #define  WGL_MAX_PBUFFER_PIXELS_ARB   0x202E
+   #define  WGL_MAX_PBUFFER_WIDTH_ARB   0x202F
+   #define  WGL_MAX_PBUFFER_HEIGHT_ARB   0x2030
+   #define  WGL_PBUFFER_LARGEST_ARB   0x2033
+   #define  WGL_PBUFFER_WIDTH_ARB   0x2034
+   #define  WGL_PBUFFER_HEIGHT_ARB   0x2035
+   #define  WGL_PBUFFER_LOST_ARB   0x2036
+   #define  ERROR_INVALID_PIXEL_TYPE_EXT   0x2043
+   #define  WGL_NUMBER_PIXEL_FORMATS_EXT   0x2000
+   #define  WGL_DRAW_TO_WINDOW_EXT   0x2001
+   #define  WGL_DRAW_TO_BITMAP_EXT   0x2002
+   #define  WGL_ACCELERATION_EXT   0x2003
+   #define  WGL_NEED_PALETTE_EXT   0x2004
+   #define  WGL_NEED_SYSTEM_PALETTE_EXT   0x2005
+   #define  WGL_SWAP_LAYER_BUFFERS_EXT   0x2006
+   #define  WGL_SWAP_METHOD_EXT   0x2007
+   #define  WGL_NUMBER_OVERLAYS_EXT   0x2008
+   #define  WGL_NUMBER_UNDERLAYS_EXT   0x2009
+   #define  WGL_TRANSPARENT_EXT   0x200A
+   #define  WGL_TRANSPARENT_VALUE_EXT   0x200B
+   #define  WGL_SHARE_DEPTH_EXT   0x200C
+   #define  WGL_SHARE_STENCIL_EXT   0x200D
+   #define  WGL_SHARE_ACCUM_EXT   0x200E
+   #define  WGL_SUPPORT_GDI_EXT   0x200F
+   #define  WGL_SUPPORT_OPENGL_EXT   0x2010
+   #define  WGL_DOUBLE_BUFFER_EXT   0x2011
+   #define  WGL_STEREO_EXT   0x2012
+   #define  WGL_PIXEL_TYPE_EXT   0x2013
+   #define  WGL_COLOR_BITS_EXT   0x2014
+   #define  WGL_RED_BITS_EXT   0x2015
+   #define  WGL_RED_SHIFT_EXT   0x2016
+   #define  WGL_GREEN_BITS_EXT   0x2017
+   #define  WGL_GREEN_SHIFT_EXT   0x2018
+   #define  WGL_BLUE_BITS_EXT   0x2019
+   #define  WGL_BLUE_SHIFT_EXT   0x201A
+   #define  WGL_ALPHA_BITS_EXT   0x201B
+   #define  WGL_ALPHA_SHIFT_EXT   0x201C
+   #define  WGL_ACCUM_BITS_EXT   0x201D
+   #define  WGL_ACCUM_RED_BITS_EXT   0x201E
+   #define  WGL_ACCUM_GREEN_BITS_EXT   0x201F
+   #define  WGL_ACCUM_BLUE_BITS_EXT   0x2020
+   #define  WGL_ACCUM_ALPHA_BITS_EXT   0x2021
+   #define  WGL_DEPTH_BITS_EXT   0x2022
+   #define  WGL_STENCIL_BITS_EXT   0x2023
+   #define  WGL_AUX_BUFFERS_EXT   0x2024
+   #define  WGL_NO_ACCELERATION_EXT   0x2025
+   #define  WGL_GENERIC_ACCELERATION_EXT   0x2026
+   #define  WGL_FULL_ACCELERATION_EXT   0x2027
+   #define  WGL_SWAP_EXCHANGE_EXT   0x2028
+   #define  WGL_SWAP_COPY_EXT   0x2029
+   #define  WGL_SWAP_UNDEFINED_EXT   0x202A
+   #define  WGL_TYPE_RGBA_EXT   0x202B
+   #define  WGL_TYPE_COLORINDEX_EXT   0x202C
+   #define  WGL_DRAW_TO_PBUFFER_EXT   0x202D
+   #define  WGL_MAX_PBUFFER_PIXELS_EXT   0x202E
+   #define  WGL_MAX_PBUFFER_WIDTH_EXT   0x202F
+   #define  WGL_MAX_PBUFFER_HEIGHT_EXT   0x2030
+   #define  WGL_OPTIMAL_PBUFFER_WIDTH_EXT   0x2031
+   #define  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT   0x2032
+   #define  WGL_PBUFFER_LARGEST_EXT   0x2033
+   #define  WGL_PBUFFER_WIDTH_EXT   0x2034
+   #define  WGL_PBUFFER_HEIGHT_EXT   0x2035
+   #define  WGL_DEPTH_FLOAT_EXT   0x2040
+   #define  WGL_SAMPLE_BUFFERS_3DFX   0x2060
+   #define  WGL_SAMPLES_3DFX   0x2061
+   #define  WGL_SAMPLE_BUFFERS_EXT   0x2041
+   #define  WGL_SAMPLES_EXT   0x2042
+   #define  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D   0x2044
+   #define  WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D   0x2045
+   #define  WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D   0x2046
+   #define  WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D   0x2047
+   #define  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D   0x2048
+   #define  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D   0x2049
+   #define  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D   0x204A
+   #define  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D   0x204B
+   #define  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D   0x204C
+   #define  WGL_GAMMA_TABLE_SIZE_I3D   0x204E
+   #define  WGL_GAMMA_EXCLUDE_DESKTOP_I3D   0x204F
+   #define  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D   0x2050
+   #define  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D   0x2051
+   #define  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D   0x2052
+   #define  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D   0x2053
+   #define  WGL_ARB_buffer_region   1
+   #define  WGL_ARB_extensions_string   1
+   #define  WGL_ARB_pixel_format   1
+   #define  WGL_ARB_make_current_read   1
+   #define  WGL_ARB_pbuffer   1
+   #define  WGL_EXT_display_color_table   1
+   #define  WGL_EXT_extensions_string   1
+   #define  WGL_EXT_make_current_read   1
+   #define  WGL_EXT_pbuffer   1
+   #define  WGL_EXT_pixel_format   1
+   #define  WGL_EXT_swap_control   1
+   #define  WGL_WGL_EXT_depth_float   1
+   #define  WGL_WGL_3DFX_multisample   1
+   #define  WGL_WGL_EXT_multisample   1
+   #define  WGL_NV_allocate_memory   1
 
-/*
-typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
-typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target);
-typedef void (APIENTRY * PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
-typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
-*/
-
-/*
-typedef int (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
-typedef int (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
-typedef int (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
-typedef int (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);
-*/
-typedef int (APIENTRY * PFNWGLCHOOSEPIXELFORMATARBPROC) ();
-typedef void * (APIENTRY * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
-typedef HDC (APIENTRY * PFNWGLGETPBUFFERDCARBPROC) (void * hPbuffer);
-typedef int (APIENTRY * PFNWGLRELEASEPBUFFERDCARBPROC) (void * hPbuffer, HDC hDC);
-typedef BOOL (APIENTRY * PFNWGLDESTROYPBUFFERARBPROC) (void * hPbuffer);
-typedef BOOL (APIENTRY * PFNWGLQUERYPBUFFERARBPROC) (void * hPbuffer, int iAttribute, int *piValue);
-
-static PFNGLMAPBUFFERARBPROC glMapBufferARB = null;
-static PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = null;
-static PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = null;
-static PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = null;
-static PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = null;
-static PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = null;
-static PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = null;
-static PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = null;
-
-static PFNGLGENBUFFERSARBPROC glGenBuffersARB = null;
-static PFNGLBINDBUFFERARBPROC glBindBufferARB = null;
-static PFNGLBUFFERDATAARBPROC glBufferDataARB = null;
-static PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = null;
-static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = null;
-static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = null;
-static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = null;
-static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB = null;
-static PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB = null;
-static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = null;
-static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB = null;
-static PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB = null;
-static PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB = null;
-
-#ifdef WGL_WGLEXT_PROTOTYPES
-extern BOOL WINAPI wglSwapIntervalEXT (int);
-extern int WINAPI wglGetSwapIntervalEXT (void);
-#endif /* WGL_WGLEXT_PROTOTYPES */
-typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
-typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
-
-static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
+   /*
+   typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);
+   typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+   typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target);
+   typedef void (APIENTRY * PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+   typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
+   */
 
-#else
+   /*
+   typedef int (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+   typedef int (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+   typedef int (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+   typedef int (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);
+   */
+   typedef int (APIENTRY * PFNWGLCHOOSEPIXELFORMATARBPROC) ();
+   typedef void * (APIENTRY * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
+   typedef HDC (APIENTRY * PFNWGLGETPBUFFERDCARBPROC) (void * hPbuffer);
+   typedef int (APIENTRY * PFNWGLRELEASEPBUFFERDCARBPROC) (void * hPbuffer, HDC hDC);
+   typedef BOOL (APIENTRY * PFNWGLDESTROYPBUFFERARBPROC) (void * hPbuffer);
+   typedef BOOL (APIENTRY * PFNWGLQUERYPBUFFERARBPROC) (void * hPbuffer, int iAttribute, int *piValue);
+   typedef const char * (APIENTRY * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
+   typedef BOOL (APIENTRY * PFNWGLBINDTEXIMAGEARBPROC) (void * hPbuffer, int iBuffer);
+   typedef BOOL (APIENTRY * PFNWGLRELEASETEXIMAGEARBPROC) (void * hPbuffer, int iBuffer);
+
+   static PFNGLMAPBUFFERARBPROC glMapBufferARB = null;
+   static PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = null;
+   static PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = null;
+   static PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = null;
+   static PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = null;
+   static PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = null;
+   static PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = null;
+   static PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = null;
+
+   static PFNGLGENBUFFERSARBPROC glGenBuffersARB = null;
+   static PFNGLBINDBUFFERARBPROC glBindBufferARB = null;
+   static PFNGLBUFFERDATAARBPROC glBufferDataARB = null;
+   static PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = null;
+   static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = null;
+   static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = null;
+   static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = null;
+   static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB = null;
+   static PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB = null;
+   static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = null;
+   static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB = null;
+   static PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB = null;
+   static PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB = null;
+
+   #define glBufferData glBufferDataARB
+
+   #ifdef WGL_WGLEXT_PROTOTYPES
+   extern BOOL WINAPI wglSwapIntervalEXT (int);
+   extern int WINAPI wglGetSwapIntervalEXT (void);
+   #endif /* WGL_WGLEXT_PROTOTYPES */
+   typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
+   typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
+
+   static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
+
+#elif defined(__ANDROID__) || defined(__ODROID__)
+
+   #define GL_FRAMEBUFFER           GL_FRAMEBUFFER_OES
+   #define GL_RENDERBUFFER          GL_RENDERBUFFER_OES
+   #define GL_COLOR_ATTACHMENT0     GL_COLOR_ATTACHMENT0_OES
+
+   #define GL_POLYGON_STIPPLE 0xFFFF
+   #define GL_LINE_STIPPLE 0xFFFF
+   #define GL_LINE 0xFFFF
+   #define GL_FILL 0xFFFF
+   #define GL_ALL_ATTRIB_BITS 0xFFFF
+   #define GL_LIGHT_MODEL_LOCAL_VIEWER 0xFFFF
+
+   #define GL_POLYGON      9
+   #define GL_QUADS        7
+
+   //#define GL_QUADS              0
+   #define GL_QUAD_STRIP         0
+   //#define GL_DOUBLE             0
+   //#define GL_UNSIGNED_INT       0
+   //#define GL_FILL               0
+   //#define GL_LINE               0
+   //#define GL_LINE_STIPPLE       0
+   #define GL_BGRA_EXT           0
+   #define GL_UNPACK_ROW_LENGTH  0
+   #define GL_UNPACK_SKIP_PIXELS 0
+   #define GL_UNPACK_SKIP_ROWS   0
+   #define GL_RGBA8              0
+   #define GL_PACK_ROW_LENGTH    0
+   #define GL_PACK_SKIP_ROWS     0
+   #define GL_PACK_SKIP_PIXELS   0
 
-#if defined(__ANDROID__)
+#endif
 
-// OpenGL ES Porting Kit
-
-#define glBindFramebuffer        glBindFramebufferOES
-#define glBindRenderbuffer       glBindRenderbufferOES
-#define GL_FRAMEBUFFER           GL_FRAMEBUFFER_OES
-#define GL_RENDERBUFFER          GL_RENDERBUFFER_OES
-#define glFramebufferTexture2D   glFramebufferTexture2DOES
-#define GL_COLOR_ATTACHMENT0     GL_COLOR_ATTACHMENT0_OES
-#define glGenFramebuffers        glGenFramebuffersOES
-#define glGenRenderbuffers       glGenRenderbuffersOES
-#define glDeleteFramebuffers     glDeleteFramebuffersOES
-#define glDeleteRenderbuffers    glDeleteRenderbuffersOES
-
-#define GL_POLYGON_STIPPLE 0xFFFF
-#define GL_LINE_STIPPLE 0xFFFF
-#define GL_LINE 0xFFFF
-#define GL_FILL 0xFFFF
-#define GL_ALL_ATTRIB_BITS 0xFFFF
-#define GL_LIGHT_MODEL_LOCAL_VIEWER 0xFFFF
-#define glDrawElementsi(type, count, start)  glDrawElements(type, count, GL_UNSIGNED_SHORT, start)
-
-#define GL_POLYGON      9
-#define GL_QUADS        7
-
-#define glBufferDatai         glesBufferDatai
-#define glBufferDatad         glesBufferDatad
-#define glVertexPointeri      glesVertexPointeri
-#define glVertexPointerd      glesVertexPointerd
-
-#define glRecti               glesRecti
-#define glBegin               glesBegin
-#define glTexCoord2i          glesTexCoord2i
-#define glVertex2i            glesVertex2i
-#define glTexCoord2d          glesTexCoord2d
-#define glVertex2d            glesVertex2d
-#define glTexCoord2f          glesTexCoord2f
-#define glVertex2f            glesVertex2f
-#define glEnd                 glesEnd
-#define glColor3f             glesColor3f
-#define glColor4ub            glesColor4ub
-#define glColor4fv            glesColor4fv
-#define glLineStipple         glesLineStipple
-#define glNormal3fv           glesNormal3fv
-#define glTexCoord2fv         glesTexCoord2fv
-#define glColorMaterial       glesColorMaterial
-
-#define glLoadMatrixd         glesLoadMatrixd
-#define glMultMatrixd         glesMultMatrixd
-#define glFrustum             glesFrustum
-#define glOrtho               glesOrtho
-#define glScaled              glesScaled
-#define glTranslated          glesTranslated
-#define glRotated             glesRotated
-#define glVertex3d            glesVertex3d
-#define glVertex3f            glesVertex3f
-#define glVertex3fv           glesVertex3fv
-#define glLightModeli         glesLightModeli
-
-#define APIENTRY
-//#define GL_QUADS              0
-#define GL_QUAD_STRIP         0
-#define GL_DOUBLE             0
-#define GL_UNSIGNED_INT       0
-//#define GL_FILL               0
-//#define GL_LINE               0
-//#define GL_LINE_STIPPLE       0
-#define GL_BGRA_EXT           0
-#define GL_UNPACK_ROW_LENGTH  0
-#define GL_UNPACK_SKIP_PIXELS 0
-#define GL_UNPACK_SKIP_ROWS   0
-#define GL_RGBA8              0
-#define GL_PACK_ROW_LENGTH    0
-#define GL_PACK_SKIP_ROWS     0
-#define GL_PACK_SKIP_PIXELS   0
-
-static EGLDisplay eglDisplay;
-static EGLSurface eglSurface;
-static EGLContext eglContext;
-static int eglWidth, eglHeight;
-
-static bool egl_init_display(ANativeWindow* window)
+#if defined(ECERE_NO3D) || defined(ECERE_VANILLA)
+public union Matrix
 {
-   const EGLint attribs[] =
-   {
-      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-      EGL_BLUE_SIZE, 8,
-      EGL_GREEN_SIZE, 8,
-      EGL_RED_SIZE, 8,
-      EGL_DEPTH_SIZE, 24,
-      EGL_NONE
-   };
-   EGLint w, h, dummy, format;
-   EGLint numConfigs;
-   EGLConfig config;
-   EGLSurface surface;
-   EGLContext context;
+   double array[16];
+   double m[4][4];
 
-   EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-   eglInitialize(display, 0, 0);
-   eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-   eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+   void Identity()
+   {
+      FillBytesBy4(this, 0, sizeof(Matrix) >> 2);
+      m[0][0]=m[1][1]=m[2][2]=m[3][3]=1;
+   }
 
-   surface = eglCreateWindowSurface(display, config, window, null);
-   context = eglCreateContext(display, config, null, null);
+   void Transpose(Matrix source)
+   {
+      int i,j;
+      for(i=0; i<4; i++)
+         for(j=0; j<4; j++)
+            m[j][i] = source.m[i][j];
+   }
 
-   if(!eglMakeCurrent(display, surface, surface, context))
-      return false;
+   void Multiply(Matrix a, Matrix b)
+   {
+      // We need a full matrix multiplication for the Projection matrix
+      m[0][0]=a.m[0][0]*b.m[0][0] + a.m[0][1]*b.m[1][0] + a.m[0][2]*b.m[2][0] + a.m[0][3]*b.m[3][0];
+      m[0][1]=a.m[0][0]*b.m[0][1] + a.m[0][1]*b.m[1][1] + a.m[0][2]*b.m[2][1] + a.m[0][3]*b.m[3][1];
+      m[0][2]=a.m[0][0]*b.m[0][2] + a.m[0][1]*b.m[1][2] + a.m[0][2]*b.m[2][2] + a.m[0][3]*b.m[3][2];
+      m[0][3]=a.m[0][0]*b.m[0][3] + a.m[0][1]*b.m[1][3] + a.m[0][2]*b.m[2][3] + a.m[0][3]*b.m[3][3];
+
+      m[1][0]=a.m[1][0]*b.m[0][0] + a.m[1][1]*b.m[1][0] + a.m[1][2]*b.m[2][0] + a.m[1][3]*b.m[3][0];
+      m[1][1]=a.m[1][0]*b.m[0][1] + a.m[1][1]*b.m[1][1] + a.m[1][2]*b.m[2][1] + a.m[1][3]*b.m[3][1];
+      m[1][2]=a.m[1][0]*b.m[0][2] + a.m[1][1]*b.m[1][2] + a.m[1][2]*b.m[2][2] + a.m[1][3]*b.m[3][2];
+      m[1][3]=a.m[1][0]*b.m[0][3] + a.m[1][1]*b.m[1][3] + a.m[1][2]*b.m[2][3] + a.m[1][3]*b.m[3][3];
+
+      m[2][0]=a.m[2][0]*b.m[0][0] + a.m[2][1]*b.m[1][0] + a.m[2][2]*b.m[2][0] + a.m[2][3]*b.m[3][0];
+      m[2][1]=a.m[2][0]*b.m[0][1] + a.m[2][1]*b.m[1][1] + a.m[2][2]*b.m[2][1] + a.m[2][3]*b.m[3][1];
+      m[2][2]=a.m[2][0]*b.m[0][2] + a.m[2][1]*b.m[1][2] + a.m[2][2]*b.m[2][2] + a.m[2][3]*b.m[3][2];
+      m[2][3]=a.m[2][0]*b.m[0][3] + a.m[2][1]*b.m[1][3] + a.m[2][2]*b.m[2][3] + a.m[2][3]*b.m[3][3];
+
+      m[3][0]=a.m[3][0]*b.m[0][0] + a.m[3][1]*b.m[1][0] + a.m[3][2]*b.m[2][0] + a.m[3][3]*b.m[3][0];
+      m[3][1]=a.m[3][0]*b.m[0][1] + a.m[3][1]*b.m[1][1] + a.m[3][2]*b.m[2][1] + a.m[3][3]*b.m[3][1];
+      m[3][2]=a.m[3][0]*b.m[0][2] + a.m[3][1]*b.m[1][2] + a.m[3][2]*b.m[2][2] + a.m[3][3]*b.m[3][2];
+      m[3][3]=a.m[3][0]*b.m[0][3] + a.m[3][1]*b.m[1][3] + a.m[3][2]*b.m[2][3] + a.m[3][3]*b.m[3][3];
+   }
+};
+#endif
 
-   eglQuerySurface(display, surface, EGL_WIDTH, &w);
-   eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+// Our own matrix stack
+static Matrix matrixStack[3][32];
+static int matrixIndex[3];
+static int curStack = 0;
+
+#if defined(_GLES)
+
+   // OpenGL ES Porting Kit
+#if defined(__ANDROID__) || defined(__ODROID__)
+   #define glBindFramebuffer        glBindFramebufferOES
+   #define glBindRenderbuffer       glBindRenderbufferOES
+   #define glFramebufferTexture2D   glFramebufferTexture2DOES
+   #define glGenFramebuffers        glGenFramebuffersOES
+   #define glGenRenderbuffers       glGenRenderbuffersOES
+   #define glDeleteFramebuffers     glDeleteFramebuffersOES
+   #define glDeleteRenderbuffers    glDeleteRenderbuffersOES
+
+   #define GL_INT                                  0x1404
+   #define GL_UNSIGNED_INT                         0x1405
+   #define GL_DOUBLE                               0x140A
+   #define APIENTRY
+#endif
 
-   eglDisplay = display;
-   eglContext = context;
-   eglSurface = surface;
-   eglWidth = w;
-   eglHeight = h;
+   #define glDrawElementsi(type, count, start)  glDrawElements(type, count, GL_UNSIGNED_SHORT, start)
+
+   #define glBufferDatai         glesBufferDatai
+   #define glBufferDatad         glesBufferDatad
+   #define glVertexPointeri      glesVertexPointeri
+   #define glVertexPointerd      glesVertexPointerd
+
+   #define glRecti               glesRecti
+   #define glBegin               glesBegin
+   #define glTexCoord2i          glesTexCoord2i
+   #define glVertex2i            glesVertex2i
+   #define glTexCoord2d          glesTexCoord2d
+   #define glVertex2d            glesVertex2d
+   #define glTexCoord2f          glesTexCoord2f
+   #define glVertex2f            glesVertex2f
+   #define glEnd                 glesEnd
+   #define glColor3f             glesColor3f
+   #define glColor4ub            glesColor4ub
+   #define glColor4fv            glesColor4fv
+   #define glLineStipple         glesLineStipple
+   #define glNormal3fv           glesNormal3fv
+   #define glNormal3f            glesNormal3f
+   #define glTexCoord2fv         glesTexCoord2fv
+   #define glColorMaterial       glesColorMaterial
+
+   #define glLoadMatrixd         glesLoadMatrixd
+   #define glMultMatrixd         glesMultMatrixd
+   #define glFrustum             glesFrustum
+   #define glOrtho               glesOrtho
+   #define glScaled              glesScaled
+   #define glTranslated          glesTranslated
+   #define glRotated             glesRotated
+   #define glVertex3d            glesVertex3d
+   #define glVertex3dv           glesVertex3dv
+   #define glVertex3f            glesVertex3f
+   #define glVertex3fv           glesVertex3fv
+   #define glLightModeli         glesLightModeli
 
-   glEnableClientState(GL_VERTEX_ARRAY);
-   /*
-   // Initialize GL state.
-   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
-   glEnable(GL_CULL_FACE);
-   glShadeModel(GL_SMOOTH);
-   glDisable(GL_DEPTH_TEST);
-   */
-   glDisable(GL_CULL_FACE);
-   glDisable(GL_DEPTH_TEST);
+#else
 
-   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-   glEnable(GL_BLEND);
+#define glVertexPointerd(nc, s, p, nv)       glVertexPointer(nc, GL_DOUBLE, s, p)
+#define glDrawElementsi(type, count, start)  glDrawElements(type, count, GL_UNSIGNED_INT, start)
 
-   glMatrixMode(GL_MODELVIEW);
-   glScalef(1.0f, 1.0f, -1.0f);
-   glMatrixMode(GL_PROJECTION);
-   glShadeModel(GL_FLAT);
+#endif
 
-   glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
-   glFogi(GL_FOG_MODE, GL_EXP);
-   glFogf(GL_FOG_DENSITY, 0);
-   glEnable(GL_NORMALIZE);
-   glDepthFunc(GL_LESS);
-   glClearDepth(1.0);
-   glDisable(GL_MULTISAMPLE_ARB);
+#if defined(__ANDROID__) || defined(__ODROID__)
+   static EGLDisplay eglDisplay;
+   static EGLSurface eglSurface;
+   static EGLContext eglContext;
+   static int eglWidth, eglHeight;
 
-   glViewport(0,0,w,h);
-   glLoadIdentity();
-   glOrtho(0,w,h,0,0.0,1.0);
-   return true;
-}  
+#if defined(__ANDROID__)
+   static bool egl_init_display(ANativeWindow* window)
+#else
+   static bool egl_init_display(uint window)
+#endif
+   {
+      const EGLint attribs[] =
+      {
+         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+         EGL_BLUE_SIZE, 8,
+         EGL_GREEN_SIZE, 8,
+         EGL_RED_SIZE, 8,
+         EGL_DEPTH_SIZE, 16, //24,
+         /*EGL_SAMPLE_BUFFERS, 1,
+         EGL_SAMPLES, 0, //2,*/
+         EGL_NONE
+      };
+      EGLint w, h, format;
+      EGLint numConfigs;
+      EGLConfig config;
+      EGLSurface surface;
+      EGLContext context;
 
-static void egl_term_display()
-{
-   if(eglDisplay != EGL_NO_DISPLAY)
-   {
-      eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-      if(eglContext != EGL_NO_CONTEXT)
-         eglDestroyContext(eglDisplay, eglContext);
-      if(eglSurface != EGL_NO_SURFACE)
-         eglDestroySurface(eglDisplay, eglSurface);
-      eglTerminate(eglDisplay);
-   }
-   eglDisplay = EGL_NO_DISPLAY;
-   eglContext = EGL_NO_CONTEXT;
-   eglSurface = EGL_NO_SURFACE;
-}
+      EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+      eglInitialize(display, 0, 0);
+      eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+      eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+
+      surface = eglCreateWindowSurface(display, config, window, null);
+      context = eglCreateContext(display, config, null, null);
+
+      if(!eglMakeCurrent(display, surface, surface, context))
+         return false;
+
+      eglQuerySurface(display, surface, EGL_WIDTH, &w);
+      eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+
+      eglDisplay = display;
+      eglContext = context;
+      eglSurface = surface;
+      eglWidth = w;
+      eglHeight = h;
+
+      glEnableClientState(GL_VERTEX_ARRAY);
+      /*
+      // Initialize GL state.
+      glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+      glEnable(GL_CULL_FACE);
+      glShadeModel(GL_SMOOTH);
+      glDisable(GL_DEPTH_TEST);
+      */
+      glDisable(GL_CULL_FACE);
+      glDisable(GL_DEPTH_TEST);
+
+      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      glEnable(GL_BLEND);
+
+      matrixStack[0][0].Identity();
+      matrixStack[1][0].Identity();
+      matrixStack[2][0].Identity();
+
+      glesMatrixMode(GL_MODELVIEW);
+      glScaled(1.0, 1.0, -1.0);
+      glesMatrixMode(GL_PROJECTION);
+      glShadeModel(GL_FLAT);
+
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+      glFogi(GL_FOG_MODE, GL_EXP);
+      glFogf(GL_FOG_DENSITY, 0);
+      glEnable(GL_NORMALIZE);
+      glDepthFunc(GL_LESS);
+      glClearDepth(1.0);
+      glDisable(GL_MULTISAMPLE_ARB);
+
+      glViewport(0,0,w,h);
+      glesLoadIdentity();
+      glOrtho(0,w,h,0,0.0,1.0);
+
+      curArrayBuffer = 0;
+      curElementBuffer = 0;
+      return true;
+   }
+
+   static void egl_term_display()
+   {
+      if(stippleTexture)
+      {
+         glDeleteTextures(1, &stippleTexture);
+         stippleTexture = 0;
+      }
+      if(eglDisplay != EGL_NO_DISPLAY)
+      {
+         eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+         if(eglContext != EGL_NO_CONTEXT)
+            eglDestroyContext(eglDisplay, eglContext);
+         if(eglSurface != EGL_NO_SURFACE)
+            eglDestroySurface(eglDisplay, eglSurface);
+         eglTerminate(eglDisplay);
+      }
+      eglDisplay = EGL_NO_DISPLAY;
+      eglContext = EGL_NO_CONTEXT;
+      eglSurface = EGL_NO_SURFACE;
+   }
+
+#endif
 
 // OpenGL Immediate Mode Porting Kit
 static int beginCount;
@@ -528,11 +697,14 @@ static int vertexCount;
 static int normalCount;
 static float *vertexPointer;
 static float *normalPointer;
-static GLenum beginMode;
-static unsigned int beginBufferSize, normalBufferSize;
+static GLenum beginMode = -1;
+static uint beginBufferSize, normalBufferSize;
 static int numVertexCoords = 2;
+static bool vertexColorValues = false;
+static int vertexStride = 4;
+static int vertexOffset = 2;
 
-void glesRecti(int a, int b, int c, int d)
+public void glesRecti(int a, int b, int c, int d)
 {
    glBegin(GL_QUADS);
    glVertex2i(a, b);
@@ -542,94 +714,111 @@ void glesRecti(int a, int b, int c, int d)
    glEnd();
 }
 
-void glesBegin(GLenum mode)
+public void glesBegin(GLenum mode)
 {
    beginMode = mode;
    beginCount = 0;
    vertexCount = 0;
+   vertexColorValues = false;
+   vertexOffset = 2;
+   vertexStride = 4;
+   numVertexCoords = 2;
+
    if(!vertexPointer)
    {
       normalBufferSize = beginBufferSize = 1024;  // default number of vertices
-      vertexPointer = new float[beginBufferSize * 5];
+      vertexPointer = new float[beginBufferSize * vertexStride];
       normalPointer = new float[normalBufferSize * 3];
    }
 }
 
-void glesTexCoord2f(float x, float y)
+public void glesTexCoord2f(float x, float y)
 {
    int count = vertexCount;
 
    if(vertexCount + numVertexCoords > beginBufferSize)
    {
       beginBufferSize = beginBufferSize + beginBufferSize/2;
-      vertexPointer = renew vertexPointer float[beginBufferSize * 5];
+      vertexPointer = renew vertexPointer float[beginBufferSize * vertexStride];
    }
 
-   vertexPointer[count*(2+numVertexCoords)  ] = x;
-   vertexPointer[count*(2+numVertexCoords)+1] = y;
+   vertexPointer[count*vertexStride  ] = x;
+   vertexPointer[count*vertexStride+1] = y;
    count++;
 
    if(beginMode == GL_QUADS && ((beginCount % 4) == 3))
    {
-      vertexPointer[count*(2+numVertexCoords)  ] = vertexPointer[(count-4)*(2+numVertexCoords)];
-      vertexPointer[count*(2+numVertexCoords)+1] = vertexPointer[(count-4)*(2+numVertexCoords)+1];
+      vertexPointer[count*vertexStride  ] = vertexPointer[(count-4)*vertexStride];
+      vertexPointer[count*vertexStride+1] = vertexPointer[(count-4)*vertexStride+1];
       count++;
-      vertexPointer[count*(2+numVertexCoords)  ] = vertexPointer[(count-3)*(2+numVertexCoords)];
-      vertexPointer[count*(2+numVertexCoords)+1] = vertexPointer[(count-3)*(2+numVertexCoords)+1];
+      vertexPointer[count*vertexStride  ] = vertexPointer[(count-3)*vertexStride];
+      vertexPointer[count*vertexStride+1] = vertexPointer[(count-3)*vertexStride+1];
       count++;
    }
-} 
-void glesTexCoord2i(int x, int y)       { glesTexCoord2f((float)x, (float)y); }
-void glesTexCoord2d(double x, double y) { glesTexCoord2f((float)x, (float)y); }
-void glesTexCoord2fv(float * a)         { glesTexCoord2f(a[0], a[1]); }
+}
+public void glesTexCoord2i(int x, int y)       { glesTexCoord2f((float)x, (float)y); }
+public void glesTexCoord2d(double x, double y) { glesTexCoord2f((float)x, (float)y); }
+public void glesTexCoord2fv(float * a)         { glesTexCoord2f(a[0], a[1]); }
 
-void glesVertex2f(float x, float y)
+public void glesVertex2f(float x, float y)
 {
    numVertexCoords = 2;
+   vertexStride = vertexOffset + numVertexCoords;
+
    if(vertexCount + 4 > beginBufferSize)
    {
       beginBufferSize = beginBufferSize + beginBufferSize/2;
-      vertexPointer = renew vertexPointer float[beginBufferSize * 5];
+      vertexPointer = renew vertexPointer float[beginBufferSize * vertexStride];
    }
 
-   vertexPointer[vertexCount*4+2] = x;
-   vertexPointer[vertexCount*4+3] = y;
+   vertexPointer[vertexCount*vertexStride+vertexOffset] = x;
+   vertexPointer[vertexCount*vertexStride+vertexOffset + 1] = y;
    vertexCount++;
 
    if(beginMode == GL_QUADS && ((beginCount % 4) == 3))
    {
-      vertexPointer[vertexCount*4+2] = vertexPointer[(vertexCount-4)*4+2];
-      vertexPointer[vertexCount*4+3] = vertexPointer[(vertexCount-4)*4+3];
+      vertexPointer[vertexCount*vertexStride+vertexOffset] = vertexPointer[(vertexCount-4)*vertexStride+vertexOffset];
+      vertexPointer[vertexCount*vertexStride+vertexOffset + 1] = vertexPointer[(vertexCount-4)*vertexStride+vertexOffset + 1];
       vertexCount++;
-      vertexPointer[vertexCount*4+2] = vertexPointer[(vertexCount-3)*4+2];
-      vertexPointer[vertexCount*4+3] = vertexPointer[(vertexCount-3)*4+3];
+      vertexPointer[vertexCount*vertexStride+vertexOffset] = vertexPointer[(vertexCount-3)*vertexStride+vertexOffset];
+      vertexPointer[vertexCount*vertexStride+vertexOffset + 1] = vertexPointer[(vertexCount-3)*vertexStride+vertexOffset + 1];
       vertexCount++;
    }
    beginCount++;
 }
-void glesVertex2i(int x, int y)         { glesVertex2f((float)x, (float)y); }
-void glesVertex2d(double x, double y)   { glesVertex2f((float)x, (float)y); }
+public void glesVertex2i(int x, int y)         { glesVertex2f((float)x, (float)y); }
+public void glesVertex2d(double x, double y)   { glesVertex2f((float)x, (float)y); }
 
-void glesEnd(void)
+public void glesEnd(void)
 {
    int mode = beginMode;
    if(mode == GL_QUADS)        mode = GL_TRIANGLES;
    else if(mode == GL_POLYGON) mode = GL_TRIANGLE_FAN;
-   GLSelectVBO(0);
+
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-   glTexCoordPointer(numVertexCoords, GL_FLOAT, (numVertexCoords+2)*sizeof(float),vertexPointer);
-   glVertexPointer  (numVertexCoords, GL_FLOAT, (numVertexCoords+2)*sizeof(float),vertexPointer+2);
+   noAB.use(texCoord, 2, GL_FLOAT, vertexStride * sizeof(float), vertexPointer);
+   if(vertexColorValues)
+   {
+      glEnableClientState(GL_COLOR_ARRAY);
+      noAB.use(color, 4, GL_FLOAT, vertexStride * sizeof(float), vertexPointer + 2);
+   }
+   noAB.use(vertex, numVertexCoords, GL_FLOAT, (vertexStride)*sizeof(float),vertexPointer+vertexOffset);
    if(normalCount && normalCount == vertexCount)
    {
       glEnableClientState(GL_NORMAL_ARRAY);
-      glNormalPointer  (GL_FLOAT, 3*sizeof(float),normalPointer);
+      noAB.use(normal, 3, GL_FLOAT, 3*sizeof(float),normalPointer);
    }
 
    glDrawArrays(mode, 0, vertexCount);
    if(normalCount)
       glDisableClientState(GL_NORMAL_ARRAY);
+   if(vertexColorValues)
+      glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    normalCount = 0;
+   vertexColorValues = false;
+   numVertexCoords = 2;
+   beginMode = -1;
 }
 
 // Vertex Pointer
@@ -642,7 +831,7 @@ static unsigned int shortVPSize = 0, floatVPSize = 0;
 static unsigned short *shortBDBuffer = null;
 static unsigned int shortBDSize = 0/*, floatVPSize = 0*/;
 
-void glesVertexPointeri(int numCoords, int stride, int *pointer, int numVertices)
+public void glesVertexPointeri(int numCoords, int stride, int *pointer, int numVertices)
 {
    if(pointer)
    {
@@ -660,7 +849,7 @@ void glesVertexPointeri(int numCoords, int stride, int *pointer, int numVertices
       glVertexPointer(numCoords, GL_SHORT, stride, 0);
 }
 
-void glesVertexPointerd(int numCoords, int stride, double *pointer, int numVertices)
+public void glesVertexPointerd(int numCoords, int stride, double *pointer, int numVertices)
 {
    if(pointer)
    {
@@ -678,32 +867,72 @@ void glesVertexPointerd(int numCoords, int stride, double *pointer, int numVerti
       glVertexPointer(numCoords, GL_FLOAT, stride, 0);
 }
 
-void glesTexReuseIntVP(int numCoords)
+public void glesTexReuseIntVP(int numCoords)
 {
    glTexCoordPointer(numCoords, GL_SHORT, 0, floatVPBuffer);
 }
 
-void glesTexReuseDoubleVP(int numCoords)
+public void glesTexReuseDoubleVP(int numCoords)
 {
    glTexCoordPointer(numCoords, GL_FLOAT, 0, floatVPBuffer);
 }
 
-void glesColor3f( float r, float g, float b )
+public void glesColor4f(float r, float g, float b, float a)
+{
+   if(beginMode != (GLenum)-1)
+   {
+      int count = vertexCount;
+
+      vertexColorValues = true;
+      vertexOffset = 6;
+      vertexStride = vertexOffset + numVertexCoords;
+
+      if(vertexCount + vertexStride > beginBufferSize)
+      {
+         beginBufferSize = beginBufferSize + beginBufferSize/2;
+         vertexPointer = renew vertexPointer float[beginBufferSize * vertexStride];
+      }
+
+      vertexPointer[count*vertexStride + 2] = r;
+      vertexPointer[count*vertexStride + 3] = g;
+      vertexPointer[count*vertexStride + 4] = b;
+      vertexPointer[count*vertexStride + 5] = a;
+      count++;
+
+      if(beginMode == GL_QUADS && ((beginCount % 4) == 3))
+      {
+         vertexPointer[count*vertexStride + 2] = vertexPointer[(count-4) * vertexStride + 2];
+         vertexPointer[count*vertexStride + 3] = vertexPointer[(count-4) * vertexStride + 3];
+         vertexPointer[count*vertexStride + 4] = vertexPointer[(count-4) * vertexStride + 4];
+         vertexPointer[count*vertexStride + 5] = vertexPointer[(count-4) * vertexStride + 5];
+         count++;
+         vertexPointer[count*vertexStride + 2] = vertexPointer[(count-3) * vertexStride + 2];
+         vertexPointer[count*vertexStride + 3] = vertexPointer[(count-3) * vertexStride + 3];
+         vertexPointer[count*vertexStride + 4] = vertexPointer[(count-3) * vertexStride + 4];
+         vertexPointer[count*vertexStride + 5] = vertexPointer[(count-3) * vertexStride + 5];
+         count++;
+      }
+   }
+   else
+      glColor4f(r, g, b, a);
+}
+
+public void glesColor3f( float r, float g, float b )
 {
-   glColor4f(r, g, b, 1.0f);
+   glesColor4f(r, g, b, 1.0f);
 }
 
-void glesColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+public void glesColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
 {
-   glColor4f(r/255.0f, g/255.0f, b/255.0f, a/255.0f);
+   glesColor4f(r/255.0f, g/255.0f, b/255.0f, a/255.0f);
 }
 
-void glesColor4fv(float * a)
+public void glesColor4fv(float * a)
 {
-   glColor4f(a[0], a[1], a[2], a[3]);
+   glesColor4f(a[0], a[1], a[2], a[3]);
 }
 
-void glesBufferDatad(int target, int size, void * data, int usage)
+public void glesBufferDatad(int target, int size, void * data, int usage)
 {
    int numElems = size/sizeof(double);
    double * dblPtr = (double *)data;
@@ -719,7 +948,7 @@ void glesBufferDatad(int target, int size, void * data, int usage)
    glBufferData(target, numElems*sizeof(float), floatVPBuffer, usage);
 }
 
-void glesBufferDatai(int target, int size, void * data, int usage)
+public void glesBufferDatai(int target, int size, void * data, int usage)
 {
    int numElems = size/sizeof(unsigned int);
    unsigned int * pointer = (unsigned int *)data;
@@ -735,7 +964,153 @@ void glesBufferDatai(int target, int size, void * data, int usage)
    glBufferData(target, numElems*sizeof(unsigned short), shortBDBuffer, usage);
 }
 
-/// *** These might require an implementation to get things working ***
+// *** Our Custom Matrix Stack ***
+
+static void LoadCurMatrix()
+{
+   double * i = matrixStack[curStack][matrixIndex[curStack]].array;
+   float m[16] =
+   {
+      (float)i[0],(float)i[1],(float)i[2],(float)i[3],
+      (float)i[4],(float)i[5],(float)i[6],(float)i[7],
+      (float)i[8],(float)i[9],(float)i[10],(float)i[11],
+      (float)i[12],(float)i[13],(float)i[14],(float)i[15]
+   };
+   glLoadMatrixf(m);
+}
+
+public void glesLoadIdentity()
+{
+   matrixStack[curStack][matrixIndex[curStack]].Identity();
+   LoadCurMatrix();
+}
+
+public void glesPushMatrix()
+{
+   if(matrixIndex[curStack] + 1 < sizeof(matrixStack[0]) / sizeof(Matrix))
+   {
+      matrixIndex[curStack]++;
+      memcpy(matrixStack[curStack][matrixIndex[curStack]].array, matrixStack[curStack][matrixIndex[curStack]-1].array, sizeof(Matrix));
+   }
+}
+
+public void glesPopMatrix()
+{
+   if(matrixIndex[curStack] > 0)
+   {
+      matrixIndex[curStack]--;
+      LoadCurMatrix();
+   }
+}
+
+public void glesLoadMatrixd(double * i)
+{
+   memcpy(matrixStack[curStack][matrixIndex[curStack]].array, i, sizeof(Matrix));
+   LoadCurMatrix();
+}
+
+public void glesOrtho( double l, double r, double b, double t, double n, double f )
+{
+   Matrix m
+   { {
+      (2 / (r - l)), 0, 0, 0,
+      0, (2 / (t - b)), 0, 0,
+      0, 0, (-2 / (f - n)), 0,
+      (-(r + l) / (r - l)), (-(t + b) / (t - b)), (-(f + n) / (f - n)), 1
+   } };
+   Matrix res;
+   res.Multiply(m, matrixStack[curStack][matrixIndex[curStack]]);
+   matrixStack[curStack][matrixIndex[curStack]] = res;
+   LoadCurMatrix();
+}
+
+public void glesFrustum( double l, double r, double b, double t, double n, double f )
+{
+   nearPlane = n;
+   n = 1;
+   l /= nearPlane;
+   r /= nearPlane;
+   b /= nearPlane;
+   t /= nearPlane;
+   f /= nearPlane;
+   {
+      double A = ((r + l) / (r - l));
+      double B = ((t + b) / (t - b));
+      double C = (-(f + n) / (f - n));
+      double D = (-2*f*n/(f-n));
+      Matrix m
+      { {
+         (2.0*n / (r - l)), 0, 0, 0,
+         0, (2.0*n / (t - b)), 0, 0,
+         A, B,             C,-1,
+         0, 0,             D, 0
+      } };
+      Matrix res;
+      res.Multiply(m, matrixStack[curStack][matrixIndex[curStack]]);
+      matrixStack[curStack][matrixIndex[curStack]] = res;
+      LoadCurMatrix();
+   }
+}
+
+#if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
+public void glesRotated( double a, double b, double c, double d )
+{
+   Quaternion q;
+   Matrix m, r;
+
+   q.RotationAxis({(float)b,(float)c,(float)-d}, a );
+   m.RotationQuaternion(q);
+   r.Multiply(m, matrixStack[curStack][matrixIndex[curStack]]);
+   matrixStack[curStack][matrixIndex[curStack]] = r;
+   LoadCurMatrix();
+}
+public void glesScaled( double a, double b, double c )
+{
+   Matrix m, r;
+
+   m.Identity();
+   m.Scale(a,b,c);
+   r.Multiply(m, matrixStack[curStack][matrixIndex[curStack]]);
+   matrixStack[curStack][matrixIndex[curStack]] = r;
+   LoadCurMatrix();
+}
+
+public void glesTranslated( double a, double b, double c )
+{
+   Matrix m, r;
+
+   m.Identity();
+   m.Translate(a,b,c);
+   r.Multiply(m, matrixStack[curStack][matrixIndex[curStack]]);
+   matrixStack[curStack][matrixIndex[curStack]] = r;
+   LoadCurMatrix();
+}
+
+public void glesMultMatrixd( double * i )
+{
+   Matrix r;
+   r.Multiply((Matrix *)i, matrixStack[curStack][matrixIndex[curStack]]);
+   matrixStack[curStack][matrixIndex[curStack]] = r;
+   LoadCurMatrix();
+}
+#endif
+
+public void glesMatrixMode(int mode)
+{
+   curStack = (mode == GL_MODELVIEW) ? 0 : (mode == GL_PROJECTION) ? 1 : 2;
+   glMatrixMode(mode);
+}
+
+#if defined(_GLES)
+
+#define glPushMatrix          glesPushMatrix
+#define glPopMatrix           glesPopMatrix
+#define glLoadIdentity        glesLoadIdentity
+#define glMatrixMode          glesMatrixMode
+
+#endif
+
+/* Using the built-in matrix stack
 void glesLoadMatrixd( double * i )
 {
    float m[16] =
@@ -752,7 +1127,7 @@ void glesOrtho( double l, double r, double b, double t, double n, double f )
 {
    float matrix[4][4] =
    {
-      { (float)(2 / (r - l)), 0, 0, 0 }, 
+      { (float)(2 / (r - l)), 0, 0, 0 },
       { 0, (float)(2 / (t - b)), 0, 0 },
       { 0, 0, (float)(-2 / (f - n)), 0 },
       { (float)(-(r + l) / (r - l)), (float)(-(t + b) / (t - b)), (float)(-(f + n) / (f - n)), 1 }
@@ -760,6 +1135,22 @@ void glesOrtho( double l, double r, double b, double t, double n, double f )
    glMultMatrixf((float *)matrix);
 }
 
+void glesFrustum( double l, double r, double b, double t, double n, double f )
+{
+   float A = (float)((r + l) / (r - l));
+   float B = (float)((t + b) / (t - b));
+   float C = (float)(-(f + n) / (f - n));
+   float D = (float)(-2*f*n/(f-n));
+   float matrix[4][4] =
+   {
+      { (float)(2*n / (r - l)), 0, 0, 0 },
+      { 0, (float)(2*n / (t - b)), 0, 0 },
+      { A, B,             C,-1 },
+      { 0, 0,             D, 0 }
+   };
+   glMultMatrixf((float *)matrix);
+}
+
 void glesRotated( double a, double b, double c, double d ) { glRotatef((float)a, (float)b, (float)c, (float)d); }
 void glesScaled( double a, double b, double c ) { glScalef((float)a, (float)b, (float)c); }
 void glesTranslated( double a, double b, double c ) { glTranslatef((float)a, (float)b, (float)c); }
@@ -775,40 +1166,44 @@ void glesMultMatrixd( double * i )
    };
    glMultMatrixf(m);
 }
+*/
 
 // Need to do these...
-void glesVertex3f( float x, float y, float z )
+public void glesVertex3f( float x, float y, float z )
 {
    numVertexCoords = 3;
-   if(vertexCount + 4 > beginBufferSize)
+   vertexStride = vertexOffset + numVertexCoords;
+
+   if(vertexCount + vertexStride > beginBufferSize)
    {
       beginBufferSize = beginBufferSize + beginBufferSize/2;
-      vertexPointer = renew vertexPointer float[beginBufferSize * 5];
+      vertexPointer = renew vertexPointer float[beginBufferSize * vertexStride];
    }
 
-   vertexPointer[vertexCount*5+2] = x;
-   vertexPointer[vertexCount*5+3] = y;
-   vertexPointer[vertexCount*5+4] = z;
+   vertexPointer[vertexCount*vertexStride+vertexOffset] = x;
+   vertexPointer[vertexCount*vertexStride+vertexOffset+1] = y;
+   vertexPointer[vertexCount*vertexStride+vertexOffset+2] = z;
    vertexCount++;
 
    if(beginMode == GL_QUADS && ((beginCount % 4) == 3))
    {
-      vertexPointer[vertexCount*5+2] = vertexPointer[(vertexCount-4)*5+2];
-      vertexPointer[vertexCount*5+3] = vertexPointer[(vertexCount-4)*5+3];
-      vertexPointer[vertexCount*5+4] = vertexPointer[(vertexCount-4)*5+4];
+      vertexPointer[vertexCount*vertexStride+vertexOffset] = vertexPointer[(vertexCount-4)*vertexStride+vertexOffset];
+      vertexPointer[vertexCount*vertexStride+vertexOffset+1] = vertexPointer[(vertexCount-4)*vertexStride+vertexOffset+1];
+      vertexPointer[vertexCount*vertexStride+vertexOffset+2] = vertexPointer[(vertexCount-4)*vertexStride+vertexOffset+2];
       vertexCount++;
-      vertexPointer[vertexCount*5+2] = vertexPointer[(vertexCount-3)*5+2];
-      vertexPointer[vertexCount*5+3] = vertexPointer[(vertexCount-3)*5+3];
-      vertexPointer[vertexCount*5+4] = vertexPointer[(vertexCount-3)*5+4];
+      vertexPointer[vertexCount*vertexStride+vertexOffset] = vertexPointer[(vertexCount-3)*vertexStride+vertexOffset];
+      vertexPointer[vertexCount*vertexStride+vertexOffset+1] = vertexPointer[(vertexCount-3)*vertexStride+vertexOffset+1];
+      vertexPointer[vertexCount*vertexStride+vertexOffset+2] = vertexPointer[(vertexCount-3)*vertexStride+vertexOffset+2];
       vertexCount++;
    }
    beginCount++;
 }
 
-void glesVertex3d( double x, double y, double z )  { glesVertex3f((float)x, (float)y, (float)z); }
-void glesVertex3fv( float* coords )                { glesVertex3f(coords[0], coords[1], coords[2]); }
+public void glesVertex3d( double x, double y, double z )  { glesVertex3f((float)x, (float)y, (float)z); }
+public void glesVertex3fv( float* coords )                { glesVertex3f(coords[0], coords[1], coords[2]); }
+public void glesVertex3dv( double* coords )               { glesVertex3f((float)coords[0], (float)coords[1], (float)coords[2]); }
 
-void glesNormal3f(float x, float y, float z)
+public void glesNormal3f(float x, float y, float z)
 {
    normalCount = vertexCount;
    if(vertexCount + 4 > normalBufferSize)
@@ -834,17 +1229,18 @@ void glesNormal3f(float x, float y, float z)
       normalCount++;
    }
 }
-void glesNormal3fd(double x, double y, double z)         { glesNormal3f((float)x, (float)y, (float)z); }
-void glesNormal3fv(float * coords)                       { glesNormal3f(coords[0], coords[1], coords[2]); }
+public void glesNormal3fd(double x, double y, double z)         { glesNormal3f((float)x, (float)y, (float)z); }
+public void glesNormal3fv(float * coords)                       { glesNormal3f(coords[0], coords[1], coords[2]); }
 
-void glesColorMaterial(int a, int b)
+public void glesColorMaterial(int a, int b)
 {
    PrintLn("glColorMaterial stub");
 }
 
-void glesTerminate()
+public void glesTerminate()
 {
    delete vertexPointer;
+   delete normalPointer;
    beginBufferSize = 0;
 
    delete floatVPBuffer;
@@ -857,34 +1253,46 @@ void glesTerminate()
    shortBDSize = 0;
 }
 
-// *** We don't support stipple yet... ***
-void glesLineStipple( int i, unsigned short j )
-{
-
-}
+static GLuint stippleTexture;
+#if defined(_GLES) || defined(EM_MODE)
+static bool stippleEnabled;
+#endif
 
-void glesFrustum( double l, double r, double b, double t, double n, double f )
+public void glesLineStipple( int i, unsigned short j )
 {
-   float A = (float)((r + l) / (r - l));
-   float B = (float)((t + b) / (t - b));
-   float C = (float)(-(f + n) / (f - n));
-   float D = (float)(-2*f*n/(f-n));
-   float matrix[4][4] =
+   uint texture[1*16];
+   int x;
+   for(x = 0; x < 16; x++)
    {
-      { (float)(2*n / (r - l)), 0, 0, 0 },
-      { 0, (float)(2*n / (t - b)), 0, 0 },
-      { A, B,             C,-1 },
-      { 0, 0,             D, 0 }
-   };
-   glMultMatrixf((float *)matrix);
+      bool v = (j & (1 << x)) != 0;
+      texture[x] = v ? 0xFFFFFFFF : 0;
+   }
+   if(!stippleTexture)
+      glGenTextures(1, &stippleTexture);
+   glBindTexture(GL_TEXTURE_2D, stippleTexture);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
+   glEnable(GL_TEXTURE_2D);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+   glMatrixMode(GL_TEXTURE);
+   glLoadIdentity();
+   //glTranslated(1.0/backAttrib->texW/2.0f, 1.0/backAttrib->texH/2.0f, 0.0f);
+   glScaled(i/16.0, 1, 1.0f);
+   glTranslated(0.5, 0.5, 0);
+   glMatrixMode(GL_PROJECTION);
 }
 
-void glesLightModeli( unsigned int pname, int param )
+public void glesLightModeli( unsigned int pname, int param )
 {
+#if !defined(EM_MODE)
    if(pname == GL_LIGHT_MODEL_TWO_SIDE)
       glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, param);
+#endif
 }
 
+#if defined(__ANDROID__) || defined(__ODROID__)
 void glClearDepth( double depth ) { glClearDepthf((float)depth); }
 void glFogi( unsigned int pname, int param ) { }
 void glPolygonMode( unsigned int i, unsigned int j ) { }
@@ -896,65 +1304,252 @@ void glLoadName( unsigned int i ) { }
 void glPopName() { }
 
 // Probably replace by regular glBlendFunc ...
-void glBlendFuncSeparate(int a, int b, int c, int d) { }
+void glBlendFuncSeparate(int a, int b, int c, int d)
+{
+   glBlendFunc(a, b);
+}
 
 // For direct pixel blitting...
 void glRasterPos2d(double a, double b) { }
 void glPixelZoom(float a, float b) { }
 void glDrawPixels(int a, int b, int c, int d, void * e) { }
 
-#else
-
-/* Non OpenGL ES friendly stuff
-#undef GL_UNSIGNED_INT
-#undef GL_DOUBLE
-#undef GL_INT
-//#undef GL_POLYGON
-//#undef GL_QUADS
-#undef GL_QUAD_STRIP
-#undef GL_POLYGON_STIPPLE
-#undef GL_LINE_STIPPLE
-#undef GL_LINE
-#undef GL_FILL
-#undef GL_ALL_ATTRIB_BITS
-#undef GL_LIGHT_MODEL_LOCAL_VIEWER
-*/
-
 #endif
 
+#if !defined(__APPLE__) && !defined(__WIN32__) && !defined(__ODROID__)
 void (APIENTRY * glBindBufferARB) (GLenum target, GLuint buffer);
 void (APIENTRY * glGenBuffersARB) (GLsizei n, GLuint *buffers);
 void (APIENTRY * glDeleteBuffersARB) (GLsizei n, const GLuint *buffers);
 void (APIENTRY * glBufferDataARB) (GLenum target, int size, const GLvoid *data, GLenum usage);
+#endif
+
+public void GLLoadMatrix(Matrix matrix)
+{
+   float m[16] =
+   {
+      (float)matrix.m[0][0], (float)matrix.m[0][1], (float)matrix.m[0][2], (float)matrix.m[0][3],
+      (float)matrix.m[1][0], (float)matrix.m[1][1], (float)matrix.m[1][2], (float)matrix.m[1][3],
+      (float)matrix.m[2][0], (float)matrix.m[2][1], (float)matrix.m[2][2], (float)matrix.m[2][3],
+      (float)matrix.m[3][0], (float)matrix.m[3][1], (float)matrix.m[3][2], (float)matrix.m[3][3]
+   };
+   glLoadMatrixf(m);
+}
+
+public enum GLBufferContents { vertex, normal, texCoord, color };
+
+public define noAB = GLAB { 0 };
+
+static uint curArrayBuffer;
 
+public struct GLAB
+{
+   uint buffer;
+
+   void upload(uint size, void * data)
+   {
+      if(this != null)
+      {
+         if(!buffer)
+            GLGenBuffers(1, this);
+         if(curArrayBuffer != buffer)
+            GLBindBuffer(GL_ARRAY_BUFFER, buffer);
+         glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);  //GL_DYNAMIC_DRAW);
+      }
+   }
+
+   void free()
+   {
+      if(this != null)
+      {
+         GLDeleteBuffers(1, this);
+         buffer = 0;
+      }
+   }
+
+   void use(GLBufferContents contents, int n, int type, uint stride, void * pointer)
+   {
+      if(curArrayBuffer != ((this != null) ? buffer : 0))
+         GLBindBuffer(GL_ARRAY_BUFFER, ((this != null) ? buffer : 0));
+      switch(contents)
+      {
+         case normal:   glNormalPointer(type, stride, pointer); break;
+         case vertex:   glVertexPointer(n, type, stride, pointer); break;
+         case texCoord: glTexCoordPointer(n, type, stride, pointer); break;
+         case color:    glColorPointer(n, type, stride, pointer); break;
+      }
+   }
+
+   void useVertTrans(uint count, int n, int type, uint stride, void * pointer)
+   {
+#ifdef _GLES
+      if(curArrayBuffer != ((this != null) ? buffer : 0))
+         GLBindBuffer(GL_ARRAY_BUFFER, ((this != null) ? buffer : 0));
+      if(type == GL_INT)
+         glVertexPointeri(n, stride, pointer, count);
+      else if(type == GL_DOUBLE)
+         glVertexPointerd(n, stride, pointer, count);
+#else
+      use(vertex, n, type, stride, pointer);
 #endif
+   }
+};
+
+static uint curElementBuffer;
 
-static int currentVertexBuffer;
+public define noEAB = GLEAB { 0 };
 
-bool GLSelectVBO(uint vbo)
+public struct GLEAB
 {
-   if(currentVertexBuffer != vbo)
+   uint buffer;
+
+   void upload(uint size, void * data)
    {
-      GLBindBuffer(GL_ARRAY_BUFFER, vbo);
-      currentVertexBuffer = vbo;
-      return true;
+      if(this != null)
+      {
+         if(!buffer)
+            GLGenBuffers(1, (GLAB *)this);
+
+         if(curElementBuffer != buffer)
+            GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+         glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);  //GL_DYNAMIC_DRAW);
+      }
+   }
+
+   void free()
+   {
+      if(this != null)
+      {
+         GLDeleteBuffers(1, (GLAB *)this);
+         buffer = 0;
+      }
    }
-   return false;
+
+   void draw(int primType, int count, int type, void * indices)
+   {
+      if(curElementBuffer != ((this != null) ? buffer : 0))
+         GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((this != null) ? buffer : 0));
+#ifdef _GLES
+      type = GL_UNSIGNED_SHORT;
+#endif
+      glDrawElements(primType, count, type, indices);
+   }
+};
+
+public void GLGenBuffers(int count, GLAB * buffers)
+{
+#if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
+   glGenBuffers(count, (GLuint *)buffers);
+#else
+#if defined(__WIN32__)
+   if(glGenBuffersARB)
+#endif
+      glGenBuffersARB(count, (GLuint *)buffers);
+#endif
+}
+
+public void GLDeleteBuffers(int count, GLAB * buffers)
+{
+   int i;
+   for(i = 0; i < count; i++)
+   {
+      uint buffer = buffers[i].buffer;
+      if(buffer == curArrayBuffer)
+         GLBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
+      else if(buffer == curElementBuffer)
+         GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+   }
+#if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
+   glDeleteBuffers(count, (GLuint *)buffers);
+#else
+#if defined(__WIN32__)
+   if(glDeleteBuffersARB)
+#endif
+      glDeleteBuffersARB(count, (GLuint *)buffers);
+#endif
 }
 
 void GLBindBuffer(int target, uint buffer)
 {
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
    glBindBuffer(target, buffer);
 #else
-   glBindBufferARB(target, buffer);
+#if defined(__WIN32__)
+   if(glBindBufferARB)
 #endif
+      glBindBufferARB(target, buffer);
+#endif
+   if(target == GL_ARRAY_BUFFER_ARB)
+      curArrayBuffer = buffer;
+   else if(target == GL_ELEMENT_ARRAY_BUFFER_ARB)
+      curElementBuffer = buffer;
 }
 
+public void GLVertexPointer(int numCoords, int glType, int stride, void *ptr, int numVertices)
+{
+#ifdef _GLES
+   if(glType == GL_DOUBLE)
+      glesVertexPointerd(numCoords, stride, ptr, numVertices);
+   else if(glType == GL_INT)
+      glesVertexPointeri(numCoords, stride, ptr, numVertices);
+   else
+#endif
+      glVertexPointer(numCoords, glType, stride, ptr);
+}
+
+public void GLBufferData(int type, GLenum target, int size, const GLvoid *data, GLenum usage)
+{
+#ifdef _GLES
+   if(type == GL_DOUBLE)
+      glesBufferDatad(target, size, (void *)data, usage);
+   else if(type == GL_UNSIGNED_INT)
+      glesBufferDatai(target, size, (void *)data, usage);
+   else
+#endif
+
+#if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
+      glBufferData(target, size, data, usage);
+#else
+
+#if defined(__WIN32__)
+   if(glBufferDataARB)
+#endif
+      glBufferDataARB(target, size, data, usage);
+#endif
+}
+
+#if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
+static int primitiveTypes[RenderPrimitiveType] =
+{
+   GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_LINE_STRIP
+};
+#endif
+
+
+// Non OpenGL ES friendly stuff
+
+#if defined(_GLES)
+
+//#undef GL_UNSIGNED_INT
+//#undef GL_DOUBLE
+#undef GL_INT
+//#undef GL_POLYGON
+//#undef GL_QUADS
+#undef GL_QUAD_STRIP
+#undef GL_POLYGON_STIPPLE
+#undef GL_LINE_STIPPLE
+#undef GL_LINE
+#undef GL_FILL
+#undef GL_ALL_ATTRIB_BITS
+#undef GL_LIGHT_MODEL_LOCAL_VIEWER
+
+#endif
+
 static int displayWidth, displayHeight;
 
 #define GL_CLAMP_TO_EDGE 0x812F
 
+static bool vboAvailable;
+
 static bool useSingleGLContext = false;
 class OGLDisplay : struct
 {
@@ -971,7 +1566,7 @@ class OGLDisplay : struct
    int imageBuffers[2];
    byte * pboMemory1, * pboMemory2;
    */
-#else
+#elif !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
    GLXContext glContext;
 
    Pixmap pixmap;
@@ -996,19 +1591,20 @@ class OGLDisplay : struct
 
 class OGLSystem : struct
 {
+   int maxTextureSize;
+   bool loadingFont;
+   bool pow2textures;
 #if defined(__WIN32__)
    PIXELFORMATDESCRIPTOR pfd;
    int format;
    HDC hdc;
    HGLRC glrc;
    HWND hwnd;
-#else
+#elif !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
    XVisualInfo * visualInfo;
    GLXContext glContext;
-   Pixmap dummyPixmap;
-   GLXPixmap dummyGLXPixmap;
+   GLXDrawable glxDrawable;
 #endif
-   bool loadingFont;
 };
 
 class OGLSurface : struct
@@ -1017,29 +1613,25 @@ class OGLSurface : struct
    bool opaqueText;
    int xOffset;
    bool writingText;
+   bool writingOutline;
 
    float foreground[4], background[4], bitmapMult[4];
 } OGLSurface;
 
 class OGLMesh : struct
 {
-   int vertices;
-   int normals;
-   int texCoords;
-   int texCoords2;
-   int colors;
+   GLAB vertices;
+   GLAB normals;
+   GLAB texCoords;
+   GLAB texCoords2;
+   GLAB colors;
 };
 
 class OGLIndices : struct
 {
    uint16 * indices;
-   int buffer;
-   int nIndices;
-};
-
-static int primitiveTypes[RenderPrimitiveType] =
-{
-   GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_LINE_STRIP
+   GLEAB buffer;
+   uint nIndices;
 };
 
 int current;
@@ -1051,23 +1643,18 @@ class OpenGLDisplayDriver : DisplayDriver
 
    bool LockSystem(DisplaySystem displaySystem)
    {
+#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
       OGLSystem oglSystem = displaySystem.driverData;
       if(useSingleGLContext) return true;
    #if defined(__WIN32__)
       wglMakeCurrent(oglSystem.hdc, oglSystem.glrc);
-   #elif defined(__unix__)
+   #elif defined(__unix__) || defined(__APPLE__)
       //if(previous) return true;
       // printf("Making SYSTEM current\n");
-/*#if defined(__APPLE__)
-      //glXMakeCurrent(xGlobalDisplay, displaySystem.window, oglSystem.glContext);
-#else*/
-      #if defined(__ANDROID__)
-      #else
-      glXMakeCurrent(xGlobalDisplay, oglSystem.dummyGLXPixmap /*displaySystem.window /-*DefaultRootWindow(xGlobalDisplay)*/, oglSystem.glContext);
-      #endif
-//#endif
+      glXMakeCurrent(xGlobalDisplay, (GLXDrawable)oglSystem.glxDrawable, oglSystem.glContext);
       //previous = oglSystem.glContext;
    #endif
+#endif
       return true;
    }
 
@@ -1076,9 +1663,9 @@ class OpenGLDisplayDriver : DisplayDriver
       if(useSingleGLContext) return;
    #if defined(__WIN32__)
       wglMakeCurrent(null, null);
-   #elif defined(__unix__)
+   #elif defined(__unix__) || defined(__APPLE__)
       // printf("Making NULL current\n");
-      #if defined(__ANDROID__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
       #else
       glXMakeCurrent(xGlobalDisplay, None, null);
       #endif
@@ -1088,20 +1675,17 @@ class OpenGLDisplayDriver : DisplayDriver
 
    bool Lock(Display display)
    {
+#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
       OGLDisplay oglDisplay = display.driverData;
-      OGLSystem oglSystem = display.displaySystem.driverData;
-
       if(useSingleGLContext) return true;
    #if defined(__WIN32__)
       wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
-   #elif defined(__unix__)
+   #elif defined(__unix__) || defined(__APPLE__)
       // if(previous) glXMakeCurrent(xGlobalDisplay, None, null);
       // printf("   Making DISPLAY current\n");
-      #if defined(__ANDROID__)
-      #else
-      glXMakeCurrent(xGlobalDisplay, (int)display.window, oglDisplay.glContext);
-      #endif
+      glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
    #endif
+#endif
       return true;
    }
 
@@ -1123,23 +1707,23 @@ class OpenGLDisplayDriver : DisplayDriver
    #if defined(__WIN32__)
          wglMakeCurrent( null, null );
 
-         if(oglDisplay.glrc) 
+         if(oglDisplay.glrc)
             wglDeleteContext(oglDisplay.glrc);
-      
+
          if(oglDisplay.hdc && oglDisplay.pBuffer)
             wglReleasePbufferDCARB(oglDisplay.pBuffer, oglDisplay.hdc);
 
          if(oglDisplay.pBuffer)
             wglDestroyPbufferARB(oglDisplay.pBuffer);
 
-         if(oglDisplay.hdc) 
+         if(oglDisplay.hdc)
             ReleaseDC(display.window, oglDisplay.hdc);
 
          if(oglDisplay.memDC) DeleteDC(oglDisplay.memDC);
-         if(oglDisplay.memBitmap) DeleteObject(oglDisplay.memBitmap); 
+         if(oglDisplay.memBitmap) DeleteObject(oglDisplay.memBitmap);
 
-   #elif defined(__unix__)
-      #if defined(__ANDROID__)
+   #elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
       #else
          if(oglDisplay.shapePixmap)
             XFreePixmap(xGlobalDisplay, oglDisplay.shapePixmap);
@@ -1163,14 +1747,14 @@ class OpenGLDisplayDriver : DisplayDriver
                if(oglDisplay.shminfoShape.shmaddr != (void *)-1)
                   shmdt(oglDisplay.shminfoShape.shmaddr);
                shmctl(oglDisplay.shminfoShape.shmid, IPC_RMID, 0);
-            }                  
+            }
             XDestroyImage(oglDisplay.shapeImage);
             oglDisplay.shapeImage = None;
          }
 
          glXMakeCurrent(xGlobalDisplay, None, null);
-      
-         if(oglDisplay.glContext) 
+
+         if(oglDisplay.glContext)
             glXDestroyContext(xGlobalDisplay, oglDisplay.glContext);
       #endif
    #endif
@@ -1180,6 +1764,14 @@ class OpenGLDisplayDriver : DisplayDriver
       }
    }
 
+   void ::CheckExtensions(OGLSystem oglSystem)
+   {
+      const char * extensions = (const char *)glGetString(GL_EXTENSIONS);
+      if(extensions)
+         oglSystem.pow2textures = strstr(extensions, "GL_ARB_texture_non_power_of_two") ? false : true;
+      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &oglSystem.maxTextureSize);
+   }
+
    bool CreateDisplaySystem(DisplaySystem displaySystem)
    {
       bool result = false;
@@ -1191,7 +1783,7 @@ class OpenGLDisplayDriver : DisplayDriver
       oglSystem.hdc = GetDC(oglSystem.hwnd);
       if(oglSystem.hdc)
       {
-          
+
          oglSystem.pfd.nSize = (short)sizeof(oglSystem.pfd);
          oglSystem.pfd.nVersion = 1;
          oglSystem.pfd.dwFlags = PFD_DRAW_TO_WINDOW /*PFD_DRAW_TO_BITMAP*/ | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
@@ -1238,6 +1830,8 @@ class OpenGLDisplayDriver : DisplayDriver
 
                wglSwapIntervalEXT = (void *)wglGetProcAddress("wglSwapIntervalEXT");
 
+               vboAvailable = glBindBufferARB != null;
+
                // eSystem_LoggingMode(LOG_MSGBOX, null);
 
                if(wglChoosePixelFormatARB)
@@ -1247,7 +1841,7 @@ class OpenGLDisplayDriver : DisplayDriver
                    int numFormats;
                    float fAttributes[] = {0,0};
                    int iAttributes[] =
-                  { 
+                  {
                      WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
                            WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
                            WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
@@ -1297,45 +1891,71 @@ class OpenGLDisplayDriver : DisplayDriver
 
                result = true;
 
+               CheckExtensions(oglSystem);
+
                wglMakeCurrent(null, null);
 
                //eSystem_DumpErrors(true);
             }
          }
       }
-   #elif defined(__unix__)
+   #elif defined(__unix__) || defined(__APPLE__)
+      vboAvailable = true;
       #if defined(__ANDROID__)
          egl_init_display(guiApp.desktop.windowHandle);
+      #elif defined(__ODROID__)
+         egl_init_display((uint)displaySystem.window);
+         CheckExtensions(oglSystem);
          result = true;
+      #elif defined(__EMSCRIPTEN__)
+         if(glfwInit() == GL_TRUE)
+         {
+            const int width = 640, height = 480;
+            if(glfwOpenWindow(width, height, 8, 8, 8, 8, 16, 0, GLFW_WINDOW) == GL_TRUE)
+            {
+               //glfwSwapBuffers();
+               result = true;
+            }
+            else
+               printf("glfwOpenWindow() failed\n"); //glfwTerminate();
+         }
+         else
+            printf("glfwInit() failed\n"); //glfwTerminate();
       #else
-      int attrList[] = 
       {
-   #ifndef ECERE_MINIGLX
-         GLX_USE_GL, GLX_DEPTH_SIZE, 1,
-   #endif
-         GLX_RGBA, 
-         GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
-         GLX_DOUBLEBUFFER, 
-         None
-      };
-      oglSystem.visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrList);
+         X11Window root = RootWindow( xGlobalDisplay, DefaultScreen( xGlobalDisplay ) );
+         XSetWindowAttributes attr;
+         unsigned long mask;
+
+         int attrList[] =
+         {
+      #ifndef ECERE_MINIGLX
+            GLX_USE_GL, GLX_DEPTH_SIZE, 1,
+      #endif
+            GLX_RGBA,
+            GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
+            GLX_DOUBLEBUFFER,
+            None
+         };
+         oglSystem.visualInfo = glXChooseVisual( xGlobalDisplay,  DefaultScreen( xGlobalDisplay ), attrList );
+         attr.background_pixel = 0;
+         attr.border_pixel = 0;
+         attr.colormap = XCreateColormap( xGlobalDisplay, root, oglSystem.visualInfo->visual, AllocNone);
+         attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+         oglSystem.glxDrawable = XCreateWindow( xGlobalDisplay, root, 0, 0, 1, 1, 0, oglSystem.visualInfo->depth, InputOutput,
+            oglSystem.visualInfo->visual, mask, &attr );
+      }
       if(oglSystem.visualInfo)
       {
-         //printf("glXChooseVisual returnded a visual info\n");
-         oglSystem.dummyPixmap = XCreatePixmap(xGlobalDisplay, (uint)displaySystem.window, 1, 1, oglSystem.visualInfo->depth);
-         oglSystem.dummyGLXPixmap = glXCreateGLXPixmap(xGlobalDisplay, oglSystem.visualInfo, oglSystem.dummyPixmap);
-         
          oglSystem.glContext = glXCreateContext(xGlobalDisplay, oglSystem.visualInfo, null, True);
-         // printf("Creating system Context (%x)!\n", oglSystem.glContext);
          if(oglSystem.glContext)
          {
-            //printf("Got a Context\n");
-            glXMakeCurrent(xGlobalDisplay, oglSystem.dummyGLXPixmap /*displaySystem.window /-*DefaultRootWindow(xGlobalDisplay)*/, oglSystem.glContext);
-
+            glXMakeCurrent(xGlobalDisplay, oglSystem.glxDrawable, oglSystem.glContext);
             // Setup Extensions
-
+            CheckExtensions(oglSystem);
             glXMakeCurrent(xGlobalDisplay, None, null);
-
             result = true;
          }
       }
@@ -1355,16 +1975,18 @@ class OpenGLDisplayDriver : DisplayDriver
    #if defined(__WIN32__)
       wglMakeCurrent( null, null );
 
-      if(oglSystem.glrc) 
+      if(oglSystem.glrc)
          wglDeleteContext(oglSystem.glrc);
-      
-      if(oglSystem.hdc) 
+
+      if(oglSystem.hdc)
          ReleaseDC(oglSystem.hwnd, oglSystem.hdc);
       DestroyWindow(oglSystem.hwnd);
 
-   #elif defined(__unix__)
-      #if defined(__ANDROID__)
+   #elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__ODROID__)
          egl_term_display();
+      #elif defined(__EMSCRIPTEN__)
+         glfwTerminate();
       #else
       if(oglSystem.visualInfo)
       {
@@ -1375,10 +1997,11 @@ class OpenGLDisplayDriver : DisplayDriver
    #endif
       }
 
-      if(oglSystem.dummyGLXPixmap)
-         glXDestroyGLXPixmap(xGlobalDisplay, oglSystem.dummyGLXPixmap);
-      if(oglSystem.dummyPixmap);
-         XFreePixmap(xGlobalDisplay, oglSystem.dummyPixmap);
+      if(oglSystem.glxDrawable)
+      {
+         XDestroyWindow(xGlobalDisplay, oglSystem.glxDrawable);
+         oglSystem.glxDrawable = 0;
+      }
       #endif
    #endif
       delete oglSystem;
@@ -1388,7 +2011,9 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       bool result = false;
       OGLDisplay oglDisplay = display.driverData;
+#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
       OGLSystem oglSystem = display.displaySystem.driverData;
+#endif
       if(!oglDisplay)
          oglDisplay = display.driverData = OGLDisplay { };
       //printf("Inside CreateDisplay\n");
@@ -1408,56 +2033,26 @@ class OpenGLDisplayDriver : DisplayDriver
          }
          else
             ReleaseDC(display.window, oglDisplay.hdc);
-   #elif defined(__unix__)
-      #if defined(__ANDROID__)
+   #elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
       #else
-         XVisualInfo * visualInfo = null;
-         /*
-         int attrib[] =
-         {
-            GLX_RENDER_TYPE, GLX_RGBA_BIT,
-            GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
-            GLX_RED_SIZE, 1,
-            GLX_GREEN_SIZE, 1,
-            GLX_BLUE_SIZE, 1,
-            GLX_DOUBLEBUFFER, True,
-            GLX_DEPTH_SIZE, 24,
-            None
-         };
-         */
-         //visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrib);
-         visualInfo = ((XWindowData)display.windowDriverData).visual;
-
+         XVisualInfo * visualInfo = ((XWindowData)display.windowDriverData).visual;
          /*
-         GLXFBConfig *fbconfigs, fbconfig;
-         int numfbconfigs;
-         fbconfigs = glXChooseFBConfig(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrib, &numfbconfigs);
-         if(fbconfigs)
-         {
-            int i;
-            for (i = 0; i < numfbconfigs; i++)
-            {
-               XRenderPictFormat * format;
-               visualInfo = glXGetVisualFromFBConfig(xGlobalDisplay, fbconfigs[i]);
-               if (!visualInfo) continue;
-               format = XRenderFindVisualFormat(xGlobalDisplay, visualInfo->visual);
-               if (!format) continue;
-
-               if(format->direct.alphaMask > 0)
-               {
-                  fbconfig = fbconfigs[i];
-                  break;
-               }
-               //XFree(visualInfo);
-            }
-
-            if (i == numfbconfigs)
-            {
-               fbconfig = fbconfigs[0];
-               visualInfo = glXGetVisualFromFBConfig(xGlobalDisplay, fbconfig);
-            }
-            XFree(fbconfigs);
-         }
+#if defined(__APPLE__)
+         XVisualInfo template = { 0 };
+         XWindowAttributes winAttr;
+         int n;
+         XGetWindowAttributes(xGlobalDisplay, (X11Window)display.window, &winAttr);
+         template.visualid = XVisualIDFromVisual(winAttr.visual);
+         visualInfo = XGetVisualInfo(xGlobalDisplay, VisualIDMask, &template, &n);
+#ifdef _DEBUG
+         printf("XGetVisualInfo visual ID = %d\n", template.visualid);
+         printf("visualInfo visual ID = %d\n", visualInfo->visualid);
+         printf("oglSystem.visualInfo visual ID = %d\n", oglSystem.visualInfo->visualid);
+         printf("((XWindowData)display.windowDriverData).visual visual ID = %d\n", ((XWindowData)display.windowDriverData).visual->visualid);
+#endif
+         // visualInfo = oglSystem.visualInfo;
+//#endif
          */
          if(visualInfo)
          {
@@ -1471,7 +2066,7 @@ class OpenGLDisplayDriver : DisplayDriver
          if(oglDisplay.glContext)
          {
             //printf("CreateDisplay Got a Context\n");
-            glXMakeCurrent(xGlobalDisplay, (int)display.window, oglDisplay.glContext);
+            glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
             result = true;
          }
       #endif
@@ -1483,23 +2078,32 @@ class OpenGLDisplayDriver : DisplayDriver
 #endif
       if(result)
       {
-#if !defined(__OLDX__)
+#if defined(__WIN32__)
          if(glBlendFuncSeparate)
             glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
          else
-#endif
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#else
+#if !defined(__OLDX__)
+          glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+#else
+         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+#endif
          glEnable(GL_BLEND);
 
          glMatrixMode(GL_MODELVIEW);
-         glScalef(1.0f, 1.0f, -1.0f);
+         glLoadIdentity(); // For setting up GLES stack
+         glScaled(1.0, 1.0, -1.0);
          // glTranslatef(0.375f, 0.375f, 0.0f);
          // glTranslatef(-0.625f, -0.625f, 0.0f);
          glMatrixMode(GL_PROJECTION);
          glShadeModel(GL_FLAT);
 
          // glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, true);
+#if !defined(EM_MODE)
          glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+#endif
          glFogi(GL_FOG_MODE, GL_EXP);
          glFogf(GL_FOG_DENSITY, 0);
          glEnable(GL_NORMALIZE);
@@ -1507,18 +2111,28 @@ class OpenGLDisplayDriver : DisplayDriver
          glClearDepth(1.0);
          glDisable(GL_MULTISAMPLE_ARB);
       }
+#if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
       display.ambient = Color { 50,50,50 };
+#endif
 
-   if(!useSingleGLContext)
+      if(!useSingleGLContext)
+      {
    #if defined(__WIN32__)
-      wglMakeCurrent(null, null);
-   #elif defined(__unix__)
-      #if defined(__ANDROID__)
-      result = true;
+         wglMakeCurrent(null, null);
+   #elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
+         result = true;
       #else
-      glXMakeCurrent(xGlobalDisplay, None, null);
+         glXMakeCurrent(xGlobalDisplay, None, null);
       #endif
    #endif
+      }
+      else
+      {
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
+         result = true;
+      #endif
+      }
 
       return result;
    }
@@ -1526,12 +2140,12 @@ class OpenGLDisplayDriver : DisplayDriver
    bool DisplaySize(Display display, int width, int height)
    {
       OGLDisplay oglDisplay = display.driverData;
-      OGLSystem oglSystem = display.displaySystem.driverData;
 
       bool result = false;
 
       //printf("Inside DisplaySize\n");
 #if defined(__WIN32__) || defined(USEPBUFFER)
+      OGLSystem oglSystem = display.displaySystem.driverData;
       if(display.alphaBlend)
       {
 #if defined(__WIN32__)
@@ -1539,7 +2153,7 @@ class OpenGLDisplayDriver : DisplayDriver
          {
             /*WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB,
             WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB, */0
-         }; 
+         };
          int pixelFormat = 0;
          if(wglChoosePixelFormatARB)
          {
@@ -1547,7 +2161,7 @@ class OpenGLDisplayDriver : DisplayDriver
             int numFormats;
             float fAttributes[] = {0,0};
             int iAttributes[] =
-            { 
+            {
                //WGL_DRAW_TO_BITMAP_ARB, GL_TRUE,
                WGL_DRAW_TO_PBUFFER_ARB,GL_TRUE,
                    WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
@@ -1561,7 +2175,7 @@ class OpenGLDisplayDriver : DisplayDriver
                    WGL_SAMPLES_ARB, 4,                                         // Check For 4x Multisampling
                    0,0
             };
-            
+
             //Log("Found wglChoosePixelFormatARB\n");
 
             valid = wglChoosePixelFormatARB(oglSystem.hdc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
@@ -1596,7 +2210,7 @@ class OpenGLDisplayDriver : DisplayDriver
             {
                wglMakeCurrent(null, null);
             }
-         }  
+         }
 
          wglMakeCurrent( null, null );
          wglMakeCurrent( oglDisplay.hdc, oglDisplay.glrc );
@@ -1607,8 +2221,8 @@ class OpenGLDisplayDriver : DisplayDriver
 
          if(!useSingleGLContext)
             wglMakeCurrent( null, null );
-           
-         if(oglDisplay.glrc) 
+
+         if(oglDisplay.glrc)
             wglDeleteContext(oglDisplay.glrc);
 
          oglDisplay.pBuffer = wglCreatePbufferARB(oglSystem.hdc, pixelFormat, width, height, attributes);
@@ -1622,8 +2236,8 @@ class OpenGLDisplayDriver : DisplayDriver
             wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
 
             //wglQueryPbufferARB(pBuffer, WGL_PBUFFER_WIDTH_ARB, &width);
-            //wglQueryPbufferARB(pBuffer, WGL_PBUFFER_HEIGHT_ARB, &height); 
-            
+            //wglQueryPbufferARB(pBuffer, WGL_PBUFFER_HEIGHT_ARB, &height);
+
             // glDeleteBuffersARB(2, oglDisplay.imageBuffers);
 
             if((info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256]))
@@ -1688,8 +2302,8 @@ class OpenGLDisplayDriver : DisplayDriver
             }
             ReleaseDC(display.window, hdc);
          }
-#elif defined(__unix__)
-      #if defined(__ANDROID__)
+#elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
          result = true;
       #else
        int attrib[] =
@@ -1753,7 +2367,7 @@ class OpenGLDisplayDriver : DisplayDriver
                   if(oglDisplay.shminfoShape.shmaddr != (void *)-1)
                      shmdt(oglDisplay.shminfoShape.shmaddr);
                   shmctl(oglDisplay.shminfoShape.shmid, IPC_RMID, 0);
-               }                  
+               }
                XDestroyImage(oglDisplay.shapeImage);
                oglDisplay.shapeImage = None;
             }
@@ -1778,14 +2392,14 @@ class OpenGLDisplayDriver : DisplayDriver
                if(oglDisplay.glContext)
                {
                   glXMakeCurrent(xGlobalDisplay, None, null);
-                  glXMakeCurrent(xGlobalDisplay, (int)display.window, oglDisplay.glContext);
+                  glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
 
                   // Initialize Shared Memory Pixmap
-                  oglDisplay.image = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 32, 
+                  oglDisplay.image = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 32,
                      ZPixmap, null, &oglDisplay.shminfo, width, height);
                   if(oglDisplay.image)
                   {
-                     oglDisplay.shminfo.shmid = shmget(IPC_PRIVATE, 
+                     oglDisplay.shminfo.shmid = shmget(IPC_PRIVATE,
                         oglDisplay.image->bytes_per_line * oglDisplay.image->height, IPC_CREAT|0777);
                      if(oglDisplay.shminfo.shmid != -1)
                      {
@@ -1795,15 +2409,15 @@ class OpenGLDisplayDriver : DisplayDriver
                            oglDisplay.shminfo.readOnly = False;
                            if(XShmAttach(xGlobalDisplay, &oglDisplay.shminfo))
                            {
-                              oglDisplay.pixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfo.shmaddr, 
+                              oglDisplay.pixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfo.shmaddr,
                                  &oglDisplay.shminfo, width, height, 32);
 
                               // Initialize Shared Memory Shape Pixmap
-                              oglDisplay.shapeImage = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 1, 
+                              oglDisplay.shapeImage = XShmCreateImage(xGlobalDisplay, DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 1,
                                  ZPixmap, null, &oglDisplay.shminfoShape, width, height);
                               if(oglDisplay.shapeImage)
                               {
-                                 oglDisplay.shminfoShape.shmid = shmget(IPC_PRIVATE, 
+                                 oglDisplay.shminfoShape.shmid = shmget(IPC_PRIVATE,
                                     oglDisplay.shapeImage->bytes_per_line * oglDisplay.shapeImage->height, IPC_CREAT|0777);
                                  if(oglDisplay.shminfoShape.shmid != -1)
                                  {
@@ -1813,7 +2427,7 @@ class OpenGLDisplayDriver : DisplayDriver
                                        oglDisplay.shminfoShape.readOnly = False;
                                        if(XShmAttach(xGlobalDisplay, &oglDisplay.shminfoShape))
                                        {
-                                          oglDisplay.shapePixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfoShape.shmaddr, 
+                                          oglDisplay.shapePixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, oglDisplay.shminfoShape.shmaddr,
                                              &oglDisplay.shminfoShape, width, height, 1);
                                           //oglDisplay.shapePixmap = XCreatePixmap(xGlobalDisplay, (X11Window)display.window, width, height, 1);
 
@@ -1827,9 +2441,9 @@ class OpenGLDisplayDriver : DisplayDriver
                                              #endif
                                              oglDisplay.pixmapPicture = XRenderCreatePicture(xGlobalDisplay, oglDisplay.pixmap, format, CPRepeat, &attributes);
                                              oglDisplay.windowPicture = XRenderCreatePicture(xGlobalDisplay, (X11Window)display.window, format, 0, &attributes);
-                                             oglDisplay.shapePicture = XRenderCreatePicture(xGlobalDisplay, oglDisplay.shapePixmap, 
+                                             oglDisplay.shapePicture = XRenderCreatePicture(xGlobalDisplay, oglDisplay.shapePixmap,
                                                 XRenderFindStandardFormat(xGlobalDisplay, PictStandardA1), 0, &attributes);
-                                          }  
+                                          }
 
                                           oglDisplay.picture = oglDisplay.shminfo.shmaddr;
                                           oglDisplay.stride = oglDisplay.image->bytes_per_line / 4;
@@ -1852,12 +2466,12 @@ class OpenGLDisplayDriver : DisplayDriver
          CreateDisplay(display);
 #if defined(__WIN32__)
          wglMakeCurrent(oglDisplay.hdc, oglDisplay.glrc);
-#elif defined(__unix__)
-      #if defined(__ANDROID__)
+#elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
          width = eglWidth;
          height = eglHeight;
       #else
-         glXMakeCurrent(xGlobalDisplay, (int)display.window, oglDisplay.glContext);
+         glXMakeCurrent(xGlobalDisplay, (GLXDrawable)display.window, oglDisplay.glContext);
       #endif
 #endif
       }
@@ -1870,10 +2484,11 @@ class OpenGLDisplayDriver : DisplayDriver
       }
       if(!result)
          return false;
-         
-      result = false;           
+
+      result = false;
 
       glViewport(0,0,width,height);
+      glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       glOrtho(0,width,height,0,0.0,1.0);
       displayWidth = display.width = width;
@@ -1883,11 +2498,15 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          oglDisplay.flipBufW = width;
          oglDisplay.flipBufH = height;
+#ifdef _GLES
+         result = true;
+#else
          oglDisplay.flippingBuffer = renew oglDisplay.flippingBuffer ColorAlpha [width * height];
+#endif
       }
       if(oglDisplay.flippingBuffer || !width || !height)
          result = true;
-         
+
       return result;
    }
 
@@ -1921,7 +2540,9 @@ class OpenGLDisplayDriver : DisplayDriver
 
    void Update(Display display, Box updateBox)
    {
+#if defined(__WIN32__) || defined(USEPBUFFER)
       OGLDisplay oglDisplay = display.driverData;
+#endif
       //Logf("DisplayScreen\n");
 
       glFlush();
@@ -1954,15 +2575,15 @@ class OpenGLDisplayDriver : DisplayDriver
             // outstanding DMA transfers into the buffer to finish.
             glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[0]);
             oglDisplay.pboMemory1 = (byte *)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
-           
+
             // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
             // oglDisplay.pboMemory2 = (byte *)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB,GL_READ_ONLY);
 
-           
+
             memcpy(oglDisplay.picture, oglDisplay.pboMemory1, display.width * display.height * 4);
             //memcpy(oglDisplay.picture + display.width * display.height * 4 / 2, oglDisplay.pboMemory2, display.width * display.height * 4/ 2);
             */
-            
+
             UpdateLayeredWindow(display.window, hdc, &point, &size, oglDisplay.memDC, &srcPoint, 0, &blend, ULW_ALPHA);
             /*
 
@@ -1972,7 +2593,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
             // glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, oglDisplay.imageBuffers[1]);
             // glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
-           
+
             // Bind two different buffer objects and start the glReadPixels
             // asynchronously. Each call will return directly after
             // starting the DMA transfer.
@@ -1984,10 +2605,10 @@ class OpenGLDisplayDriver : DisplayDriver
             */
 
             ReleaseDC(0, hdc);
-#elif defined(__unix__)
-      #if defined(__ANDROID__)
+#elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__ODROID__)
       #else
-            XTransform transform = 
+            XTransform transform =
             {
                {
                   { (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)),  (int)(0 * (1 << 16)) },
@@ -1999,7 +2620,7 @@ class OpenGLDisplayDriver : DisplayDriver
             XRenderComposite(xGlobalDisplay, PictOpSrc, oglDisplay.pixmapPicture, None, oglDisplay.shapePicture, 0, 0, 0, 0, 0, 0, display.width, display.height);
             XRenderComposite(xGlobalDisplay, PictOpSrc, oglDisplay.pixmapPicture, None, oglDisplay.windowPicture, 0, 0, 0, 0, 0, 0, display.width, display.height);
             #if !defined(__APPLE__) && !defined(__OLDX__)
-            XShapeCombineMask(xGlobalDisplay, (uint)display.window, ShapeInput, 0, 0, oglDisplay.shapePixmap, ShapeSet);
+            XShapeCombineMask(xGlobalDisplay, (X11Window)display.window, ShapeInput, 0, 0, oglDisplay.shapePixmap, ShapeSet);
             #else
             XShapeCombineMask(xGlobalDisplay, display.window, 2, 0, 0, oglDisplay.shapePixmap, ShapeSet);
             #endif
@@ -2007,18 +2628,20 @@ class OpenGLDisplayDriver : DisplayDriver
      #endif
 #endif
          }
-      } 
+      }
       else
 #endif
       {
 #if defined(__WIN32__)
-         //wglSwapLayerBuffers(oglDisplay.hdc,WGL_SWAP_MAIN_PLANE); 
+         //wglSwapLayerBuffers(oglDisplay.hdc,WGL_SWAP_MAIN_PLANE);
          SwapBuffers(oglDisplay.hdc);
-#elif defined(__unix__)
-      #if defined(__ANDROID__)
+#elif defined(__unix__) || defined(__APPLE__)
+      #if defined(__ANDROID__) || defined(__ODROID__)
          eglSwapBuffers(eglDisplay, eglSurface);
+      #elif defined(__EMSCRIPTEN__)
+         glfwSwapBuffers();
       #else
-         glXSwapBuffers(xGlobalDisplay, (int)display.window);
+         glXSwapBuffers(xGlobalDisplay, (GLXDrawable)display.window);
       #endif
 #endif
       }
@@ -2027,21 +2650,30 @@ class OpenGLDisplayDriver : DisplayDriver
 
    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
    {
-      glDeleteTextures(1, (int *)&bitmap.driverData);
-      bitmap.driverData = 0;
-
+      if(bitmap.driverData)
+      {
+         GLuint tex = (GLuint)(uintptr)bitmap.driverData;
+         glDeleteTextures(1, &tex);
+         bitmap.driverData = 0;
+      }
       bitmap.driver = ((subclass(DisplayDriver))class(LFBDisplayDriver));
    }
 
    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
    {
+      OGLSystem oglSystem = displaySystem.driverData;
       bool result = false;
       Bitmap mipMap { };
-      int glBitmap = -1;
-      
-      uint w = pow2i(Min(width, 1024)), h = pow2i(Min(height, 1024));
-      //uint w = pow2i(Min(width, 2048)), h = pow2i(Min(height, 2048));
-      //uint w = pow2i(Min(width, 512)), h = pow2i(Min(height, 512));
+      GLuint glBitmap = 0;
+
+      uint w = width, h = height;
+      if(oglSystem.pow2textures)
+      {
+         w = pow2i(w);
+         h = pow2i(h);
+      }
+      w = Min(w, oglSystem.maxTextureSize);
+      h = Min(h, oglSystem.maxTextureSize);
 
       glGenTextures(1, &glBitmap);
       glBindTexture(GL_TEXTURE_2D, glBitmap);
@@ -2063,7 +2695,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
       delete mipMap;
 
-      bitmap.driverData = (void *)glBitmap;
+      bitmap.driverData = (void *)(uintptr)glBitmap;
       bitmap.driver = displaySystem.driver;
       bitmap.width = w;
       bitmap.height = h;
@@ -2076,14 +2708,32 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       bool result = false;
       OGLSystem oglSystem = displaySystem.driverData;
+      Bitmap convBitmap = bitmap;
+      if(bitmap.keepData)
+      {
+         convBitmap = { };
+         convBitmap.Copy(bitmap);
+      }
 
       // Pre process the bitmap... First make it 32 bit
-      if(/*bitmap.pixelFormat == pixelFormatRGBA || */bitmap.Convert(null, pixelFormat888, null))
+      if(/*bitmap.pixelFormat == pixelFormatRGBA || */convBitmap.Convert(null, pixelFormat888, null))
       {
          int c, level;
-         uint w = pow2i(Min(bitmap.width, 1024)), h = pow2i(Min(bitmap.height, 1024));
-         //uint w = pow2i(Min(bitmap.width, 512)), h = pow2i(Min(bitmap.height, 512));
-         int glBitmap = -1;
+         uint w = bitmap.width, h = bitmap.height;
+         GLuint glBitmap = 0;
+         if(oglSystem.pow2textures)
+         {
+            w = pow2i(w);
+            h = pow2i(h);
+         }
+         w = Min(w, oglSystem.maxTextureSize);
+         h = Min(h, oglSystem.maxTextureSize);
+
+         if(mipMaps)
+         {
+            while(w * 2 < h) w *= 2;
+            while(h * 2 < w) h *= 2;
+         }
 
          // Switch ARGB to RGBA
          //if(bitmap.format != pixelFormatRGBA)
@@ -2091,27 +2741,27 @@ class OpenGLDisplayDriver : DisplayDriver
             for(c=0; c<bitmap.size; c++)
             {
                // ((ColorRGBA *)bitmap.picture)[c] = ((ColorAlpha *)bitmap.picture)[c];
-               // TODO: 
-               ColorAlpha color = ((ColorAlpha *)bitmap.picture)[c];
-               ((ColorRGBA *)bitmap.picture)[c] = ColorRGBA { color.color.r, color.color.g, color.color.b, color.a };
+               // TODO:
+               ColorAlpha color = ((ColorAlpha *)convBitmap.picture)[c];
+               ((ColorRGBA *)convBitmap.picture)[c] = ColorRGBA { color.color.r, color.color.g, color.color.b, color.a };
             }
          }
-         bitmap.pixelFormat = pixelFormat888;
+         // convBitmap.pixelFormat = pixelFormat888;
 
          glGetError();
          glGenTextures(1, &glBitmap);
-         if(glBitmap == -1)
+         if(glBitmap == 0)
          {
-            int error = glGetError();
+            //int error = glGetError();
             return false;
-            //Print("");
          }
 
          glBindTexture(GL_TEXTURE_2D, glBitmap);
          glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
 
-         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mipMaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
          //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
          //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
@@ -2119,21 +2769,24 @@ class OpenGLDisplayDriver : DisplayDriver
 
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0 );
 
          glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
 
          result = true;
 
-         for(level = 0; result && (w > 1 || h > 1); level++, w >>= 1, h >>= 1)
+         for(level = 0; result && (w >= 1 || h >= 1); level++, w >>= 1, h >>= 1)
          {
             Bitmap mipMap;
+            if(!w) w = 1;
+            if(!h) h = 1;
             if(bitmap.width != w || bitmap.height != h)
             {
                mipMap = Bitmap { };
-               if(mipMap.Allocate(null, w, h, w, bitmap.pixelFormat, false))
+               if(mipMap.Allocate(null, w, h, w, convBitmap.pixelFormat, false))
                {
                   Surface mipSurface = mipMap.GetSurface(0,0,null);
-                  mipSurface.Filter(bitmap, 0,0,0,0, w, h, bitmap.width, bitmap.height);
+                  mipSurface.Filter(convBitmap, 0,0,0,0, w, h, convBitmap.width, convBitmap.height);
                   delete mipSurface;
                }
                else
@@ -2142,8 +2795,8 @@ class OpenGLDisplayDriver : DisplayDriver
                   delete mipMap;
                }
             }
-            else 
-               mipMap = bitmap;
+            else
+               mipMap = convBitmap;
 
             if(result)
             {
@@ -2162,15 +2815,16 @@ class OpenGLDisplayDriver : DisplayDriver
                   result = false;
                }
             }
-            if(mipMap != bitmap) 
+            if(mipMap != convBitmap)
                delete mipMap;
             if(!mipMaps) break;
          }
 
-         if(!bitmap.keepData)
-            bitmap.driver.FreeBitmap(bitmap.displaySystem, bitmap);
-         bitmap.driverData = (void *)glBitmap;
+         convBitmap.driver.FreeBitmap(convBitmap.displaySystem, convBitmap);
+         bitmap.driverData = (void *)(uintptr)glBitmap;
          bitmap.driver = displaySystem.driver;
+         if(bitmap.keepData)
+            delete convBitmap;
 
          if(!result)
             FreeBitmap(displaySystem, bitmap);
@@ -2263,7 +2917,7 @@ class OpenGLDisplayDriver : DisplayDriver
       bool result = false;
       OGLDisplay oglDisplay = display.driverData;
       ColorAlpha * flippingBuffer = oglDisplay.flippingBuffer;
-      
+
       if(oglDisplay.flippingBuffer)
       {
          if(bitmap.pixelFormat != pixelFormat888 || bitmap.width < w || bitmap.height < h)
@@ -2343,49 +2997,110 @@ class OpenGLDisplayDriver : DisplayDriver
       glBegin(GL_POINTS);
       // glVertex2i(x+surface.offset.x, y+surface.offset.y);
       glVertex2f(x+surface.offset.x + 0.5f, y+surface.offset.y + 0.5f);
-       
+
       glEnd();
    }
 
-   void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
+   void DrawLine(Display display, Surface surface, int _x1, int _y1, int _x2, int _y2)
    {
       OGLSurface oglSurface = surface.driverData;
-      if(x1 == x2) { y2++; y1--; }
-      else if(y1 == y2) { x2++; x1--; }
+      float x1 = _x1, x2 = _x2, y1 = _y1, y2 = _y2;
+      if(_x1 == _x2)
+      {
+         if(_y2 >= _y1)
+            y2 += 1;
+         else
+            y1 += 1;
+      }
+      else if(_y1 == _y2)
+      {
+         if(_x2 >= _x1)
+            x2 += 1;
+         else
+            x1 += 1;
+      }
+      x1 += surface.offset.x;
+      y1 += surface.offset.y;
+      x2 += surface.offset.x;
+      y2 += surface.offset.y;
 
       //Logf("Line\n");
 
       glColor4fv(oglSurface.foreground);
       glBegin(GL_LINES);
-      /*
-      glVertex2i(x1+surface.offset.x, y1+surface.offset.y);
-      glVertex2i(x2+surface.offset.x, y2+surface.offset.y);
-      */
-      glVertex2f(x1+surface.offset.x + 0.5f, y1+surface.offset.y + 0.5f);
-      glVertex2f(x2+surface.offset.x + 0.5f, y2+surface.offset.y + 0.5f);
-      
+#if defined(_GLES) || defined(EM_MODE)
+      if(stippleEnabled)
+      {
+         glTexCoord2f(0.5f, 0);
+         glVertex2f(x1 + 0.5f, y1 + 0.5f);
+         glTexCoord2f(Max(x2-x1, y2-y1) + 0.5f, 0);
+         glVertex2f(x2 + 0.5f, y2 + 0.5f);
+      }
+      else
+#endif
+      {
+         /*
+         glVertex2i(x1, y1);
+         glVertex2i(x2, y2);
+         */
+         glVertex2f(x1 + 0.5f, y1 + 0.5f);
+         glVertex2f(x2 + 0.5f, y2 + 0.5f);
+      }
+
       glEnd();
    }
 
    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
    {
       OGLSurface oglSurface = surface.driverData;
+      x1 += surface.offset.x;
+      y1 += surface.offset.y;
+      x2 += surface.offset.x;
+      y2 += surface.offset.y;
 
       //Logf("Rectangle\n");
 
       glColor4fv(oglSurface.foreground);
-      glBegin(GL_LINE_LOOP);
-      /*
-      glVertex2i(x1+surface.offset.x, y1+surface.offset.y);
-      glVertex2i(x1+surface.offset.x, y2+surface.offset.y);
-      glVertex2i(x2+surface.offset.x, y2+surface.offset.y);
-      glVertex2i(x2+surface.offset.x, y1+surface.offset.y);
-      */
-      glVertex2f(x1+surface.offset.x + 0.5f, y1+surface.offset.y + 0.5f);
-      glVertex2f(x1+surface.offset.x + 0.5f, y2+surface.offset.y + 0.5f);
-      glVertex2f(x2+surface.offset.x + 0.5f, y2+surface.offset.y + 0.5f);
-      glVertex2f(x2+surface.offset.x + 0.5f, y1+surface.offset.y + 0.5f);
-      
+#if defined(_GLES) || defined(EM_MODE)
+      if(stippleEnabled)
+      {
+         glBegin(GL_LINES);
+
+         glTexCoord2f(0.5f, 0);
+         glVertex2f(x1 + 0.5f, y1 + 0.5f);
+         glTexCoord2f(y2-y1 + 0.5f, 0);
+         glVertex2f(x1 + 0.5f, y2 + 0.5f);
+
+         glTexCoord2f(0.5f, 0);
+         glVertex2f(x1 + 0.5f, y2 + 0.5f);
+         glTexCoord2f(x2 - x1 + 0.5f, 0);
+         glVertex2f(x2 + 0.5f, y2 + 0.5f);
+
+         glTexCoord2f(0.5f, 0);
+         glVertex2f(x2 + 0.5f, y2 + 0.5f);
+         glTexCoord2f(y1 - y2 + 0.5f, 0);
+         glVertex2f(x2 + 0.5f, y1 + 0.5f);
+
+         glTexCoord2f(0.5f, 0);
+         glVertex2f(x2 + 0.5f, y1 + 0.5f);
+         glTexCoord2f(x1 - x2 + 0.5f, 0);
+         glVertex2f(x1 + 0.5f, y1 + 0.5f);
+      }
+      else
+#endif
+      {
+         glBegin(GL_LINE_LOOP);
+         /*
+         glVertex2i(x1, y1);
+         glVertex2i(x1, y2);
+         glVertex2i(x2, y2);
+         glVertex2i(x2, y1);
+         */
+         glVertex2f(x1 + 0.5f, y1 + 0.5f);
+         glVertex2f(x1 + 0.5f, y2 + 0.5f);
+         glVertex2f(x2 + 0.5f, y2 + 0.5f);
+         glVertex2f(x2 + 0.5f, y1 + 0.5f);
+      }
       glEnd();
    }
 
@@ -2395,9 +3110,18 @@ class OpenGLDisplayDriver : DisplayDriver
       //Logf("Area\n");
 
       glColor4fv(oglSurface.background);
+
+#ifdef EM_MODE
+      glBegin(GL_QUADS);
+      glVertex2f(x1+surface.offset.x, y1+surface.offset.y);
+      glVertex2f(x1+surface.offset.x, y2+surface.offset.y+1);
+      glVertex2f(x2+surface.offset.x+1, y2+surface.offset.y+1);
+      glVertex2f(x2+surface.offset.x+1, y1+surface.offset.y);
+      glEnd();
+#else
       glRecti(x1+surface.offset.x, y1+surface.offset.y,
               x2+surface.offset.x + 1, y2+surface.offset.y + 1);
-              
+#endif
       /*
       glRectf(x1+surface.offset.x, y1+surface.offset.y,
               x2+surface.offset.x + 1, y2+surface.offset.y + 1);
@@ -2446,9 +3170,9 @@ class OpenGLDisplayDriver : DisplayDriver
          glColor4fv(oglSurface.bitmapMult);
       }
       else if(oglSurface.xOffset)
-         glTranslatef(oglSurface.xOffset / 64.0f/*-0.375f*/, 0.0f, 0.0f);
-         
-      glBindTexture(GL_TEXTURE_2D, (uint)bitmap.driverData);
+         glTranslated(oglSurface.xOffset / 64.0/*-0.375*/, 0.0, 0.0);
+
+      glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)bitmap.driverData);
       glBegin(GL_QUADS);
 
       if(h < 0)
@@ -2490,10 +3214,10 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          glDisable(GL_TEXTURE_2D);
 
-         //glTranslatef(0.375f, 0.375f, 0.0f);
+         //glTranslate(0.375, 0.375, 0.0);
       }
       else if(oglSurface.xOffset)
-         glTranslatef(-oglSurface.xOffset / 64.0f/*+0.375f*/, 0.0f, 0.0f);
+         glTranslated(-oglSurface.xOffset / 64.0/*+0.375*/, 0.0, 0.0);
 
 #if !defined(__OLDX__)
          /*if(glBlendFuncSeparate && !oglSurface.writingText)
@@ -2505,7 +3229,7 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       OGLSurface oglSurface = surface.driverData;
 
-      //glTranslatef(-0.375f, -0.375f, 0.0f);
+      //glTranslate(-0.375, -0.375, 0.0);
 
       //Logf("Stretch\n");
 
@@ -2515,7 +3239,7 @@ class OpenGLDisplayDriver : DisplayDriver
 #endif
 
       glEnable(GL_TEXTURE_2D);
-      glBindTexture(GL_TEXTURE_2D, (uint)bitmap.driverData);
+      glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)bitmap.driverData);
 
       glColor4fv(oglSurface.bitmapMult);
 
@@ -2525,13 +3249,13 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          glTexCoord2f((float)(sx)/ bitmap.width, (float)(sy+sh)/ bitmap.height);
          glVertex2i(dx+surface.offset.x, dy+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx+sw) / bitmap.width, (float)(sy+sh)/ bitmap.height);
          glVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx+sw)/ bitmap.width, (float)(sy)/ bitmap.height);
          glVertex2i(dx+w+surface.offset.x, dy-h+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx) / bitmap.width, (float)(sy)/ bitmap.height);
          glVertex2i(dx+surface.offset.x, dy-h+surface.offset.y);
       }
@@ -2539,13 +3263,13 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          glTexCoord2f((float)(sx) / bitmap.width, (float)(sy)/ bitmap.height);
          glVertex2i(dx+surface.offset.x, dy+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx+sw)/ bitmap.width, (float)(sy)/ bitmap.height);
          glVertex2i(dx+w+surface.offset.x, dy+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx+sw) / bitmap.width, (float)(sy+sh)/ bitmap.height);
          glVertex2i(dx+w+surface.offset.x, dy+h+surface.offset.y);
-      
+
          glTexCoord2f((float)(sx)/ bitmap.width, (float)(sy+sh)/ bitmap.height);
          glVertex2i(dx+surface.offset.x, dy+h+surface.offset.y);
       }
@@ -2554,7 +3278,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
       glDisable(GL_TEXTURE_2D);
 
-      //glTranslatef(0.375f, 0.375f, 0.0f);
+      //glTranslate(0.375, 0.375, 0.0);
 #if !defined(__OLDX__)
       /*if(glBlendFuncSeparate)
          glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);*/
@@ -2569,8 +3293,9 @@ class OpenGLDisplayDriver : DisplayDriver
 
    void StretchDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
    {
+#if !defined(EM_MODE)
       float s2dw,s2dh,d2sw,d2sh;
-      bool flipX = false, flipY = false;
+      //bool flipX = false, flipY = false;
 
       //Logf("StretchDI\n");
 
@@ -2578,13 +3303,13 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          w = Abs(w);
          sw = Abs(sw);
-         flipX = true; 
+         //flipX = true;
       }
       if(Sgn(h) != Sgn(sh))
       {
          h = Abs(h);
          sh = Abs(sh);
-         flipY = true; 
+         //flipY = true;
       }
 
       s2dw=(float)w / sw;
@@ -2621,7 +3346,7 @@ class OpenGLDisplayDriver : DisplayDriver
       //Clip against the edges of the surfaceination
       if(dx<surface.box.left)
       {
-         //if(!flip) 
+         //if(!flip)
          sx+=(int)((surface.box.left-dx)*d2sw);
          sw-=(int)((surface.box.left-dx)*d2sw);
          w-=surface.box.left-dx;
@@ -2662,11 +3387,15 @@ class OpenGLDisplayDriver : DisplayDriver
          glDrawPixels(sw,sh,GL_BGRA_EXT,GL_UNSIGNED_BYTE, bitmap.picture);
          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
          glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
       }
+#endif
    }
 
    void BlitDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h)
    {
+#if !defined(EM_MODE)
       //Logf("BlitDI\n");
 
       //Clip against the edges of the source
@@ -2689,7 +3418,7 @@ class OpenGLDisplayDriver : DisplayDriver
       //Clip against the edges of the surfaceination
       if(dx<surface.box.left)
       {
-         //if(!flip) 
+         //if(!flip)
          sx+=surface.box.left-dx;
          w-=surface.box.left-dx;
          dx=surface.box.left;
@@ -2724,7 +3453,10 @@ class OpenGLDisplayDriver : DisplayDriver
          glDrawPixels(w,h,GL_BGRA_EXT,GL_UNSIGNED_BYTE, bitmap.picture);
          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
          glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+         glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+         glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
       }
+#endif
    }
 
    void FilterDI(Display display, Surface surface, Bitmap bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
@@ -2737,7 +3469,7 @@ class OpenGLDisplayDriver : DisplayDriver
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
    }
 
-   Font LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags)
+   Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
    {
       Font font;
       OGLSystem oglSystem = displaySystem.driverData;
@@ -2746,18 +3478,18 @@ class OpenGLDisplayDriver : DisplayDriver
       return font;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, char * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
    {
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, char * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
    {
       OGLSurface oglSurface = surface.driverData;
       OGLSystem oglSystem = display.displaySystem.driverData;
       oglSystem.loadingFont = true;
 
-      //glTranslatef(-0.375f, -0.375f, 0.0f);
+      //glTranslated(-0.375, -0.375, 0.0);
 
       //Logf("Blit\n");
 
@@ -2771,6 +3503,18 @@ class OpenGLDisplayDriver : DisplayDriver
       oglSurface.writingText = true;
 
       glEnable(GL_TEXTURE_2D);
+
+      if(surface.outline.size)
+      {
+         ColorAlpha outlineColor = surface.outline.color;
+         glColor4ub(outlineColor.color.r, outlineColor.color.g, outlineColor.color.b, outlineColor.a);
+         //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+         //glEnable(GL_BLEND);
+
+         oglSurface.writingOutline = true;
+         ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+         oglSurface.writingOutline = false;
+      }
       glColor4fv(oglSurface.foreground);
 
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
@@ -2779,7 +3523,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
       glDisable(GL_TEXTURE_2D);
 
-      //glTranslatef(0.375f, 0.375f, 0.0f);
+      //glTranslated(0.375, 0.375, 0.0);
    }
 
    void TextFont(Display display, Surface surface, Font font)
@@ -2793,7 +3537,7 @@ class OpenGLDisplayDriver : DisplayDriver
       oglSurface.opaqueText = opaque;
    }
 
-   void TextExtent(Display display, Surface surface, char * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
    {
       OGLSurface oglSurface = surface.driverData;
       OGLSystem oglSystem = display.displaySystem.driverData;
@@ -2813,13 +3557,28 @@ class OpenGLDisplayDriver : DisplayDriver
 
       if(stipple)
       {
+#if defined(_GLES) || defined(EM_MODE)
+         stippleEnabled = true;
+         glesLineStipple(1, (uint16)stipple);
+#else
          glLineStipple(1, (uint16)stipple);
          glEnable(GL_LINE_STIPPLE);
+#endif
       }
       else
+      {
+#if defined(_GLES) || defined(EM_MODE)
+         stippleEnabled = false;
+         glMatrixMode(GL_TEXTURE);
+         glLoadIdentity();
+         glMatrixMode(GL_PROJECTION);
+         glDisable(GL_TEXTURE_2D);
+#else
          glDisable(GL_LINE_STIPPLE);
+#endif
+      }
    }
-
+#if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
    void SetRenderState(Display display, RenderState state, uint value)
    {
       OGLDisplay oglDisplay = display.driverData;
@@ -2834,14 +3593,16 @@ class OpenGLDisplayDriver : DisplayDriver
                glDisable(GL_MULTISAMPLE_ARB);
             break;
          case fillMode:
+#if !defined(_GLES)
             glPolygonMode(GL_FRONT_AND_BACK, ((FillModeValue)value == solid) ? GL_FILL : GL_LINE);
+#endif
             break;
          case depthTest:
             if(value) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
             break;
          case depthWrite:
             if(value) glDepthMask((byte)bool::true); else glDepthMask((byte)bool::false);
-            oglDisplay.depthWrite = value;
+            oglDisplay.depthWrite = (bool)value;
             break;
          case fogColor:
          {
@@ -2850,15 +3611,17 @@ class OpenGLDisplayDriver : DisplayDriver
             break;
          }
          case fogDensity:
-            glFogf(GL_FOG_DENSITY, *(float *)(void *)&value);
+            glFogf(GL_FOG_DENSITY, (float)(RenderStateFloat { ui = value }.f * nearPlane));
             break;
          case blend:
             if(value) glEnable(GL_BLEND); else glDisable(GL_BLEND);
             break;
          case ambient:
          {
+#if !defined(EM_MODE)
             float ambient[4] = { ((Color)value).r/255.0f, ((Color)value).g/255.0f, ((Color)value).b/255.0f, 1.0f };
             glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+#endif
             break;
          }
          case alphaWrite:
@@ -2878,6 +3641,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
    void SetLight(Display display, int id, Light light)
    {
+#if !defined(EM_MODE)
       //Logf("SetLight\n");
 
       if(light != null)
@@ -2899,7 +3663,7 @@ class OpenGLDisplayDriver : DisplayDriver
          color[1] = light.diffuse.g * light.multiplier;
          color[2] = light.diffuse.b * light.multiplier;
          glLightfv(GL_LIGHT0 + id, GL_DIFFUSE, color);
-         
+
          color[0] = light.ambient.r * light.multiplier;
          color[1] = light.ambient.g * light.multiplier;
          color[2] = light.ambient.b * light.multiplier;
@@ -2908,7 +3672,7 @@ class OpenGLDisplayDriver : DisplayDriver
          color[1] = light.specular.g * light.multiplier;
          color[2] = light.specular.b * light.multiplier;
          glLightfv(GL_LIGHT0 + id, GL_SPECULAR,color);
-         
+
          if(lightObject)
          {
             Vector3D positionVector;
@@ -2946,7 +3710,7 @@ class OpenGLDisplayDriver : DisplayDriver
             position[0] = (float)positionVector.x;
             position[1] = (float)positionVector.y;
             position[2] = (float)positionVector.z;
-            
+
             glLightfv(GL_LIGHT0 + id, GL_POSITION, position);
 
             /*
@@ -2960,7 +3724,7 @@ class OpenGLDisplayDriver : DisplayDriver
             glEnd();
             glEnable(GL_DEPTH_TEST);
             glEnable(GL_LIGHTING);
-                     
+
 
             // Display Target
             if(lightObject.flags.root || !lightObject.parent)
@@ -2970,7 +3734,7 @@ class OpenGLDisplayDriver : DisplayDriver
             }
             else
             {
-               positionVector.MultMatrix(light.target.transform.position, 
+               positionVector.MultMatrix(light.target.transform.position,
                   lightObject.light.target.parent.matrix);
                positionVector.Subtract(positionVector, display.camera.cPosition);
             }
@@ -3012,7 +3776,7 @@ class OpenGLDisplayDriver : DisplayDriver
          }
          else
          {
-            
+
             Vector3Df vector { 0,0,-1 };
             Vector3Df direction;
             Matrix mat;
@@ -3029,6 +3793,7 @@ class OpenGLDisplayDriver : DisplayDriver
       }
       else
          glDisable(GL_LIGHT0 + id);
+#endif
    }
 
    void SetCamera(Display display, Surface surface, Camera camera)
@@ -3053,15 +3818,15 @@ class OpenGLDisplayDriver : DisplayDriver
          glViewport(x, y, w, h);
 
          // *** Projection Matrix ***
+         glMatrixMode(GL_PROJECTION);
          if(!display.display3D.camera)
             glPushMatrix();
-         else
-            glMatrixMode(GL_PROJECTION);
+
          if(display.display3D.collectingHits)
          {
             float pickX = display.display3D.pickX + surface.offset.x;
             float pickY = display.height - (display.display3D.pickY + surface.offset.y) - 1;
-            Matrix pickMatrix = 
+            Matrix pickMatrix
             {
                {
                   w / display.display3D.pickWidth, 0, 0, 0,
@@ -3090,7 +3855,8 @@ class OpenGLDisplayDriver : DisplayDriver
             glPushMatrix();
 
          glLoadIdentity();
-         glScalef(1.0f, 1.0f, -1.0f);
+
+         glScaled(1.0/nearPlane, 1.0/nearPlane, -1.0/nearPlane);
 
          // *** View Matrix ***
          glMultMatrixd(camera.viewMatrix.array);
@@ -3099,8 +3865,10 @@ class OpenGLDisplayDriver : DisplayDriver
          // ...
 
          glEnable(GL_DEPTH_TEST);
+//#if !defined(EM_MODE)
          glEnable(GL_LIGHTING);
          glShadeModel(GL_SMOOTH);
+//#endif
          glDepthMask((byte)bool::true);
          oglDisplay.depthWrite = true;
 
@@ -3116,7 +3884,9 @@ class OpenGLDisplayDriver : DisplayDriver
          glDisable(GL_LIGHTING);
          glDisable(GL_FOG);
          glDisable(GL_TEXTURE_2D);
+//#if !defined(EM_MODE)
          glShadeModel(GL_FLAT);
+//#endif
          glEnable(GL_BLEND);
          glDisable(GL_MULTISAMPLE_ARB);
 
@@ -3128,8 +3898,6 @@ class OpenGLDisplayDriver : DisplayDriver
          glPopMatrix();
       }
 
-      if(glBindBufferARB)
-         glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
    }
 
    void ApplyMaterial(Display display, Material material, Mesh mesh)
@@ -3139,12 +3907,16 @@ class OpenGLDisplayDriver : DisplayDriver
       // Basic Properties
       if(material.flags.doubleSided)
       {
+#if !defined(EM_MODE)
          glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, !material.flags.singleSideLight);
+#endif
          glDisable(GL_CULL_FACE);
       }
       else
       {
+#if !defined(EM_MODE)
          glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, bool::false);
+#endif
          glEnable(GL_CULL_FACE);
       }
 
@@ -3155,11 +3927,17 @@ class OpenGLDisplayDriver : DisplayDriver
          glEnable(GL_FOG);
 
       // Maps
-      if(material.baseMap && mesh.texCoords)
+      if(material.baseMap && (mesh.texCoords || mesh.flags.texCoords1))
       {
          Bitmap map = material.baseMap;
          glEnable(GL_TEXTURE_2D);
-         glBindTexture(GL_TEXTURE_2D, (uint)map.driverData);
+         glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)map.driverData);
+
+         glMatrixMode(GL_TEXTURE);
+         glLoadIdentity();
+         if(material.uScale && material.vScale)
+            glScalef(material.uScale, material.vScale, 1);
+         glMatrixMode(GL_MODELVIEW);
 
          if(material.flags.tile)
          {
@@ -3175,6 +3953,9 @@ class OpenGLDisplayDriver : DisplayDriver
       else
          glDisable(GL_TEXTURE_2D);
 
+#ifdef EM_MODE
+      glColor4f(material.diffuse.r, material.diffuse.g, material.diffuse.b, material.opacity);
+#else
       if(mesh.flags.colors)
       {
          glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
@@ -3192,7 +3973,7 @@ class OpenGLDisplayDriver : DisplayDriver
             glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
          }
       }
-      {   
+      {
          float color[4] = { material.specular.r, material.specular.g, material.specular.b, 0 };
          glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
       }
@@ -3200,8 +3981,9 @@ class OpenGLDisplayDriver : DisplayDriver
          float color[4] = { material.emissive.r, material.emissive.g, material.emissive.b, 0 };
          glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);
       }
-      
+
       glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &material.power);
+#endif
    }
 
    void FreeMesh(DisplaySystem displaySystem, Mesh mesh)
@@ -3211,49 +3993,28 @@ class OpenGLDisplayDriver : DisplayDriver
       {
          if(!mesh.flags.vertices)
          {
-            if(oglMesh.vertices)
-            {
-               glDeleteBuffersARB(1, &oglMesh.vertices);
-               oglMesh.vertices = 0;
-            }
+            oglMesh.vertices.free();
             delete mesh.vertices;
          }
          if(!mesh.flags.normals)
          {
-            if(oglMesh.normals)
-            {
-               glDeleteBuffersARB(1, &oglMesh.normals);
-               oglMesh.normals = 0;
-            }
+            oglMesh.normals.free();
             delete mesh.normals;
          }
          if(!mesh.flags.texCoords1)
          {
-            if(oglMesh.texCoords)
-            {
-               glDeleteBuffersARB(1, &oglMesh.texCoords);
-               oglMesh.texCoords = 0;
-            }
+            oglMesh.texCoords.free();
             delete mesh.texCoords;
          }
          if(!mesh.flags.texCoords2)
          {
-            if(oglMesh.texCoords2)
-            {
-               glDeleteBuffersARB(1, &oglMesh.texCoords2);
-               oglMesh.texCoords2 = 0;
-            }
-            /*
-            delete mesh.texCoords2;
-            */
+            oglMesh.texCoords2.free();
+            // delete mesh.texCoords2;
          }
          if(!mesh.flags.colors)
          {
-            if(oglMesh.colors)
-            {
-               glDeleteBuffersARB(1, &oglMesh.colors);
-               oglMesh.colors = 0;
-            }
+            oglMesh.colors.free();
+            delete mesh.colors;
          }
          if(!mesh.flags)
          {
@@ -3263,7 +4024,7 @@ class OpenGLDisplayDriver : DisplayDriver
       }
    }
 
-   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh)
+   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
    {
       bool result = false;
 
@@ -3271,31 +4032,69 @@ class OpenGLDisplayDriver : DisplayDriver
          mesh.data = OGLMesh { };
       if(mesh.data)
       {
-         OGLMesh oglMesh = mesh.data;
-
-         if(mesh.flags.vertices && !oglMesh.vertices && !mesh.vertices)
-         {
-            mesh.vertices = mesh.flags.doubleVertices ? (Vector3Df *)new Vector3D[mesh.nVertices] : new Vector3Df[mesh.nVertices];
-            if(glGenBuffersARB)
-               glGenBuffersARB(1, &oglMesh.vertices);
-         }
-         if(mesh.flags.normals && !oglMesh.normals && !mesh.normals)
+         if(mesh.nVertices == nVertices)
          {
-            if(glGenBuffersARB)
-               glGenBuffersARB( 1, &oglMesh.normals);
-            mesh.normals = mesh.flags.doubleNormals ? (Vector3Df *)new Vector3D[mesh.nVertices] : new Vector3Df[mesh.nVertices];
-         }
-         if(mesh.flags.texCoords1 && !oglMesh.texCoords && !mesh.texCoords)
-         {
-            if(glGenBuffersARB)
-               glGenBuffersARB( 1, &oglMesh.texCoords);
-            mesh.texCoords = new Pointf[mesh.nVertices];
+            // Same number of vertices, adding features (Leaves the other features pointers alone)
+            if(mesh.flags != flags)
+            {
+               if(!mesh.flags.vertices && flags.vertices)
+               {
+                  if(flags.doubleVertices)
+                  {
+                     mesh.vertices = (Vector3Df *)new Vector3D[nVertices];
+                  }
+                  else
+                     mesh.vertices = new Vector3Df[nVertices];
+               }
+               if(!mesh.flags.normals && flags.normals)
+               {
+                  if(flags.doubleNormals)
+                  {
+                     mesh.normals = (Vector3Df *)new Vector3D[nVertices];
+                  }
+                  else
+                     mesh.normals = new Vector3Df[nVertices];
+               }
+               if(!mesh.flags.texCoords1 && flags.texCoords1)
+               {
+                  mesh.texCoords = new Pointf[nVertices];
+               }
+               if(!mesh.flags.colors && flags.colors)
+               {
+                  mesh.colors = new ColorRGBAf[nVertices];
+               }
+            }
          }
-         if(mesh.flags.colors && !oglMesh.colors && !mesh.colors)
+         else
          {
-            if(glGenBuffersARB)
-               glGenBuffersARB( 1, &oglMesh.colors);
-            mesh.colors = new ColorRGBAf[mesh.nVertices];
+            // New number of vertices, reallocate all current and new features
+            flags |= mesh.flags;
+            if(flags.vertices)
+            {
+               if(flags.doubleVertices)
+               {
+                  mesh.vertices = (Vector3Df *)renew mesh.vertices Vector3D[nVertices];
+               }
+               else
+                  mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
+            }
+            if(flags.normals)
+            {
+               if(flags.doubleNormals)
+               {
+                  mesh.normals = (Vector3Df *)renew mesh.normals Vector3D[nVertices];
+               }
+               else
+                  mesh.normals = renew mesh.normals Vector3Df[nVertices];
+            }
+            if(flags.texCoords1)
+            {
+               mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
+            }
+            if(flags.colors)
+            {
+               mesh.colors = renew mesh.colors ColorRGBAf[nVertices];
+            }
          }
          result = true;
       }
@@ -3306,34 +4105,24 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       OGLMesh oglMesh = mesh.data;
       if(!flags) flags = mesh.flags;
-      
-      if(glGenBuffersARB)
-      {
-         if(!(flags.vertices) || oglMesh.vertices)
-         {
-            glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.vertices);
-            glBufferDataARB( GL_ARRAY_BUFFER_ARB, mesh.nVertices * (mesh.flags.doubleVertices ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.vertices, GL_STATIC_DRAW_ARB );
-         }
 
-         if(!(flags.normals) || oglMesh.normals)
-         {
-            glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.normals);
-            glBufferDataARB( GL_ARRAY_BUFFER_ARB, mesh.nVertices * (mesh.flags.doubleNormals ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.normals, GL_STATIC_DRAW_ARB );
-         }
+      if(vboAvailable)
+      {
+         if(flags.vertices)
+            oglMesh.vertices.upload(
+               mesh.nVertices * (mesh.flags.doubleVertices ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.vertices); //, GL_STATIC_DRAW_ARB );
 
-         if(!(flags.texCoords1) || oglMesh.texCoords)
-         {
-            glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.texCoords);
-            glBufferDataARB( GL_ARRAY_BUFFER_ARB, mesh.nVertices * sizeof(Pointf), mesh.texCoords, GL_STATIC_DRAW_ARB );
-         }
+         if(flags.normals)
+            oglMesh.normals.upload(
+               mesh.nVertices * (mesh.flags.doubleNormals ? sizeof(Vector3D) : sizeof(Vector3Df)), mesh.normals); //, GL_STATIC_DRAW_ARB );
 
-         if(!(flags.colors) || oglMesh.colors)
-         {
-            glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.colors);
-            glBufferDataARB( GL_ARRAY_BUFFER_ARB, mesh.nVertices * sizeof(ColorRGBAf), mesh.colors, GL_STATIC_DRAW_ARB );
-         }
+         if(flags.texCoords1)
+            oglMesh.texCoords.upload(
+               mesh.nVertices * sizeof(Pointf), mesh.texCoords); //, GL_STATIC_DRAW_ARB );
 
-         glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0);
+         if(flags.colors)
+            oglMesh.colors.upload(
+               mesh.nVertices * sizeof(ColorRGBAf), mesh.colors); //, GL_STATIC_DRAW_ARB );
       }
    }
 
@@ -3348,8 +4137,7 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       if(oglIndices)
       {
-         if(oglIndices.buffer) 
-            glDeleteBuffersARB(1, &oglIndices.buffer);
+         oglIndices.buffer.free();
          delete oglIndices.indices;
          delete oglIndices;
       }
@@ -3361,8 +4149,6 @@ class OpenGLDisplayDriver : DisplayDriver
       if(oglIndices)
       {
          oglIndices.indices = (void *)(indices32bit ? new uint32[nIndices] : new uint16[nIndices]);
-         if(glGenBuffersARB)
-            glGenBuffersARB( 1, &oglIndices.buffer);
          oglIndices.nIndices = nIndices;
       }
       return oglIndices;
@@ -3370,18 +4156,28 @@ class OpenGLDisplayDriver : DisplayDriver
 
    void UnlockIndices(DisplaySystem displaySystem, OGLIndices oglIndices, bool indices32bit, int nIndices)
    {
-      if(glGenBuffersARB)
+      if(vboAvailable)
       {
-         glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, oglIndices.buffer);
-         glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, nIndices * (indices32bit ? sizeof(uint32) : sizeof(uint16)), 
-            oglIndices.indices, GL_STATIC_DRAW_ARB);
-         glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+#ifdef _GLES
+         if(indices32bit)
+         {
+            if(!oglIndices.buffer.buffer)
+               GLGenBuffers(1, (GLAB *)&oglIndices.buffer);
+            if(curElementBuffer != oglIndices.buffer.buffer)
+               GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oglIndices.buffer.buffer);
+            glesBufferDatai(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * nIndices, oglIndices.indices, GL_STATIC_DRAW_ARB);
+         }
+         else
+#endif
+         oglIndices.buffer.upload(
+            nIndices * (indices32bit ? sizeof(uint32) : sizeof(uint16)),
+            oglIndices.indices); //GL_STATIC_DRAW_ARB);
       }
    }
 
    uint16 * LockIndices(DisplaySystem displaySystem, OGLIndices oglIndices)
    {
-      
+
       return oglIndices.indices;
    }
 
@@ -3389,104 +4185,102 @@ class OpenGLDisplayDriver : DisplayDriver
    {
       //Logf("SelectMesh\n");
 
-#ifndef __ANDROID__
-      if(display.display3D.mesh && glUnlockArraysEXT)   
-         glUnlockArraysEXT();
+#if !defined( __ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
+
+#if defined(__WIN32__)
+      if(glUnlockArraysEXT)
+#endif
+         if(!vboAvailable && display.display3D.mesh)
+            glUnlockArraysEXT();
+
 #endif
       if(mesh)
       {
-         OGLDisplay oglDisplay = display.driverData;
          OGLMesh oglMesh = mesh.data;
 
          // *** Vertex Stream ***
          glEnableClientState(GL_VERTEX_ARRAY);
          if(!display.display3D.collectingHits && oglMesh)
          {
-            if(glBindBufferARB)
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, oglMesh.vertices );
-            glVertexPointer(3, mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT, 0, glBindBufferARB ? null : mesh.vertices);
+            oglMesh.vertices.use(vertex, 3, (mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT), 0, oglMesh.vertices.buffer ? null : (double *)mesh.vertices);
 
             // *** Normals Stream ***
-            if(mesh.normals)
+            if(mesh.normals || mesh.flags.normals)
             {
                glEnableClientState(GL_NORMAL_ARRAY);
-               if(glBindBufferARB)
-                  glBindBufferARB(GL_ARRAY_BUFFER_ARB, oglMesh.normals);
-               glNormalPointer(mesh.flags.doubleNormals ? GL_DOUBLE : GL_FLOAT, 0, glBindBufferARB ? null : mesh.normals);
+               oglMesh.normals.use(normal, 3, GL_FLOAT, 0, oglMesh.normals.buffer ? null : mesh.normals);
             }
             else
                glDisableClientState(GL_NORMAL_ARRAY);
 
             // *** Texture Coordinates Stream ***
-            if(mesh.texCoords)
+            if(mesh.texCoords || mesh.flags.texCoords1)
             {
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               if(glBindBufferARB)
-                  glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.texCoords);
-               glTexCoordPointer(2, GL_FLOAT, 0, glBindBufferARB ? null : mesh.texCoords);
+               oglMesh.texCoords.use(texCoord, 2, GL_FLOAT, 0, oglMesh.texCoords.buffer ? null : mesh.texCoords);
             }
             else
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
             // *** Color Stream ***
-            if(mesh.colors)
+            if(mesh.colors || mesh.flags.colors)
             {
                glEnableClientState(GL_COLOR_ARRAY);
-               if(glBindBufferARB)
-                  glBindBufferARB( GL_ARRAY_BUFFER_ARB, oglMesh.colors);
-               glColorPointer(4, GL_FLOAT, 0, glBindBufferARB ? null : mesh.colors);
+               oglMesh.colors.use(color, 4, GL_FLOAT, 0, oglMesh.colors.buffer ? null : mesh.colors);
             }
             else
                glDisableClientState(GL_COLOR_ARRAY);
-
          }
          else
          {
-            if(glBindBufferARB)
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0);
-            glVertexPointer(3,mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT,0,mesh.vertices);
-            if(mesh.normals && !display.display3D.collectingHits)
+            noAB.use(vertex, 3, (mesh.flags.doubleVertices ? GL_DOUBLE : GL_FLOAT), 0, (double *)mesh.vertices);
+            if((mesh.normals || mesh.flags.normals) && !display.display3D.collectingHits)
             {
                glEnableClientState(GL_NORMAL_ARRAY);
-               glNormalPointer(mesh.flags.doubleNormals ? GL_DOUBLE : GL_FLOAT, 0, mesh.normals);
+               noAB.use(normal, 3, GL_FLOAT, 0, mesh.normals);
             }
             else
                glDisableClientState(GL_NORMAL_ARRAY);
-            if(mesh.texCoords && !display.display3D.collectingHits)
+            if((mesh.texCoords || mesh.flags.texCoords1) && !display.display3D.collectingHits)
             {
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               glTexCoordPointer(2, GL_FLOAT, 0, mesh.texCoords);
+               noAB.use(texCoord, 2, GL_FLOAT, 0, mesh.texCoords);
             }
             else
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-            if(mesh.colors && !display.display3D.collectingHits)
+            if((mesh.colors || mesh.flags.colors) && !display.display3D.collectingHits)
             {
                glEnableClientState(GL_COLOR_ARRAY);
-               glColorPointer(4, GL_FLOAT, 0, mesh.colors);
+               noAB.use(color, 4, GL_FLOAT, 0, mesh.colors);
             }
             else
                glDisableClientState(GL_COLOR_ARRAY);
          }
 
-#ifndef __ANDROID__
-         if(glLockArraysEXT) glLockArraysEXT(0, mesh.nVertices);
+#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ODROID__)
+
+#if defined(__WIN32__)
+         if(glLockArraysEXT)
+#endif
+            if(!vboAvailable)
+               glLockArraysEXT(0, mesh.nVertices);
+
 #endif
       }
-      else if(glBindBufferARB)
-         glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
    }
 
    void DrawPrimitives(Display display, PrimitiveSingle * primitive, Mesh mesh)
    {
-      OGLDisplay oglDisplay = display.driverData;
       //Logf("DrawPrimitives\n");
 
       if(primitive->type.vertexRange)
          glDrawArrays(primitiveTypes[primitive->type.primitiveType], primitive->first, primitive->nVertices);
       else
       {
-         //    *** Hoping the data won't be uploaded at all (Won't really work if another group of the mesh is using the mesh ) *** 
+         //    *** Hoping the data won't be uploaded at all (Won't really work if another group of the mesh is using the mesh ) ***
          // HACK TO SPEED THINGS UP...
+#ifndef __ANDROID__
+         /*GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
          if(primitive->nIndices < (mesh.nVertices >> 2) && !primitive->type.indices32bit)
          {
             int c;
@@ -3497,7 +4291,7 @@ class OpenGLDisplayDriver : DisplayDriver
                MeshFeatures flags = mesh.flags;
                for(c = 0; c<primitive->nIndices; c++)
                {
-                  short index = ((short *) oglIndices.indices)[c];
+                  uint16 index = ((uint16 *) oglIndices.indices)[c];
                   if(flags.normals) glNormal3fv((float *)&mesh.normals[index]);
                   if(flags.texCoords1) glTexCoord2fv((float *)&mesh.texCoords[index]);
                   if(flags.colors) glColor4fv((float *)&mesh.colors[index]);
@@ -3506,23 +4300,17 @@ class OpenGLDisplayDriver : DisplayDriver
             }
             glEnd();
          }
-         else
+         else*/
+#endif
+
          {
             OGLIndices oglIndices = primitive->data;
+            GLEAB eab = ((!display.display3D.collectingHits && oglIndices) ? oglIndices.buffer : noEAB);
 
-            if(!display.display3D.collectingHits && glBindBufferARB && oglIndices)
-            {
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, oglIndices.buffer);
-               glDrawElements(primitiveTypes[primitive->type.primitiveType], primitive->nIndices, 
-                  primitive->type.indices32bit ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
-            }
-            else if(oglIndices)
-               glDrawElements(primitiveTypes[primitive->type.primitiveType], primitive->nIndices, 
-                  primitive->type.indices32bit ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, oglIndices.indices);
-            else
-               glDrawElements(primitiveTypes[primitive->type.primitiveType], primitive->nIndices, 
-                  primitive->type.indices32bit ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, primitive->indices);
+            eab.draw(primitiveTypes[primitive->type.primitiveType], primitive->nIndices,
+               primitive->type.indices32bit ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT,
+               eab.buffer ? 0 : (oglIndices ? oglIndices.indices : primitive->indices));
+            GLBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
          }
       }
    }
@@ -3545,7 +4333,7 @@ class OpenGLDisplayDriver : DisplayDriver
       if(viewSpace)
       {
          glLoadIdentity();
-         glScalef(1.0f, 1.0f, -1.0f);
+         glScaled(1.0/nearPlane, 1.0/nearPlane, -1.0/nearPlane);
       }
       else if(camera)
       {
@@ -3566,6 +4354,7 @@ class OpenGLDisplayDriver : DisplayDriver
 
       glMultMatrixd(matrix.array);
    }
+#endif
 }
 
 public void UseSingleGLContext(bool useSingle)
@@ -3573,4 +4362,26 @@ public void UseSingleGLContext(bool useSingle)
    useSingleGLContext = useSingle;
 }
 
+default dllexport void *
+#if defined(__WIN32__)
+__attribute__((stdcall))
+#endif
+IS_GLGetContext(DisplaySystem displaySystem)
+{
+   if(displaySystem)
+   {
+#if defined(__WIN32__)
+      OGLSystem system = displaySystem.driverData;
+      return system.glrc;
+#elif defined(__ANDROID__) || defined(__ODROID__)
+      return eglContext;
+#elif defined(__EMSCRIPTEN__)
+#else
+      OGLSystem system = displaySystem.driverData;
+      return system.glContext;
+#endif
+   }
+   return null;
+}
+
 #endif