/*
 *  <Short Description>
 *  Copyright (C) 2023  Brett Terpstra
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <blt/gfx/renderer/batch_2d_renderer.h>
#include <blt/gfx/renderer/2d_textured.vert>
#include <blt/gfx/renderer/2d_textured.frag>

float square_vertices[20] = {
        // positions        // texture coords
        0.5f, 0.5f, 0.0f, 1.0f, 1.0f,   // top right
        0.5f, -0.5f, 0.0f, 1.0f, 0.0f,   // bottom right
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,   // bottom left
        -0.5f, 0.5f, 0.0f, 0.0f, 1.0f    // top left
};
const unsigned int square_indices[6] = {
        0, 1, 3,   // first triangle
        1, 2, 3    // second triangle
};

namespace blt::gfx
{
    
    void batch_renderer_2d::create()
    {
        vbo_t vertices_vbo;
        vbo_t indices_vbo;
        
        vertices_vbo.create();
        indices_vbo.create(GL_ELEMENT_ARRAY_BUFFER);
        
        vertices_vbo.allocate(sizeof(square_vertices), square_vertices);
        indices_vbo.allocate(sizeof(square_indices), square_indices);
        
        square_vao = new vertex_array();
        square_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0);
        square_vao->bindVBO(vertices_vbo, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
        square_vao->bindElement(indices_vbo);
        
        shader = new shader_t(shader_2d_textured_vert, shader_2d_textured_frag);
        shader->bindAttribute(0, "vertex");
        shader->bindAttribute(1, "uv_in");
    }
    
    void batch_renderer_2d::cleanup()
    {
        delete square_vao;
        delete shader;
    }
    
    void batch_renderer_2d::render()
    {
        draw_count_ = 0;
        shader->bind();
        square_vao->bind();
        glActiveTexture(GL_TEXTURE0);
        for (auto& textures : complex_rectangles)
        {
            // resource manager handles the check for empty string
            if (auto val = resources.get(textures.first))
                val.value()->bind();
            for (auto& colors : textures.second)
            {
                shader->setVec4("color", colors.first);
                for (auto& blend_factors : colors.second)
                {
                    shader->setVec4("use_texture", blend_factors.first);
                    for (auto& rect : blend_factors.second)
                    {
                        blt::mat4x4 model;
                        model.translate(rect.x, rect.y, 0.0f);
                        model.scale(rect.width, rect.height, 1);
                        if (rect.rotation != 0)
                            model.rotateZ(blt::toRadians(rect.rotation));
                        shader->setMatrix("model", model);
                        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
                        draw_count_++;
                    }
                    blend_factors.second.clear();
                }
            }
        }
    }
}