
/**
 * These are some Espial utilities for debugging OpenGL.
 */

#ifndef GLUtils_h
#define GLUtils_h 1

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#define GL_GLEXT_PROTOTYPES 1
#if USE(OPENGL_ES_2)
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#else
#include <GL/gl.h>
#include <GL/glext.h>
#endif

/* check for gl errors */
#ifndef DEBUG_GL_ERROR
#define DEBUG_GL_ERROR 0
#endif

/* abort on gl error */
#define DEBUG_GL_ABORT 0

/* trace all gl function calls */
#define GLES2_DEBUG_TRACE 0

// these are not yet implemented for new webkit
#define GLES2_DEBUG_SHADER 0       /* debug shader compilation */
#define GLES2_DEBUG_SHADER_ABORT 0 /* abort on shader compile failure */


#if GLES2_DEBUG_TRACE
#define GLES2_TRACE(str, ...) \
    fprintf(stderr, "GraphicsContext3D::%s():%i " str "\n", \
            __func__, __LINE__ , ##__VA_ARGS__)
#else
#define GLES2_TRACE(str, ...) /* nothing */
#endif


#if DEBUG_GL_ERROR
#pragma GCC diagnostic ignored "-Wformat-zero-length"

static void GLReportErrorV(GLuint error,
        const char* file, int line, const char* func,
        const char* format, va_list args)
    __attribute__((format(printf, 5, 0)));

static void GLReportErrorV(GLuint error,
        const char* file, int line, const char* func,
        const char* format, va_list args)
{

    // remove path from filename
    const char* shortfile = strrchr(file, '/');
    if (shortfile)
        ++shortfile;
    else
        shortfile = file;
    
    // convert error code to string (we use hardcoded values because not all
    // constants are defined in all OpenGL versions)
    const char* str = "unknown";
    switch (error) {
        case 0x0500:  str = "GL_INVALID_ENUM";                  break;
        case 0x0501:  str = "GL_INVALID_VALUE";                 break;
        case 0x0502:  str = "GL_INVALID_OPERATION";             break;
        case 0x0503:  str = "GL_STACK_OVERFLOW";                break;
        case 0x0504:  str = "GL_STACK_UNDERFLOW";               break;
        case 0x0505:  str = "GL_OUT_OF_MEMORY";                 break;
        case 0x0506:  str = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
        default: break;
    }

    // format error
    fprintf(stderr, "OpenGL error in %s() at %s:%i 0x%x (%s)\n",
            func, shortfile, line, error, str);
    if (format && strlen(format) > 0) {
        fprintf(stderr, "    ");
        vfprintf(stderr, format, args);
        fprintf(stderr, "\n");
    }

#if DEBUG_GL_ABORT
    abort();
#endif
}

__attribute__((unused))
static void GLReportError(GLuint error,
        const char* file, int line, const char* func,
        const char* format, ...)
    __attribute__((format(printf, 5, 6)));

static void GLReportError(GLuint error,
        const char* file, int line, const char* func,
        const char* format, ...)
{
    va_list args;
    va_start(args, format);
    GLReportErrorV(error, file, line, func, format, args);
    va_end(args);
}

#define CHECK_GL_ERROR(...)                                                   \
    do {                                                                      \
        GLuint _e = glGetError();                                             \
        if (_e)                                                               \
            GLReportError(_e, __FILE__, __LINE__, __func__ , "" __VA_ARGS__); \
    } while (0)

#define synthesizeGLErrorWrapper(x)                          \
    do {                                                     \
        GLReportError(x, __FILE__, __LINE__, __func__ , ""); \
        synthesizeGLError(x);                                \
    } while (0)

#else
#define CHECK_GL_ERROR(...) ((void)0)
#define synthesizeGLErrorWrapper synthesizeGLError
#endif

#endif

