#include "pch.h"

#include "Shader2D.h"


// 顶点着色器 GLSL 代码 (对应 VertexShaders.java)
static const std::string VERTEX_SHADER_SRC = "\r\n#version 330 core\r\nlayout(location = 0) in vec2 aPosition;\r\nlayout(location = 1) in vec2 aTexCoord;\r\nout vec2 vTexCoord;\r\nout vec2 vWorldPos;\r\n\r\nuniform mat3 uModelMatrix;\r\nuniform mat3 uViewMatrix;\r\nuniform mat3 uProjectionMatrix;\r\n\r\nvoid main() {\r\n    vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0);\r\n    gl_Position = vec4(p.xy, 0.0, 1.0);\r\n    vTexCoord = aTexCoord;\r\n    vWorldPos = (uModelMatrix * vec3(aPosition, 1.0)).xy;\r\n}\r\n";
// 片段着色器 GLSL 代码 (对应 FragmentShaders.java)
static const std::string FRAGMENT_SHADER_SRC = "\r\n#version 330 core\r\nin vec2 vTexCoord;\r\nin vec2 vWorldPos;\r\nout vec4 FragColor;\r\n\r\nuniform sampler2D uTexture;\r\nuniform vec4 uColor;\r\nuniform float uOpacity;\r\nuniform int uBlendMode;\r\nuniform int uDebugMode;\r\n\r\n#define MAX_LIGHTS 8\r\nuniform vec2 uLightsPos[MAX_LIGHTS];\r\nuniform vec3 uLightsColor[MAX_LIGHTS];\r\nuniform float uLightsIntensity[MAX_LIGHTS];\r\nuniform int uLightsIsAmbient[MAX_LIGHTS];\r\nuniform int uLightCount;\r\n\r\nconst float ATT_CONST = 1.0;\r\nconst float ATT_LINEAR = 0.09;\r\nconst float ATT_QUAD = 0.032;\r\n\r\nvoid main() {\r\n    int i;\r\n\r\n    vec4 tex = texture(uTexture, vTexCoord);\r\n    float alpha = tex.a * uOpacity;\r\n    if (alpha <= 0.001) discard;\r\n\r\n    if (uLightCount == 0) {\r\n        vec3 base = tex.rgb * uColor.rgb;\r\n        base = clamp(base, 0.0, 1.0);\r\n        FragColor = vec4(base, alpha);\r\n        return;\r\n    }\r\n\r\n    vec3 baseColor = tex.rgb * uColor.rgb;\r\n    vec3 ambient = vec3(0.06);\r\n    vec3 lighting = vec3(0.0);\r\n    vec3 specularAccum = vec3(0.0);\r\n\r\n    for (i = 0; i < uLightCount; ++i) {\r\n        if (uLightsIsAmbient[i] == 1) {\r\n            lighting += uLightsColor[i] * uLightsIntensity[i];\r\n        }\r\n    }\r\n    lighting += ambient;\r\n\r\n    for (i = 0; i < uLightCount; ++i) {\r\n        if (uLightsIsAmbient[i] == 1) continue;\r\n\r\n        vec2 toLight = uLightsPos[i] - vWorldPos;\r\n        float dist = length(toLight);\r\n        float attenuation = ATT_CONST / (ATT_CONST + ATT_LINEAR * dist + ATT_QUAD * dist * dist);\r\n\r\n        float radiance = uLightsIntensity[i] * attenuation;\r\n\r\n        float diffuseFactor = clamp(1.0 - (dist * 0.0015), 0.0, 1.0); \r\n        vec3 diff = uLightsColor[i] * radiance * diffuseFactor;\r\n        lighting += diff;\r\n\r\n        vec3 lightDir3 = normalize(vec3(toLight, 0.0));\r\n        vec3 viewDir = vec3(0.0, 0.0, 1.0);\r\n        vec3 normal = vec3(0.0, 0.0, 1.0);\r\n        vec3 reflectDir = reflect(-lightDir3, normal);\r\n        float specFactor = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); \r\n        float specIntensity = 0.2; \r\n        specularAccum += uLightsColor[i] * radiance * specFactor * specIntensity;\r\n    }\r\n\r\n    vec3 totalLighting = min(lighting + specularAccum, vec3(2.0));\r\n    vec3 finalColor = baseColor * totalLighting;\r\n\r\n    if (uBlendMode == 1) finalColor = tex.rgb + uColor.rgb;\r\n    else if (uBlendMode == 2) finalColor = tex.rgb * uColor.rgb;\r\n    else if (uBlendMode == 3) finalColor = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb);\r\n\r\n    finalColor = clamp(finalColor, 0.0, 1.0);\r\n    FragColor = vec4(finalColor, alpha);\r\n}\r\n";

class Shader2D::VertexShaders final : public Shader {
public:
    virtual ~VertexShaders() = default;
    std::string getShaderCode() const override {
        return VERTEX_SHADER_SRC;
    }
    std::string getShaderName() const override {
        return "Vertex Shaders";
    }
};

class Shader2D::FragmentShaders final : public Shader {
public:
    virtual ~FragmentShaders() = default;
    std::string getShaderCode() const override {
        return FRAGMENT_SHADER_SRC;
    }
    std::string getShaderName() const override {
        return "Fragment shaders";
    }
};

const Shader2D::VertexShaders Shader2D::s_vertexShader;
const Shader2D::FragmentShaders Shader2D::s_fragmentShader;

Shader2D::Shader2D()
{
}

const Shader& Shader2D::getVertexShader() const
{
    return s_vertexShader;
}

const Shader& Shader2D::getFragmentShader() const
{
    return s_fragmentShader;
}

void Shader2D::setDefaultUniforms(ShaderProgram* program) const
{
}