// Copyright (c) 2021 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <OpenGl_GlNative.hxx>

#include <OpenGl_Context.hxx>

#include <OpenGl_ArbTBO.hxx>
#include <OpenGl_ArbIns.hxx>
#include <OpenGl_ArbDbg.hxx>
#include <OpenGl_ArbFBO.hxx>
#include <OpenGl_ExtGS.hxx>
#include <OpenGl_ArbSamplerObject.hxx>
#include <OpenGl_ArbTexBindless.hxx>
#include <OpenGl_GlCore46.hxx>

#if !defined(HAVE_EGL) && defined(HAVE_XLIB)
  #include <GL/glx.h>
#endif

#ifdef __EMSCRIPTEN__
  #include <emscripten.h>
  #include <emscripten/html5.h>
#endif

// This debug macros can be enabled to help debugging OpenGL implementations
// without solid / working debugging capabilities.
//#define TO_TRACE

#define WrapProxyProc(theFunc) this->theFunc=opencascade::theFunc
#define WrapProxyProc5(theFunc1,theFunc2,theFunc3,theFunc4,theFunc5) \
  WrapProxyProc(theFunc1);WrapProxyProc(theFunc2);WrapProxyProc(theFunc3);WrapProxyProc(theFunc4);WrapProxyProc(theFunc5)

#ifdef TO_TRACE
  #define OpenGl_TRACE(theName) {OpenGl_GlFunctions::debugPrintError(#theName);}
  #define WrapProxyDef(theFunc) this->theFunc=opencascade::theFunc
#else
  #define OpenGl_TRACE(theName)
  // skip wrapper and set pointer to global function
  #define WrapProxyDef(theFunc) this->theFunc=opencascade::theFunc;this->theFunc=::theFunc;
#endif

#define WrapProxyDef5(theFunc1,theFunc2,theFunc3,theFunc4,theFunc5) \
  WrapProxyDef(theFunc1);WrapProxyDef(theFunc2);WrapProxyDef(theFunc3);WrapProxyDef(theFunc4);WrapProxyDef(theFunc5)

namespace opencascade
{
  static void APIENTRY glReadBuffer (GLenum mode)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF); // added to OpenGL ES 3.0
    (void )mode;
  #else
    ::glReadBuffer (mode);
  #endif
    OpenGl_TRACE(glReadBuffer)
  }

  static void APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF); // added to OpenGL ES 3.1
    (void )target; (void )level; (void )pname; (void )params;
  #else
    ::glGetTexLevelParameteriv (target, level, pname, params);
  #endif
    OpenGl_TRACE(glGetTexLevelParameteriv)
  }

  static void APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF); // added to OpenGL ES 3.1
    (void )target; (void )level; (void )pname; (void )params;
  #else
    ::glGetTexLevelParameterfv (target, level, pname, params);
  #endif
    OpenGl_TRACE(glGetTexLevelParameterfv)
  }

  static void APIENTRY glGetPointerv (GLenum name, GLvoid* *params)
  {
  #if defined(GL_ES_VERSION_2_0)
    *params = NULL;
    ::glEnable (0xFFFF); // added to OpenGL ES 3.2
    (void )name;
  #else
    ::glGetPointerv (name, params);
  #endif
    OpenGl_TRACE(glGetPointerv)
  }

  static void APIENTRY glDrawBuffer (GLenum mode)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )mode;
  #else
    ::glDrawBuffer (mode);
  #endif
    OpenGl_TRACE(glDrawBuffer)
  }

  // Miscellaneous

  static void APIENTRY glClearColor (GLclampf theRed, GLclampf theGreen, GLclampf theBlue, GLclampf theAlpha)
  {
    ::glClearColor  (theRed, theGreen, theBlue, theAlpha);
    OpenGl_TRACE(glClearColor)
  }

  static void APIENTRY glClear (GLbitfield theMask)
  {
    ::glClear (theMask);
    OpenGl_TRACE(glClear)
  }

  static void APIENTRY glColorMask (GLboolean theRed, GLboolean theGreen, GLboolean theBlue, GLboolean theAlpha)
  {
    ::glColorMask (theRed, theGreen, theBlue, theAlpha);
    OpenGl_TRACE(glColorMask)
  }

  static void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor)
  {
    ::glBlendFunc(sfactor, dfactor);
    OpenGl_TRACE(glBlendFunc)
  }

  static void APIENTRY glCullFace (GLenum theMode)
  {
    ::glCullFace (theMode);
    OpenGl_TRACE(glCullFace)
  }

  static void APIENTRY glFrontFace (GLenum theMode)
  {
    ::glFrontFace (theMode);
    OpenGl_TRACE(glFrontFace)
  }

  static void APIENTRY glLineWidth (GLfloat theWidth)
  {
    ::glLineWidth (theWidth);
    OpenGl_TRACE(glLineWidth)
  }

  static void APIENTRY glPolygonOffset (GLfloat theFactor, GLfloat theUnits)
  {
    ::glPolygonOffset (theFactor, theUnits);
    OpenGl_TRACE(glPolygonOffset)
  }

  static void APIENTRY glScissor (GLint theX, GLint theY, GLsizei theWidth, GLsizei theHeight)
  {
    ::glScissor (theX, theY, theWidth, theHeight);
    OpenGl_TRACE(glScissor)
  }

  static void APIENTRY glEnable (GLenum theCap)
  {
    ::glEnable (theCap);
    OpenGl_TRACE(glEnable)
  }

  static void APIENTRY glDisable (GLenum theCap)
  {
    ::glDisable (theCap);
    OpenGl_TRACE(glDisable)
  }

  static GLboolean APIENTRY glIsEnabled (GLenum theCap)
  {
    return ::glIsEnabled (theCap);
  }

  static void APIENTRY glGetBooleanv (GLenum theParamName, GLboolean* theValues)
  {
    ::glGetBooleanv (theParamName, theValues);
    OpenGl_TRACE(glGetBooleanv)
  }

  static void APIENTRY glGetFloatv (GLenum theParamName, GLfloat* theValues)
  {
    ::glGetFloatv (theParamName, theValues);
    OpenGl_TRACE(glGetFloatv)
  }

  static void APIENTRY glGetIntegerv (GLenum theParamName, GLint* theValues)
  {
    ::glGetIntegerv (theParamName, theValues);
    OpenGl_TRACE(glGetIntegerv)
  }

  static GLenum APIENTRY glGetError()
  {
    return ::glGetError();
  }

  static const GLubyte* APIENTRY glGetString (GLenum theName)
  {
    const GLubyte* aRes = ::glGetString (theName);
    OpenGl_TRACE(glGetString)
    return aRes;
  }

  static void APIENTRY glFinish()
  {
    ::glFinish();
    OpenGl_TRACE(glFinish)
  }

  static void APIENTRY glFlush()
  {
    ::glFlush();
    OpenGl_TRACE(glFlush)
  }

  static void APIENTRY glHint (GLenum theTarget, GLenum theMode)
  {
    ::glHint (theTarget, theMode);
    OpenGl_TRACE(glHint)
  }

  // Depth Buffer

  static void APIENTRY glClearDepth (GLclampd theDepth)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glClearDepthf ((GLfloat )theDepth);
  #else
    ::glClearDepth (theDepth);
  #endif
    OpenGl_TRACE(glClearDepth)
  }

  static void APIENTRY glClearDepthf (GLfloat theDepth)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glClearDepthf (theDepth);
  #else
    ::glClearDepth (theDepth);
  #endif
    OpenGl_TRACE(glClearDepthf)
  }

  static void APIENTRY glDepthFunc (GLenum theFunc)
  {
    ::glDepthFunc (theFunc);
    OpenGl_TRACE(glDepthFunc)
  }

  static void APIENTRY glDepthMask (GLboolean theFlag)
  {
    ::glDepthMask (theFlag);
    OpenGl_TRACE(glDepthMask)
  }

  static void APIENTRY glDepthRange (GLclampd theNearValue,
                                     GLclampd theFarValue)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glDepthRangef ((GLfloat )theNearValue, (GLfloat )theFarValue);
  #else
    ::glDepthRange (theNearValue, theFarValue);
  #endif
    OpenGl_TRACE(glDepthRange)
  }

  static void APIENTRY glDepthRangef (GLfloat theNearValue,
                                      GLfloat theFarValue)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glDepthRangef (theNearValue, theFarValue);
  #else
    ::glDepthRange (theNearValue, theFarValue);
  #endif
    OpenGl_TRACE(glDepthRangef)
  }

  // Transformation

  static void APIENTRY glViewport (GLint theX, GLint theY, GLsizei theWidth, GLsizei theHeight)
  {
    ::glViewport (theX, theY, theWidth, theHeight);
    OpenGl_TRACE(glViewport)
  }

  // Vertex Arrays

  static void APIENTRY glDrawArrays (GLenum theMode, GLint theFirst, GLsizei theCount)
  {
    ::glDrawArrays (theMode, theFirst, theCount);
    OpenGl_TRACE(glDrawArrays)
  }

  static void APIENTRY glDrawElements (GLenum theMode, GLsizei theCount, GLenum theType, const GLvoid* theIndices)
  {
    ::glDrawElements (theMode, theCount, theType, theIndices);
    OpenGl_TRACE(glDrawElements)
  }

  // Raster functions

  static void APIENTRY glPixelStorei (GLenum theParamName, GLint   theParam)
  {
    ::glPixelStorei (theParamName, theParam);
    OpenGl_TRACE(glPixelStorei)
  }

  static void APIENTRY glReadPixels (GLint x, GLint y,
                                     GLsizei width, GLsizei height,
                                     GLenum format, GLenum type,
                                     GLvoid* pixels)
  {
    ::glReadPixels (x, y, width, height, format, type, pixels);
    OpenGl_TRACE(glReadPixels)
  }

  // Stenciling

  static void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask)
  {
    ::glStencilFunc (func, ref, mask);
    OpenGl_TRACE(glStencilFunc)
  }

  static void APIENTRY glStencilMask (GLuint mask)
  {
    ::glStencilMask (mask);
    OpenGl_TRACE(glStencilMask)
  }

  static void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
  {
    ::glStencilOp (fail, zfail, zpass);
    OpenGl_TRACE(glStencilOp)
  }

  static void APIENTRY glClearStencil (GLint s)
  {
    ::glClearStencil (s);
    OpenGl_TRACE(glClearStencil)
  }

  // Texture mapping

  static void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param)
  {
    ::glTexParameterf (target, pname, param);
    OpenGl_TRACE(glTexParameterf)
  }

  static void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param)
  {
    ::glTexParameteri (target, pname, param);
    OpenGl_TRACE(glTexParameteri)
  }

  static void APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params)
  {
    ::glTexParameterfv (target, pname, params);
    OpenGl_TRACE(glTexParameterfv)
  }

  static void APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params)
  {
    ::glTexParameteriv (target, pname, params);
    OpenGl_TRACE(glTexParameteriv)
  }

  static void APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params)
  {
    ::glGetTexParameterfv (target, pname, params);
    OpenGl_TRACE(glGetTexParameterfv)
  }

  static void APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params)
  {
    ::glGetTexParameteriv (target, pname, params);
    OpenGl_TRACE(glGetTexParameteriv)
  }

  static void APIENTRY glTexImage2D (GLenum target, GLint level,
                                     GLint internalFormat,
                                     GLsizei width, GLsizei height,
                                     GLint border, GLenum format, GLenum type,
                                     const GLvoid* pixels)
  {
    ::glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);
    OpenGl_TRACE(glTexImage2D)
  }

  static void APIENTRY glGenTextures (GLsizei n, GLuint* textures)
  {
    ::glGenTextures(n, textures);
    OpenGl_TRACE(glGenTextures)
  }

  static void APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures)
  {
    ::glDeleteTextures(n, textures);
    OpenGl_TRACE(glDeleteTextures)
  }

  static void APIENTRY glBindTexture (GLenum target, GLuint texture)
  {
    ::glBindTexture(target, texture);
    OpenGl_TRACE(glBindTexture)
  }

  static GLboolean APIENTRY glIsTexture (GLuint texture)
  {
    const GLboolean aRes = ::glIsTexture (texture);
    OpenGl_TRACE(glIsTexture)
    return aRes;
  }

  static void APIENTRY glTexSubImage2D (GLenum target, GLint level,
                                        GLint xoffset, GLint yoffset,
                                        GLsizei width, GLsizei height,
                                        GLenum format, GLenum type,
                                        const GLvoid* pixels)
  {
    ::glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
    OpenGl_TRACE(glTexSubImage2D)
  }

  static void APIENTRY glCopyTexImage2D (GLenum target, GLint level,
                                         GLenum internalformat,
                                         GLint x, GLint y,
                                         GLsizei width, GLsizei height,
                                         GLint border)
  {
    ::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
    OpenGl_TRACE(glCopyTexImage2D)
  }

  static void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level,
                                            GLint xoffset, GLint yoffset,
                                            GLint x, GLint y,
                                            GLsizei width, GLsizei height)
  {
    ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
    OpenGl_TRACE(glCopyTexSubImage2D)
  }

  // desktop extensions - not supported in OpenGL ES 2.0

  static void APIENTRY glTexImage1D (GLenum target, GLint level,
                                     GLint internalFormat,
                                     GLsizei width, GLint border,
                                     GLenum format, GLenum type,
                                     const GLvoid* pixels)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )target; (void )level; (void )internalFormat; (void )width; (void )border; (void )format; (void )type; (void )pixels;
  #else
    ::glTexImage1D(target, level, internalFormat, width, border, format, type, pixels);
  #endif
    OpenGl_TRACE(glTexImage1D)
  }

  static void APIENTRY glTexSubImage1D (GLenum target, GLint level,
                                        GLint xoffset,
                                        GLsizei width, GLenum format,
                                        GLenum type, const GLvoid* pixels)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )target; (void )level; (void )xoffset; (void )width; (void )format; (void )type; (void )pixels;
  #else
    ::glTexSubImage1D(target, level, xoffset, width, format, type, pixels);
  #endif
    OpenGl_TRACE(glTexSubImage1D)
  }

  static void APIENTRY glCopyTexImage1D (GLenum target, GLint level,
                                         GLenum internalformat,
                                         GLint x, GLint y,
                                         GLsizei width, GLint border)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )target; (void )level; (void )internalformat; (void )x; (void )y; (void )width; (void )border;
  #else
    ::glCopyTexImage1D(target, level, internalformat, x, y, width, border);
  #endif
    OpenGl_TRACE(glCopyTexImage1D)
  }

  static void APIENTRY glCopyTexSubImage1D (GLenum target, GLint level,
                                            GLint xoffset, GLint x, GLint y,
                                            GLsizei width)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )target; (void )level; (void )xoffset; (void )x; (void )y; (void )width;
  #else
    ::glCopyTexSubImage1D(target, level, xoffset, x, y, width);
  #endif
    OpenGl_TRACE(glCopyTexSubImage1D)
  }

  static void APIENTRY glGetTexImage (GLenum target, GLint level,
                                      GLenum format, GLenum type,
                                      GLvoid* pixels)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )target; (void )level; (void )format; (void )type; (void )pixels;
  #else
    ::glGetTexImage (target, level, format, type, pixels);
  #endif
    OpenGl_TRACE(glGetTexImage)
  }

  static void APIENTRY glAlphaFunc (GLenum theFunc, GLclampf theRef)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )theFunc; (void )theRef;
  #else
    ::glAlphaFunc (theFunc, theRef);
  #endif
    OpenGl_TRACE(glAlphaFunc)
  }

  static void APIENTRY glPointSize (GLfloat theSize)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )theSize;
  #else
    ::glPointSize (theSize);
  #endif
    OpenGl_TRACE(glPointSize)
  }

  static void APIENTRY glPolygonMode (GLenum face, GLenum mode)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )face; (void )mode;
  #else
    ::glPolygonMode (face, mode);
  #endif
    OpenGl_TRACE(glPolygonMode);
  }

  static void APIENTRY glLogicOp (GLenum opcode)
  {
  #if defined(GL_ES_VERSION_2_0)
    ::glEnable (0xFFFF);
    (void )opcode;
  #else
    ::glLogicOp (opcode);
  #endif
    OpenGl_TRACE(glLogicOp)
  }

  static void APIENTRY glMultiDrawElements (GLenum theMode, const GLsizei* theCount, GLenum theType, const void* const* theIndices, GLsizei theDrawCount)
  {
    if (theCount   == NULL
        || theIndices == NULL)
    {
      return;
    }

    for (GLsizei aBatchIter = 0; aBatchIter < theDrawCount; ++aBatchIter)
    {
      ::glDrawElements (theMode, theCount[aBatchIter], theType, theIndices[aBatchIter]);
    }
    OpenGl_TRACE(glMultiDrawElements)
  }

