--[[
    shadertoy_scene.lua

    A minimal example of the simple shadertoy - a blended fulscreen quad.
]]
shadertoy_scene = {}

local openGL = require("opengl")
local ffi = require("ffi")
local sf = require("util.shaderfunctions")
local bf = require("util.bmfont")
local mm = require("util.matrixmath")
local fsq = require("effect.fullscreen_quad")

-- Types from:
-- https://github.com/nanoant/glua/blob/master/init.lua
local glIntv     = ffi.typeof('GLint[?]')
local glUintv    = ffi.typeof('GLuint[?]')
local glCharv    = ffi.typeof('GLchar[?]')
local glSizeiv   = ffi.typeof('GLsizei[?]')
local glFloatv   = ffi.typeof('GLfloat[?]')
local glConstCharpp = ffi.typeof('const GLchar *[1]')

local globalTime = 0
local vao = 0
local prog = 0
local vvbo
local vbos = {}

local basic_vert = [[
#version 410 core

in vec4 vPosition;

void main()
{
    gl_Position = vPosition;
}
]]

local basic_frag = [[
#version 330

uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iGlobalTime; // shader playback time (in seconds)

out vec4 glFragColor;

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;
    fragColor = vec4(uv,0.5+0.5*sin(iGlobalTime),1.0);
}

void main()
{
    vec4 fragcol = vec4(0.);
    mainImage(fragcol, gl_FragCoord.xy);
    glFragColor = fragcol;
}
]]

function shadertoy_scene.initGL()
    local vaoId = ffi.new("int[1]")
    gl.GenVertexArrays(1, vaoId)
    vao = vaoId[0]
    gl.BindVertexArray(vao)

    sf.CHECK_GL_ERROR()
    prog = sf.make_shader_from_source({
        vsrc = basic_vert,
        fsrc = basic_frag,
        })
    vbos = {}

    local verts = glFloatv(4*2, {
        -1,-1,
        1,-1,
        1,1,
        -1,1,
        })

    local vpos_loc = gl.GetAttribLocation(prog, "vPosition")
    local vcol_loc = gl.GetAttribLocation(prog, "vColor")

    local vvbo = glIntv(0)
    gl.GenBuffers(1, vvbo)
    gl.BindBuffer(GL.ARRAY_BUFFER, vvbo[0])
    gl.BufferData(GL.ARRAY_BUFFER, ffi.sizeof(verts), verts, GL.STATIC_DRAW)
    gl.VertexAttribPointer(vpos_loc, 2, GL.FLOAT, GL.FALSE, 0, nil)
    table.insert(vbos, vvbo)

    sf.CHECK_GL_ERROR()
    gl.EnableVertexAttribArray(vpos_loc)

    local quads = glUintv(3*2, {
        1,0,2,
        2,0,3,
    })
    local qvbo = glIntv(0)
    gl.GenBuffers(1, qvbo)
    gl.BindBuffer(GL.ELEMENT_ARRAY_BUFFER, qvbo[0])
    gl.BufferData(GL.ELEMENT_ARRAY_BUFFER, ffi.sizeof(quads), quads, GL.STATIC_DRAW)
    table.insert(vbos, qvbo)

    sf.CHECK_GL_ERROR()

    gl.BindVertexArray(0)
end

function shadertoy_scene.exitGL()
    for k,v in pairs(vbos) do
        print(k,v[0])
        gl.DeleteBuffers(1,v)
    end
    vbos = nil
    gl.DeleteProgram(prog)

    local vaoId = ffi.new("GLuint[1]", vao)
    gl.DeleteVertexArrays(1, vaoId)
end

function shadertoy_scene.render_for_one_eye(mview, proj)
    gl.UseProgram(prog)
    local ures_loc = gl.GetUniformLocation(prog, "iResolution")
    gl.Uniform3f(ures_loc, 800, 600, 0) -- TODO: pass in
    local utim_loc = gl.GetUniformLocation(prog, "iGlobalTime")
    gl.Uniform1f(utim_loc, globalTime)

    gl.BindVertexArray(vao)
    gl.DrawElements(GL.TRIANGLES, 3*2, GL.UNSIGNED_INT, nil)
    gl.BindVertexArray(0)

    sf.CHECK_GL_ERROR()

    gl.UseProgram(0)
end

function shadertoy_scene.timestep(absTime, dt)
    globalTime = absTime
end

return shadertoy_scene
