--- Require

local mp = require("mp")

--- Constants

local SHADER_META = [[
//!HOOK MAINPRESUB
//!DESC GPU rotate
//!BIND HOOKED
]]

local SHADER_DEFINE = "#define angle"

local SHADER_HOOK = [[
vec4 hook()
{
    float rad = radians(angle);
    float c   = cos(rad);
    float s   = sin(rad);
    mat2  rot = mat2(c, -s, s, c);
    vec2  pos = rot * ((HOOKED_pos - 0.5) * HOOKED_size) * HOOKED_pt + 0.5;
    if (!all(equal(pos, clamp(pos, 0.0, 1.0))))
        return vec4(0.0);
    return HOOKED_tex(pos);
}
]]

--- State

local state = {
    angle  = 0.0,
    shader = nil,
}

--- Functions

local function shader_define()
    return table.concat({SHADER_DEFINE, state.angle}, " ")
end

local function remove()
    if state.shader then
        mp.msg.debug("Removing", state.shader)
        mp.commandv("change-list", "glsl-shaders", "remove", state.shader)
        os.remove(state.shader)
        state.shader = nil
    end
end

local function append(angle)
    state.angle = angle % 360
    local shader = nil
    if state.angle ~= 0 then
        shader = os.tmpname()
        mp.msg.debug("Writing", shader)
        local file = io.open(shader, "w")
        file:write(table.concat({
            SHADER_META,
            shader_define(),
            SHADER_HOOK,
        }, "\n"))
        file:close()
        mp.commandv("change-list", "glsl-shaders", "append", shader)
    end
    remove()
    state.shader = shader
end

--- Events

mp.register_event("shutdown", remove)

--- Script messages

local function set(angle) append(angle)               end
local function add(angle) append(angle + state.angle) end
mp.register_script_message("set", set)
mp.register_script_message("add", add)