#include <wasm-rt.h>
#include <client.h>

#include <iostream>

#include <GLES2/gl2.h>
#include <emscripten/html5.h>

#include "fugg.h"

#define TRACE_GL_CALLS 0

/* import: 'a' 'i' */
// "i": "_glDisableVertexAttribArray",
WASM_IMPORT_IMPL(env, _glDisableVertexAttribArray) = [](u32 a) {
    const auto& index = reinterpret_cast<GLuint>(a);

#if TRACE_GL_CALLS
    std::cout << "_glDisableVertexAttribArray("
              << a << ")" << std::endl;
#endif

    glDisableVertexAttribArray(index);
};
/* import: 'a' 'j' */
// "j": "_glUniformMatrix4fv",
WASM_IMPORT_IMPL(env, _glUniformMatrix4fv) = [](u32 a, u32 b, u32 c, u32 d) {
    const auto& location = reinterpret_cast<GLuint>(a);
    const auto& count = static_cast<GLsizei>(b);
    const auto& transpose = static_cast<GLboolean>(c);
    const auto& value = fugg::ModulePointer<const GLfloat>(d);

#if TRACE_GL_CALLS
    std::cout << "_glUniformMatrix4fv("
              << a << ", " 
              << b << ", " 
              << c << ", " 
              << value 
              << ")" << std::endl;
#endif

    glUniformMatrix4fv(location, count, transpose, value);
};

