#include "ShaderRect.h"

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <GL/gl.h>

#include "spdlog/spdlog.h"

ShaderRect::ShaderRect()
{

}

ShaderRect::~ShaderRect()
{
    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
    if (m_VAO != 0) {
        if (gl) {
            gl->glDeleteVertexArrays(1, &m_VAO);
            gl->glDeleteBuffers(1, &m_VBO);
            gl->glDeleteBuffers(1, &m_EBO);
        }
    }

}

/* 初始化形状 */
GLuint ShaderRect::initShape()
{
    const int vertexCount = 4;    // 顶点数量
    const int vertexSize = 8;     // 顶点大小
    /* 矩形位置，铺满屏幕 */
    float vertices [vertexCount * vertexSize] {
        /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
        -1.0f, -1.0f, 0.0f,     1.0f, 1.0f, 0.0f,   0.0f, 0.0f,     // 左下
        1.0f, -1.0f, 0.0f,      0.0f, 0.0f, 1.0f,   1.0f, 0.0f,     // 右下
        1.0f,  1.0f, 0.0f,      1.0f, 0.0f, 0.0f,   1.0f, 1.0f,     // 右上
        -1.0f, 1.0f, 0.0f,      0.0f, 1.0f, 0.0f,   0.0f, 1.0f      // 右上
    };
    const int indexCount = 6; // 索引数量
    /* 顶点顺序 */
    uint32_t indices [indexCount] {
        0, 1, 2, // 第一个三角形
        2, 3, 0  // 第二个三角形
    };

    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
    if (!gl) {
        SPDLOG_ERROR("Failed to get OpenGL functions");
        return 0;
    }
    /* -------------------------------------------------------------------------------------
     * 顶点数组对象
     * ------------------------------------------------------------------------------------ */
    gl->glGenVertexArrays(1, &m_VAO); // 生成一个VAO，返回的ID存储在VAO1中
    gl->glBindVertexArray(m_VAO); // 绑定VAO

    /* -------------------------------------------------------------------------------------
     * 创建顶点数组缓冲区
     * ------------------------------------------------------------------------------------ */
    gl->glGenBuffers(1, &m_VBO);
    gl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // 绑定VBO
    gl->glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize * sizeof(float), vertices, GL_STATIC_DRAW);

    /* -------------------------------------------------------------------------------------
     * 创建EBO
     * ------------------------------------------------------------------------------------ */
    gl->glGenBuffers(1, &m_EBO);
    gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
    gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(uint32_t), indices, GL_STATIC_DRAW); // 绑定EBO


    /* -------------------------------------------------------------------------------------
     * 链接顶点属性
     * ------------------------------------------------------------------------------------ */
    // 设置顶点属性指针，告诉OpenGL如何解析顶点数据
    gl->glVertexAttribPointer(
                    0,                  /* 顶点属性位置，0表示第一个属性 */
                    3,                  /* 每个顶点属性的大小，这里是3，表示x、y、z坐标 */
                    GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
                    vertexSize * sizeof(float), /* 步长，表示每个顶点属性之间的间隔 */
                    (void*)0            /* 偏移量，表示该属性（顶点坐标）从第0个字节开始 */
                ); 
    /* 启用顶点属性 */
    gl->glEnableVertexAttribArray(0);
 
    // 设置颜色位置，最后一个参数表示从第3个字节开始，倒数第二个参数是两个数据之间起始位置间隔8个字节
    gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(3*sizeof(float))); 
    gl->glEnableVertexAttribArray(1);
 
    /* 设置纹理位置 */
    gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
    gl->glEnableVertexAttribArray(2); // 启用纹理坐标属性

    return m_VAO;
}

/* 绘制图形 */
void ShaderRect::drawShape()
{
    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
    /* 需要在使用时手动绑定VAO，绘制图形 */
    gl->glBindVertexArray(m_VAO); // 绑定VAO

    gl->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形

    gl->glBindVertexArray(0); // 解绑VAO
}

/* 初始化纹理对象 */
bool ShaderRect::initTextures()
{
    /* 创建一个纹理对象 */
    auto unit = createTexture(m_textureRGBAName);
    if(unit < 0)
    {
        SPDLOG_ERROR("RGBA着色器创建纹理失败!");
        return false;
    }

    return true;
}

/* 刷新一帧 */
bool ShaderRect::refreshFrameRGBA(const QImage& image, int textureUnit)
{
    if(image.isNull()) {
        SPDLOG_WARN("Texture Image is null");
        return false;
    }
    QOpenGLTexture* texture = m_mapTexture.find(textureUnit)->second;
    if(texture == nullptr)
    {
        SPDLOG_ERROR("错误的纹理编号:{}", textureUnit);
        return false;
    }
    if(m_lastSize != image.size())
    {
        texture->destroy();   // 释放OpenGL资源
        texture->create();    // 重新创建OpenGL资源
        texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
        texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
        texture->allocateStorage(); // 分配纹理存储空间
    }
    m_lastSize = image.size();
    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.bits()); // 设置纹理数据

    texture->generateMipMaps(); // 生成多级渐远纹理

    printGLerror("ShaderRect::refreshFrame");

    return true;
}

