text: #if defined(USE_OPENGL_API)
  
  #include "MiniFB_GL.h"
  #if defined(_WIN32) || defined(WIN32)
      #include <windows/WindowData_Win.h>
      #include <gl/gl.h>
  #elif defined(linux)
      #include <x11/WindowData_X11.h>
      #include <GL/gl.h>
      #include <GL/glx.h>
  #endif
  #include <stdio.h>
  #include <stdlib.h>
  
  //#define kUse_Clean_UP
  #if defined(kUse_Clean_UP)
      #define UseCleanUp(x) x
  #else
      #define UseCleanUp(x)
  #endif
  
  //-------------------------------------
  #if defined(_WIN32) || defined(WIN32)
  bool
  setup_pixel_format(HDC hDC) {
      int pixelFormat;
  
      PIXELFORMATDESCRIPTOR pfd = {
          sizeof(PIXELFORMATDESCRIPTOR),  // size
          1,                              // version
          PFD_SUPPORT_OPENGL |            //
          PFD_DRAW_TO_WINDOW |            //
          PFD_DOUBLEBUFFER,               // support double-buffering
          PFD_TYPE_RGBA,                  // color type
          24,                             // preferred color depth
          0, 0, 0, 0, 0, 0,               // color and shift bits (ignored)
          0,                              // no alpha buffer
          0,                              // alpha bits (ignored)
          0,                              // no accumulation buffer
          0, 0, 0, 0,                     // accum bits (ignored)
          24,                             // depth buffer
          8,                              // no stencil buffer
          0,                              // no auxiliary buffers
          PFD_MAIN_PLANE,                 // main layer
          0,                              // reserved
          0, 0, 0,                        // no layer, visible, damage masks
      };
  
      pixelFormat = ChoosePixelFormat(hDC, &pfd);
      if (pixelFormat == 0) {
          MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
          return false;
      }
  
      if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
          MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK);
          return false;
      }
  
      return true;
  }
  #endif
  
  //-------------------------------------
  bool 
  create_GL_context(SWindowData *window_data) {
  #if defined(_WIN32) || defined(WIN32)
      SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
  
      if(setup_pixel_format(window_data_win->hdc) == false)
          return false;
      window_data_win->hGLRC = wglCreateContext(window_data_win->hdc);
      wglMakeCurrent(window_data_win->hdc, window_data_win->hGLRC);
      init_GL(window_data);
  
      return true;
  
  #elif defined(linux)
      SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
  
      GLint majorGLX, minorGLX = 0;
      glXQueryVersion(window_data_x11->display, &majorGLX, &minorGLX);
      if (majorGLX <= 1 && minorGLX < 2) {
          fprintf(stderr, "GLX 1.2 or greater is required.\n");
          XCloseDisplay(window_data_x11->display);
          return false;
      }
      else {
          //fprintf(stdout, "GLX version: %d.%d\n", majorGLX, minorGLX);
      }
  
      GLint glxAttribs[] = {
          GLX_RGBA,
          GLX_DOUBLEBUFFER,
          GLX_DEPTH_SIZE,     24,
          GLX_STENCIL_SIZE,   8,
          GLX_RED_SIZE,       8,
          GLX_GREEN_SIZE,     8,
          GLX_BLUE_SIZE,      8,
          GLX_DEPTH_SIZE,     24,
          GLX_STENCIL_SIZE,   8,
          GLX_SAMPLE_BUFFERS, 0,
          GLX_SAMPLES,        0,
          None
      };
      XVisualInfo* visualInfo = glXChooseVisual(window_data_x11->display, window_data_x11->screen, glxAttribs);
      if (visualInfo == 0) {
          fprintf(stderr, "Could not create correct visual window.\n");
          XCloseDisplay(window_data_x11->display);
          return false;
      }
  
      window_data_x11->context = glXCreateContext(window_data_x11->display, visualInfo, NULL, GL_TRUE);
      glXMakeCurrent(window_data_x11->display, window_data_x11->window, window_data_x11->context);
  
      //fprintf(stdout, "GL Vendor: %s\n", glGetString(GL_VENDOR));
      //fprintf(stdout, "GL Renderer: %s\n", glGetString(GL_RENDERER));
      //fprintf(stdout, "GL Version: %s\n", glGetString(GL_VERSION));
      //fprintf(stdout, "GL Shading Language: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
  
      init_GL(window_data);
  
      return true;
  #endif
  }
  
  //-------------------------------------
  void 
  destroy_GL_context(SWindowData *window_data) {
  #if defined(_WIN32) || defined(WIN32)
  
      SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific;
      if (window_data_win->hGLRC) {
          wglMakeCurrent(NULL, NULL);
          wglDeleteContext(window_data_win->hGLRC);
          window_data_win->hGLRC = 0;
      }
  
  #elif defined(linux)
  
      SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific;
      glXDestroyContext(window_data_x11->display, window_data_x11->context);
  
  #endif
  }
  
  //-------------------------------------
  #if defined(RGB)
      #undef RGB
  #endif
  
  #define TEXTURE0    0x84C0  // [ Core in gl 1.3, gles1 1.0, gles2 2.0, glsc2 2.0, Provided by GL_ARB_multitexture (gl) ]
  #define RGB         0x1907  // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ]    
  #define RGBA        0x1908  // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ]
  #define BGR         0x80E0  // [ Core in gl 1.2 ]
  #define BGRA        0x80E1  // [ Core in gl 1.2, Provided by GL_ARB_vertex_array_bgra (gl|glcore) ]
  
  //-------------------------------------
  void 
  init_GL(SWindowData *window_data) {
  #if defined(_WIN32) || defined(WIN32)
  
      SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
  
  #elif defined(linux)
  
      SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
  
  #endif
  
  
      glViewport(0, 0, window_data->window_width, window_data->window_height);
  
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048);
  
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
  
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_STENCIL_TEST);
  
      glEnable(GL_TEXTURE_2D);
  
      glGenTextures(1, &window_data_ex->text_id);
      //glActiveTexture(TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  
      glEnableClientState(GL_VERTEX_ARRAY);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  
      UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
      UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY));
      UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0));
  }
  
  //-------------------------------------
  void 
  resize_GL(SWindowData *window_data) {
      if(window_data->is_initialized) {
      #if defined(_WIN32) || defined(WIN32)
  
          SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
          wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC);
  
      #elif defined(linux)
  
          SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
          glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context);
  
      #endif
  
          glViewport(0, 0, window_data->window_width, window_data->window_height);
  
          glMatrixMode(GL_PROJECTION);
          glLoadIdentity();
          glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048);
  
          glClear(GL_COLOR_BUFFER_BIT);
      }
  }
  
  //-------------------------------------
  void 
  redraw_GL(SWindowData *window_data, const void *pixels) {
  #if defined(_WIN32) || defined(WIN32)
  
      SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific;
      GLenum format = BGRA;
  
      wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC);
  
  #elif defined(linux)
  
      SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific;
      GLenum format = BGRA;
  
      glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context);
  
  #endif
  
      float           x, y, w, h;
  
      x = (float) window_data->dst_offset_x;
      y = (float) window_data->dst_offset_y;
      w = (float) window_data->dst_offset_x + window_data->dst_width;
      h = (float) window_data->dst_offset_y + window_data->dst_height;
  
      float vertices[] = {
          x, y,
          0, 0, 
  
          w, y,
          1, 0,
          
          x, h,
          0, 1,
  
          w, h,
          1, 1,
      };
  
      glClear(GL_COLOR_BUFFER_BIT);
  
      UseCleanUp(glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id));
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_data->buffer_width, window_data->buffer_height, 0, format, GL_UNSIGNED_BYTE, pixels);
      //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, window_data->buffer_width, window_data->buffer_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  
      UseCleanUp(glEnableClientState(GL_VERTEX_ARRAY));
      UseCleanUp(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
      glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), vertices);
      glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), vertices + 2);
  
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
      UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
      UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY));
      UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0));
  
  #if defined(_WIN32) || defined(WIN32)
      SwapBuffers(window_data_ex->hdc);
  #elif defined(linux)
      glXSwapBuffers(window_data_ex->display, window_data_ex->window);
  #endif
  }
  
  #endif