
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)





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

--[[

The uniform buffer structure in the vertex shader:

struct CameraTransform
{
  mat4 ViewProjectionMatrix;
};

struct ObjectTransform
{
  mat4 ModelMatrix;
};

layout (std140, binding = 0) uniform uniforms_t
{ 
  CameraTransform C[2];
  ObjectTransform O[2];
} ub;

--]]



function UpdateCameraTransform(cam, ub, index)
  local mat4x4_size = 64
  local buffer_offset_bytes = mat4x4_size * index
  gh_gpu_buffer.set_matrix4x4(ub, buffer_offset_bytes, cam, "camera_view_projection")
end

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


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









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

UpdateCameraTransform(camera, ub1, 1)


-----------------------------------------------------------------------
-- Ortho camera.
--
camera_ortho = gh_camera.create_ortho(-1, 1, -1, 1, 1.0, 10.0)
gh_camera.set_viewport(camera_ortho, 0, 0, winW, winH)
gh_camera.set_position(camera_ortho, 0, 0, 4)

UpdateCameraTransform(camera_ortho, ub1, 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/03-vs-02.spv"
local pixel_shader = demo_dir .. "spirv/03-ps-02.spv"
texture_prog = gh_gpu_program.vk_create_from_spirv_module_file("texture-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 = 0
local compressed_texture = 0
local free_cpu_memory = 1
tex0 = gh_texture.create_from_file_v6(demo_dir .. "textures/bkg01.jpg", pixel_format, gen_mipmaps, compressed_texture)
tex1 = gh_texture.create_from_file_v6(demo_dir .. "textures/vulkan-industry-forged-logo.jpg", pixel_format, gen_mipmaps, compressed_texture)


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






-----------------------------------------------------------------------
-- Descriptor set that describes what resources (GPU buffer and textures) 
-- will be used for drawing.
-- In this demo, one GPU buffer will be used in the vertex shader.
--
ds = gh_vk.descriptorset_create()

-- The binding point is very important because it is used in ther vertex shader to reference
-- the GPU buffer.
local binding_point = 0
gh_vk.descriptorset_add_resource_gpu_buffer(ds, ub1, binding_point, SHADER_STAGE_VERTEX)


-- add an array of textures (uniform sampler2D tex[2]) to binding point 1:
binding_point = 1
resource_index = gh_vk.descriptorset_add_resource_empty_texture_array(ds, 2, binding_point, SHADER_STAGE_FRAGMENT)
gh_vk.descriptorset_update_resource_texture_array(ds, resource_index, 0, tex0, sampler)
gh_vk.descriptorset_update_resource_texture_array(ds, resource_index, 1, tex1, sampler)


-- Push constant.
local constant_size_bytes = 64 -- 64 bytes = 4 integers
local constant_offset_bytes = 0
push_constant_shader_flags = SHADER_STAGE_VERTEX | SHADER_STAGE_FRAGMENT
gh_vk.descriptorset_add_push_constant_range(ds, constant_size_bytes, constant_offset_bytes, push_constant_shader_flags)


gh_vk.descriptorset_build(ds)
gh_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", texture_prog, "")
local depth_test_enabled = 0 -- no depth test in this demo.
gh_vk.pipeline_set_attrib_4i(pso01, "DEPTH_TEST", depth_test_enabled, 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)
pso_valid = gh_vk.pipeline_build(pso01, ds)
if (pso_valid == 0) then
	print("ERROR: pipeline pso01 is not valid.")
end





-----------------------------------------------------------------------
-- Background quad
--
bkg_quad = gh_mesh.create_quad(2, 2)
gh_mesh.set_vertices_color(bkg_quad, 1.0, 1.0, 1.0, 1.0)

UpdateObjectTransform(bkg_quad, ub1, 0)



-----------------------------------------------------------------------
-- Image quad
--
quad = gh_mesh.create_quad(2, 2)
gh_mesh.set_vertices_color(quad, 1.0, 1.0, 1.0, 1.0)

UpdateObjectTransform(quad, ub1, 1)





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





function build_command_buffer(w, h)

	------ Opens the command buffer for recording.
	gh_vk.clear_color_depth_buffers(0.0, 0.0, 0.0, 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 objects. Keep in mind that objects are not really rendered:
	-- only drawing commands are recorded in the command buffer. Objects
	-- will be rendered later when the command buffer will be executed.  
	--


  -- Renders the background quad.
  --
  local camera_index = 0
  local object_index = 0
  local tex_index = 0
  gh_vk.descriptorset_push_constant_1i(ds, camera_index, 0, push_constant_shader_flags)
  gh_vk.descriptorset_push_constant_1i(ds, object_index, 4, push_constant_shader_flags)
  gh_vk.descriptorset_push_constant_1i(ds, tex_index, 8, push_constant_shader_flags)
  gh_object.render(bkg_quad)


  -- Renders the foreground and rotating quad.
  --
  camera_index = 1
  object_index = 1
  tex_index = 1
  gh_vk.descriptorset_push_constant_1i(ds, camera_index, 0, push_constant_shader_flags)
  gh_vk.descriptorset_push_constant_1i(ds, object_index, 4, push_constant_shader_flags)
  gh_vk.descriptorset_push_constant_1i(ds, tex_index, 8, push_constant_shader_flags)
  --gh_object.set_euler_angles(quad, 0, 0, elapsed_time*21.0)
  --UpdateObjectTransform(quad, ub1, 1)
  gh_object.render(quad)


	
	----- 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)


