    
    
local demo_dir = gh_utils.get_demo_dir() 		

local lib_dir = gh_utils.get_lib_dir() 		
dofile(lib_dir .. "lua/vk.lua")
dofile(lib_dir .. "lua/imgui.lua")    



    
winW, winH = gh_window.getsize(0)



-----------------------------------------------------------------------
--
-- In this demo, there are N uniform buffers and descriptor sets where N is the number of swapchain images.
--
--
swapchain_image_count = gh_vk.swapchain_get_image_count()
print("swapchain_buffer_count => " .. swapchain_image_count)





-----------------------------------------------------------------------
-- Perspective camera.
--
local aspect = winW / winH
camera_params = { fov=60, znear=0.1, zfar=1000.0 }
camera = gh_camera.create_persp(camera_params.fov, aspect, camera_params.znear, camera_params.zfar)
gh_camera.set_viewport(camera, 0, 0, winW, winH)
gh_camera.set_position(camera, 0, 0, 15)
gh_camera.set_lookat(camera, 0, 0, 0, 1)
gh_camera.set_upvec(camera, 0, 1, 0, 0)







-----------------------------------------------------------------------
--
--[[

Uniform buffer structure in the shader.

layout (std140, binding = 0) uniform uniforms_t
{ 
  mat4 ProjectionMatrix;
  mat4 ViewMatrix;
  mat4 ModelMatrix;
  vec4 uv_tiling;
  vec4 light_position;
  vec4 tess_params;
} ub;

--]]



function UpdateCameraTransform(ub, cam)
  local buffer_offset_bytes = 0
  gh_gpu_buffer.set_matrix4x4(ub, buffer_offset_bytes, cam, "camera_projection")
  
  buffer_offset_bytes = 64
  gh_gpu_buffer.set_matrix4x4(ub, buffer_offset_bytes, cam, "camera_view")  
end


function UpdateObjectTransform(ub, obj)
  local buffer_offset_bytes = 64 * 2
  gh_gpu_buffer.set_matrix4x4(ub, buffer_offset_bytes, obj, "object_global_transform")
end


function UpdateUVTiling(ub, s, t)
  local buffer_offset_bytes = 64 * 3
  gh_gpu_buffer.set_value_4f(ub, buffer_offset_bytes, s, t, 0, 0)
end

function UpdateLightPosition(ub, x, y, z)
  local buffer_offset_bytes = (64 * 3) + 16
  gh_gpu_buffer.set_value_4f(ub, buffer_offset_bytes, x, y, z, 1)
end

function UpdateTessellationParams(ub, tess_level_outer, tess_level_inner, tess_alpha, bump_scale)
  local buffer_offset_bytes = (64 * 3) + 16 + 16
  gh_gpu_buffer.set_value_4f(ub, buffer_offset_bytes, tess_level_outer, tess_level_inner, tess_alpha, bump_scale)
end



ubs = {} -- All uniform buffers are stored in this table.

for i=0, swapchain_image_count-1 do
  local ub_size = 512
  local ub = gh_gpu_buffer.create("UNIFORM", "NONE", ub_size, "")

  ubs[i+1] = ub

  gh_gpu_buffer.bind(ub)
  gh_gpu_buffer.map(ub)
  UpdateCameraTransform(ub, camera)
  UpdateUVTiling(ub, 6.0, 6.0)
  UpdateLightPosition(ub, 20, 10, 30)
  UpdateTessellationParams(ub, 16.0, 16.0, 0.5, 1.1)
  gh_gpu_buffer.unmap(ub)
end



-----------------------------------------------------------------------
--
local vertex_shader = demo_dir .. "spirv/12-vs.spv"
local tessellation_control_shader = demo_dir .. "spirv/12-tcs.spv"
local tessellation_eval_shader = demo_dir .. "spirv/12-tes.spv"
local pixel_shader = demo_dir .. "spirv/12-ps.spv"
tess_shader = gh_gpu_program.vk_create_from_spirv_module_file("phong_shader",   vertex_shader, "main",     pixel_shader, "main",    "", "",    tessellation_control_shader, "main",     tessellation_eval_shader, "main",    "", "") 