#if defined(GL_ES_VERSION_2_0)

// OpenGL ES 1.1

  static void APIENTRY glActiveTexture (GLenum texture)
  {
    ::glActiveTexture (texture);
    OpenGl_TRACE(glActiveTexture)
  }

  static void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
  {
    ::glCompressedTexImage2D (target, level, internalformat, width, height, border, imageSize, data);
    OpenGl_TRACE(glCompressedTexImage2D)
  }

  static void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
  {
    ::glCompressedTexSubImage2D (target, level, xoffset, yoffset, width, height, format, imageSize, data);
    OpenGl_TRACE(glCompressedTexSubImage2D)
  }

  static void APIENTRY glBindBuffer (GLenum target, GLuint buffer)
  {
    ::glBindBuffer (target, buffer);
    OpenGl_TRACE(glBindBuffer)
  }

  static void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage)
  {
    ::glBufferData (target, size, data, usage);
    OpenGl_TRACE(glBufferData)
  }

  static void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
  {
    ::glBufferSubData (target, offset, size, data);
    OpenGl_TRACE(glBufferSubData)
  }

  static void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers)
  {
    ::glDeleteBuffers (n, buffers);
    OpenGl_TRACE(glDeleteBuffers)
  }

  static void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers)
  {
    ::glGenBuffers (n, buffers);
    OpenGl_TRACE(glGenBuffers)
  }

  static void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params)
  {
    ::glGetBufferParameteriv (target, pname, params);
    OpenGl_TRACE(glGetBufferParameteriv)
  }

  static GLboolean APIENTRY glIsBuffer (GLuint buffer)
  {
    return ::glIsBuffer (buffer);
  }

  static void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert)
  {
    ::glSampleCoverage (value, invert);
    OpenGl_TRACE(glSampleCoverage)
  }

  // OpenGL ES 2.0

  static void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
  {
    ::glBlendColor (red, green, blue, alpha);
    OpenGl_TRACE(glBlendColor)
  }

  static void APIENTRY glBlendEquation (GLenum mode)
  {
    ::glBlendEquation (mode);
    OpenGl_TRACE(glBlendEquation)
  }

  static void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)
  {
    ::glBlendFuncSeparate (sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
    OpenGl_TRACE(glBlendFuncSeparate)
  }

  static void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha)
  {
    ::glBlendEquationSeparate (modeRGB, modeAlpha);
    OpenGl_TRACE(glBlendEquationSeparate)
  }

  static void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
  {
    ::glStencilOpSeparate (face, sfail, dpfail, dppass);
    OpenGl_TRACE(glStencilOpSeparate)
  }

  static void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask)
  {
    ::glStencilFuncSeparate (face, func, ref, mask);
    OpenGl_TRACE(glStencilFuncSeparate)
  }

  static void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask)
  {
    ::glStencilMaskSeparate (face, mask);
    OpenGl_TRACE(glStencilMaskSeparate)
  }

  static void APIENTRY glAttachShader (GLuint program, GLuint shader)
  {
    ::glAttachShader (program, shader);
    OpenGl_TRACE(glAttachShader)
  }

  static void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name)
  {
    ::glBindAttribLocation (program, index, name);
    OpenGl_TRACE(glBindAttribLocation)
  }

  static void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer)
  {
    ::glBindFramebuffer (target, framebuffer);
    OpenGl_TRACE(glBindFramebuffer)
  }

  static void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer)
  {
    ::glBindRenderbuffer (target, renderbuffer);
    OpenGl_TRACE(glBindRenderbuffer)
  }

  static GLenum APIENTRY glCheckFramebufferStatus (GLenum target)
  {
    return ::glCheckFramebufferStatus (target);
  }

  static void APIENTRY glCompileShader (GLuint shader)
  {
    ::glCompileShader (shader);
    OpenGl_TRACE(glCompileShader)
  }

  static GLuint APIENTRY glCreateProgram()
  {
    return ::glCreateProgram();
  }

  static GLuint APIENTRY glCreateShader (GLenum type)
  {
    return ::glCreateShader (type);
  }

  static void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers)
  {
    ::glDeleteFramebuffers (n, framebuffers);
    OpenGl_TRACE(glDeleteFramebuffers)
  }

  static void APIENTRY glDeleteProgram (GLuint program)
  {
    ::glDeleteProgram (program);
    OpenGl_TRACE(glDeleteProgram)
  }

  static void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers)
  {
    ::glDeleteRenderbuffers (n, renderbuffers);
    OpenGl_TRACE(glDeleteRenderbuffers)
  }

  static void APIENTRY glDeleteShader (GLuint shader)
  {
    ::glDeleteShader (shader);
    OpenGl_TRACE(glDeleteShader)
  }

  static void APIENTRY glDetachShader (GLuint program, GLuint shader)
  {
    ::glDetachShader (program, shader);
    OpenGl_TRACE(glDetachShader)
  }

  static void APIENTRY glDisableVertexAttribArray (GLuint index)
  {
    ::glDisableVertexAttribArray (index);
    OpenGl_TRACE(glDisableVertexAttribArray)
  }

  static void APIENTRY glEnableVertexAttribArray (GLuint index)
  {
    ::glEnableVertexAttribArray (index);
    OpenGl_TRACE(glEnableVertexAttribArray)
  }

  static void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
  {
    ::glFramebufferRenderbuffer (target, attachment, renderbuffertarget, renderbuffer);
    OpenGl_TRACE(glFramebufferRenderbuffer)
  }

  static void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
  {
    ::glFramebufferTexture2D (target, attachment, textarget, texture, level);
    OpenGl_TRACE(glFramebufferTexture2D)
  }

  static void APIENTRY glGenerateMipmap (GLenum target)
  {
    ::glGenerateMipmap (target);
    OpenGl_TRACE(glGenerateMipmap)
  }

  static void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers)
  {
    ::glGenFramebuffers (n, framebuffers);
    OpenGl_TRACE(glGenFramebuffers)
  }

  static void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers)
  {
    ::glGenRenderbuffers (n, renderbuffers);
    OpenGl_TRACE(glGenRenderbuffers)
  }

  static void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name)
  {
    ::glGetActiveAttrib (program, index, bufSize, length, size, type, name);
    OpenGl_TRACE(glGetActiveAttrib)
  }

  static void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name)
  {
    ::glGetActiveUniform (program, index, bufSize, length, size, type, name);
    OpenGl_TRACE(glGetActiveUniform)
  }

  static void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders)
  {
    ::glGetAttachedShaders (program, maxCount, count, shaders);
    OpenGl_TRACE(glGetAttachedShaders)
  }

  static GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name)
  {
    const GLint aRes = ::glGetAttribLocation (program, name);
    OpenGl_TRACE(glGetAttribLocation)
    return aRes;
  }

  static void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params)
  {
    ::glGetFramebufferAttachmentParameteriv (target, attachment, pname, params);
    OpenGl_TRACE(glGetFramebufferAttachmentParameteriv)
  }

  static void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params)
  {
    ::glGetProgramiv (program, pname, params);
    OpenGl_TRACE(glGetProgramiv)
  }

  static void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
  {
    ::glGetProgramInfoLog (program, bufSize, length, infoLog);
    OpenGl_TRACE(glGetProgramInfoLog)
  }

  static void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params)
  {
    ::glGetRenderbufferParameteriv (target, pname, params);
    OpenGl_TRACE(glGetRenderbufferParameteriv)
  }

  static void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params)
  {
    ::glGetShaderiv (shader, pname, params);
    OpenGl_TRACE(glGetShaderiv)
  }

  static void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
  {
    ::glGetShaderInfoLog (shader, bufSize, length, infoLog);
    OpenGl_TRACE(glGetShaderInfoLog)
  }

  static void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
  {
    ::glGetShaderPrecisionFormat (shadertype, precisiontype, range, precision);
    OpenGl_TRACE(glGetShaderPrecisionFormat)
  }

  static void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source)
  {
    ::glGetShaderSource (shader, bufSize, length, source);
    OpenGl_TRACE(glGetShaderSource)
  }

  static void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params)
  {
    ::glGetUniformfv (program, location, params);
    OpenGl_TRACE(glGetUniformfv)
  }

  static void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params)
  {
    ::glGetUniformiv (program, location, params);
    OpenGl_TRACE(glGetUniformiv)
  }

  static GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name)
  {
    const GLint aRes = ::glGetUniformLocation (program, name);
    OpenGl_TRACE(glGetUniformLocation)
    return aRes;
  }

  static void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params)
  {
    ::glGetVertexAttribfv (index, pname, params);
    OpenGl_TRACE(glGetVertexAttribfv)
  }

  static void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params)
  {
    ::glGetVertexAttribiv (index, pname, params);
    OpenGl_TRACE(glGetVertexAttribiv)
  }

  static void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void* *pointer)
  {
    ::glGetVertexAttribPointerv (index, pname, pointer);
    OpenGl_TRACE(glGetVertexAttribPointerv)
  }

  static GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer)
  {
    return ::glIsFramebuffer (framebuffer);
  }

  static GLboolean APIENTRY glIsProgram (GLuint program)
  {
    return ::glIsProgram (program);
  }

  static GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer)
  {
    return ::glIsRenderbuffer (renderbuffer);
  }

  static GLboolean APIENTRY glIsShader (GLuint shader)
  {
    return ::glIsShader (shader);
  }

  static void APIENTRY glLinkProgram (GLuint program)
  {
    ::glLinkProgram (program);
    OpenGl_TRACE(glLinkProgram)
  }

  static void APIENTRY glReleaseShaderCompiler()
  {
    ::glReleaseShaderCompiler();
    OpenGl_TRACE(glReleaseShaderCompiler)
  }

  static void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
  {
    ::glRenderbufferStorage (target, internalformat, width, height);
    OpenGl_TRACE(glRenderbufferStorage)
  }

  static void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length)
  {
    ::glShaderBinary (count, shaders, binaryformat, binary, length);
    OpenGl_TRACE(glShaderBinary)
  }

  static void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint* length)
  {
    ::glShaderSource (shader, count, string, length);
    OpenGl_TRACE(glShaderSource)
  }

  static void APIENTRY glUniform1f (GLint location, GLfloat v0)
  {
    ::glUniform1f (location, v0);
    OpenGl_TRACE(glUniform1f)
  }

  static void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* value)
  {
    ::glUniform1fv (location, count, value);
    OpenGl_TRACE(glUniform1fv)
  }

  static void APIENTRY glUniform1i (GLint location, GLint v0)
  {
    ::glUniform1i (location, v0);
    OpenGl_TRACE(glUniform1i)
  }

  static void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* value)
  {
    ::glUniform1iv (location, count, value);
    OpenGl_TRACE(glUniform1iv)
  }

  static void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1)
  {
    ::glUniform2f (location, v0, v1);
    OpenGl_TRACE(glUniform2f)
  }

  static void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* value)
  {
    ::glUniform2fv (location, count, value);
    OpenGl_TRACE(glUniform2fv)
  }

  static void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1)
  {
    ::glUniform2i (location, v0, v1);
    OpenGl_TRACE(glUniform2i)
  }

  static void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* value)
  {
    ::glUniform2iv (location, count, value);
    OpenGl_TRACE(glUniform2iv)
  }

  static void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
  {
    ::glUniform3f (location, v0, v1, v2);
    OpenGl_TRACE(glUniform3f)
  }

  static void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* value)
  {
    ::glUniform3fv (location, count, value);
    OpenGl_TRACE(glUniform3fv)
  }

  static void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2)
  {
    ::glUniform3i (location, v0, v1, v2);
    OpenGl_TRACE(glUniform3i)
  }

  static void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* value)
  {
    ::glUniform3iv (location, count, value);
    OpenGl_TRACE(glUniform3iv)
  }

  static void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
  {
    ::glUniform4f (location, v0, v1, v2, v3);
    OpenGl_TRACE(glUniform4f)
  }

  static void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* value)
  {
    ::glUniform4fv (location, count, value);
    OpenGl_TRACE(glUniform4fv)
  }

  static void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
  {
    ::glUniform4i (location, v0, v1, v2, v3);
    OpenGl_TRACE(glUniform4i)
  }

  static void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* value)
  {
    ::glUniform4iv (location, count, value);
    OpenGl_TRACE(glUniform4iv)
  }

  static void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
  {
    ::glUniformMatrix2fv (location, count, transpose, value);
    OpenGl_TRACE(glUniformMatrix2fv)
  }

  static void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
  {
    ::glUniformMatrix3fv (location, count, transpose, value);
    OpenGl_TRACE(glUniformMatrix3fv)
  }

  static void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
  {
    ::glUniformMatrix4fv (location, count, transpose, value);
    OpenGl_TRACE(glUniformMatrix4fv)
  }

  static void APIENTRY glUseProgram (GLuint program)
  {
    ::glUseProgram (program);
    OpenGl_TRACE(glUseProgram)
  }

  static void APIENTRY glValidateProgram (GLuint program)
  {
    ::glValidateProgram (program);
    OpenGl_TRACE(glValidateProgram)
  }

  static void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x)
  {
    ::glVertexAttrib1f (index, x);
    OpenGl_TRACE(glVertexAttrib1f)
  }

  static void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat* v)
  {
    ::glVertexAttrib1fv (index, v);
    OpenGl_TRACE(glVertexAttrib1fv)
  }

  static void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y)
  {
    ::glVertexAttrib2f (index, x, y);
    OpenGl_TRACE(glVertexAttrib2f)
  }

  static void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat* v)
  {
    ::glVertexAttrib2fv (index, v);
    OpenGl_TRACE(glVertexAttrib2fv)
  }

  static void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z)
  {
    ::glVertexAttrib3f (index, x, y, z);
    OpenGl_TRACE(glVertexAttrib3f)
  }

  static void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat* v)
  {
    ::glVertexAttrib3fv (index, v);
    OpenGl_TRACE(glVertexAttrib3fv)
  }

  static void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
  {
    ::glVertexAttrib4f (index, x, y, z, w);
    OpenGl_TRACE(glVertexAttrib4f)
  }

  static void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat* v)
  {
    ::glVertexAttrib4fv (index, v);
    OpenGl_TRACE(glVertexAttrib4fv)
  }

  static void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer)
  {
    ::glVertexAttribPointer (index, size, type, normalized, stride, pointer);
    OpenGl_TRACE(glVertexAttribPointer)
  }

