//
// Created by matin on 20/07/22.
//

#include "ShapeCornersShader.h"
#include <QFile>
#include <QStandardPaths>

#include <kwineffects.h>
#include <kwinglutils.h>

#define SHADOW_RADIUS 12                 // 阴影默认圆角大小
#define SHADOW_BORDER_ACTIVE 38          // 阴影大小激活状态
#define SHADOW_BORDER_INACTIVE 25        // 阴影大小非激活状态
#define SHADOW_SHIFT_Y_ACTIVE 22         // 阴影偏移激活状态
#define SHADOW_SHIFT_Y_INACTIVE 15       // 阴影偏移非激活状态
#define SHADOWCOLOR_ALPHAF_ACTIVE 0.60   // 阴影透明度激活状态
#define SHADOWCOLOR_ALPHAF_INACTIVE 0.40 // 阴影透明度激活状态
#define SHADOW_BORDER_ALPHA 0.15         // 描边透明度

static void ensureResources()
{
    // Must initialize resources manually because the effect is a static lib.
    Q_INIT_RESOURCE(shapecorners);
}

namespace KWin {

ShapeCornersShader::ShapeCornersShader()
    : m_manager(ShaderManager::instance())
    , m_shadowRadius(SHADOW_RADIUS)
    , m_shadowBorder_active(SHADOW_BORDER_ACTIVE)
    , m_shadowBorder_inactive(SHADOW_BORDER_INACTIVE)
    , m_shadowShift_active(0, SHADOW_SHIFT_Y_ACTIVE)
    , m_shadowShift_inactive(0, SHADOW_SHIFT_Y_INACTIVE)
    , m_shadowAlphaF_active(SHADOWCOLOR_ALPHAF_ACTIVE)
    , m_shadowAlphaF_inactive(SHADOWCOLOR_ALPHAF_INACTIVE)
    , m_borderAlphaF(SHADOW_BORDER_ALPHA)
    , m_borderActiveColor(QColor(0, 0, 0, 255 * SHADOW_BORDER_ALPHA))
    , m_borderInactiveColor(QColor(0, 0, 0, 255 * SHADOW_BORDER_ALPHA))
    , m_shadowActiveColor(QColor(0, 0, 0, 255 * SHADOWCOLOR_ALPHAF_ACTIVE))
    , m_shadowInactiveColor(QColor(0, 0, 0, 255 * SHADOWCOLOR_ALPHAF_INACTIVE))
{
    ensureResources();

    const QString shaderFilePath = QStringLiteral(":/effects/shapecorners/shaders/shapecorners.frag");
    m_shader = m_manager->generateShaderFromFile(ShaderTrait::MapTexture, QString(), shaderFilePath);

    if (!m_shader->isValid())
        qCritical() << "ShapeCorners: no valid shaders found! ShapeCorners will not work.";

    m_shader_windowSize = m_shader->uniformLocation("windowSize");
    m_shader_windowExpandedSize = m_shader->uniformLocation("windowExpandedSize");
    m_shader_windowTopLeft = m_shader->uniformLocation("windowTopLeft");
    m_shader_shadowArea = m_shader->uniformLocation("shadowArea");
    m_shader_shadowColor = m_shader->uniformLocation("shadowColor");
    m_shader_shadowSize = m_shader->uniformLocation("shadowSize");
    m_shader_radius = m_shader->uniformLocation("radius");
    m_shader_outlineColor = m_shader->uniformLocation("outlineColor");
    m_shader_outlineThickness = m_shader->uniformLocation("outlineThickness");
    m_shader_front = m_shader->uniformLocation("front");
    qInfo() << "ShapeCorners: shaders loaded.";
}

bool ShapeCornersShader::IsValid() const
{
    return m_shader && m_shader->isValid();
}

const std::unique_ptr<GLShader> &
ShapeCornersShader::Bind(EffectWindow *window, qreal scale) const
{
    auto frameGeometry = window->frameGeometry();
    auto expandedGeometry = window->expandedGeometry();
    m_manager->pushShader(m_shader.get());
    m_shader->setUniform(m_shader_windowSize, toVector2D(frameGeometry.size()));
    m_shader->setUniform(m_shader_front, 0);
    m_shader->setUniform(m_shader_radius, static_cast<float>((window->quickTileMode() ? 0 : m_shadowRadius) * scale));
    m_shader->setUniform(m_shader_outlineThickness, 1);

    if (effects->activeWindow() == window) {
        auto dropShadowRect = frameGeometry.adjusted(m_shadowShift_active.x() - m_shadowBorder_active,
                                                     m_shadowShift_active.y() - m_shadowBorder_active,
                                                     m_shadowShift_active.x() + m_shadowBorder_active,
                                                     m_shadowShift_active.y() + m_shadowBorder_active);

        m_shader->setUniform(m_shader_shadowSize, static_cast<float>(m_shadowBorder_active * scale));
        m_shader->setUniform(m_shader_windowExpandedSize, toVector2D(expandedGeometry.size() * scale));
        m_shader->setUniform(m_shader_windowTopLeft, QVector2D(frameGeometry.topLeft() * scale - expandedGeometry.topLeft() * scale));
        m_shader->setUniform(m_shader_shadowArea, QVector4D(dropShadowRect.topLeft().x() * scale, dropShadowRect.topLeft().y() * scale, dropShadowRect.width() * scale, dropShadowRect.height() * scale));
        m_shader->setUniform(m_shader_outlineColor, m_borderActiveColor);
        m_shader->setUniform(m_shader_shadowColor, m_shadowActiveColor);
    } else {
        auto dropShadowRect = frameGeometry.adjusted(m_shadowShift_inactive.x() - m_shadowBorder_inactive,
                                                     m_shadowShift_inactive.y() - m_shadowBorder_inactive,
                                                     m_shadowShift_inactive.x() + m_shadowBorder_inactive,
                                                     m_shadowShift_inactive.y() + m_shadowBorder_inactive);

        m_shader->setUniform(m_shader_shadowSize, static_cast<float>(m_shadowBorder_inactive * scale));
        m_shader->setUniform(m_shader_windowExpandedSize, toVector2D(expandedGeometry.size() * scale));
        m_shader->setUniform(m_shader_windowTopLeft, QVector2D(frameGeometry.topLeft() * scale - expandedGeometry.topLeft() * scale));
        m_shader->setUniform(m_shader_shadowArea, QVector4D(dropShadowRect.topLeft().x() * scale, dropShadowRect.topLeft().y() * scale, dropShadowRect.width() * scale, dropShadowRect.height() * scale));

        m_shader->setUniform(m_shader_outlineColor, m_borderInactiveColor);
        m_shader->setUniform(m_shader_shadowColor, m_shadowInactiveColor);
    }

    return m_shader;
}

void ShapeCornersShader::Unbind() const
{
    m_manager->popShader();
}

}