package.path    = package.path..";../../?.lua"
local dirtools  = require("tools.vfs.dirtools").init("sokol%-luajit")

local sapp  = require("sokol_app")
sg          = require("sokol_gfx")
local slib  = require("sokol_libs") -- Warn - always after gfx!!

local ffi = require("ffi")

ffi.cdef[[
/* application state */
typedef struct state {
    sg_pipeline pip;
    sg_bindings bind;
    sg_pass_action pass_action;
} state;
]]

-- --------------------------------------------------------------------------------------
-- Manual example of adding a created header file. This may be necessary if the compiler cant
--   process a complex shader.

-- local vs_source_glsl430 = ffi.new("uint8_t[194]", {
--     0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x6c,0x61,
--     0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,
--     0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,
--     0x69,0x6f,0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,
--     0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,
--     0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,
--     0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,
--     0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,
--     0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,
--     0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,
--     0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,
--     0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,
--     0x0a,0x00,
-- })

-- local fs_source_glsl430 = ffi.new("uint8_t[135]", {
--     0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x6c,0x61,
--     0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,
--     0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,
--     0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,
--     0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,
--     0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,
--     0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,
--     0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,
--     0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00,
-- })

-- -- DL - Taken from the glsl.h file. I think a simple lua parser could convert to ffi fairly easy.
-- local shader = ffi.new("sg_shader_desc[1]")
-- shader[0].attrs[0].name = "position"
-- shader[0].attrs[1].name = "color0"
-- shader[0].vs.source = vs_source_glsl430
-- shader[0].vs.entry = "main"
-- shader[0].fs.source = fs_source_glsl430
-- shader[0].fs.entry = "main"
-- shader[0].label = "triangle_shader"

-- --------------------------------------------------------------------------------------
-- The nice way to take a glsl shader and load, compile and return a shader description
local shc       = require("tools.shader_compiler.shc_compile").init( "sokol%-luajit", false )
local shader    = shc.compile("./projects/examples/samples/triangle-sapp.glsl")

-- --------------------------------------------------------------------------------------

local state = ffi.new("state[1]")

local function slog_func(tag, log_level, log_item, message, line_nr, filename, udata) 
    print(tag .. log_level .. log_item .. message .. line_nr .. filename)
end

local function init()

    local desc = ffi.new("sg_desc[1]")
    desc[0].environment = slib.sglue_environment()
    desc[0].logger.func = slib.slog_func

    sg.sg_setup( desc )

    local vertices = ffi.new("float[21]") 
    vertices[0] = 0.0; vertices[1] = 0.5; vertices[2] = 0.5; 
    vertices[7] = 0.5; vertices[8] = -0.5; vertices[9] = 0.5; 
    vertices[14] = -0.5; vertices[15] = -0.5; vertices[16] = 0.5; 

    vertices[3] = 1.0; vertices[4] = 0.0; vertices[5] = 0.0; vertices[6] = 1.0; 
    vertices[10] = 0.0; vertices[11] = 1.0; vertices[12] = 0.0; vertices[13] = 1.0; 
    vertices[17] = 0.0; vertices[18] = 0.0; vertices[19] = 1.0; vertices[20] = 1.0; 

    local buffer_desc = ffi.new("sg_buffer_desc[1]")
    buffer_desc[0].data.ptr = vertices
    buffer_desc[0].data.size = 21 * ffi.sizeof("float") 
    buffer_desc[0].label = "triangle-vertices"

    state[0].bind.vertex_buffers[0] = sg.sg_make_buffer(buffer_desc)

    local shd = sg.sg_make_shader(shader)

    local pipe_desc = ffi.new("sg_pipeline_desc[1]")
    pipe_desc[0].shader = shd 
    pipe_desc[0].layout.attrs[0].format = 3     -- vs_position float3
    pipe_desc[0].layout.attrs[1].format = 4     -- vs_color float4
    pipe_desc[0].label = "triangle-pipeline"

    state[0].pip = sg.sg_make_pipeline(pipe_desc)

    local pass_action = ffi.new("sg_pass_action[1]")
    pass_action[0].colors[0].load_action = sg.SG_LOADACTION_CLEAR
    pass_action[0].colors[0].clear_value = { 0.0, 0.0, 0.0, 1.0 }
    state[0].pass_action = pass_action[0]
end

local function frame()

    local pass = ffi.new("sg_pass[1]")
    pass[0].action = state[0].pass_action
    pass[0].swapchain = sg.sglue_swapchain()
    
    sg.sg_begin_pass(pass)
    sg.sg_apply_pipeline(state[0].pip)
    sg.sg_apply_bindings(state[0].bind)
    sg.sg_draw(0, 3, 1)
    sg.sg_end_pass()
    sg.sg_commit()
end

local function cleanup()
    sg.sg_shutdown()
end

local app_desc = ffi.new("sapp_desc[1]")
app_desc[0].init_cb = init
app_desc[0].frame_cb = frame
app_desc[0].cleanup_cb = cleanup
app_desc[0].width = 1920
app_desc[0].height = 1080
app_desc[0].window_title = "Triangle (sokol-app)"
app_desc[0].icon.sokol_default = true 
app_desc[0].logger.func = slib.slog_func 

sapp.sapp_run( app_desc )