#else
  // legacy OpenGL 1.1 FFP

  static void APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param)
  {
    ::glTexEnvi (target, pname, param);
    OpenGl_TRACE(glTexEnvi)
  }

  static void APIENTRY glGetTexEnviv (GLenum target, GLenum pname, GLint *params)
  {
    ::glGetTexEnviv (target, pname, params);
    OpenGl_TRACE(glGetTexEnviv)
  }

  // Begin/End primitive specification (removed since 3.1)

  static void APIENTRY glColor4fv (const GLfloat* theVec)
  {
    ::glColor4fv (theVec);
    OpenGl_TRACE(glColor4fv)
  }

  // Matrix operations (removed since 3.1)

  static void APIENTRY glMatrixMode (GLenum theMode)
  {
    ::glMatrixMode (theMode);
    OpenGl_TRACE(glMatrixMode)
  }

  static void APIENTRY glLoadIdentity()
  {
    ::glLoadIdentity();
    OpenGl_TRACE(glLoadIdentity)
  }

  static void APIENTRY glLoadMatrixf (const GLfloat* theMatrix)
  {
    ::glLoadMatrixf (theMatrix);
    OpenGl_TRACE(glLoadMatrixf)
  }

  // Line and Polygon stipple (removed since 3.1)

  static void APIENTRY glLineStipple (GLint theFactor, GLushort thePattern)
  {
    ::glLineStipple (theFactor, thePattern);
    OpenGl_TRACE(glLineStipple)
  }

  static void APIENTRY glPolygonStipple (const GLubyte* theMask)
  {
    ::glPolygonStipple (theMask);
    OpenGl_TRACE(glPolygonStipple)
  }

  // Fixed pipeline lighting (removed since 3.1)

  static void APIENTRY glShadeModel (GLenum theMode)
  {
    ::glShadeModel (theMode);
    OpenGl_TRACE(glShadeModel)
  }

  static void APIENTRY glLightf (GLenum theLight, GLenum pname, GLfloat param)
  {
    ::glLightf (theLight, pname, param);
    OpenGl_TRACE(glLightf)
  }

  static void APIENTRY glLightfv (GLenum theLight, GLenum pname, const GLfloat* params)
  {
    ::glLightfv (theLight, pname, params);
    OpenGl_TRACE(glLightfv)
  }

  static void APIENTRY glLightModeli (GLenum pname, GLint param)
  {
    ::glLightModeli(pname, param);
    OpenGl_TRACE(glLightModeli)
  }

  static void APIENTRY glLightModelfv (GLenum pname, const GLfloat* params)
  {
    ::glLightModelfv(pname, params);
    OpenGl_TRACE(glLightModelfv)
  }

  static void APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param)
  {
    ::glMaterialf(face, pname, param);
    OpenGl_TRACE(glMaterialf)
  }

  static void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat* params)
  {
    ::glMaterialfv(face, pname, params);
    OpenGl_TRACE(glMaterialfv)
  }

  static void APIENTRY glColorMaterial (GLenum face, GLenum mode)
  {
    ::glColorMaterial(face, mode);
    OpenGl_TRACE(glColorMaterial)
  }

  // clipping plane (removed since 3.1)

  static void APIENTRY glClipPlane (GLenum thePlane, const GLdouble* theEquation)
  {
    ::glClipPlane (thePlane, theEquation);
    OpenGl_TRACE(glClipPlane)
  }

  // Display lists (removed since 3.1)

  static void APIENTRY glDeleteLists (GLuint theList, GLsizei theRange)
  {
    ::glDeleteLists (theList, theRange);
    OpenGl_TRACE(glDeleteLists)
  }

  static GLuint APIENTRY glGenLists (GLsizei theRange)
  {
    const GLuint aRes = ::glGenLists (theRange);
    OpenGl_TRACE(glGenLists)
    return aRes;
  }

  static void APIENTRY glNewList (GLuint theList, GLenum theMode)
  {
    ::glNewList (theList, theMode);
    OpenGl_TRACE(glNewList)
  }

  static void APIENTRY glEndList()
  {
    ::glEndList();
    OpenGl_TRACE(glEndList)
  }

  static void APIENTRY glCallList (GLuint theList)
  {
    ::glCallList (theList);
    OpenGl_TRACE(glCallList)
  }

  static void APIENTRY glCallLists (GLsizei theNb, GLenum theType, const GLvoid* theLists)
  {
    ::glCallLists (theNb, theType, theLists);
    OpenGl_TRACE(glCallLists)
  }

  static void APIENTRY glListBase (GLuint theBase)
  {
    ::glListBase (theBase);
    OpenGl_TRACE(glListBase)
  }

  // Current raster position and Rectangles (removed since 3.1)

  static void APIENTRY glRasterPos2i (GLint    x, GLint    y)
  {
    ::glRasterPos2i (x, y);
    OpenGl_TRACE(glRasterPos2i)
  }

  static void APIENTRY glRasterPos3fv (const GLfloat*  theVec)
  {
    ::glRasterPos3fv (theVec);
    OpenGl_TRACE(glRasterPos3fv)
  }

  // Texture mapping (removed since 3.1)

  static void APIENTRY glTexGeni (GLenum coord, GLenum pname, GLint param)
  {
    ::glTexGeni (coord, pname, param);
    OpenGl_TRACE(glTexGeni)
  }

  static void APIENTRY glTexGenfv (GLenum coord, GLenum pname, const GLfloat* params)
  {
    ::glTexGenfv (coord, pname, params);
    OpenGl_TRACE(glTexGenfv)
  }

  // Pixel copying (removed since 3.1)

  static void APIENTRY glDrawPixels (GLsizei width, GLsizei height,
                                     GLenum format, GLenum type,
                                     const GLvoid* pixels)
  {
    ::glDrawPixels (width, height, format, type, pixels);
    OpenGl_TRACE(glDrawPixels)
  }

  static void APIENTRY glCopyPixels (GLint x, GLint y,
                                     GLsizei width, GLsizei height,
                                     GLenum type)
  {
    ::glCopyPixels (x, y, width, height, type);
    OpenGl_TRACE(glCopyPixels)
  }

  static void APIENTRY glBitmap (GLsizei width, GLsizei height,
                                 GLfloat xorig, GLfloat yorig,
                                 GLfloat xmove, GLfloat ymove,
                                 const GLubyte* bitmap)
  {
    ::glBitmap (width, height, xorig, yorig, xmove, ymove, bitmap);
    OpenGl_TRACE(glBitmap)
  }

  // Edge flags and fixed-function vertex processing (removed since 3.1)

  static void APIENTRY glIndexPointer (GLenum theType, GLsizei theStride, const GLvoid* thePtr)
  {
    ::glIndexPointer (theType, theStride, thePtr);
    OpenGl_TRACE(glIndexPointer)
  }

  static void APIENTRY glVertexPointer (GLint theSize, GLenum theType, GLsizei theStride, const GLvoid* thePtr)
  {
    ::glVertexPointer (theSize, theType, theStride, thePtr);
    OpenGl_TRACE(glVertexPointer)
  }

  static void APIENTRY glNormalPointer (GLenum theType, GLsizei theStride, const GLvoid* thePtr)
  {
    ::glNormalPointer (theType, theStride, thePtr);
    OpenGl_TRACE(glNormalPointer)
  }

  static void APIENTRY glColorPointer (GLint theSize, GLenum theType, GLsizei theStride, const GLvoid* thePtr)
  {
    ::glColorPointer (theSize, theType, theStride, thePtr);
    OpenGl_TRACE(glColorPointer)
  }

  static void APIENTRY glTexCoordPointer (GLint theSize, GLenum theType, GLsizei theStride, const GLvoid* thePtr)
  {
    ::glTexCoordPointer (theSize, theType, theStride, thePtr);
    OpenGl_TRACE(glTexCoordPointer)
  }

  static void APIENTRY glEnableClientState (GLenum theCap)
  {
    ::glEnableClientState (theCap);
    OpenGl_TRACE(glEnableClientState)
  }

  static void APIENTRY glDisableClientState (GLenum theCap)
  {
    ::glDisableClientState (theCap);
    OpenGl_TRACE(glDisableClientState)
  }

  static void APIENTRY glPixelTransferi (GLenum pname, GLint param)
  {
    ::glPixelTransferi (pname, param);
    OpenGl_TRACE(glPixelTransferi)
  }
#endif
}

// =======================================================================
// function : debugPrintError
// purpose  :
// =======================================================================
bool OpenGl_GlFunctions::debugPrintError (const char* theName)
{
  const int anErr = ::glGetError();
  if (anErr != GL_NO_ERROR)
  {
    Message::SendFail() << theName << "(), unhandled GL error: " << OpenGl_Context::FormatGlError (anErr);
    // there is no glSetError(), just emulate non-clear state
    switch (anErr)
    {
      case GL_INVALID_VALUE:
      {
        ::glLineWidth(-1.0f);
        ::glLineWidth( 1.0f);
        break;
      }
      default:
      case GL_INVALID_ENUM:
      {
        ::glEnable (0xFFFF);
        break;
      }
    }
  }
  return anErr != GL_NO_ERROR;
}

// =======================================================================
// function : readGlVersion
// purpose  :
// =======================================================================
void OpenGl_GlFunctions::readGlVersion (Standard_Integer& theGlVerMajor,
                                        Standard_Integer& theGlVerMinor)
{
  // reset values
  theGlVerMajor = 0;
  theGlVerMinor = 0;

  bool toCheckVer3 = true;
#if defined(__EMSCRIPTEN__)
  // WebGL 1.0 prints annoying invalid enumeration warnings to console.
  toCheckVer3 = false;
  if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
  {
    EmscriptenWebGLContextAttributes anAttribs = {};
    if (emscripten_webgl_get_context_attributes (aWebGlCtx, &anAttribs) == EMSCRIPTEN_RESULT_SUCCESS)
    {
      toCheckVer3 = anAttribs.majorVersion >= 2;
    }
  }
#endif

  // Available since OpenGL 3.0 and OpenGL ES 3.0.
  if (toCheckVer3)
  {
    GLint aMajor = 0, aMinor = 0;
    ::glGetIntegerv (GL_MAJOR_VERSION, &aMajor);
    ::glGetIntegerv (GL_MINOR_VERSION, &aMinor);
    // glGetError() sometimes does not report an error here even if
    // GL does not know GL_MAJOR_VERSION and GL_MINOR_VERSION constants.
    // This happens on some renderers like e.g. Cygwin MESA.
    // Thus checking additionally if GL has put anything to
    // the output variables.
    if (::glGetError() == GL_NO_ERROR && aMajor != 0 && aMinor != 0)
    {
      theGlVerMajor = aMajor;
      theGlVerMinor = aMinor;
      return;
    }
    for (GLenum anErr = ::glGetError(), aPrevErr = GL_NO_ERROR;; aPrevErr = anErr, anErr = ::glGetError())
    {
      if (anErr == GL_NO_ERROR
       || anErr == aPrevErr)
      {
        break;
      }
    }
  }

  // Read version string.
  // Notice that only first two numbers split by point '2.1 XXXXX' are significant.
  // Following trash (after space) is vendor-specific.
  // New drivers also returns micro version of GL like '3.3.0' which has no meaning
  // and should be considered as vendor-specific too.
  const char* aVerStr = (const char* )::glGetString (GL_VERSION);
  if (aVerStr == NULL || *aVerStr == '\0')
  {
    // invalid GL context
    return;
  }

//#if defined(GL_ES_VERSION_2_0)
  // skip "OpenGL ES-** " section
  for (; *aVerStr != '\0'; ++aVerStr)
  {
    if (*aVerStr >= '0' && *aVerStr <= '9')
    {
      break;
    }
  }
//#endif

  // parse string for major number
  char aMajorStr[32];
  char aMinorStr[32];
  size_t aMajIter = 0;
  while (aVerStr[aMajIter] >= '0' && aVerStr[aMajIter] <= '9')
  {
    ++aMajIter;
  }
  if (aMajIter == 0 || aMajIter >= sizeof(aMajorStr))
  {
    return;
  }
  memcpy (aMajorStr, aVerStr, aMajIter);
  aMajorStr[aMajIter] = '\0';

  // parse string for minor number
  aVerStr += aMajIter + 1;
  size_t aMinIter = 0;
  while (aVerStr[aMinIter] >= '0' && aVerStr[aMinIter] <= '9')
  {
    ++aMinIter;
  }
  if (aMinIter == 0 || aMinIter >= sizeof(aMinorStr))
  {
    return;
  }
  memcpy (aMinorStr, aVerStr, aMinIter);
  aMinorStr[aMinIter] = '\0';

  // read numbers
  theGlVerMajor = atoi (aMajorStr);
  theGlVerMinor = atoi (aMinorStr);
#if defined(__EMSCRIPTEN__)
  if (theGlVerMajor >= 3)
  {
    if (!toCheckVer3
     || ::strstr (aVerStr, "WebGL 1.0") != NULL)
    {
      Message::SendWarning() << "Warning! OpenGL context reports version " << theGlVerMajor << "." << theGlVerMinor
                             << " but WebGL 2.0 was unavailable\n"
                             << "Fallback to OpenGL ES 2.0 will be used instead of reported version";
      theGlVerMajor = 2;
      theGlVerMinor = 0;
    }
  }
#endif

  if (theGlVerMajor <= 0)
  {
    theGlVerMajor = 0;
    theGlVerMinor = 0;
  }
}

