// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2020
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
// File Version: This file is automatically generated.

#include <Graphics/GL45/GL45.h>
#include <cassert>
#include <cstring>
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>

// Support for versioning.
#define OPENGL_VERSION_NONE  0
#define OPENGL_VERSION_1_0  10
#define OPENGL_VERSION_1_1  11
#define OPENGL_VERSION_1_2  12
#define OPENGL_VERSION_1_3  13
#define OPENGL_VERSION_1_4  14
#define OPENGL_VERSION_1_5  15
#define OPENGL_VERSION_2_0  20
#define OPENGL_VERSION_2_1  21
#define OPENGL_VERSION_3_0  30
#define OPENGL_VERSION_3_1  31
#define OPENGL_VERSION_3_2  32
#define OPENGL_VERSION_3_3  33
#define OPENGL_VERSION_4_0  40
#define OPENGL_VERSION_4_1  41
#define OPENGL_VERSION_4_2  42
#define OPENGL_VERSION_4_3  43
#define OPENGL_VERSION_4_4  44
#define OPENGL_VERSION_4_5  45

// Support for querying the OpenGL function pointers.  Each platform must
// provide its own GetOpenGLFunctionPointer.
template <typename PGLFunction>
static void GetOpenGLFunction(char const* name, PGLFunction& function)
{
    extern void* GetOpenGLFunctionPointer(char const*);
    function = (PGLFunction)GetOpenGLFunctionPointer(name);
}

// Listen for glError warnings or errors.
#define GTE_GL45_THROW_ON_REPORT_LISTENER_WARNING
void OpenGLReportListener(char const* glFunction, GLenum code)
{
    if (!glFunction)
    {
        throw std::runtime_error("OpenGL function pointer is null.");
    }

    std::string strFunction(glFunction);
    if (code != GL_ZERO)
    {
        std::string strCode;
        switch (code)
        {
        case GL_INVALID_ENUM:
            strCode = "GL_INVALID_ENUM";
            return;
        case GL_INVALID_VALUE:
            strCode = "GL_INVALID_VALUE";
            return;
        case GL_INVALID_OPERATION:
            strCode = "GL_INVALID_OPERATION";
            return;
        case GL_STACK_OVERFLOW:
            strCode = "GL_STACK_OVERFLOW";
            return;
        case GL_STACK_UNDERFLOW:
            strCode = "GL_STACK_UNDERFLOW";
            return;
        case GL_OUT_OF_MEMORY:
            strCode = "GL_OUT_OF_MEMORY";
            return;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            strCode = "GL_INVALID_FRAMEBUFFER_OPERATION";
            return;
        case GL_CONTEXT_LOST:
            strCode = "GL_CONTEXT_LOST";
            return;
        default:
#if defined(GTE_GL45_THROW_ON_REPORT_LISTENER_WARNING)
            throw std::runtime_error("GL error <" + strCode + "> in " + strFunction);
#endif
        }
    }
}
static int GetOpenGLVersion()
{
    GLint major = 0, minor = 0;
    glGetIntegerv(GL_MAJOR_VERSION, &major);
    glGetIntegerv(GL_MINOR_VERSION, &minor);
    return 10 * major + minor;
}

static void ReportGLError(const char* glFunction)
{
    // code:
    //   0x0500 GL_INVALID_ENUM
    //   0x0501 GL_INVALID_VALUE
    //   0x0502 GL_INVALID_OPERATION
    //   0x0503 GL_STACK_OVERFLOW
    //   0x0504 GL_STACK_UNDERFLOW
    //   0x0505 GL_OUT_OF_MEMORY
    //   0x0506 GL_INVALID_FRAMEBUFFER_OPERATION
    //   0x0507 GL_CONTEXT_LOST

    GLenum code = glGetError();
    while (code != GL_NO_ERROR)
    {
        OpenGLReportListener(glFunction, code);
        code = glGetError();
    }
}

static void ReportGLNullFunction(const char* glFunction)
{
    OpenGLReportListener(glFunction, GL_ZERO);
}
