#include "twn_draw_c.h"

#include <stb_ds.h>

#include <stddef.h>


void finally_render_quads(const Primitive2D primitives[],
                          const struct QuadBatch batch,
                          const VertexBuffer buffer)
{
    DeferredCommandDraw command = {0};

    GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;

    if (!batch.constant_colored && batch.textured) {
        off   = offsetof(ElementIndexedQuad, v1);
        voff  = offsetof(ElementIndexedQuad, v0);
        uvoff = offsetof(ElementIndexedQuad, uv0);
        coff  = offsetof(ElementIndexedQuad, c0);
    } else if (batch.constant_colored && batch.textured) {
        off   = offsetof(ElementIndexedQuadWithoutColor, v1);
        voff  = offsetof(ElementIndexedQuadWithoutColor, v0);
        uvoff = offsetof(ElementIndexedQuadWithoutColor, uv0);
    } else if (!batch.constant_colored && !batch.textured) {
        off   = offsetof(ElementIndexedQuadWithoutTexture, v1);
        voff  = offsetof(ElementIndexedQuadWithoutTexture, v0);
        coff  = offsetof(ElementIndexedQuad, c0);
    } else if (batch.constant_colored && !batch.textured) {
        off   = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v1);
        voff  = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
    }

    command.vertices = (AttributeArrayPointer) {
        .arity = 2,
        .type = GL_FLOAT,
        .stride = off,
        .offset = voff,
        .buffer = buffer
    };

    if (batch.textured)
        command.texcoords = (AttributeArrayPointer) {
            .arity = 2,
            .type = GL_FLOAT,
            .stride = off,
            .offset = uvoff,
            .buffer = buffer
        };

    if (!batch.constant_colored) {
        command.colors = (AttributeArrayPointer) {
            .arity = 4,
            .type = GL_UNSIGNED_BYTE,
            .stride = off,
            .offset = coff,
            .buffer = buffer
        };
    } else {
        command.constant_colored = true;
        command.color = primitives[0].sprite.color;
    }

    if (batch.textured) {
        command.textured = true;
        command.texture_key = batch.texture_key;
        command.texture_repeat = batch.repeat;
    }

    command.element_buffer = get_quad_element_buffer();
    command.element_count = 6 * (GLsizei)batch.size;
    command.range_end = 6 * (GLsizei)batch.size;

    use_texture_mode(batch.mode);

    DeferredCommand final_command = {
        .type = DEFERRED_COMMAND_TYPE_DRAW,
        .draw = command
    };

    arrpush(deferred_commands, final_command);
}


size_t get_quad_payload_size(struct QuadBatch batch) {
    if (batch.constant_colored && batch.textured)
        return sizeof (ElementIndexedQuadWithoutColor);
    else if (!batch.constant_colored && batch.textured)
        return sizeof (ElementIndexedQuad);
    else if (batch.constant_colored && !batch.textured)
        return sizeof (ElementIndexedQuadWithoutColorWithoutTexture);
    else if (!batch.constant_colored && !batch.textured)
        return sizeof (ElementIndexedQuadWithoutTexture);

    SDL_assert(false);
    return 0;
}


bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
                                                VertexBufferBuilder *builder,
                                                Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
                                                Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,
                                                Color color)
{
    if (!batch.constant_colored && batch.textured) {
        ElementIndexedQuad const buffer_element = {
            .v0 = v0,
            .v1 = v1,
            .v2 = v2,
            .v3 = v3,

            .uv0 = uv0,
            .uv1 = uv1,
            .uv2 = uv2,
            .uv3 = uv3,

            /* equal for all (flat shaded) */
            .c0 = color,
            // .c1 = color,
            .c2 = color,
            // .c3 = color,
        };

        return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);

    } else if (batch.constant_colored && batch.textured) {
        ElementIndexedQuadWithoutColor const buffer_element = {
            .v0 = v0,
            .v1 = v1,
            .v2 = v2,
            .v3 = v3,

            .uv0 = uv0,
            .uv1 = uv1,
            .uv2 = uv2,
            .uv3 = uv3,
        };

        return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);

    } else if (!batch.constant_colored && !batch.textured) {
        ElementIndexedQuadWithoutTexture const buffer_element = {
            .v0 = v0,
            .v1 = v1,
            .v2 = v2,
            .v3 = v3,

            /* equal for all (flat shaded) */
            .c0 = color,
            // .c1 = color,
            .c2 = color,
            // .c3 = color,
        };

        return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);

    } else if (batch.constant_colored && !batch.textured) {
        ElementIndexedQuadWithoutColorWithoutTexture const buffer_element = {
            .v0 = v0,
            .v1 = v1,
            .v2 = v2,
            .v3 = v3,
        };

        return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
    }

    SDL_assert(false);
    return false;
}