-----------------------------------------------------------------------
--
local PF_U8_RGBA = 3
tex0 = gh_texture.create_from_file_v5(demo_dir .. "textures/1596-diffuse.jpg", PF_U8_RGBA)
tex1 = gh_texture.create_from_file_v5(demo_dir .. "textures/1596-normal.jpg", PF_U8_RGBA)
tex2 = gh_texture.create_from_file_v5(demo_dir .. "textures/1596-bump.jpg", PF_U8_RGBA)


-----------------------------------------------------------------------
--
local anisotropy = 1.0
sampler = gh_vk.sampler_create("LINEAR", "WRAP", anisotropy, 0)







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

--[[
VK_SHADER_STAGE_VERTEX = 1
VK_SHADER_STAGE_TESSELLATION_CONTROL = 2
VK_SHADER_STAGE_TESSELLATION_EVALUATION = 4
VK_SHADER_STAGE_GEOMETRY = 8
VK_SHADER_STAGE_FRAGMENT = 16
VK_SHADER_STAGE_COMPUTE = 32

0010 0000 = 32
0001 0000 = 16
0000 1000 = 8
0000 0100 = 4
0000 0010 = 2
0000 0001 = 1
--]]



dss = {} -- All descriptor sets are stored in this table.


for i=0, swapchain_image_count-1 do
  local ds = gh_vk.descriptorset_create()
  dss[i+1] = ds

  ub_binding_point = 0
  local shader_stages = SHADER_STAGE_TESSELLATION_CONTROL + SHADER_STAGE_TESSELLATION_EVALUATION + SHADER_STAGE_FRAGMENT
  local ub = ubs[i+1]
  gh_vk.descriptorset_add_resource_gpu_buffer(ds, ub, ub_binding_point, shader_stages)
  
  tex_binding_point = 1
  tex_res_index = gh_vk.descriptorset_add_resource_texture(ds, tex0, sampler, tex_binding_point, SHADER_STAGE_FRAGMENT)
  tex_binding_point = 2
  tex_res_index = gh_vk.descriptorset_add_resource_texture(ds, tex1, sampler, tex_binding_point, SHADER_STAGE_FRAGMENT)
  tex_binding_point = 3
  tex_res_index = gh_vk.descriptorset_add_resource_texture(ds, tex2, sampler, tex_binding_point, SHADER_STAGE_TESSELLATION_EVALUATION)

  gh_vk.descriptorset_build(ds)
  gh_vk.descriptorset_update(ds)
end



-- All descriptor sets have the same layout, we can then create only one pipeline that use one of those DSs. 
--
local ds = dss[1]



-----------------------------------------------------------------------
--
-- Pipeline for solid rendering
--
pso01 = gh_vk.pipeline_create("pso01", tess_shader, "")
gh_vk.pipeline_set_attrib_4i(pso01, "DEPTH_TEST", 1, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01, "FILL_MODE", POLYGON_MODE_SOLID, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01, "PRIMITIVE_TYPE", PRIMITIVE_PATCH, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01, "CCW", 0, 0, 0, 0)
pso_valid = gh_vk.pipeline_build(pso01, ds)
if (pso_valid == 0) then
	print("ERROR: pipeline state pso01 is not valid.")
end


-- Pipeline for wireframe rendering
--
pso01_wireframe = gh_vk.pipeline_create("pso01_wireframe", tess_shader, "")
gh_vk.pipeline_set_attrib_4i(pso01_wireframe, "DEPTH_TEST", 1, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01_wireframe, "FILL_MODE", POLYGON_MODE_LINE, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01_wireframe, "PRIMITIVE_TYPE", PRIMITIVE_PATCH, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01_wireframe, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01_wireframe, "CCW", 0, 0, 0, 0)
pso_valid = gh_vk.pipeline_build(pso01_wireframe, ds)
if (pso_valid == 0) then
  print("ERROR: pipeline state pso01_wireframe is not valid.")
end





