#include "twn_draw_c.h"
#include "twn_engine_context_c.h"
#include "twn_util_c.h"

#ifdef EMSCRIPTEN
#include <GLES2/gl2.h>
#else
#include <glad/glad.h>
#endif


void setup_viewport(int x, int y, int width, int height) {
    glViewport(x, y, width, height);
}


VertexBuffer create_vertex_buffer(void) {
    GLuint result;
    glGenBuffers(1, &result);
    return result;
}


void delete_vertex_buffer(VertexBuffer buffer) {
    glDeleteBuffers(1, &buffer);
}


void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes) {
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW);
}


void bind_quad_element_buffer(void) {
    static GLuint buffer = 0;

    /* it's only generated once at runtime */
    if (buffer == 0) {
        glGenBuffers(1, &buffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     QUAD_ELEMENT_BUFFER_LENGTH * 6 * sizeof(uint16_t),
                     NULL,
                     GL_STATIC_DRAW);

        uint16_t *const indices = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER,
                                              GL_WRITE_ONLY);
        if (!indices)
            CRY("Quad indices generation", "glMapBuffer() failed");

        for (uint16_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
            indices[i * 6 + 0] = (uint16_t)(i * 4 + 0);
            indices[i * 6 + 1] = (uint16_t)(i * 4 + 1);
            indices[i * 6 + 2] = (uint16_t)(i * 4 + 2);
            indices[i * 6 + 3] = (uint16_t)(i * 4 + 2);
            indices[i * 6 + 4] = (uint16_t)(i * 4 + 3);
            indices[i * 6 + 5] = (uint16_t)(i * 4 + 0);
        }

        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);

    } else
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
}


void clear_draw_buffer(void) {
    /* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/
    glClearColor((1.0f / 255) * 230,
                 (1.0f / 255) * 230,
                 (1.0f / 255) * 230, 1);

    /* TODO: don't clear color when skybox is applied? */
    /*       for that window should match framebuffer */
    /*       also it is driver dependent, from what i can gather */
    glClear(GL_COLOR_BUFFER_BIT |
            GL_DEPTH_BUFFER_BIT |
            GL_STENCIL_BUFFER_BIT);
}


void swap_buffers(void) {
    SDL_GL_SwapWindow(ctx.window);
}


void set_depth_range(double low, double high) {
    glDepthRange(low, high);
}