/* import: 'a' 'd' */
// "d": "_glActiveTexture",
/* _glActiveTexture */
WASM_IMPORT_IMPL(env, _glActiveTexture) = [](u32 a) {    
    const auto& texture = reinterpret_cast<GLenum>(a);

#if TRACE_GL_CALLS
    std::cout << "_glActiveTexture("
              << a 
              << ")" << std::endl;
#endif

    glActiveTexture(texture);
};
/* import: 'a' 'e' */
// "e": "_glBindTexture",
/* _glBindTexture */
WASM_IMPORT_IMPL(env, _glBindTexture) = [](u32 a, u32 b) {
    const auto& target = reinterpret_cast<GLenum>(a);
    const auto& texture = reinterpret_cast<GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glBindTexture("
              << a << ", " 
              << b 
              << ")" << std::endl;
#endif

    glBindTexture(target, texture);
};
/* import: 'a' 'f' */
// "f": "_glVertexAttribPointer",
WASM_IMPORT_IMPL(env, _glVertexAttribPointer) = [](u32 a, u32 b, u32 c, u32 d, u32 e, u32 f) {
    const auto& index = reinterpret_cast<GLuint>(a);
    const auto& size = static_cast<GLint>(b);
    const auto& type = reinterpret_cast<GLenum>(c);
    const auto& normalized = static_cast<GLboolean>(d);
    const auto& stride = static_cast<GLsizei>(e);
    // Specifies a offset of the first component, so although it's a pointer,
    // it's doesn't need to be transformed.
    const auto& pointer = reinterpret_cast<const void*>(f);

#if TRACE_GL_CALLS
    std::cout << "_glVertexAttribPointer("
              << a << ", " 
              << b << ", " 
              << c << ", " 
              << d << ", " 
              << e << ", " 
              << pointer 
              << ")" << std::endl;
#endif

    glVertexAttribPointer(index, size, type, normalized, stride, pointer);
};

// "m": "_glBindBuffer",
WASM_IMPORT_IMPL(env, _glBindBuffer) = [](u32 a, u32 b) {
    const auto& target = reinterpret_cast<GLenum>(a);
    const auto& buffer = reinterpret_cast<GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glBindBuffer("
              << a << ", " 
              << b 
              << ")" << std::endl;
#endif

    glBindBuffer(target, buffer);
};

// "n": "_glDisable",
WASM_IMPORT_IMPL(env, _glDisable) = [](u32 a) {
    const auto& cap = reinterpret_cast<GLenum>(a);

#if TRACE_GL_CALLS
    std::cout << "_glDisable("
              << a 
              << ")" << std::endl;
#endif

    glDisable(cap);
};


/* import: 'a' 'q' */
// "q": "_glUniform1f",
WASM_IMPORT_IMPL(env, _glUniform1f) = [](u32 a, f32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glUniform1f("
              << a << ", " 
              << b 
              << ")" << std::endl;
#endif

    glUniform1f(
        a,
        b
    );
};
// "r": "_glEnable",
WASM_IMPORT_IMPL(env, _glEnable) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glEnable("
              << a 
              << ")" << std::endl;
#endif

    glEnable(a);
};
/* import: 'a' 's' */
// "s": "_glTexParameteri",
WASM_IMPORT_IMPL(env, _glTexParameteri) = [](u32 a, u32 b, u32 c) {
#if TRACE_GL_CALLS
    std::cout << "_glTexParameteri("
              << a << ", " 
              << b << ", " 
              << c 
              << ")" << std::endl;
#endif

    glTexParameteri(
        a,
        b,
        c
    );
};
/* import: 'a' 'v' */
// "v": "_glUseProgram",
WASM_IMPORT_IMPL(env, _glUseProgram) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glUseProgram("
              << a 
              << ")" << std::endl;
#endif


    glUseProgram(a);
};
// "x": "_glEnableVertexAttribArray",
WASM_IMPORT_IMPL(env, _glEnableVertexAttribArray) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glEnableVertexAttribArray("
              << a 
              << ")" << std::endl;
#endif

    glEnableVertexAttribArray(a);
};

/* import: 'a' 'A' */
/* _glDepthMask */
WASM_IMPORT_IMPL(env, _glDepthMask) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glDepthMask("
              << a 
              << ")" << std::endl;
#endif

    glDepthMask(a);
};
/* import: 'a' 'B' */
/* _glBlendFunc */
WASM_IMPORT_IMPL(env, _glBlendFunc) = [](u32 a, u32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glBlendFunc("
              << a << ", "
              << b
              << ")" << std::endl;
#endif

    glBlendFunc(a, b);
};
/* import: 'a' 'C' */
/* _glBindFramebuffer */
WASM_IMPORT_IMPL(env, _glBindFramebuffer) = [](u32 a, u32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glBindFramebuffer("
              << a << ", "
              << b
              << ")" << std::endl;
#endif

    glBindFramebuffer(
        a,
        b
    );
};
/* import: 'a' 'D' */
/* _glDrawElements */
WASM_IMPORT_IMPL(env, _glDrawElements) = [](u32 a, u32 b, u32 c, u32 d) {
    const auto& indices = reinterpret_cast<const void*>(d);

#if TRACE_GL_CALLS
    std::cout << "_glDrawElements("
              << a << ", "
              << b << ", "
              << c << ", "
              << indices
              << ")" << std::endl;
#endif

    glDrawElements(
        a,
        b,
        c,
        indices
    );
};

/* import: 'a' 'I' */
/* "I": "_glUniform3fv" */
WASM_IMPORT_IMPL(env, _glUniform3fv) = [](u32 a, u32 b, u32 c) {
    const auto& value = fugg::ModulePointer<const GLfloat>(c);

#if TRACE_GL_CALLS
    std::cout << "_glUniform3fv("
              << a << ", "
              << b << ", "
              << value
              << ")" << std::endl;
#endif

    glUniform3fv(
        a,
        b,
        value
    );
};

/* import: 'a' 'K' */
// "K": "_glTexImage2D",
WASM_IMPORT_IMPL(env, _glTexImage2D) = [](u32 target, u32 level, u32 internalformat, u32 d, u32 e, u32 f, u32 g, u32 h, u32 i) {
    const auto& pixels = fugg::ModulePointer<const void>(i);

#if TRACE_GL_CALLS
    std::cout << "_glTexImage2D("
              << target << ", "
              << level << ", "
              << internalformat << ", "
              << d << ", "
              << e << ", "
              << f << ", "
              << g << ", "
              << h << ", "
              << pixels
              << ")" << std::endl;
#endif

    glTexImage2D(
        target,
        level,
        internalformat,
        d,
        e,
        f,
        g,
        h,
        pixels
    );
};

/* import: 'a' 'M' */
// "M": "_glViewport",
WASM_IMPORT_IMPL(env, _glViewport) = [](u32 a, u32 b, u32 c, u32 d) {
#if TRACE_GL_CALLS
    std::cout << "_glViewport("
              << a << ", "
              << b << ", "
              << c << ", "
              << d 
              << ")" << std::endl;
#endif

    glViewport(
        a, 
        b, 
        c, 
        d
    );
};
// "N": "_glGetError",
WASM_IMPORT_IMPL(env, _glGetError) = []() {
#if TRACE_GL_CALLS
    std::cout << "_glGetError()" << std::endl;
#endif

    return glGetError();
};
// "O": "_glDeleteFramebuffers",
WASM_IMPORT_IMPL(env, _glDeleteFramebuffers) = [](u32 a, u32 b) {
    const auto& framebuffers = fugg::ModulePointer<const GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glDeleteFramebuffers("
              << a << ", "
              << framebuffers
              << ")" << std::endl;
#endif

    glDeleteFramebuffers(
        a,
        framebuffers
    );
};
/* import: 'a' 'P' */
// "P": "_glColorMask",
WASM_IMPORT_IMPL(env, _glColorMask) = [](u32 a, u32 b, u32 c, u32 d) {
#if TRACE_GL_CALLS
    std::cout << "_glColorMask("
              << a << ", "
              << b << ", "
              << c << ", "
              << d
              << ")" << std::endl;
#endif

    glColorMask(
        a,
        b,
        c,
        d
    );
};
// "R": "_glDeleteBuffers",
WASM_IMPORT_IMPL(env, _glDeleteBuffers) = [](u32 a, u32 b) {
    const auto& n = static_cast<GLsizei>(a);
    const auto& buffers = fugg::ModulePointer<const GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glDeleteBuffers("
              << a << ", "
              << buffers
              << ")" << std::endl;
#endif

    glDeleteBuffers(n, buffers);
};
// "S": "_glBufferData",
WASM_IMPORT_IMPL(env, _glBufferData) = [](u32 a, u32 b, u32 c, u32 d) {
    const auto& size = static_cast<GLsizeiptr>(b);
    const auto& data = fugg::ModulePointer<const void>(c);

#if TRACE_GL_CALLS
    std::cout << "_glBufferData("
              << a << ", "
              << b << ", "
              << data << ", "
              << d
              << ")" << std::endl;
#endif

    glBufferData(
        a,
        size,
        data,
        d
    );
};
/* import: 'a' 'T' */
// "T": "_glGenBuffers",
WASM_IMPORT_IMPL(env, _glGenBuffers) = [](u32 a, u32 b) {
    const auto& n = static_cast<GLsizei>(a);
    const auto& buffers = fugg::ModulePointer<GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glGenBuffers("
              << a << ", "
              << buffers
              << ")" << std::endl;
#endif

    glGenBuffers(
        a,
        buffers
    );
};
/* import: 'a' 'U' */
// "U": "_glScissor",
WASM_IMPORT_IMPL(env, _glScissor) = [](u32 a, u32 b, u32 c, u32 d) {
#if TRACE_GL_CALLS
    std::cout << "_glScissor("
              << a << ", "
              << b << ", "
              << c << ", "
              << d
              << ")" << std::endl;
#endif

    glScissor(
        a,
        b,
        c,
        d
    );
};
/* import: 'a' 'V' */
// "V": "_glStencilMask",
WASM_IMPORT_IMPL(env, _glStencilMask) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glStencilMask("
              << a 
              << ")" << std::endl;
#endif

    glStencilMask(a);
};

/* import: 'a' 'Z' */
// "Z": "_glGenTextures",
WASM_IMPORT_IMPL(env, _glGenTextures) = [](u32 a, u32 b) {
    const auto& n = static_cast<GLsizei>(a);
    const auto& textures = fugg::ModulePointer<GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glGenTextures("
              << a << ", "
              << textures
              << ")" << std::endl;
#endif

    glGenTextures(n, textures);
};
/* import: 'a' '_' */
// "_": "_glUniform2f",
WASM_IMPORT_IMPL(env, _glUniform2f) = [](u32 a, f32 b, f32 c) {
#if TRACE_GL_CALLS
    std::cout << "_glUniform2f("
              << a << ", "
              << b << ", "
              << c
              << ")" << std::endl;
#endif

    glUniform2f(
        a,
        b,
        c
    );
};
/* import: 'a' '$' */
/* _glUniform2fv */
WASM_IMPORT_IMPL(env, _glUniform2fv) = [](u32 a, u32 b, u32 c) {
    const auto& value = fugg::ModulePointer<const GLfloat>(c);

#if TRACE_GL_CALLS
    std::cout << "_glUniform2fv("
              << a << ", "
              << b << ", "
              << value
              << ")" << std::endl;
#endif

    glUniform2fv(
        a,
        b,
        value
    );
};
// "aa": "_glFrontFace",
WASM_IMPORT_IMPL(env, _glFrontFace) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glFrontFace("
              << a 
              << ")" << std::endl;
#endif

    glFrontFace(a);
};
// "ba": "_glFramebufferTexture2D",
WASM_IMPORT_IMPL(env, _glFramebufferTexture2D) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
#if TRACE_GL_CALLS
    std::cout << "_glFramebufferTexture2D("
              << a << ", "
              << b << ", "
              << c << ", "
              << d << ", "
              << e
              << ")" << std::endl;
#endif

    glFramebufferTexture2D(
        a,
        b,
        c,
        d,
        e
    );
};
/* import: 'a' 'ea' */
// "ea": "_glGetProgramiv",
WASM_IMPORT_IMPL(env, _glGetProgramiv) = [](u32 a, u32 b, u32 c) {
    const auto& params = fugg::ModulePointer<GLint>(c);

#if TRACE_GL_CALLS
    std::cout << "_glGetProgramiv("
              << a << ", "
              << b << ", "
              << params
              << ")" << std::endl;
#endif

    glGetProgramiv(
        a,
        b,
        params
    );
};
/* import: 'a' 'fa' */
// "fa": "_glStencilFunc",
WASM_IMPORT_IMPL(env, _glStencilFunc) = [](u32 a, u32 b, u32 c) {
#if TRACE_GL_CALLS
    std::cout << "_glStencilFunc("
              << a << ", "
              << b << ", "
              << c
              << ")" << std::endl;
#endif

    glStencilFunc(
        a,
        b,
        c
    );
};
/* import: 'a' 'ga' */
// "ga": "_glGenFramebuffers",
WASM_IMPORT_IMPL(env, _glGenFramebuffers) = [](u32 a, u32 b) {
    const auto& framebuffers = fugg::ModulePointer<GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glGenFramebuffers("
              << a << ", "
              << framebuffers
              << ")" << std::endl;
#endif

    glGenFramebuffers(
        a,
        framebuffers
    );
};

/* import: 'a' 'ia' */
// "ia": "_glGetIntegerv",
WASM_IMPORT_IMPL(env, _glGetIntegerv) = [](u32 a, u32 b) {
    const auto& data = fugg::ModulePointer<GLint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glGetIntegerv("
              << a << ", "
              << data
              << ")" << std::endl;
#endif

    glGetIntegerv(
        a,
        data
    );
};
/* import: 'a' 'ja' */
// "ja": "_glUniform1i",
WASM_IMPORT_IMPL(env, _glUniform1i) = [](u32 a, u32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glUniform1i("
              << a << ", "
              << b
              << ")" << std::endl;
#endif

    glUniform1i(
        a,
        b
    );
};

/* import: 'a' 'na' */
// "na": "_glClear",
WASM_IMPORT_IMPL(env, _glClear) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glClear("
              << a 
              << ")" << std::endl;
#endif
              
    glClear(a);
};

/* import: 'a' 'ta' */
// "ta": "_glDeleteProgram",
WASM_IMPORT_IMPL(env, _glDeleteProgram) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glDeleteProgram("
              << a 
              << ")" << std::endl;
#endif

    glDeleteProgram(a);
};

/* import: 'a' 'wa' */
// "wa": "_glDeleteShader",
WASM_IMPORT_IMPL(env, _glDeleteShader) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glDeleteShader("
              << a 
              << ")" << std::endl;
#endif

    glDeleteShader(a);
};
/* import: 'a' 'xa' */
// "xa": "_glDepthFunc",
WASM_IMPORT_IMPL(env, _glDepthFunc) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glDepthFunc("
              << a 
              << ")" << std::endl;
#endif

    glDepthFunc(a);
};

/* import: 'a' 'Sa' */
// "Sa": "_glClearColor",
WASM_IMPORT_IMPL(env, _glClearColor) = [](f32 a, f32 b, f32 c, f32 d) {
#if TRACE_GL_CALLS
    std::cout << "_glClearColor("
              << a << ", "
              << b << ", "
              << c << ", "
              << d
              << ")" << std::endl;
#endif

    glClearColor(
        a,
        b,
        c,
        d
    );
};
/* import: 'a' 'Ta' */
// "Ta": "_glGetProgramInfoLog",
WASM_IMPORT_IMPL(env, _glGetProgramInfoLog) = [](u32 a, u32 b, u32 c, u32 d) {
    const auto& program = reinterpret_cast<GLuint>(a);
    const auto& buf_size = static_cast<GLsizei>(b);
    const auto& length  = fugg::ModulePointer<GLsizei>(c);
    const auto& infolog = fugg::ModulePointer<GLchar>(d);

#if TRACE_GL_CALLS
    std::cout << "_glGetProgramInfoLog("
              << a << ", "
              << b << ", "
              << length << ", "
              << infolog
              << ")" << std::endl;
#endif

    glGetProgramInfoLog(
        a,
        b,
        length,
        infolog
    );
};
/* import: 'a' 'Ua' */
// "Ua": "_glLinkProgram",
WASM_IMPORT_IMPL(env, _glLinkProgram) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glLinkProgram("
              << a 
              << ")" << std::endl;
#endif

    glLinkProgram(a);
};
/* import: 'a' 'Va' */
// "Va": "_glAttachShader",
WASM_IMPORT_IMPL(env, _glAttachShader) = [](u32 a, u32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glAttachShader("
              << a << ", "
              << b
              << ")" << std::endl;
#endif

    glAttachShader(
        a,
        b
    );
};
/* import: 'a' 'Wa' */
// "Wa": "_glGetShaderiv",
WASM_IMPORT_IMPL(env, _glGetShaderiv) = [](u32 a, u32 b, u32 c) {
    const auto& params = fugg::ModulePointer<GLint>(c);

#if TRACE_GL_CALLS
    std::cout << "_glGetShaderiv("
              << a << ", "
              << b << ", "
              << params
              << ")" << std::endl;
#endif

    glGetShaderiv(
        a,
        b,
        params
    );
};
/* import: 'a' 'Xa' */
// "Xa": "_glLineWidth",
WASM_IMPORT_IMPL(env, _glLineWidth) = [](f32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glLineWidth("
              << a 
              << ")" << std::endl;
#endif

    glLineWidth(a);
};

/* import: 'a' 'kb' */
// "kb": "_glUniform4f",
WASM_IMPORT_IMPL(env, _glUniform4f) = [](u32 a, f32 b, f32 c, f32 d, f32 e) {
#if TRACE_GL_CALLS
    std::cout << "_glUniform4f("
              << a << ", "
              << b << ", "
              << c << ", "
              << d << ", "
              << e
              << ")" << std::endl;
#endif

    glUniform4f(
        a,
        b,
        c,
        d,
        e
    );
};
/* import: 'a' 'lb' */
// "lb": "_glCompressedTexImage2D",
WASM_IMPORT_IMPL(env, _glCompressedTexImage2D) = [](u32 target, u32 level, u32 internalformat, u32 width, u32 height, u32 border, u32 image_size, u32 h) {
    const auto& data = fugg::ModulePointer<const void>(h);

#if TRACE_GL_CALLS
    std::cout << "_glCompressedTexImage2D("
              << target << ", "
              << level << ", "
              << internalformat << ", "
              << width << ", "
              << height << ", "
              << border << ", "
              << image_size << ", "
              << data
              << ")" << std::endl;
#endif

    glCompressedTexImage2D(
        target,
        level,
        internalformat,
        width,
        height,
        border,
        image_size,
        data
    );
};
/* import: 'a' 'mb' */
// "mb": "_glBindAttribLocation",
WASM_IMPORT_IMPL(env, _glBindAttribLocation) = [](u32 a, u32 b, u32 c) {
    const auto& name = fugg::ModulePointer<const GLchar>(c);

#if TRACE_GL_CALLS
    std::cout << "_glBindAttribLocation("
              << a << ", "
              << b << ", "
              << name
              << ")" << std::endl;
#endif

    glBindAttribLocation(
        a,
        b,
        name
    );
};
/* import: 'a' 'nb' */
// "nb": "_glGetActiveAttrib",
WASM_IMPORT_IMPL(env, _glGetActiveAttrib) = [](u32 a, u32 b, u32 c, u32 d, u32 e, u32 f, u32 g) {
    const auto& length = fugg::ModulePointer<GLsizei>(d);
    const auto& size = fugg::ModulePointer<GLint>(e);
    const auto& type = fugg::ModulePointer<GLenum>(f);
    const auto& name = fugg::ModulePointer<GLchar>(g);

#if TRACE_GL_CALLS
    std::cout << "_glGetActiveAttrib("
              << a << ", "
              << b << ", "
              << c << ", "
              << length << ", "
              << size << ", "
              << type << ", "
              << name 
              << ")" << std::endl;
#endif

    glGetActiveAttrib(
        a,
        b,
        c,
        length,
        size,
        type,
        name
    );
};

/* import: 'a' 'pb' */
// "pb": "_glCreateProgram",
WASM_IMPORT_IMPL(env, _glCreateProgram) = []() {
    const auto& result = glCreateProgram();

#if TRACE_GL_CALLS
    std::cout << "_glCreateProgram() = " << result << std::endl;
#endif

    return static_cast<u32>(result);
};
/* import: 'a' 'qb' */
// "qb": "_glGetShaderInfoLog",
WASM_IMPORT_IMPL(env, _glGetShaderInfoLog) = [](u32 a, u32 b, u32 c, u32 d) {
    const auto& shader = reinterpret_cast<GLuint>(a);
    const auto& buf_size = static_cast<GLsizei>(b);
    const auto& length  = fugg::ModulePointer<GLsizei>(c);
    const auto& infolog = fugg::ModulePointer<GLchar>(d);

#if TRACE_GL_CALLS
    std::cout << "_glGetShaderInfoLog("
              << a << ", "
              << b << ", "
              << length << ", "
              << infolog 
              << ")" << std::endl;
#endif

    glGetShaderInfoLog(shader, buf_size, length, infolog);
};
/* import: 'a' 'rb' */
// "rb": "_glCompileShader",
WASM_IMPORT_IMPL(env, _glCompileShader) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glCompileShader("
              << a 
              << ")" << std::endl;
#endif

    glCompileShader(a);
};
/* import: 'a' 'sb' */
// "sb": "_glShaderSource",
WASM_IMPORT_IMPL(env, _glShaderSource) = [](u32 shader, u32 count, u32 string_, u32 length_) {
    // `string_` and `length_` are double pointers, ex:
    // GLchar const* files[] = { v.c_str(), c.c_str(), s.c_str() };
    // GLint lengths[]       = { v.size(),  c.size(),  s.size()  }; 
    // to allow multiple shaders to be compiled.
    // We need to fix the pointers to point into the WASM runtime.

    const auto& string = fugg::ModulePointer<GLchar *>(string_);
    const auto& length = fugg::ModulePointer<GLint>(length_);

    for(unsigned int i = 0; i < count; i++) {
        string[i] = fugg::ModulePointer<GLchar> { string[i] };
    }

    glShaderSource(
        shader,
        count,
        // Lastly, convert the string_ pointer to be readable outside the WASM runtime.
        string,
        length
    );
};
/* import: 'a' 'tb' */
// "tb": "_glCreateShader",
WASM_IMPORT_IMPL(env, _glCreateShader) = [](u32 a) {
    const auto& result = glCreateShader(a);

#if TRACE_GL_CALLS
    std::cout << "_glCreateShader(" << a << ") = " << result << std::endl;
#endif

    return static_cast<u32>(result);
};
/* import: 'a' 'ub' */
// "ub": "_glCullFace",
WASM_IMPORT_IMPL(env, _glCullFace) = [](u32 a) {
#if TRACE_GL_CALLS
    std::cout << "_glCullFace("
              << a 
              << ")" << std::endl;
#endif

    glCullFace(a);
};

/* import: 'a' 'wb' */
// "wb": "_glGetString",
WASM_IMPORT_IMPL(env, _glGetString) = [](u32 a) {
    const auto& result = glGetString(a);

#if TRACE_GL_CALLS
    std::cout << "_glGetString("
              << a 
              << ") = " << result << std::endl;
#endif

    return static_cast<u32>(
        fugg::RuntimePointer<const GLubyte> { result }.as_raw()
    );
};
/* import: 'a' 'xb' */
// "xb": "_glStencilOp",
WASM_IMPORT_IMPL(env, _glStencilOp) = [](u32 a, u32 b, u32 c) {
#if TRACE_GL_CALLS
    std::cout << "_glStencilOp("
              << a << ", "
              << b << ", "
              << c 
              << ")" << std::endl;
#endif

    glStencilOp(
        a,
        b,
        c
    );
};

/* import: 'a' 'zb' */
// "zb": "_glDeleteTextures",
WASM_IMPORT_IMPL(env, _glDeleteTextures) = [](u32 a, u32 b) {
    const auto& textures = fugg::ModulePointer<const GLuint>(b);

#if TRACE_GL_CALLS
    std::cout << "_glDeleteTextures("
              << a << ", "
              << textures 
              << ")" << std::endl;
#endif

    glDeleteTextures(
        a,
        textures
    );
};

/* import: 'a' 'Nb' */
// "Nb": "_glCopyTexSubImage2D",
WASM_IMPORT_IMPL(env, _glCopyTexSubImage2D) = [](u32 a, u32 b, u32 c, u32 d, u32 e, u32 f, u32 g, u32 h) {
#if TRACE_GL_CALLS
    std::cout << "_glCopyTexSubImage2D("
              << a << ", "
              << b << ", "
              << c << ", "
              << d << ", "
              << e << ", "
              << f << ", "
              << g << ", "
              << h 
              << ")" << std::endl;
#endif


    glCopyTexSubImage2D(
        a,
        b,
        c,
        d,
        e,
        f,
        g,
        h
    );
};

/* import: 'a' 'dc' */
// "dc": "_glTexSubImage2D",
WASM_IMPORT_IMPL(env, _glTexSubImage2D) = [](u32 a, u32 b, u32 c, u32 d, u32 e, u32 f, u32 g, u32 h, u32 i) {
    const auto& pixels = fugg::ModulePointer<const void>(i);

#if TRACE_GL_CALLS
    std::cout << "_glTexSubImage2D("
              << a << ", "
              << b << ", "
              << c << ", "
              << d << ", "
              << e << ", "
              << f << ", "
              << g << ", "
              << h << ", "
              << pixels 
              << ")" << std::endl;
#endif

    glTexSubImage2D(
        a,
        b,
        c,
        d,
        e,
        f,
        g,
        h,
        pixels
    );
};

/* import: 'a' 'z' */
// "z": "_glDrawArrays",
WASM_IMPORT_IMPL(env, _glDrawArrays) = [](u32 a, u32 b, u32 c) {
#if TRACE_GL_CALLS
    std::cout << "_glDrawArrays("
              << a << ", "
              << b << ", "
              << c 
              << ")" << std::endl;
#endif

    glDrawArrays(
        a,
        b,
        c
    );
};
/* import: 'a' 'G' */
/* _glGetUniformLocation */
WASM_IMPORT_IMPL(env, _glGetUniformLocation) = [](u32 a, u32 b) {
    const auto& name = fugg::ModulePointer<GLchar>(b);

#if TRACE_GL_CALLS
    std::cout << "_glGetUniformLocation("
              << a << ", "
              << name 
              << ")" << std::endl;
#endif

    return static_cast<u32>(
        glGetUniformLocation(
            a,
            name
        )
    );
};
/* import: 'a' 'ka' */
// "ka": "_glCheckFramebufferStatus",
WASM_IMPORT_IMPL(env, _glCheckFramebufferStatus) = [](u32 a) {
    const auto& result = glCheckFramebufferStatus(a);

#if TRACE_GL_CALLS
    std::cout << "_glCheckFramebufferStatus("
              << a 
              << ") = " 
              << result 
              << std::endl;
#endif

    return static_cast<u32>(result);
};

/* import: 'a' 'ra' */
// "ra": "_glDetachShader",
WASM_IMPORT_IMPL(env, _glDetachShader) = [](u32 a, u32 b) {
#if TRACE_GL_CALLS
    std::cout << "_glDetachShader("
              << a << ", "
              << b 
              << ")" << std::endl;
#endif

    glDetachShader(
        a,
        b
    );
};
/* import: 'a' 'hb' */
// "hb": "_emscripten_webgl_make_context_current",
WASM_IMPORT_IMPL(env, _emscripten_webgl_make_context_current) = [](u32 a) {
    return static_cast<u32>(
        emscripten_webgl_make_context_current(
            static_cast<EMSCRIPTEN_WEBGL_CONTEXT_HANDLE>(a)
        )
    );
};
/* import: 'a' 'ib' */
// "ib": "_emscripten_webgl_create_context",
WASM_IMPORT_IMPL(env, _emscripten_webgl_create_context) = [](u32 a, u32 b) {
    const auto& target = fugg::ModulePointer<const char>(a);
    const auto& attributes = fugg::ModulePointer<const EmscriptenWebGLContextAttributes>(b);

#if TRACE_EM_CALLS
    std::cout << "_emscripten_webgl_create_context(" 
              << target << ", "
              << attributes 
              << ")" << std::endl;
#endif

    auto attr = static_cast<const EmscriptenWebGLContextAttributes*>(attributes);
    std::cout << "Trying to create a context with version " << attr->majorVersion << "." << attr->minorVersion << std::endl;

    return static_cast<u32>(
        emscripten_webgl_create_context(target, attributes)
    );
};
/* import: 'a' 'jb' */
// "jb": "_emscripten_webgl_init_context_attributes",
WASM_IMPORT_IMPL(env, _emscripten_webgl_init_context_attributes) = [](u32 a) {
    const auto& attributes = fugg::ModulePointer<EmscriptenWebGLContextAttributes>(a);

#if TRACE_EM_CALLS
    std::cout << "_emscripten_webgl_init_context_attributes(" 
              << attributes 
              << ")" << std::endl;
#endif
              
    emscripten_webgl_init_context_attributes(attributes);
};
/* import: 'a' 'vb' */
// "vb": "_emscripten_webgl_enable_extension",
WASM_IMPORT_IMPL(env, _emscripten_webgl_enable_extension) = [](u32 a, u32 b) {
    const auto& extension = fugg::ModulePointer<const char>(b);

#if TRACE_GL_CALLS
    std::cout << "_emscripten_webgl_enable_extension("
              << a << ", "
              << extension
              << ")" << std::endl;
#endif

    return static_cast<u32>(
        emscripten_webgl_enable_extension(a, extension)
    );
};