// =======================================================================
// function : load
// purpose  :
// =======================================================================
void OpenGl_GlFunctions::load (OpenGl_Context& theCtx,
                               Standard_Boolean theIsCoreProfile)
{
#if !defined(GL_ES_VERSION_2_0)
  bool isCoreProfile = false;
  if (theCtx.GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGL
   && theCtx.IsGlGreaterEqual (3, 2))
  {
    isCoreProfile = (theIsCoreProfile == true);

    // detect Core profile
    if (!isCoreProfile)
    {
      GLint aProfile = 0;
      ::glGetIntegerv (GL_CONTEXT_PROFILE_MASK, &aProfile);
      isCoreProfile = (aProfile & GL_CONTEXT_CORE_PROFILE_BIT) != 0;
    }
  }
#else
  (void )theIsCoreProfile;
#endif

  // set built-in functions
  WrapProxyDef5 (glGetIntegerv, glClearColor, glClear, glColorMask, glBlendFunc);
  WrapProxyDef5 (glCullFace, glFrontFace, glLineWidth, glPolygonOffset, glScissor);
  WrapProxyDef5 (glEnable, glDisable, glIsEnabled, glGetBooleanv, glGetFloatv);
  WrapProxyDef5 (glGetIntegerv, glGetError, glGetString, glFinish, glFlush);
  WrapProxyDef5 (glHint, glDepthFunc, glDepthMask, glPixelStorei, glClearStencil);
  WrapProxyDef5 (glReadPixels, glStencilFunc, glStencilMask, glStencilOp, glTexParameterf);
  WrapProxyDef5 (glTexParameterf, glTexParameteri, glTexParameterfv, glTexParameteriv, glGetTexParameterfv);
  WrapProxyDef5 (glGetTexParameteriv, glTexImage2D, glGenTextures, glDeleteTextures, glBindTexture);
  WrapProxyDef5 (glIsTexture, glTexSubImage2D, glCopyTexImage2D, glCopyTexSubImage2D, glViewport);
  WrapProxyProc5 (glDrawArrays, glDrawElements, glMultiDrawElements, glClearDepth, glClearDepthf);
  WrapProxyProc5 (glReadBuffer, glDrawBuffer, glGetPointerv, glDepthRange, glDepthRangef);
  WrapProxyProc5 (glTexImage1D, glTexSubImage1D, glCopyTexImage1D, glCopyTexSubImage1D, glGetTexImage);

#if defined(GL_ES_VERSION_2_0)
  WrapProxyDef5 (glActiveTexture, glCompressedTexImage2D, glCompressedTexSubImage2D, glBindBuffer, glBufferData);
  WrapProxyDef5 (glBufferSubData, glDeleteBuffers, glDepthRangef, glGenBuffers, glGetBufferParameteriv);
  WrapProxyDef5 (glIsBuffer, glSampleCoverage, glBlendColor, glBlendEquation, glBlendFuncSeparate);
  WrapProxyDef5 (glBlendEquationSeparate, glStencilOpSeparate, glStencilFuncSeparate, glStencilMaskSeparate, glAttachShader);
  WrapProxyDef5 (glBindAttribLocation, glBindFramebuffer, glBindRenderbuffer, glCheckFramebufferStatus, glCompileShader);
  WrapProxyDef5 (glCreateProgram, glCreateShader, glDeleteFramebuffers, glDeleteProgram, glDeleteRenderbuffers);
  WrapProxyDef5 (glDeleteShader, glDetachShader, glDisableVertexAttribArray, glEnableVertexAttribArray, glFramebufferRenderbuffer);
  WrapProxyDef5 (glFramebufferTexture2D, glGenerateMipmap, glGenFramebuffers, glGenRenderbuffers, glGetActiveAttrib);
  WrapProxyDef5 (glGetActiveUniform, glGetAttachedShaders, glGetAttribLocation, glGetFramebufferAttachmentParameteriv, glGetProgramiv);
  WrapProxyDef5 (glGetProgramInfoLog, glGetRenderbufferParameteriv, glGetShaderiv, glGetShaderInfoLog, glGetShaderPrecisionFormat);
  WrapProxyDef5 (glGetShaderSource, glGetUniformfv, glGetUniformiv, glGetUniformLocation, glGetVertexAttribfv);
  WrapProxyDef5 (glGetVertexAttribiv, glGetVertexAttribPointerv, glIsFramebuffer, glIsProgram, glIsRenderbuffer);
  WrapProxyDef5 (glIsShader, glLinkProgram, glReleaseShaderCompiler, glRenderbufferStorage, glShaderBinary);
  WrapProxyDef5 (glShaderSource, glUniform1f, glUniform1fv, glUniform1i, glUniform1iv);
  WrapProxyDef5 (glUniform2f, glUniform2fv, glUniform2i, glUniform2iv, glUniform3f);
  WrapProxyDef5 (glUniform3fv, glUniform3i, glUniform3iv, glUniform4f, glUniform4fv);
  WrapProxyDef5 (glUniform4i, glUniform4iv, glUniformMatrix2fv, glUniformMatrix3fv, glUniformMatrix4fv);
  WrapProxyDef5 (glUseProgram, glValidateProgram, glVertexAttrib1f, glVertexAttrib1fv, glVertexAttrib2f);
  WrapProxyDef5 (glVertexAttrib2fv, glVertexAttrib3f, glVertexAttrib3fv, glVertexAttrib4f, glVertexAttrib4fv);
  WrapProxyDef (glVertexAttribPointer);
  // empty fallbacks
  WrapProxyProc5 (glAlphaFunc, glPointSize, glLogicOp, glPolygonMode, glGetTexLevelParameteriv);
  WrapProxyProc (glGetTexLevelParameterfv);
#else
  WrapProxyDef5 (glAlphaFunc, glPointSize, glLogicOp, glPolygonMode, glGetTexLevelParameteriv);
  WrapProxyDef (glGetTexLevelParameterfv);
  if (!isCoreProfile)
  {
    WrapProxyDef5 (glTexEnvi, glGetTexEnviv, glColor4fv, glMatrixMode, glLoadIdentity);
    WrapProxyDef5 (glLoadMatrixf, glLineStipple, glPolygonStipple, glShadeModel, glLightf);
    WrapProxyDef5 (glLightfv, glLightModeli, glLightModelfv, glMaterialf, glMaterialfv);
    WrapProxyDef5 (glColorMaterial, glClipPlane, glDeleteLists, glGenLists, glNewList);
    WrapProxyDef5 (glEndList, glCallList, glCallLists, glListBase, glRasterPos2i);
    WrapProxyDef5 (glRasterPos3fv, glTexGeni, glTexGenfv, glDrawPixels, glCopyPixels);
    WrapProxyDef5 (glBitmap, glIndexPointer, glVertexPointer, glNormalPointer, glColorPointer);
    WrapProxyDef (glTexCoordPointer);
    WrapProxyDef (glEnableClientState);
    WrapProxyDef (glDisableClientState);
    WrapProxyDef (glPixelTransferi);
  }
#endif

  if (theCtx.IsGlGreaterEqual (3, 0))
  {
    // retrieve auxiliary function in advance
    theCtx.FindProc ("glGetStringi", theCtx.myFuncs->glGetStringi);
  }

#if defined(GL_ES_VERSION_2_0)
  theCtx.core11ffp = NULL;
#else
  theCtx.core11ffp = !isCoreProfile ? (OpenGl_GlCore11* )this : NULL;
#endif
  theCtx.core11fwd  = (OpenGl_GlCore11Fwd* )this;
  theCtx.core15     = NULL;
  theCtx.core15fwd  = NULL;
  theCtx.core20     = NULL;
  theCtx.core20fwd  = NULL;
  theCtx.core30     = NULL;
  theCtx.core32     = NULL;
  theCtx.core33     = NULL;
  theCtx.core41     = NULL;
  theCtx.core42     = NULL;
  theCtx.core43     = NULL;
  theCtx.core44     = NULL;
  theCtx.core45     = NULL;
  theCtx.core46     = NULL;
  theCtx.arbTBO     = NULL;
  theCtx.arbTboRGB32 = false;
  theCtx.arbClipControl = false;
  theCtx.arbIns     = NULL;
  theCtx.arbDbg     = NULL;
  theCtx.arbFBO     = NULL;
  theCtx.arbFBOBlit = NULL;
  theCtx.extGS      = NULL;

  //! Make record shorter to retrieve function pointer using variable with same name
  const char* aLastFailedProc = NULL;
  #define FindProcShort(theFunc) theCtx.FindProcVerbose(aLastFailedProc, #theFunc, this->theFunc)
  #define checkExtensionShort theCtx.CheckExtension
  #define isGlGreaterEqualShort(theMaj,theMin) theCtx.IsGlGreaterEqual(theMaj,theMin)

#if defined(GL_ES_VERSION_2_0)

  theCtx.hasTexRGBA8 = isGlGreaterEqualShort (3, 0)
                    || checkExtensionShort ("GL_OES_rgb8_rgba8");
  theCtx.hasTexSRGB  = isGlGreaterEqualShort (3, 0);
  theCtx.hasFboSRGB  = isGlGreaterEqualShort (3, 0);
  if (!isGlGreaterEqualShort (3, 0)
    && checkExtensionShort ("GL_EXT_sRGB"))
  {
    // limited support
    theCtx.hasTexSRGB = true;
    theCtx.hasFboSRGB = true;
  }
  theCtx.hasFboRenderMipmap = isGlGreaterEqualShort (3, 0)
                           || checkExtensionShort ("GL_OES_fbo_render_mipmap");
  theCtx.hasSRGBControl = checkExtensionShort ("GL_EXT_sRGB_write_control");
  theCtx.hasPackRowLength   = isGlGreaterEqualShort (3, 0);
  theCtx.hasUnpackRowLength = isGlGreaterEqualShort (3, 0); // || checkExtensionShort ("GL_EXT_unpack_subimage");
  // NPOT textures has limited support within OpenGL ES 2.0
  // which are relaxed by OpenGL ES 3.0 or some extensions
  //theCtx.arbNPTW = isGlGreaterEqualShort (3, 0)
  //           || checkExtensionShort ("GL_OES_texture_npot")
  //           || checkExtensionShort ("GL_NV_texture_npot_2D_mipmap");
  theCtx.arbNPTW     = true;
  theCtx.arbTexRG    = isGlGreaterEqualShort (3, 0)
                    || checkExtensionShort ("GL_EXT_texture_rg");
  theCtx.extBgra     = checkExtensionShort ("GL_EXT_texture_format_BGRA8888");
  theCtx.extTexR16   = checkExtensionShort ("GL_EXT_texture_norm16");
  theCtx.extAnis = checkExtensionShort ("GL_EXT_texture_filter_anisotropic");
  theCtx.extPDS  = isGlGreaterEqualShort (3, 0)
                || checkExtensionShort ("GL_OES_packed_depth_stencil");

  theCtx.core11fwd = (OpenGl_GlCore11Fwd* )this;
  if (isGlGreaterEqualShort (2, 0))
  {
    // enable compatible functions
    theCtx.core20    = (OpenGl_GlCore20* )this;
    theCtx.core20fwd = (OpenGl_GlCore20* )this;
    theCtx.core15    = (OpenGl_GlCore15* )this;
    theCtx.core15fwd = (OpenGl_GlCore15* )this;
    theCtx.arbFBO    = (OpenGl_ArbFBO*   )this;
  }
  if (isGlGreaterEqualShort (3, 0)
   && FindProcShort (glBlitFramebuffer))
  {
    theCtx.arbFBOBlit = (OpenGl_ArbFBOBlit* )this;
  }
  if (isGlGreaterEqualShort (3, 0)
   && FindProcShort (glGenSamplers)
   && FindProcShort (glDeleteSamplers)
   && FindProcShort (glIsSampler)
   && FindProcShort (glBindSampler)
   && FindProcShort (glSamplerParameteri)
   && FindProcShort (glSamplerParameteriv)
   && FindProcShort (glSamplerParameterf)
   && FindProcShort (glSamplerParameterfv)
   && FindProcShort (glGetSamplerParameteriv)
   && FindProcShort (glGetSamplerParameterfv))
   //&& FindProcShort (glSamplerParameterIiv) // only on Desktop or with extensions GL_OES_texture_border_clamp/GL_EXT_texture_border_clamp
   //&& FindProcShort (glSamplerParameterIuiv)
   //&& FindProcShort (glGetSamplerParameterIiv)
   //&& FindProcShort (glGetSamplerParameterIuiv))
  {
    theCtx.arbSamplerObject = (OpenGl_ArbSamplerObject* )this;
  }
  theCtx.extFragDepth = !isGlGreaterEqualShort(3, 0)
                      && checkExtensionShort ("GL_EXT_frag_depth");
  if (isGlGreaterEqualShort (3, 1)
   && FindProcShort (glTexStorage2DMultisample))
  {
    //
  }

  theCtx.hasUintIndex = isGlGreaterEqualShort (3, 0)
                     || checkExtensionShort ("GL_OES_element_index_uint");
  theCtx.hasHighp     = checkExtensionShort ("GL_OES_fragment_precision_high");
  GLint aRange[2] = {0, 0};
  GLint aPrec     = 0;
  ::glGetShaderPrecisionFormat (GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, aRange, &aPrec);
  if (aPrec != 0)
  {
    theCtx.hasHighp = Standard_True;
  }

  theCtx.arbTexFloat = (isGlGreaterEqualShort (3, 0)
                     && FindProcShort (glTexImage3D))
                     || checkExtensionShort ("GL_OES_texture_float");
  theCtx.hasTexFloatLinear = theCtx.arbTexFloat
                          && checkExtensionShort ("GL_OES_texture_float_linear");

  const bool hasTexBuffer32  = isGlGreaterEqualShort (3, 2) && FindProcShort (glTexBuffer);
  const bool hasExtTexBuffer = checkExtensionShort ("GL_EXT_texture_buffer") && theCtx.FindProc ("glTexBufferEXT", this->glTexBuffer);
  if (hasTexBuffer32 || hasExtTexBuffer)
  {
    theCtx.arbTBO = reinterpret_cast<OpenGl_ArbTBO*> (this);
  }

  bool hasInstanced = isGlGreaterEqualShort (3, 0)
       && FindProcShort (glVertexAttribDivisor)
       && FindProcShort (glDrawArraysInstanced)
       && FindProcShort (glDrawElementsInstanced);
  if (!hasInstanced)
  {
    hasInstanced = checkExtensionShort ("GL_ANGLE_instanced_arrays")
       && theCtx.FindProc ("glVertexAttribDivisorANGLE",   this->glVertexAttribDivisor)
       && theCtx.FindProc ("glDrawArraysInstancedANGLE",   this->glDrawArraysInstanced)
       && theCtx.FindProc ("glDrawElementsInstancedANGLE", this->glDrawElementsInstanced);
  }
  if (hasInstanced)
  {
    theCtx.arbIns = (OpenGl_ArbIns* )this;
  }

  const bool hasVAO = isGlGreaterEqualShort (3, 0)
       && FindProcShort (glBindVertexArray)
       && FindProcShort (glDeleteVertexArrays)
       && FindProcShort (glGenVertexArrays)
       && FindProcShort (glIsVertexArray);
#ifndef __EMSCRIPTEN__ // latest Emscripten does not pretend having / simulating mapping buffer functions
  const bool hasMapBufferRange = isGlGreaterEqualShort (3, 0)
       && FindProcShort (glMapBufferRange)
       && FindProcShort (glUnmapBuffer)
       && FindProcShort (glGetBufferPointerv)
       && FindProcShort (glFlushMappedBufferRange);
#endif

  // load OpenGL ES 3.0 new functions
  const bool has30es = isGlGreaterEqualShort (3, 0)
       && hasVAO
    #ifndef __EMSCRIPTEN__
       && hasMapBufferRange
    #endif
       && hasInstanced
       && theCtx.arbSamplerObject != NULL
       && theCtx.arbFBOBlit != NULL
       && FindProcShort (glReadBuffer)
       && FindProcShort (glDrawRangeElements)
       && FindProcShort (glTexImage3D)
       && FindProcShort (glTexSubImage3D)
       && FindProcShort (glCopyTexSubImage3D)
       && FindProcShort (glCompressedTexImage3D)
       && FindProcShort (glCompressedTexSubImage3D)
       && FindProcShort (glGenQueries)
       && FindProcShort (glDeleteQueries)
       && FindProcShort (glIsQuery)
       && FindProcShort (glBeginQuery)
       && FindProcShort (glEndQuery)
       && FindProcShort (glGetQueryiv)
       && FindProcShort (glGetQueryObjectuiv)
       && FindProcShort (glDrawBuffers)
       && FindProcShort (glUniformMatrix2x3fv)
       && FindProcShort (glUniformMatrix3x2fv)
       && FindProcShort (glUniformMatrix2x4fv)
       && FindProcShort (glUniformMatrix4x2fv)
       && FindProcShort (glUniformMatrix3x4fv)
       && FindProcShort (glUniformMatrix4x3fv)
       && FindProcShort (glRenderbufferStorageMultisample)
       && FindProcShort (glFramebufferTextureLayer)
       && FindProcShort (glGetIntegeri_v)
       && FindProcShort (glBeginTransformFeedback)
       && FindProcShort (glEndTransformFeedback)
       && FindProcShort (glBindBufferRange)
       && FindProcShort (glBindBufferBase)
       && FindProcShort (glTransformFeedbackVaryings)
       && FindProcShort (glGetTransformFeedbackVarying)
       && FindProcShort (glVertexAttribIPointer)
       && FindProcShort (glGetVertexAttribIiv)
       && FindProcShort (glGetVertexAttribIuiv)
       && FindProcShort (glVertexAttribI4i)
       && FindProcShort (glVertexAttribI4ui)
       && FindProcShort (glVertexAttribI4iv)
       && FindProcShort (glVertexAttribI4uiv)
       && FindProcShort (glGetUniformuiv)
       && FindProcShort (glGetFragDataLocation)
       && FindProcShort (glUniform1ui)
       && FindProcShort (glUniform2ui)
       && FindProcShort (glUniform3ui)
       && FindProcShort (glUniform4ui)
       && FindProcShort (glUniform1uiv)
       && FindProcShort (glUniform2uiv)
       && FindProcShort (glUniform3uiv)
       && FindProcShort (glUniform4uiv)
       && FindProcShort (glClearBufferiv)
       && FindProcShort (glClearBufferuiv)
       && FindProcShort (glClearBufferfv)
       && FindProcShort (glClearBufferfi)
       && FindProcShort (glGetStringi)
       && FindProcShort (glCopyBufferSubData)
       && FindProcShort (glGetUniformIndices)
       && FindProcShort (glGetActiveUniformsiv)
       && FindProcShort (glGetUniformBlockIndex)
       && FindProcShort (glGetActiveUniformBlockiv)
       && FindProcShort (glGetActiveUniformBlockName)
       && FindProcShort (glUniformBlockBinding)
       && FindProcShort (glFenceSync)
       && FindProcShort (glIsSync)
       && FindProcShort (glDeleteSync)
       && FindProcShort (glClientWaitSync)
       && FindProcShort (glWaitSync)
       && FindProcShort (glGetInteger64v)
       && FindProcShort (glGetSynciv)
       && FindProcShort (glGetInteger64i_v)
       && FindProcShort (glGetBufferParameteri64v)
       && FindProcShort (glBindTransformFeedback)
       && FindProcShort (glDeleteTransformFeedbacks)
       && FindProcShort (glGenTransformFeedbacks)
       && FindProcShort (glIsTransformFeedback)
       && FindProcShort (glPauseTransformFeedback)
       && FindProcShort (glResumeTransformFeedback)
       && FindProcShort (glGetProgramBinary)
       && FindProcShort (glProgramBinary)
       && FindProcShort (glProgramParameteri)
       && FindProcShort (glInvalidateFramebuffer)
       && FindProcShort (glInvalidateSubFramebuffer)
       && FindProcShort (glTexStorage2D)
       && FindProcShort (glTexStorage3D)
       && FindProcShort (glGetInternalformativ);
  if (!has30es)
  {
    theCtx.checkWrongVersion (3, 0, aLastFailedProc);
  }
  else
  {
    theCtx.core30 = (OpenGl_GlCore30* )this;
    theCtx.hasGetBufferData = true;
  }

  // load OpenGL ES 3.1 new functions
  const bool has31es = isGlGreaterEqualShort (3, 1)
       && has30es
       && FindProcShort (glDispatchCompute)
       && FindProcShort (glDispatchComputeIndirect)
       && FindProcShort (glDrawArraysIndirect)
       && FindProcShort (glDrawElementsIndirect)
       && FindProcShort (glFramebufferParameteri)
       && FindProcShort (glGetFramebufferParameteriv)
       && FindProcShort (glGetProgramInterfaceiv)
       && FindProcShort (glGetProgramResourceIndex)
       && FindProcShort (glGetProgramResourceName)
       && FindProcShort (glGetProgramResourceiv)
       && FindProcShort (glGetProgramResourceLocation)
       && FindProcShort (glUseProgramStages)
       && FindProcShort (glActiveShaderProgram)
       && FindProcShort (glCreateShaderProgramv)
       && FindProcShort (glBindProgramPipeline)
       && FindProcShort (glDeleteProgramPipelines)
       && FindProcShort (glGenProgramPipelines)
       && FindProcShort (glIsProgramPipeline)
       && FindProcShort (glGetProgramPipelineiv)
       && FindProcShort (glProgramUniform1i)
       && FindProcShort (glProgramUniform2i)
       && FindProcShort (glProgramUniform3i)
       && FindProcShort (glProgramUniform4i)
       && FindProcShort (glProgramUniform1ui)
       && FindProcShort (glProgramUniform2ui)
       && FindProcShort (glProgramUniform3ui)
       && FindProcShort (glProgramUniform4ui)
       && FindProcShort (glProgramUniform1f)
       && FindProcShort (glProgramUniform2f)
       && FindProcShort (glProgramUniform3f)
       && FindProcShort (glProgramUniform4f)
       && FindProcShort (glProgramUniform1iv)
       && FindProcShort (glProgramUniform2iv)
       && FindProcShort (glProgramUniform3iv)
       && FindProcShort (glProgramUniform4iv)
       && FindProcShort (glProgramUniform1uiv)
       && FindProcShort (glProgramUniform2uiv)
       && FindProcShort (glProgramUniform3uiv)
       && FindProcShort (glProgramUniform4uiv)
       && FindProcShort (glProgramUniform1fv)
       && FindProcShort (glProgramUniform2fv)
       && FindProcShort (glProgramUniform3fv)
       && FindProcShort (glProgramUniform4fv)
       && FindProcShort (glProgramUniformMatrix2fv)
       && FindProcShort (glProgramUniformMatrix3fv)
       && FindProcShort (glProgramUniformMatrix4fv)
       && FindProcShort (glProgramUniformMatrix2x3fv)
       && FindProcShort (glProgramUniformMatrix3x2fv)
       && FindProcShort (glProgramUniformMatrix2x4fv)
       && FindProcShort (glProgramUniformMatrix4x2fv)
       && FindProcShort (glProgramUniformMatrix3x4fv)
       && FindProcShort (glProgramUniformMatrix4x3fv)
       && FindProcShort (glValidateProgramPipeline)
       && FindProcShort (glGetProgramPipelineInfoLog)
       && FindProcShort (glBindImageTexture)
       && FindProcShort (glGetBooleani_v)
       && FindProcShort (glMemoryBarrier)
       && FindProcShort (glMemoryBarrierByRegion)
       && FindProcShort (glTexStorage2DMultisample)
       && FindProcShort (glGetMultisamplefv)
       && FindProcShort (glSampleMaski)
       && FindProcShort (glGetTexLevelParameteriv)
       && FindProcShort (glGetTexLevelParameterfv)
       && FindProcShort (glBindVertexBuffer)
       && FindProcShort (glVertexAttribFormat)
       && FindProcShort (glVertexAttribIFormat)
       && FindProcShort (glVertexAttribBinding)
       && FindProcShort (glVertexBindingDivisor);
  if (!has31es)
  {
    theCtx.checkWrongVersion (3, 1, aLastFailedProc);
  }

  // initialize debug context extension
  if (isGlGreaterEqualShort (3, 2)
   || checkExtensionShort ("GL_KHR_debug"))
  {
    // this functionality become a part of OpenGL ES 3.2
    theCtx.arbDbg = NULL;
    if (isGlGreaterEqualShort (3, 2)
     && FindProcShort (glDebugMessageControl)
     && FindProcShort (glDebugMessageInsert)
     && FindProcShort (glDebugMessageCallback)
     && FindProcShort (glGetDebugMessageLog))
    {
      theCtx.arbDbg = (OpenGl_ArbDbg* )this;
    }
    // According to GL_KHR_debug spec, all functions should have KHR suffix.
    // However, some implementations can export these functions without suffix.
    else if (!isGlGreaterEqualShort (3, 2)
     && theCtx.FindProc ("glDebugMessageControlKHR",  this->glDebugMessageControl)
     && theCtx.FindProc ("glDebugMessageInsertKHR",   this->glDebugMessageInsert)
     && theCtx.FindProc ("glDebugMessageCallbackKHR", this->glDebugMessageCallback)
     && theCtx.FindProc ("glGetDebugMessageLogKHR",   this->glGetDebugMessageLog))
    {
      theCtx.arbDbg = (OpenGl_ArbDbg* )this;
    }
  }

  // load OpenGL ES 3.2 new functions
  const bool has32es = isGlGreaterEqualShort (3, 2)
       && has31es
       && hasTexBuffer32
       && theCtx.arbDbg != NULL
       && FindProcShort (glBlendBarrier)
       && FindProcShort (glCopyImageSubData)
       && FindProcShort (glPushDebugGroup)
       && FindProcShort (glPopDebugGroup)
       && FindProcShort (glObjectLabel)
       && FindProcShort (glGetObjectLabel)
       && FindProcShort (glObjectPtrLabel)
       && FindProcShort (glGetObjectPtrLabel)
       && FindProcShort (glGetPointerv)
       && FindProcShort (glEnablei)
       && FindProcShort (glDisablei)
       && FindProcShort (glBlendEquationi)
       && FindProcShort (glBlendEquationSeparatei)
       && FindProcShort (glBlendFunci)
       && FindProcShort (glBlendFuncSeparatei)
       && FindProcShort (glColorMaski)
       && FindProcShort (glIsEnabledi)
       && FindProcShort (glDrawElementsBaseVertex)
       && FindProcShort (glDrawRangeElementsBaseVertex)
       && FindProcShort (glDrawElementsInstancedBaseVertex)
       && FindProcShort (glFramebufferTexture)
       && FindProcShort (glPrimitiveBoundingBox)
       && FindProcShort (glGetGraphicsResetStatus)
       && FindProcShort (glReadnPixels)
       && FindProcShort (glGetnUniformfv)
       && FindProcShort (glGetnUniformiv)
       && FindProcShort (glGetnUniformuiv)
       && FindProcShort (glMinSampleShading)
       && FindProcShort (glPatchParameteri)
       && FindProcShort (glTexParameterIiv)
       && FindProcShort (glTexParameterIuiv)
       && FindProcShort (glGetTexParameterIiv)
       && FindProcShort (glGetTexParameterIuiv)
       && FindProcShort (glSamplerParameterIiv)
       && FindProcShort (glSamplerParameterIuiv)
       && FindProcShort (glGetSamplerParameterIiv)
       && FindProcShort (glGetSamplerParameterIuiv)
       && FindProcShort (glTexBufferRange)
       && FindProcShort (glTexStorage3DMultisample);
  if (!has32es)
  {
    theCtx.checkWrongVersion (3, 2, aLastFailedProc);
  }

  theCtx.arbTboRGB32 = isGlGreaterEqualShort (3, 2); // OpenGL ES 3.2 introduces TBO already supporting RGB32 format
  theCtx.extDrawBuffers = checkExtensionShort ("GL_EXT_draw_buffers") && theCtx.FindProc ("glDrawBuffersEXT", this->glDrawBuffers);
  theCtx.arbDrawBuffers = checkExtensionShort ("GL_ARB_draw_buffers") && theCtx.FindProc ("glDrawBuffersARB", this->glDrawBuffers);

  if (isGlGreaterEqualShort (3, 0) && FindProcShort (glDrawBuffers))
  {
    theCtx.hasDrawBuffers = OpenGl_FeatureInCore;
  }
  else if (theCtx.extDrawBuffers || theCtx.arbDrawBuffers)
  {
    theCtx.hasDrawBuffers = OpenGl_FeatureInExtensions;
  }

  // float textures available since OpenGL ES 3.0+,
  // but renderable only since 3.2+ or with extension
  theCtx.hasFloatBuffer = theCtx.hasHalfFloatBuffer = OpenGl_FeatureNotAvailable;
  if (isGlGreaterEqualShort (3, 2))
  {
    theCtx.hasFloatBuffer = theCtx.hasHalfFloatBuffer = OpenGl_FeatureInCore;
  }
  else
  {
    if (checkExtensionShort ("GL_EXT_color_buffer_float"))
    {
      theCtx.hasFloatBuffer = isGlGreaterEqualShort (3, 0) ? OpenGl_FeatureInCore : OpenGl_FeatureInExtensions;
    }
    if (checkExtensionShort ("GL_EXT_color_buffer_half_float"))
    {
      // GL_HALF_FLOAT_OES for OpenGL ES 2.0 and GL_HALF_FLOAT for OpenGL ES 3.0+
      theCtx.hasHalfFloatBuffer = isGlGreaterEqualShort (3, 0) ? OpenGl_FeatureInCore : OpenGl_FeatureInExtensions;
    }
  }

  theCtx.oesSampleVariables = checkExtensionShort ("GL_OES_sample_variables");
  theCtx.oesStdDerivatives  = checkExtensionShort ("GL_OES_standard_derivatives");
  theCtx.hasSampleVariables = isGlGreaterEqualShort (3, 2) ? OpenGl_FeatureInCore :
                              theCtx.oesSampleVariables ? OpenGl_FeatureInExtensions
                                                        : OpenGl_FeatureNotAvailable;
  theCtx.hasGlslBitwiseOps = isGlGreaterEqualShort (3, 0)
                           ? OpenGl_FeatureInCore
                           : OpenGl_FeatureNotAvailable;
  // without hasHighp, dFdx/dFdy precision is considered too low for flat shading (visual artifacts)
  theCtx.hasFlatShading = isGlGreaterEqualShort (3, 0)
                        ? OpenGl_FeatureInCore
                         : (theCtx.oesStdDerivatives && theCtx.hasHighp
                          ? OpenGl_FeatureInExtensions
                          : OpenGl_FeatureNotAvailable);
  if (!isGlGreaterEqualShort (3, 1)
    && theCtx.Vendor().Search("qualcomm") != -1)
  {
    // dFdx/dFdy are completely broken on tested Adreno devices with versions below OpenGl ES 3.1
    theCtx.hasFlatShading = OpenGl_FeatureNotAvailable;
  }

  theCtx.hasGeometryStage = isGlGreaterEqualShort (3, 2)
                   ? OpenGl_FeatureInCore
                   : (checkExtensionShort ("GL_EXT_geometry_shader") && checkExtensionShort ("GL_EXT_shader_io_blocks")
                     ? OpenGl_FeatureInExtensions
                     : OpenGl_FeatureNotAvailable);
#else

  theCtx.hasTexRGBA8 = true;
  theCtx.hasTexSRGB       = isGlGreaterEqualShort (2, 1);
  theCtx.hasFboSRGB       = isGlGreaterEqualShort (2, 1);
  theCtx.hasSRGBControl   = theCtx.hasFboSRGB;
  theCtx.hasFboRenderMipmap = true;
  theCtx.arbDrawBuffers   = checkExtensionShort ("GL_ARB_draw_buffers");
  theCtx.arbNPTW          = checkExtensionShort ("GL_ARB_texture_non_power_of_two");
  theCtx.arbTexFloat      = isGlGreaterEqualShort (3, 0)
                  || checkExtensionShort ("GL_ARB_texture_float");
  theCtx.hasTexFloatLinear = theCtx.arbTexFloat;
  theCtx.arbSampleShading = checkExtensionShort ("GL_ARB_sample_shading");
  theCtx.arbDepthClamp    = isGlGreaterEqualShort (3, 2)
                  || checkExtensionShort ("GL_ARB_depth_clamp")
                  || checkExtensionShort ("NV_depth_clamp");
  theCtx.extBgra          = isGlGreaterEqualShort (1, 2)
                  || checkExtensionShort ("GL_EXT_bgra");
  theCtx.extTexR16 = true;
  theCtx.extAnis = checkExtensionShort ("GL_EXT_texture_filter_anisotropic");
  theCtx.extPDS  = checkExtensionShort ("GL_EXT_packed_depth_stencil");
  theCtx.atiMem  = checkExtensionShort ("GL_ATI_meminfo");
  theCtx.nvxMem  = checkExtensionShort ("GL_NVX_gpu_memory_info");

  theCtx.hasDrawBuffers = isGlGreaterEqualShort (2, 0) ? OpenGl_FeatureInCore :
                          theCtx.arbDrawBuffers ? OpenGl_FeatureInExtensions 
                                                : OpenGl_FeatureNotAvailable;

  theCtx.hasGlslBitwiseOps = isGlGreaterEqualShort (3, 0)
                           ? OpenGl_FeatureInCore
                           : checkExtensionShort ("GL_EXT_gpu_shader4")
                            ? OpenGl_FeatureInExtensions
                            : OpenGl_FeatureNotAvailable;

  theCtx.hasFloatBuffer = theCtx.hasHalfFloatBuffer =
    isGlGreaterEqualShort (3, 0) ? OpenGl_FeatureInCore :
    checkExtensionShort ("GL_ARB_color_buffer_float") ? OpenGl_FeatureInExtensions
                                                      : OpenGl_FeatureNotAvailable;

  theCtx.hasGeometryStage = isGlGreaterEqualShort (3, 2)
                          ? OpenGl_FeatureInCore
                          : OpenGl_FeatureNotAvailable;

  theCtx.hasSampleVariables = isGlGreaterEqualShort (4, 0) ? OpenGl_FeatureInCore :
                              theCtx.arbSampleShading ? OpenGl_FeatureInExtensions
                                                      : OpenGl_FeatureNotAvailable;

  bool has12 = false, has13 = false, has14 = false, has15 = false;
  bool has20 = false, has21 = false;
  bool has30 = false, has31 = false, has32 = false, has33 = false;
  bool has40 = false, has41 = false, has42 = false, has43 = false, has44 = false, has45 = false, has46 = false;

  // retrieve platform-dependent extensions
#if defined(HAVE_EGL)
  //
#elif defined(_WIN32)
  if (FindProcShort (wglGetExtensionsStringARB))
  {
    const char* aWglExts = this->wglGetExtensionsStringARB (wglGetCurrentDC());
    if (checkExtensionShort (aWglExts, "WGL_EXT_swap_control"))
    {
      FindProcShort (wglSwapIntervalEXT);
    }
    if (checkExtensionShort (aWglExts, "WGL_ARB_pixel_format"))
    {
      FindProcShort (wglChoosePixelFormatARB);
    }
    if (checkExtensionShort (aWglExts, "WGL_ARB_create_context_profile"))
    {
      FindProcShort (wglCreateContextAttribsARB);
    }
    if (checkExtensionShort (aWglExts, "WGL_NV_DX_interop"))
    {
      FindProcShort (wglDXSetResourceShareHandleNV);
      FindProcShort (wglDXOpenDeviceNV);
      FindProcShort (wglDXCloseDeviceNV);
      FindProcShort (wglDXRegisterObjectNV);
      FindProcShort (wglDXUnregisterObjectNV);
      FindProcShort (wglDXObjectAccessNV);
      FindProcShort (wglDXLockObjectsNV);
      FindProcShort (wglDXUnlockObjectsNV);
    }
    if (checkExtensionShort (aWglExts, "WGL_AMD_gpu_association"))
    {
      FindProcShort (wglGetGPUIDsAMD);
      FindProcShort (wglGetGPUInfoAMD);
      FindProcShort (wglGetContextGPUIDAMD);
    }
  }
#elif defined(HAVE_XLIB)
    const char* aGlxExts = ::glXQueryExtensionsString ((Display* )theCtx.myDisplay, DefaultScreen ((Display* )theCtx.myDisplay));
    if (checkExtensionShort (aGlxExts, "GLX_EXT_swap_control"))
    {
      FindProcShort (glXSwapIntervalEXT);
    }
    if (checkExtensionShort (aGlxExts, "GLX_SGI_swap_control"))
    {
      FindProcShort (glXSwapIntervalSGI);
    }
    if (checkExtensionShort (aGlxExts, "GLX_MESA_query_renderer"))
    {
      FindProcShort (glXQueryRendererIntegerMESA);
      FindProcShort (glXQueryCurrentRendererIntegerMESA);
      FindProcShort (glXQueryRendererStringMESA);
      FindProcShort (glXQueryCurrentRendererStringMESA);
    }
    //extSwapTear = checkExtensionShort (aGlxExts, "GLX_EXT_swap_control_tear");
#endif

  // load OpenGL 1.2 new functions
  has12 = isGlGreaterEqualShort (1, 2)
       && FindProcShort (glBlendColor)
       && FindProcShort (glBlendEquation)
       && FindProcShort (glDrawRangeElements)
       && FindProcShort (glTexImage3D)
       && FindProcShort (glTexSubImage3D)
       && FindProcShort (glCopyTexSubImage3D);
  if (!has12)
  {
    theCtx.checkWrongVersion (1, 2, aLastFailedProc);
  }

  // load OpenGL 1.3 new functions
  has13 = isGlGreaterEqualShort (1, 3)
       && FindProcShort (glActiveTexture)
       && FindProcShort (glSampleCoverage)
       && FindProcShort (glCompressedTexImage3D)
       && FindProcShort (glCompressedTexImage2D)
       && FindProcShort (glCompressedTexImage1D)
       && FindProcShort (glCompressedTexSubImage3D)
       && FindProcShort (glCompressedTexSubImage2D)
       && FindProcShort (glCompressedTexSubImage1D)
       && FindProcShort (glGetCompressedTexImage);
  if (!has13)
  {
    theCtx.checkWrongVersion (1, 3, aLastFailedProc);
  }

  // load OpenGL 1.4 new functions
  has14 = isGlGreaterEqualShort (1, 4)
       && FindProcShort (glBlendFuncSeparate)
       && FindProcShort (glMultiDrawArrays)
       && FindProcShort (glMultiDrawElements)
       && FindProcShort (glPointParameterf)
       && FindProcShort (glPointParameterfv)
       && FindProcShort (glPointParameteri)
       && FindProcShort (glPointParameteriv);
  if (!has14)
  {
    theCtx.checkWrongVersion (1, 4, aLastFailedProc);
  }

  // load OpenGL 1.5 new functions
  has15 = isGlGreaterEqualShort (1, 5)
       && FindProcShort (glGenQueries)
       && FindProcShort (glDeleteQueries)
       && FindProcShort (glIsQuery)
       && FindProcShort (glBeginQuery)
       && FindProcShort (glEndQuery)
       && FindProcShort (glGetQueryiv)
       && FindProcShort (glGetQueryObjectiv)
       && FindProcShort (glGetQueryObjectuiv)
       && FindProcShort (glBindBuffer)
       && FindProcShort (glDeleteBuffers)
       && FindProcShort (glGenBuffers)
       && FindProcShort (glIsBuffer)
       && FindProcShort (glBufferData)
       && FindProcShort (glBufferSubData)
       && FindProcShort (glGetBufferSubData)
       && FindProcShort (glMapBuffer)
       && FindProcShort (glUnmapBuffer)
       && FindProcShort (glGetBufferParameteriv)
       && FindProcShort (glGetBufferPointerv);
  if (has15)
  {
    theCtx.core15    = (OpenGl_GlCore15* )this;
    theCtx.core15fwd = (OpenGl_GlCore15* )this;
    theCtx.hasGetBufferData = true;
  }
  else
  {
    theCtx.checkWrongVersion (1, 5, aLastFailedProc);
  }

  // load OpenGL 2.0 new functions
  has20 = isGlGreaterEqualShort (2, 0)
       && FindProcShort (glBlendEquationSeparate)
       && FindProcShort (glDrawBuffers)
       && FindProcShort (glStencilOpSeparate)
       && FindProcShort (glStencilFuncSeparate)
       && FindProcShort (glStencilMaskSeparate)
       && FindProcShort (glAttachShader)
       && FindProcShort (glBindAttribLocation)
       && FindProcShort (glCompileShader)
       && FindProcShort (glCreateProgram)
       && FindProcShort (glCreateShader)
       && FindProcShort (glDeleteProgram)
       && FindProcShort (glDeleteShader)
       && FindProcShort (glDetachShader)
       && FindProcShort (glDisableVertexAttribArray)
       && FindProcShort (glEnableVertexAttribArray)
       && FindProcShort (glGetActiveAttrib)
       && FindProcShort (glGetActiveUniform)
       && FindProcShort (glGetAttachedShaders)
       && FindProcShort (glGetAttribLocation)
       && FindProcShort (glGetProgramiv)
       && FindProcShort (glGetProgramInfoLog)
       && FindProcShort (glGetShaderiv)
       && FindProcShort (glGetShaderInfoLog)
       && FindProcShort (glGetShaderSource)
       && FindProcShort (glGetUniformLocation)
       && FindProcShort (glGetUniformfv)
       && FindProcShort (glGetUniformiv)
       && FindProcShort (glGetVertexAttribdv)
       && FindProcShort (glGetVertexAttribfv)
       && FindProcShort (glGetVertexAttribiv)
       && FindProcShort (glGetVertexAttribPointerv)
       && FindProcShort (glIsProgram)
       && FindProcShort (glIsShader)
       && FindProcShort (glLinkProgram)
       && FindProcShort (glShaderSource)
       && FindProcShort (glUseProgram)
       && FindProcShort (glUniform1f)
       && FindProcShort (glUniform2f)
       && FindProcShort (glUniform3f)
       && FindProcShort (glUniform4f)
       && FindProcShort (glUniform1i)
       && FindProcShort (glUniform2i)
       && FindProcShort (glUniform3i)
       && FindProcShort (glUniform4i)
       && FindProcShort (glUniform1fv)
       && FindProcShort (glUniform2fv)
       && FindProcShort (glUniform3fv)
       && FindProcShort (glUniform4fv)
       && FindProcShort (glUniform1iv)
       && FindProcShort (glUniform2iv)
       && FindProcShort (glUniform3iv)
       && FindProcShort (glUniform4iv)
       && FindProcShort (glUniformMatrix2fv)
       && FindProcShort (glUniformMatrix3fv)
       && FindProcShort (glUniformMatrix4fv)
       && FindProcShort (glValidateProgram)
       && FindProcShort (glVertexAttrib1d)
       && FindProcShort (glVertexAttrib1dv)
       && FindProcShort (glVertexAttrib1f)
       && FindProcShort (glVertexAttrib1fv)
       && FindProcShort (glVertexAttrib1s)
       && FindProcShort (glVertexAttrib1sv)
       && FindProcShort (glVertexAttrib2d)
       && FindProcShort (glVertexAttrib2dv)
       && FindProcShort (glVertexAttrib2f)
       && FindProcShort (glVertexAttrib2fv)
       && FindProcShort (glVertexAttrib2s)
       && FindProcShort (glVertexAttrib2sv)
       && FindProcShort (glVertexAttrib3d)
       && FindProcShort (glVertexAttrib3dv)
       && FindProcShort (glVertexAttrib3f)
       && FindProcShort (glVertexAttrib3fv)
       && FindProcShort (glVertexAttrib3s)
       && FindProcShort (glVertexAttrib3sv)
       && FindProcShort (glVertexAttrib4Nbv)
       && FindProcShort (glVertexAttrib4Niv)
       && FindProcShort (glVertexAttrib4Nsv)
       && FindProcShort (glVertexAttrib4Nub)
       && FindProcShort (glVertexAttrib4Nubv)
       && FindProcShort (glVertexAttrib4Nuiv)
       && FindProcShort (glVertexAttrib4Nusv)
       && FindProcShort (glVertexAttrib4bv)
       && FindProcShort (glVertexAttrib4d)
       && FindProcShort (glVertexAttrib4dv)
       && FindProcShort (glVertexAttrib4f)
       && FindProcShort (glVertexAttrib4fv)
       && FindProcShort (glVertexAttrib4iv)
       && FindProcShort (glVertexAttrib4s)
       && FindProcShort (glVertexAttrib4sv)
       && FindProcShort (glVertexAttrib4ubv)
       && FindProcShort (glVertexAttrib4uiv)
       && FindProcShort (glVertexAttrib4usv)
       && FindProcShort (glVertexAttribPointer);
  if (has20)
  {
    const char* aGlslVer = (const char* )::glGetString (GL_SHADING_LANGUAGE_VERSION);
    if (aGlslVer == NULL
    || *aGlslVer == '\0')
    {
      // broken context has been detected
      theCtx.checkWrongVersion (2, 0, "GLSL 1.1");
    }
    else
    {
      theCtx.core20    = (OpenGl_GlCore20* )this;
      theCtx.core20fwd = (OpenGl_GlCore20* )this;
    }
  }
  else
  {
    theCtx.checkWrongVersion (2, 0, aLastFailedProc);
  }

  // load OpenGL 2.1 new functions
  has21 = isGlGreaterEqualShort (2, 1)
       && FindProcShort (glUniformMatrix2x3fv)
       && FindProcShort (glUniformMatrix3x2fv)
       && FindProcShort (glUniformMatrix2x4fv)
       && FindProcShort (glUniformMatrix4x2fv)
       && FindProcShort (glUniformMatrix3x4fv)
       && FindProcShort (glUniformMatrix4x3fv);
  if (!has21)
  {
    theCtx.checkWrongVersion (2, 1, aLastFailedProc);
  }

  // load GL_ARB_framebuffer_object (added to OpenGL 3.0 core)
  const bool hasFBO = (isGlGreaterEqualShort (3, 0) || checkExtensionShort ("GL_ARB_framebuffer_object"))
       && FindProcShort (glIsRenderbuffer)
       && FindProcShort (glBindRenderbuffer)
       && FindProcShort (glDeleteRenderbuffers)
       && FindProcShort (glGenRenderbuffers)
       && FindProcShort (glRenderbufferStorage)
       && FindProcShort (glGetRenderbufferParameteriv)
       && FindProcShort (glIsFramebuffer)
       && FindProcShort (glBindFramebuffer)
       && FindProcShort (glDeleteFramebuffers)
       && FindProcShort (glGenFramebuffers)
       && FindProcShort (glCheckFramebufferStatus)
       && FindProcShort (glFramebufferTexture1D)
       && FindProcShort (glFramebufferTexture2D)
       && FindProcShort (glFramebufferTexture3D)
       && FindProcShort (glFramebufferRenderbuffer)
       && FindProcShort (glGetFramebufferAttachmentParameteriv)
       && FindProcShort (glGenerateMipmap)
       && FindProcShort (glBlitFramebuffer)
       && FindProcShort (glRenderbufferStorageMultisample)
       && FindProcShort (glFramebufferTextureLayer);

  // load GL_ARB_vertex_array_object (added to OpenGL 3.0 core)
  const bool hasVAO = (isGlGreaterEqualShort (3, 0) || checkExtensionShort ("GL_ARB_vertex_array_object"))
       && FindProcShort (glBindVertexArray)
       && FindProcShort (glDeleteVertexArrays)
       && FindProcShort (glGenVertexArrays)
       && FindProcShort (glIsVertexArray);

  // load GL_ARB_map_buffer_range (added to OpenGL 3.0 core)
  const bool hasMapBufferRange = (isGlGreaterEqualShort (3, 0) || checkExtensionShort ("GL_ARB_map_buffer_range"))
       && FindProcShort (glMapBufferRange)
       && FindProcShort (glFlushMappedBufferRange);

  // load OpenGL 3.0 new functions
  has30 = isGlGreaterEqualShort (3, 0)
       && hasFBO
       && hasVAO
       && hasMapBufferRange
       && FindProcShort (glColorMaski)
       && FindProcShort (glGetBooleani_v)
       && FindProcShort (glGetIntegeri_v)
       && FindProcShort (glEnablei)
       && FindProcShort (glDisablei)
       && FindProcShort (glIsEnabledi)
       && FindProcShort (glBeginTransformFeedback)
       && FindProcShort (glEndTransformFeedback)
       && FindProcShort (glBindBufferRange)
       && FindProcShort (glBindBufferBase)
       && FindProcShort (glTransformFeedbackVaryings)
       && FindProcShort (glGetTransformFeedbackVarying)
       && FindProcShort (glClampColor)
       && FindProcShort (glBeginConditionalRender)
       && FindProcShort (glEndConditionalRender)
       && FindProcShort (glVertexAttribIPointer)
       && FindProcShort (glGetVertexAttribIiv)
       && FindProcShort (glGetVertexAttribIuiv)
       && FindProcShort (glVertexAttribI1i)
       && FindProcShort (glVertexAttribI2i)
       && FindProcShort (glVertexAttribI3i)
       && FindProcShort (glVertexAttribI4i)
       && FindProcShort (glVertexAttribI1ui)
       && FindProcShort (glVertexAttribI2ui)
       && FindProcShort (glVertexAttribI3ui)
       && FindProcShort (glVertexAttribI4ui)
       && FindProcShort (glVertexAttribI1iv)
       && FindProcShort (glVertexAttribI2iv)
       && FindProcShort (glVertexAttribI3iv)
       && FindProcShort (glVertexAttribI4iv)
       && FindProcShort (glVertexAttribI1uiv)
       && FindProcShort (glVertexAttribI2uiv)
       && FindProcShort (glVertexAttribI3uiv)
       && FindProcShort (glVertexAttribI4uiv)
       && FindProcShort (glVertexAttribI4bv)
       && FindProcShort (glVertexAttribI4sv)
       && FindProcShort (glVertexAttribI4ubv)
       && FindProcShort (glVertexAttribI4usv)
       && FindProcShort (glGetUniformuiv)
       && FindProcShort (glBindFragDataLocation)
       && FindProcShort (glGetFragDataLocation)
       && FindProcShort (glUniform1ui)
       && FindProcShort (glUniform2ui)
       && FindProcShort (glUniform3ui)
       && FindProcShort (glUniform4ui)
       && FindProcShort (glUniform1uiv)
       && FindProcShort (glUniform2uiv)
       && FindProcShort (glUniform3uiv)
       && FindProcShort (glUniform4uiv)
       && FindProcShort (glTexParameterIiv)
       && FindProcShort (glTexParameterIuiv)
       && FindProcShort (glGetTexParameterIiv)
       && FindProcShort (glGetTexParameterIuiv)
       && FindProcShort (glClearBufferiv)
       && FindProcShort (glClearBufferuiv)
       && FindProcShort (glClearBufferfv)
       && FindProcShort (glClearBufferfi)
       && FindProcShort (glGetStringi);
  if (!has30)
  {
    theCtx.checkWrongVersion (3, 0, aLastFailedProc);
  }

  // load GL_ARB_uniform_buffer_object (added to OpenGL 3.1 core)
  const bool hasUBO = (isGlGreaterEqualShort (3, 1) || checkExtensionShort ("GL_ARB_uniform_buffer_object"))
       && FindProcShort (glGetUniformIndices)
       && FindProcShort (glGetActiveUniformsiv)
       && FindProcShort (glGetActiveUniformName)
       && FindProcShort (glGetUniformBlockIndex)
       && FindProcShort (glGetActiveUniformBlockiv)
       && FindProcShort (glGetActiveUniformBlockName)
       && FindProcShort (glUniformBlockBinding);

  // load GL_ARB_copy_buffer (added to OpenGL 3.1 core)
  const bool hasCopyBufSubData = (isGlGreaterEqualShort (3, 1) || checkExtensionShort ("GL_ARB_copy_buffer"))
       && FindProcShort (glCopyBufferSubData);

  if (has30)
  {
    // NPOT textures are required by OpenGL 2.0 specifications
    // but doesn't hardware accelerated by some ancient OpenGL 2.1 hardware (GeForce FX, RadeOn 9700 etc.)
    theCtx.arbNPTW  = true;
    theCtx.arbTexRG = true;

    theCtx.core30 = (OpenGl_GlCore30* )this;
  }

  // load OpenGL 3.1 new functions
  has31 = isGlGreaterEqualShort (3, 1)
       && hasUBO
       && hasCopyBufSubData
       && FindProcShort (glDrawArraysInstanced)
       && FindProcShort (glDrawElementsInstanced)
       && FindProcShort (glTexBuffer)
       && FindProcShort (glPrimitiveRestartIndex);
  if (has31)
  {
    theCtx.arbTBO = (OpenGl_ArbTBO* )this;
    theCtx.arbIns = (OpenGl_ArbIns* )this;
  }
  else
  {
    theCtx.checkWrongVersion (3, 1, aLastFailedProc);

    // initialize TBO extension (ARB)
    if (checkExtensionShort ("GL_ARB_texture_buffer_object")
     && theCtx.FindProc ("glTexBufferARB", this->glTexBuffer))
    {
      theCtx.arbTBO = (OpenGl_ArbTBO* )this;
    }

    // initialize hardware instancing extension (ARB)
    if (checkExtensionShort ("GL_ARB_draw_instanced")
     && theCtx.FindProc ("glDrawArraysInstancedARB",   this->glDrawArraysInstanced)
     && theCtx.FindProc ("glDrawElementsInstancedARB", this->glDrawElementsInstanced))
    {
      theCtx.arbIns = (OpenGl_ArbIns* )this;
    }
  }

  theCtx.arbTboRGB32 = checkExtensionShort ("GL_ARB_texture_buffer_object_rgb32");

  // load GL_ARB_draw_elements_base_vertex (added to OpenGL 3.2 core)
  const bool hasDrawElemsBaseVert = (isGlGreaterEqualShort (3, 2) || checkExtensionShort ("GL_ARB_draw_elements_base_vertex"))
       && FindProcShort (glDrawElementsBaseVertex)
       && FindProcShort (glDrawRangeElementsBaseVertex)
       && FindProcShort (glDrawElementsInstancedBaseVertex)
       && FindProcShort (glMultiDrawElementsBaseVertex);

  // load GL_ARB_provoking_vertex (added to OpenGL 3.2 core)
  const bool hasProvokingVert = (isGlGreaterEqualShort (3, 2) || checkExtensionShort ("GL_ARB_provoking_vertex"))
       && FindProcShort (glProvokingVertex);

  // load GL_ARB_sync (added to OpenGL 3.2 core)
  const bool hasSync = (isGlGreaterEqualShort (3, 2) || checkExtensionShort ("GL_ARB_sync"))
       && FindProcShort (glFenceSync)
       && FindProcShort (glIsSync)
       && FindProcShort (glDeleteSync)
       && FindProcShort (glClientWaitSync)
       && FindProcShort (glWaitSync)
       && FindProcShort (glGetInteger64v)
       && FindProcShort (glGetSynciv);

  // load GL_ARB_texture_multisample (added to OpenGL 3.2 core)
  const bool hasTextureMultisample = (isGlGreaterEqualShort (3, 2) || checkExtensionShort ("GL_ARB_texture_multisample"))
       && FindProcShort (glTexImage2DMultisample)
       && FindProcShort (glTexImage3DMultisample)
       && FindProcShort (glGetMultisamplefv)
       && FindProcShort (glSampleMaski);

  // load OpenGL 3.2 new functions
  has32 = isGlGreaterEqualShort (3, 2)
       && hasDrawElemsBaseVert
       && hasProvokingVert
       && hasSync
       && hasTextureMultisample
       && FindProcShort (glGetInteger64i_v)
       && FindProcShort (glGetBufferParameteri64v)
       && FindProcShort (glFramebufferTexture);
  if (has32)
  {
    theCtx.core32 = (OpenGl_GlCore32* )this;
  }
  else
  {
    theCtx.checkWrongVersion (3, 2, aLastFailedProc);
  }

  // load GL_ARB_blend_func_extended (added to OpenGL 3.3 core)
  const bool hasBlendFuncExtended = (isGlGreaterEqualShort (3, 3) || checkExtensionShort ("GL_ARB_blend_func_extended"))
       && FindProcShort (glBindFragDataLocationIndexed)
       && FindProcShort (glGetFragDataIndex);

  // load GL_ARB_sampler_objects (added to OpenGL 3.3 core)
  const bool hasSamplerObjects = (isGlGreaterEqualShort (3, 3) || checkExtensionShort ("GL_ARB_sampler_objects"))
       && FindProcShort (glGenSamplers)
       && FindProcShort (glDeleteSamplers)
       && FindProcShort (glIsSampler)
       && FindProcShort (glBindSampler)
       && FindProcShort (glSamplerParameteri)
       && FindProcShort (glSamplerParameteriv)
       && FindProcShort (glSamplerParameterf)
       && FindProcShort (glSamplerParameterfv)
       && FindProcShort (glSamplerParameterIiv)
       && FindProcShort (glSamplerParameterIuiv)
       && FindProcShort (glGetSamplerParameteriv)
       && FindProcShort (glGetSamplerParameterIiv)
       && FindProcShort (glGetSamplerParameterfv)
       && FindProcShort (glGetSamplerParameterIuiv);
  if (hasSamplerObjects)
  {
    theCtx.arbSamplerObject = (OpenGl_ArbSamplerObject* )this;
  }

  // load GL_ARB_timer_query (added to OpenGL 3.3 core)
  const bool hasTimerQuery = (isGlGreaterEqualShort (3, 3) || checkExtensionShort ("GL_ARB_timer_query"))
       && FindProcShort (glQueryCounter)
       && FindProcShort (glGetQueryObjecti64v)
       && FindProcShort (glGetQueryObjectui64v);

  // load GL_ARB_vertex_type_2_10_10_10_rev (added to OpenGL 3.3 core)
  const bool hasVertType21010101rev = (isGlGreaterEqualShort (3, 3) || checkExtensionShort ("GL_ARB_vertex_type_2_10_10_10_rev"))
       && FindProcShort (glVertexAttribP1ui)
       && FindProcShort (glVertexAttribP1uiv)
       && FindProcShort (glVertexAttribP2ui)
       && FindProcShort (glVertexAttribP2uiv)
       && FindProcShort (glVertexAttribP3ui)
       && FindProcShort (glVertexAttribP3uiv)
       && FindProcShort (glVertexAttribP4ui)
       && FindProcShort (glVertexAttribP4uiv);

  // load OpenGL 3.3 extra functions
  has33 = isGlGreaterEqualShort (3, 3)
       && hasBlendFuncExtended
       && hasSamplerObjects
       && hasTimerQuery
       && hasVertType21010101rev
       && FindProcShort (glVertexAttribDivisor);
  if (has33)
  {
    theCtx.core33 = (OpenGl_GlCore33* )this;
  }
  else
  {
    theCtx.checkWrongVersion (3, 3, aLastFailedProc);
  }

  // load GL_ARB_draw_indirect (added to OpenGL 4.0 core)
  const bool hasDrawIndirect = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_draw_indirect"))
       && FindProcShort (glDrawArraysIndirect)
       && FindProcShort (glDrawElementsIndirect);

  // load GL_ARB_gpu_shader_fp64 (added to OpenGL 4.0 core)
  const bool hasShaderFP64 = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_gpu_shader_fp64"))
       && FindProcShort (glUniform1d)
       && FindProcShort (glUniform2d)
       && FindProcShort (glUniform3d)
       && FindProcShort (glUniform4d)
       && FindProcShort (glUniform1dv)
       && FindProcShort (glUniform2dv)
       && FindProcShort (glUniform3dv)
       && FindProcShort (glUniform4dv)
       && FindProcShort (glUniformMatrix2dv)
       && FindProcShort (glUniformMatrix3dv)
       && FindProcShort (glUniformMatrix4dv)
       && FindProcShort (glUniformMatrix2x3dv)
       && FindProcShort (glUniformMatrix2x4dv)
       && FindProcShort (glUniformMatrix3x2dv)
       && FindProcShort (glUniformMatrix3x4dv)
       && FindProcShort (glUniformMatrix4x2dv)
       && FindProcShort (glUniformMatrix4x3dv)
       && FindProcShort (glGetUniformdv);

  // load GL_ARB_shader_subroutine (added to OpenGL 4.0 core)
  const bool hasShaderSubroutine = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_shader_subroutine"))
       && FindProcShort (glGetSubroutineUniformLocation)
       && FindProcShort (glGetSubroutineIndex)
       && FindProcShort (glGetActiveSubroutineUniformiv)
       && FindProcShort (glGetActiveSubroutineUniformName)
       && FindProcShort (glGetActiveSubroutineName)
       && FindProcShort (glUniformSubroutinesuiv)
       && FindProcShort (glGetUniformSubroutineuiv)
       && FindProcShort (glGetProgramStageiv);

  // load GL_ARB_tessellation_shader (added to OpenGL 4.0 core)
  const bool hasTessellationShader = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_tessellation_shader"))
       && FindProcShort (glPatchParameteri)
       && FindProcShort (glPatchParameterfv);

  // load GL_ARB_transform_feedback2 (added to OpenGL 4.0 core)
  const bool hasTrsfFeedback2 = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_transform_feedback2"))
       && FindProcShort (glBindTransformFeedback)
       && FindProcShort (glDeleteTransformFeedbacks)
       && FindProcShort (glGenTransformFeedbacks)
       && FindProcShort (glIsTransformFeedback)
       && FindProcShort (glPauseTransformFeedback)
       && FindProcShort (glResumeTransformFeedback)
       && FindProcShort (glDrawTransformFeedback);

  // load GL_ARB_transform_feedback3 (added to OpenGL 4.0 core)
  const bool hasTrsfFeedback3 = (isGlGreaterEqualShort (4, 0) || checkExtensionShort ("GL_ARB_transform_feedback3"))
       && FindProcShort (glDrawTransformFeedbackStream)
       && FindProcShort (glBeginQueryIndexed)
       && FindProcShort (glEndQueryIndexed)
       && FindProcShort (glGetQueryIndexediv);

  // load OpenGL 4.0 new functions
  has40 = isGlGreaterEqualShort (4, 0)
      && hasDrawIndirect
      && hasShaderFP64
      && hasShaderSubroutine
      && hasTessellationShader
      && hasTrsfFeedback2
      && hasTrsfFeedback3
      && FindProcShort (glMinSampleShading)
      && FindProcShort (glBlendEquationi)
      && FindProcShort (glBlendEquationSeparatei)
      && FindProcShort (glBlendFunci)
      && FindProcShort (glBlendFuncSeparatei);
  if (has40)
  {
    theCtx.arbTboRGB32 = true; // in core since OpenGL 4.0
  }
  else
  {
    theCtx.checkWrongVersion (4, 0, aLastFailedProc);
  }

  // load GL_ARB_ES2_compatibility (added to OpenGL 4.1 core)
  const bool hasES2Compatibility = (isGlGreaterEqualShort (4, 1) || checkExtensionShort ("GL_ARB_ES2_compatibility"))
       && FindProcShort (glReleaseShaderCompiler)
       && FindProcShort (glShaderBinary)
       && FindProcShort (glGetShaderPrecisionFormat)
       && FindProcShort (glDepthRangef)
       && FindProcShort (glClearDepthf);

  // load GL_ARB_get_program_binary (added to OpenGL 4.1 core)
  const bool hasGetProgramBinary = (isGlGreaterEqualShort (4, 1) || checkExtensionShort ("GL_ARB_get_program_binary"))
       && FindProcShort (glGetProgramBinary)
       && FindProcShort (glProgramBinary)
       && FindProcShort (glProgramParameteri);


  // load GL_ARB_separate_shader_objects (added to OpenGL 4.1 core)
  const bool hasSeparateShaderObjects = (isGlGreaterEqualShort (4, 1) || checkExtensionShort ("GL_ARB_separate_shader_objects"))
       && FindProcShort (glUseProgramStages)
       && FindProcShort (glActiveShaderProgram)
       && FindProcShort (glCreateShaderProgramv)
       && FindProcShort (glBindProgramPipeline)
       && FindProcShort (glDeleteProgramPipelines)
       && FindProcShort (glGenProgramPipelines)
       && FindProcShort (glIsProgramPipeline)
       && FindProcShort (glGetProgramPipelineiv)
       && FindProcShort (glProgramUniform1i)
       && FindProcShort (glProgramUniform1iv)
       && FindProcShort (glProgramUniform1f)
       && FindProcShort (glProgramUniform1fv)
       && FindProcShort (glProgramUniform1d)
       && FindProcShort (glProgramUniform1dv)
       && FindProcShort (glProgramUniform1ui)
       && FindProcShort (glProgramUniform1uiv)
       && FindProcShort (glProgramUniform2i)
       && FindProcShort (glProgramUniform2iv)
       && FindProcShort (glProgramUniform2f)
       && FindProcShort (glProgramUniform2fv)
       && FindProcShort (glProgramUniform2d)
       && FindProcShort (glProgramUniform2dv)
       && FindProcShort (glProgramUniform2ui)
       && FindProcShort (glProgramUniform2uiv)
       && FindProcShort (glProgramUniform3i)
       && FindProcShort (glProgramUniform3iv)
       && FindProcShort (glProgramUniform3f)
       && FindProcShort (glProgramUniform3fv)
       && FindProcShort (glProgramUniform3d)
       && FindProcShort (glProgramUniform3dv)
       && FindProcShort (glProgramUniform3ui)
       && FindProcShort (glProgramUniform3uiv)
       && FindProcShort (glProgramUniform4i)
       && FindProcShort (glProgramUniform4iv)
       && FindProcShort (glProgramUniform4f)
       && FindProcShort (glProgramUniform4fv)
       && FindProcShort (glProgramUniform4d)
       && FindProcShort (glProgramUniform4dv)
       && FindProcShort (glProgramUniform4ui)
       && FindProcShort (glProgramUniform4uiv)
       && FindProcShort (glProgramUniformMatrix2fv)
       && FindProcShort (glProgramUniformMatrix3fv)
       && FindProcShort (glProgramUniformMatrix4fv)
       && FindProcShort (glProgramUniformMatrix2dv)
       && FindProcShort (glProgramUniformMatrix3dv)
       && FindProcShort (glProgramUniformMatrix4dv)
       && FindProcShort (glProgramUniformMatrix2x3fv)
       && FindProcShort (glProgramUniformMatrix3x2fv)
       && FindProcShort (glProgramUniformMatrix2x4fv)
       && FindProcShort (glProgramUniformMatrix4x2fv)
       && FindProcShort (glProgramUniformMatrix3x4fv)
       && FindProcShort (glProgramUniformMatrix4x3fv)
       && FindProcShort (glProgramUniformMatrix2x3dv)
       && FindProcShort (glProgramUniformMatrix3x2dv)
       && FindProcShort (glProgramUniformMatrix2x4dv)
       && FindProcShort (glProgramUniformMatrix4x2dv)
       && FindProcShort (glProgramUniformMatrix3x4dv)
       && FindProcShort (glProgramUniformMatrix4x3dv)
       && FindProcShort (glValidateProgramPipeline)
       && FindProcShort (glGetProgramPipelineInfoLog);

  // load GL_ARB_vertex_attrib_64bit (added to OpenGL 4.1 core)
  const bool hasVertAttrib64bit = (isGlGreaterEqualShort (4, 1) || checkExtensionShort ("GL_ARB_vertex_attrib_64bit"))
       && FindProcShort (glVertexAttribL1d)
       && FindProcShort (glVertexAttribL2d)
       && FindProcShort (glVertexAttribL3d)
       && FindProcShort (glVertexAttribL4d)
       && FindProcShort (glVertexAttribL1dv)
       && FindProcShort (glVertexAttribL2dv)
       && FindProcShort (glVertexAttribL3dv)
       && FindProcShort (glVertexAttribL4dv)
       && FindProcShort (glVertexAttribLPointer)
       && FindProcShort (glGetVertexAttribLdv);

  // load GL_ARB_viewport_array (added to OpenGL 4.1 core)
  const bool hasViewportArray = (isGlGreaterEqualShort (4, 1) || checkExtensionShort ("GL_ARB_viewport_array"))
       && FindProcShort (glViewportArrayv)
       && FindProcShort (glViewportIndexedf)
       && FindProcShort (glViewportIndexedfv)
       && FindProcShort (glScissorArrayv)
       && FindProcShort (glScissorIndexed)
       && FindProcShort (glScissorIndexedv)
       && FindProcShort (glDepthRangeArrayv)
       && FindProcShort (glDepthRangeIndexed)
       && FindProcShort (glGetFloati_v)
       && FindProcShort (glGetDoublei_v);

  has41 = isGlGreaterEqualShort (4, 1)
       && hasES2Compatibility
       && hasGetProgramBinary
       && hasSeparateShaderObjects
       && hasVertAttrib64bit
       && hasViewportArray;
  if (has41)
  {
    theCtx.core41 = (OpenGl_GlCore41* )this;
  }
  else
  {
    theCtx.checkWrongVersion (4, 1, aLastFailedProc);
  }

  // load GL_ARB_base_instance (added to OpenGL 4.2 core)
  const bool hasBaseInstance = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_base_instance"))
       && FindProcShort (glDrawArraysInstancedBaseInstance)
       && FindProcShort (glDrawElementsInstancedBaseInstance)
       && FindProcShort (glDrawElementsInstancedBaseVertexBaseInstance);

  // load GL_ARB_transform_feedback_instanced (added to OpenGL 4.2 core)
  const bool hasTrsfFeedbackInstanced = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_transform_feedback_instanced"))
       && FindProcShort (glDrawTransformFeedbackInstanced)
       && FindProcShort (glDrawTransformFeedbackStreamInstanced);

  // load GL_ARB_internalformat_query (added to OpenGL 4.2 core)
  const bool hasInternalFormatQuery = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_internalformat_query"))
       && FindProcShort (glGetInternalformativ);

  // load GL_ARB_shader_atomic_counters (added to OpenGL 4.2 core)
  const bool hasShaderAtomicCounters = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_shader_atomic_counters"))
       && FindProcShort (glGetActiveAtomicCounterBufferiv);

  // load GL_ARB_shader_image_load_store (added to OpenGL 4.2 core)
  const bool hasShaderImgLoadStore = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_shader_image_load_store"))
       && FindProcShort (glBindImageTexture)
       && FindProcShort (glMemoryBarrier);

  // load GL_ARB_texture_storage (added to OpenGL 4.2 core)
  const bool hasTextureStorage = (isGlGreaterEqualShort (4, 2) || checkExtensionShort ("GL_ARB_texture_storage"))
       && FindProcShort (glTexStorage1D)
       && FindProcShort (glTexStorage2D)
       && FindProcShort (glTexStorage3D);

  has42 = isGlGreaterEqualShort (4, 2)
       && hasBaseInstance
       && hasTrsfFeedbackInstanced
       && hasInternalFormatQuery
       && hasShaderAtomicCounters
       && hasShaderImgLoadStore
       && hasTextureStorage;
  if (has42)
  {
    theCtx.core42 = (OpenGl_GlCore42* )this;
  }
  else
  {
    theCtx.checkWrongVersion (4, 2, aLastFailedProc);
  }

  has43 = isGlGreaterEqualShort (4, 3)
       && FindProcShort (glClearBufferData)
       && FindProcShort (glClearBufferSubData)
       && FindProcShort (glDispatchCompute)
       && FindProcShort (glDispatchComputeIndirect)
       && FindProcShort (glCopyImageSubData)
       && FindProcShort (glFramebufferParameteri)
       && FindProcShort (glGetFramebufferParameteriv)
       && FindProcShort (glGetInternalformati64v)
       && FindProcShort (glInvalidateTexSubImage)
       && FindProcShort (glInvalidateTexImage)
       && FindProcShort (glInvalidateBufferSubData)
       && FindProcShort (glInvalidateBufferData)
       && FindProcShort (glInvalidateFramebuffer)
       && FindProcShort (glInvalidateSubFramebuffer)
       && FindProcShort (glMultiDrawArraysIndirect)
       && FindProcShort (glMultiDrawElementsIndirect)
       && FindProcShort (glGetProgramInterfaceiv)
       && FindProcShort (glGetProgramResourceIndex)
       && FindProcShort (glGetProgramResourceName)
       && FindProcShort (glGetProgramResourceiv)
       && FindProcShort (glGetProgramResourceLocation)
       && FindProcShort (glGetProgramResourceLocationIndex)
       && FindProcShort (glShaderStorageBlockBinding)
       && FindProcShort (glTexBufferRange)
       && FindProcShort (glTexStorage2DMultisample)
       && FindProcShort (glTexStorage3DMultisample)
       && FindProcShort (glTextureView)
       && FindProcShort (glBindVertexBuffer)
       && FindProcShort (glVertexAttribFormat)
       && FindProcShort (glVertexAttribIFormat)
       && FindProcShort (glVertexAttribLFormat)
       && FindProcShort (glVertexAttribBinding)
       && FindProcShort (glVertexBindingDivisor)
       && FindProcShort (glDebugMessageControl)
       && FindProcShort (glDebugMessageInsert)
       && FindProcShort (glDebugMessageCallback)
       && FindProcShort (glGetDebugMessageLog)
       && FindProcShort (glPushDebugGroup)
       && FindProcShort (glPopDebugGroup)
       && FindProcShort (glObjectLabel)
       && FindProcShort (glGetObjectLabel)
       && FindProcShort (glObjectPtrLabel)
       && FindProcShort (glGetObjectPtrLabel);
  if (has43)
  {
    theCtx.core43 = (OpenGl_GlCore43* )this;
  }
  else
  {
    theCtx.checkWrongVersion (4, 3, aLastFailedProc);
  }

  // load GL_ARB_clear_texture (added to OpenGL 4.4 core)
  bool arbTexClear = (isGlGreaterEqualShort (4, 4) || checkExtensionShort ("GL_ARB_clear_texture"))
       && FindProcShort (glClearTexImage)
       && FindProcShort (glClearTexSubImage);

  has44 = isGlGreaterEqualShort (4, 4)
       && arbTexClear
       && FindProcShort (glBufferStorage)
       && FindProcShort (glBindBuffersBase)
       && FindProcShort (glBindBuffersRange)
       && FindProcShort (glBindTextures)
       && FindProcShort (glBindSamplers)
       && FindProcShort (glBindImageTextures)
       && FindProcShort (glBindVertexBuffers);
  if (has44)
  {
    theCtx.core44 = (OpenGl_GlCore44* )this;
  }
  else
  {
    theCtx.checkWrongVersion (4, 4, aLastFailedProc);
  }

  has45 = isGlGreaterEqualShort (4, 5)
       && FindProcShort (glBindVertexBuffers)
       && FindProcShort (glClipControl)
       && FindProcShort (glCreateTransformFeedbacks)
       && FindProcShort (glTransformFeedbackBufferBase)
       && FindProcShort (glTransformFeedbackBufferRange)
       && FindProcShort (glGetTransformFeedbackiv)
       && FindProcShort (glGetTransformFeedbacki_v)
       && FindProcShort (glGetTransformFeedbacki64_v)
       && FindProcShort (glCreateBuffers)
       && FindProcShort (glNamedBufferStorage)
       && FindProcShort (glNamedBufferData)
       && FindProcShort (glNamedBufferSubData)
       && FindProcShort (glCopyNamedBufferSubData)
       && FindProcShort (glClearNamedBufferData)
       && FindProcShort (glClearNamedBufferSubData)
       && FindProcShort (glMapNamedBuffer)
       && FindProcShort (glMapNamedBufferRange)
       && FindProcShort (glUnmapNamedBuffer)
       && FindProcShort (glFlushMappedNamedBufferRange)
       && FindProcShort (glGetNamedBufferParameteriv)
       && FindProcShort (glGetNamedBufferParameteri64v)
       && FindProcShort (glGetNamedBufferPointerv)
       && FindProcShort (glGetNamedBufferSubData)
       && FindProcShort (glCreateFramebuffers)
       && FindProcShort (glNamedFramebufferRenderbuffer)
       && FindProcShort (glNamedFramebufferParameteri)
       && FindProcShort (glNamedFramebufferTexture)
       && FindProcShort (glNamedFramebufferTextureLayer)
       && FindProcShort (glNamedFramebufferDrawBuffer)
       && FindProcShort (glNamedFramebufferDrawBuffers)
       && FindProcShort (glNamedFramebufferReadBuffer)
       && FindProcShort (glInvalidateNamedFramebufferData)
       && FindProcShort (glInvalidateNamedFramebufferSubData)
       && FindProcShort (glClearNamedFramebufferiv)
       && FindProcShort (glClearNamedFramebufferuiv)
       && FindProcShort (glClearNamedFramebufferfv)
       && FindProcShort (glClearNamedFramebufferfi)
       && FindProcShort (glBlitNamedFramebuffer)
       && FindProcShort (glCheckNamedFramebufferStatus)
       && FindProcShort (glGetNamedFramebufferParameteriv)
       && FindProcShort (glGetNamedFramebufferAttachmentParameteriv)
       && FindProcShort (glCreateRenderbuffers)
       && FindProcShort (glNamedRenderbufferStorage)
       && FindProcShort (glNamedRenderbufferStorageMultisample)
       && FindProcShort (glGetNamedRenderbufferParameteriv)
       && FindProcShort (glCreateTextures)
       && FindProcShort (glTextureBuffer)
       && FindProcShort (glTextureBufferRange)
       && FindProcShort (glTextureStorage1D)
       && FindProcShort (glTextureStorage2D)
       && FindProcShort (glTextureStorage3D)
       && FindProcShort (glTextureStorage2DMultisample)
       && FindProcShort (glTextureStorage3DMultisample)
       && FindProcShort (glTextureSubImage1D)
       && FindProcShort (glTextureSubImage2D)
       && FindProcShort (glTextureSubImage3D)
       && FindProcShort (glCompressedTextureSubImage1D)
       && FindProcShort (glCompressedTextureSubImage2D)
       && FindProcShort (glCompressedTextureSubImage3D)
       && FindProcShort (glCopyTextureSubImage1D)
       && FindProcShort (glCopyTextureSubImage2D)
       && FindProcShort (glCopyTextureSubImage3D)
       && FindProcShort (glTextureParameterf)
       && FindProcShort (glTextureParameterfv)
       && FindProcShort (glTextureParameteri)
       && FindProcShort (glTextureParameterIiv)
       && FindProcShort (glTextureParameterIuiv)
       && FindProcShort (glTextureParameteriv)
       && FindProcShort (glGenerateTextureMipmap)
       && FindProcShort (glBindTextureUnit)
       && FindProcShort (glGetTextureImage)
       && FindProcShort (glGetCompressedTextureImage)
       && FindProcShort (glGetTextureLevelParameterfv)
       && FindProcShort (glGetTextureLevelParameteriv)
       && FindProcShort (glGetTextureParameterfv)
       && FindProcShort (glGetTextureParameterIiv)
       && FindProcShort (glGetTextureParameterIuiv)
       && FindProcShort (glGetTextureParameteriv)
       && FindProcShort (glCreateVertexArrays)
       && FindProcShort (glDisableVertexArrayAttrib)
       && FindProcShort (glEnableVertexArrayAttrib)
       && FindProcShort (glVertexArrayElementBuffer)
       && FindProcShort (glVertexArrayVertexBuffer)
       && FindProcShort (glVertexArrayVertexBuffers)
       && FindProcShort (glVertexArrayAttribBinding)
       && FindProcShort (glVertexArrayAttribFormat)
       && FindProcShort (glVertexArrayAttribIFormat)
       && FindProcShort (glVertexArrayAttribLFormat)
       && FindProcShort (glVertexArrayBindingDivisor)
       && FindProcShort (glGetVertexArrayiv)
       && FindProcShort (glGetVertexArrayIndexediv)
       && FindProcShort (glGetVertexArrayIndexed64iv)
       && FindProcShort (glCreateSamplers)
       && FindProcShort (glCreateProgramPipelines)
       && FindProcShort (glCreateQueries)
       && FindProcShort (glGetQueryBufferObjecti64v)
       && FindProcShort (glGetQueryBufferObjectiv)
       && FindProcShort (glGetQueryBufferObjectui64v)
       && FindProcShort (glGetQueryBufferObjectuiv)
       && FindProcShort (glMemoryBarrierByRegion)
       && FindProcShort (glGetTextureSubImage)
       && FindProcShort (glGetCompressedTextureSubImage)
       && FindProcShort (glGetGraphicsResetStatus)
       && FindProcShort (glGetnUniformfv)
       && FindProcShort (glGetnUniformiv)
       && FindProcShort (glGetnUniformuiv)
       && FindProcShort (glReadnPixels)
       && FindProcShort (glTextureBarrier);
  bool hasGetnTexImage = has45
                      && FindProcShort (glGetnCompressedTexImage)
                      && FindProcShort (glGetnTexImage)
                      && FindProcShort (glGetnUniformdv);
  if (has45 && !hasGetnTexImage)
  {
    // Intel driver exports only ARB-suffixed functions in a violation to OpenGL 4.5 specs
    hasGetnTexImage = checkExtensionShort ("GL_ARB_robustness")
                   && theCtx.FindProc ("glGetnCompressedTexImageARB", this->glGetnCompressedTexImage)
                   && theCtx.FindProc ("glGetnTexImageARB",           this->glGetnTexImage)
                   && theCtx.FindProc ("glGetnUniformdvARB",          this->glGetnUniformdv);
    has45 = hasGetnTexImage;
    if (hasGetnTexImage)
    {
      Message::SendTrace() << "Warning! glGetnCompressedTexImage function required by OpenGL 4.5 specs is not found.\n"
                              "A non-standard glGetnCompressedTexImageARB fallback will be used instead.\n"
                              "Please report this issue to OpenGL driver vendor '" << theCtx.myVendor << "'.";
    }
  }
  if (has45)
  {
    theCtx.core45 = (OpenGl_GlCore45* )this;
    theCtx.arbClipControl = true;
  }
  else
  {
    theCtx.checkWrongVersion (4, 5, aLastFailedProc);
  }

  has46 = isGlGreaterEqualShort (4, 6)
       && FindProcShort (glSpecializeShader)
       && FindProcShort (glPolygonOffsetClamp);

  bool hasIndParams = has46
                   && FindProcShort (glMultiDrawArraysIndirectCount)
                   && FindProcShort (glMultiDrawElementsIndirectCount);
  if (has46 && !hasIndParams)
  {
    // Intel driver exports only ARB-suffixed functions in a violation to OpenGL 4.6 specs
    hasIndParams = checkExtensionShort ("GL_ARB_indirect_parameters")
                && theCtx.FindProc ("glMultiDrawArraysIndirectCountARB",   this->glMultiDrawArraysIndirectCount)
                && theCtx.FindProc ("glMultiDrawElementsIndirectCountARB", this->glMultiDrawElementsIndirectCount);
    has46 = hasIndParams;
    if (hasIndParams)
    {
      Message::SendTrace() << "Warning! glMultiDrawArraysIndirectCount function required by OpenGL 4.6 specs is not found.\n"
                              "A non-standard glMultiDrawArraysIndirectCountARB fallback will be used instead.\n"
                              "Please report this issue to OpenGL driver vendor '" << theCtx.myVendor << "'.";
    }
  }

  if (has46)
  {
    theCtx.core46 = (OpenGl_GlCore46* )this;
  }
  else
  {
    theCtx.checkWrongVersion (4, 6, aLastFailedProc);
  }

  // initialize debug context extension
  if (checkExtensionShort ("GL_ARB_debug_output"))
  {
    theCtx.arbDbg = NULL;
    if (has43)
    {
      theCtx.arbDbg = (OpenGl_ArbDbg* )this;
    }
    else if (theCtx.FindProc ("glDebugMessageControlARB",  this->glDebugMessageControl)
          && theCtx.FindProc ("glDebugMessageInsertARB",   this->glDebugMessageInsert)
          && theCtx.FindProc ("glDebugMessageCallbackARB", this->glDebugMessageCallback)
          && theCtx.FindProc ("glGetDebugMessageLogARB",   this->glGetDebugMessageLog))
    {
      theCtx.arbDbg = (OpenGl_ArbDbg* )this;
    }
  }

  // initialize FBO extension (ARB)
  if (hasFBO)
  {
    theCtx.arbFBO     = (OpenGl_ArbFBO*     )this;
    theCtx.arbFBOBlit = (OpenGl_ArbFBOBlit* )this;
    theCtx.extPDS = Standard_True; // extension for EXT, but part of ARB
  }

  // initialize GS extension (EXT)
  if (checkExtensionShort ("GL_EXT_geometry_shader4")
   && FindProcShort (glProgramParameteriEXT))
  {
    theCtx.extGS = (OpenGl_ExtGS* )this;
  }

  // initialize bindless texture extension (ARB)
  if (checkExtensionShort ("GL_ARB_bindless_texture")
   && FindProcShort (glGetTextureHandleARB)
   && FindProcShort (glGetTextureSamplerHandleARB)
   && FindProcShort (glMakeTextureHandleResidentARB)
   && FindProcShort (glMakeTextureHandleNonResidentARB)
   && FindProcShort (glGetImageHandleARB)
   && FindProcShort (glMakeImageHandleResidentARB)
   && FindProcShort (glMakeImageHandleNonResidentARB)
   && FindProcShort (glUniformHandleui64ARB)
   && FindProcShort (glUniformHandleui64vARB)
   && FindProcShort (glProgramUniformHandleui64ARB)
   && FindProcShort (glProgramUniformHandleui64vARB)
   && FindProcShort (glIsTextureHandleResidentARB)
   && FindProcShort (glIsImageHandleResidentARB)
   && FindProcShort (glVertexAttribL1ui64ARB)
   && FindProcShort (glVertexAttribL1ui64vARB)
   && FindProcShort (glGetVertexAttribLui64vARB))
  {
    theCtx.arbTexBindless = (OpenGl_ArbTexBindless* )this;
  }

  if (!has45
    && checkExtensionShort ("GL_ARB_clip_control")
    && FindProcShort (glClipControl))
  {
    theCtx.arbClipControl = true;
  }

  if (has30)
  {
    if (!has32
     && checkExtensionShort ("GL_ARB_texture_multisample")
     && FindProcShort (glTexImage2DMultisample))
    {
      //
    }
    if (!has43
     && checkExtensionShort ("GL_ARB_texture_storage_multisample")
     && FindProcShort (glTexStorage2DMultisample))
    {
      //
    }
  }
#endif
}
