#include "pch.h"

#include "ShaderProgram.h"
#include <spdlog/spdlog.h> 

ShaderProgram::ShaderProgram(GLuint programId)
    : m_programId(programId)
{
    spdlog::info("ShaderProgram created with ID: {}", programId);
}

// 虚析构函数
ShaderProgram::~ShaderProgram()
{
    deleteProgram();
    spdlog::info("ShaderProgram {} destroyed.", m_programId);
}

void ShaderProgram::use() const
{
    glUseProgram(m_programId);
}

void ShaderProgram::stop() const
{
    glUseProgram(0);
}

GLint ShaderProgram::getUniformLocation(const std::string& name)
{
    if (auto it = m_uniformCache.find(name); it != m_uniformCache.end()) {
        return it->second;
    }
    GLint location = glGetUniformLocation(m_programId, name.c_str());
    m_uniformCache[name] = location;
    if (location == -1) {
        spdlog::warn("Uniform '{}' not found in program ID: {}", name, m_programId);
    }
    return location;
}

// --- uniform 设置方法 (使用 name) ---

void ShaderProgram::setUniform1i(const std::string& name, GLint value)
{
    GLint location = getUniformLocation(name);
    setUniform1i(location, value);
}

void ShaderProgram::setUniform1f(const std::string& name, GLfloat value)
{
    GLint location = getUniformLocation(name);
    setUniform1f(location, value);
}

void ShaderProgram::setUniform2f(const std::string& name, GLfloat x, GLfloat y)
{
    GLint location = getUniformLocation(name);
    if (location != -1) {
        glUniform2f(location, x, y);
    }
}

void ShaderProgram::setUniform3f(const std::string& name, GLfloat x, GLfloat y, GLfloat z)
{
    GLint location = getUniformLocation(name);
    if (location != -1) {
        glUniform3f(location, x, y, z);
    }
}

void ShaderProgram::setUniform4f(const std::string& name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
    GLint location = getUniformLocation(name);
    setUniform4f(location, x, y, z, w);
}

void ShaderProgram::setUniformMatrix3(const std::string& name, const glm::mat3& matrix)
{
    GLint location = getUniformLocation(name);
    setUniformMatrix3(location, matrix);
}

// --- uniform 设置方法 (使用 location) ---

void ShaderProgram::setUniform1i(GLint location, GLint value)
{
    if (location != -1) {
        glUniform1i(location, value);
    }
}

void ShaderProgram::setUniform1f(GLint location, GLfloat value)
{
    if (location != -1) {
        glUniform1f(location, value);
    }
}

void ShaderProgram::setUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
    if (location != -1) {
        glUniform4f(location, x, y, z, w);
    }
}

void ShaderProgram::setUniformMatrix3(GLint location, const glm::mat3& matrix)
{
    if (location != -1) {
        glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
    }
}

void ShaderProgram::deleteProgram()
{
    if (glIsProgram(m_programId)) {
        glDeleteProgram(m_programId);
        m_uniformCache.clear();
    }
}