-----------------------------------------------------------------------
--
--mesh = gh_mesh.create_torus(6.0, 2.0, 10) -- 200f / 121v
--mesh = gh_mesh.create_torus(6.0, 2.0, 20) -- 800f / 441v
--mesh = gh_mesh.create_torus(6.0, 2.0, 40) -- 3200f / 1681v
--mesh = gh_mesh.create_torus(6.0, 2.0, 50) -- 5000f / 2601v
--mesh = gh_mesh.create_torus(6.0, 2.0, 100) -- 20'000f / 10'201v
--mesh = gh_mesh.create_torus(6.0, 2.0, 200) -- 80'000f / 40'401v
--mesh = gh_mesh.create_torus(6.0, 2.0, 400) -- 320'000f / 160'801v
--mesh = gh_mesh.create_torus(6.0, 2.0, 500) -- 500'000f / 251'001v
--mesh = gh_mesh.create_torus(6.0, 2.0, 1000) -- 2'000'000f / 1'002'001v

mesh = gh_mesh.create_sphere(5.0, 50, 50)
gh_mesh.set_vertices_color(mesh, 1.0, 1.0, 1.0, 1.0)


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


function build_command_buffer(w, h)

  --print("demo - build_command_buffer() START")
  
  local frame_index = gh_vk.frame_get_active_command_buffer_index()
  local ds = dss[frame_index+1]


	------ Opens the command buffer for recording.
  gh_vk.clear_color_depth_buffers(bkg_color.r, bkg_color.g, bkg_color.b, bkg_color.a, 1.0)
	gh_vk.frame_command_buffer_begin()

	
	--------------------------
	gh_vk.set_viewport_scissor(0, 0, w, h)

	-- Binds the descriptor set and PSO.
	--
  if (g_wireframe == 1) then
    gh_vk.pipeline_bind(pso01_wireframe)
  else  
    gh_vk.pipeline_bind(pso01)
  end
  

  gh_vk.descriptorset_bind(ds)

  
  gh_object.render(mesh)
  --------------------------

  
  







  imgui_frame_begin()

  local is_open = imgui_window_begin_v1("Control panel", 300, 220, 20, 20)
  if (is_open == 1) then
  
    local window_w = gh_imgui.get_content_region_available_width()
  
    local widget_width = window_w * 1.0
    
    
    gh_imgui.text("Press [ESC] to quit the demo")
  
    imgui_vertical_space()
    imgui_vertical_space()
  
    g_wireframe = gh_imgui.checkbox("Wireframe", g_wireframe)
  
  
    gh_imgui.text("Tessellation factor")
    local power = 1.0
    local min_value = 1
    local max_value = 64
    gh_imgui.push_item_width(widget_width)
    g_tess_params.tess_level = gh_imgui.slider_1f("##tesslevel", g_tess_params.tess_level,   min_value, max_value, power)
  
  
    gh_imgui.text("Tessellation bump scale")
    min_value = 0.1
    max_value = 10.0
    g_tess_params.bump_scale = gh_imgui.slider_1f("##bumpscale", g_tess_params.bump_scale,   min_value, max_value,   power)
    gh_imgui.pop_item_width()
  
    gh_imgui.push_item_width(widget_width * 0.75)
    gh_imgui.text("Background color")
    bkg_color.r, bkg_color.g, bkg_color.b, bkg_color.a = gh_imgui.color_edit_rgba("##colorpicker-Bgcolor", bkg_color.r, bkg_color.g, bkg_color.b, bkg_color.a)
    gh_imgui.pop_item_width()
  
  end 
  
  imgui_window_end()
  
  imgui_frame_end()
  









	----- Close the command buffer.
	gh_vk.frame_command_buffer_end()

end









g_tess_params = {tess_level=8, bump_scale=2.0}
g_wireframe = 0

bkg_color = {r=0.2, g=0.2, b=0.2, a=1.0}




--[[
for i=0, swapchain_image_count-1 do
	gh_vk.frame_set_active_command_buffer_index(i)
	build_command_buffer(winW, winH)
end
gh_vk.frame_set_active_command_buffer_index(0)
--]]






