local demo_dir = gh_utils.get_demo_dir() 		

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




    
winW, winH = gh_window.getsize(0)







-----------------------------------------------------------------------
-- 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, 10)
gh_camera.set_lookat(camera, 0, 0, 0, 1)
gh_camera.set_upvec(camera, 0, 1, 0, 0)





-----------------------------------------------------------------------
-- GPU buffer to store uniform data used by the shaders.
--


function UpdateCameraTransform(ub, cam)
  local buffer_offset_bytes = 0
  --gh_gpu_buffer.set_matrix4x4(ub, buffer_offset_bytes, cam, "camera_projection_vk")
  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


local ub_size = 512
ub1 = gh_gpu_buffer.create("UNIFORM", "NONE", ub_size, "")
gh_gpu_buffer.bind(ub1)
gh_gpu_buffer.map(ub1)



UpdateCameraTransform(ub1, camera)
UpdateUVTiling(ub1, 2.0, 2.0)












-----------------------------------------------------------------------
-- SPIR-V shaders.
--
-- The SPIR-V shaders have been created from GLSL shaders using the 
-- glslangValidator.exe on Windows. This utility is available in the 
-- spirv/ folder.
--
local vertex_shader = demo_dir .. "spirv/08-vs.spv"
local pixel_shader = demo_dir .. "spirv/08-ps.spv"
phong_shader = gh_gpu_program.vk_create_from_spirv_module_file("phong_shader",   vertex_shader, "main",     pixel_shader, "main",    "", "",    "", "",     "", "",    "", "") 





-----------------------------------------------------------------------
--
local abs_path = 0
local PF_U8_RGB = 1
local PF_U8_RGBA = 3
local pixel_format = PF_U8_RGBA
local gen_mipmaps = 1
local compressed_texture = 0
local free_cpu_memory = 1
tex0 = gh_texture.create_from_file_v6(demo_dir .. "textures/t08.jpg", pixel_format, gen_mipmaps, compressed_texture)

num_mipmaps = gh_texture.get_num_mipmaps(tex0)
print("num_mipmaps for tex0: " .. num_mipmaps)


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






-----------------------------------------------------------------------
-- Descriptor set that describes what resources (GPU buffer and textures) 
-- will be used for drawing.
--
ds = gh_vk.descriptorset_create()

local binding_point = 0
gh_vk.descriptorset_add_resource_gpu_buffer(ds, ub1, binding_point, SHADER_STAGE_VERTEX)

binding_point = 1
tex_res_index = gh_vk.descriptorset_add_resource_texture(ds, tex0, sampler, binding_point, SHADER_STAGE_FRAGMENT)

gh_renderer.vk_descriptorset_build(ds)
gh_renderer.vk_descriptorset_update(ds)







-----------------------------------------------------------------------
-- The pipeline object or PSO.
-- The PSO stores all graphics pipeline states (what shaders are used, depth state, blending, etc.)
-- in one place. The PSO is an immutable object: once created, it can not be changed. So if you need
-- to draw an object with solid polygon mode and another object in wireframe, you have to create 
-- two PSOs.
--
pso01 = gh_vk.pipeline_create("pso01", phong_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_TRIANGLE, 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, "CULL_MODE", POLYGON_FACE_BACK, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(pso01, "CCW", 1, 0, 0, 0)
pso_valid = gh_vk.pipeline_build(pso01, ds)
if (pso_valid == 0) then
	print("ERROR: pipeline pso01 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

gh_mesh.set_vertices_color(mesh, 1.0, 1.0, 0.0, 1.0)

UpdateObjectTransform(ub1, mesh)
UpdateUVTiling(ub1, 2.0, 2.0)







-----------------------------------------------------------------------
-- Wait for GPU: be sure that all init commands are done.
--
gh_renderer.wait_for_gpu()





function build_command_buffer(w, h)

	gh_vk.clear_color_depth_buffers(0.4, 0.15, 0.1, 1.0, 1.0)
	gh_vk.frame_command_buffer_begin()


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

	-- Binds the descriptor set and PSO.
	--
	gh_vk.descriptorset_bind(ds)
	gh_vk.pipeline_bind(pso01)

	-- Render the object. Keep in mind that the object is not really rendered:
	-- only the drawing command is recorded in the command buffer. The object 
	-- will be rendered later when the command buffer will be executed.  
	--
	gh_object.render(mesh)
	--------------------------

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




swapchain_image_count = gh_vk.swapchain_get_image_count()
print("swapchain_image_count => " .. swapchain_image_count)

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)


build_command_buffer_every_frame = true
