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")    
dofile(lib_dir .. "lua/libfont/vklibfont1.lua")    



    
winW, winH = gh_window.getsize(0)




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)



camera_ortho = gh_camera.create_ortho(-winW/2, winW/2, -winH/2, winH/2, 1.0, 10.0)
gh_camera.set_viewport(camera_ortho, 0, 0, winW, winH)
gh_camera.set_position(camera_ortho, 0, 0, 4)








--[[
vklibfont_init_dynamic_text(1)

vklibfont_begin()
vklibfont_print(20, 20, 1, 1, 0, 1, "Hello in Yellow")
vklibfont_print(20, 40, 1, 0, 0, 1, "Hello in Red")
--vklibfont_print(20, 100, 1, 1, 1, 1, string.format("Elasped time: %.2f sec", elapsed_time))
vklibfont_end()
--]]







mesh = gh_mesh.create_torus(5.0, 1.5, 50)
gh_object.set_euler_angles(mesh, 20.0, 0.0, 15.0)
ang_x = 0

--mesh = gh_mesh.create_sphere(4.0, 50, 50)
--gh_object.set_euler_angles(mesh, 90.0, 0.0, 0.0)
--ang_x = 90

--mesh = gh_mesh.create_triangle()


-- meshlet_max_vertices and meshlet_max_indices must match values in the mesh shader (ms.mesh).
-- meshlet_max_vertices and meshlet_max_indices are used to update the meshlet GPU buffer.
--
-- In ms.mesh file:
-- layout(triangles, max_vertices = 64, max_primitives = 126) out;
-- ...
-- struct s_meshlet
-- {
-- 	uint vertices[64];
-- 	uint indices[378]; // up to 126 triangles
-- 	uint vertex_count;
-- 	uint index_count;
-- };
-- ...
--


-- 256 vertices maximum (see maxMeshOutputVertices) - recommended 64 vertices
meshlet_max_vertices = 64 -- max values for GPU buffer allocation

-- 512 primitives maximum (see maxMeshOutputPrimitives) - recommended 126 triangles (allocation prefers 40, 84, 126, 254 or 510 triangles)
meshlet_max_primitives = 126 -- 378 indices
meshlet_max_indices = meshlet_max_primitives * 3 -- max values for GPU buffer allocation

-- 126 triangles is the maximum recommended. But we can create meshlets with less triangles!
-- In this demo: max vertices: 64 and max triangles: 16
meshlet_vertices = 64
meshlet_triangles = 16
meshlet_indices = meshlet_triangles*3
gh_mesh.meshlet_generate(mesh, meshlet_vertices, meshlet_indices)



------------------------------------------------------------
-- Uniform buffer for transformations (matrices).
--
-- layout (std140, binding = 0) uniform uniforms_t
-- { 
--   mat4 ViewProjectionMatrix; // 64 bytes
--   mat4 ModelMatrix; // 64 bytes
-- } transform_ub;
--

function UpdateTransformBuffer()
	gh_gpu_buffer.map(transform_ub)

  local buffer_offset_bytes = 0
	gh_gpu_buffer.set_matrix4x4(transform_ub, buffer_offset_bytes, camera, "camera_view_projection")
	
	buffer_offset_bytes = 64
	gh_gpu_buffer.set_matrix4x4(transform_ub, buffer_offset_bytes, mesh, "object_global_transform")
	
	gh_gpu_buffer.unmap(transform_ub)
end


function UpdateTransformBuffer_Camera()
	gh_gpu_buffer.map(transform_ub)

  local buffer_offset_bytes = 0
	gh_gpu_buffer.set_matrix4x4(transform_ub, buffer_offset_bytes, camera, "camera_view_projection")
	
	gh_gpu_buffer.unmap(transform_ub)
end


function UpdateTransformBuffer_Object()
	gh_gpu_buffer.map(transform_ub)

	local buffer_offset_bytes = 64
	gh_gpu_buffer.set_matrix4x4(transform_ub, buffer_offset_bytes, mesh, "object_global_transform")
	
	gh_gpu_buffer.unmap(transform_ub)
end


local ub_size = 256
transform_ub = gh_gpu_buffer.create("UNIFORM", "NONE", ub_size, "")
gh_gpu_buffer.bind(transform_ub)
UpdateTransformBuffer()












-----------------------------------------------------------------------
-- SPIR-V color program.
-- The torus will be rendered wit this program if mesh shaders are no supported.
--
local vertex_shader = demo_dir .. "spirv/vs.spv"
local pixel_shader = demo_dir .. "spirv/ps.spv"
color_prog = gh_gpu_program.vk_create_from_spirv_module_file("color_prog",   vertex_shader, "main",   pixel_shader, "main",  "","",    "","",    "","",   "","") 


-----------------------------------------------------------------------
-- 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, transform_ub, binding_point, SHADER_STAGE_VERTEX)

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.
--
color_pipeline = gh_vk.pipeline_create("color_pipeline", color_prog, "")
gh_vk.pipeline_set_attrib_4i(color_pipeline, "DEPTH_TEST", 1, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(color_pipeline, "FILL_MODE", POLYGON_MODE_LINE, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(color_pipeline, "PRIMITIVE_TYPE", PRIMITIVE_TRIANGLE, 0, 0, 0)
gh_vk.pipeline_set_attrib_4i(color_pipeline, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
color_pipeline_valid = gh_vk.pipeline_build(color_pipeline, ds)
if (color_pipeline_valid == 1) then
	print("color_pipeline => id:" ..  color_pipeline)
else	
	print("ERROR: color_pipeline is not valid.")
end









local gpu_index = gh_vk.get_current_gpu()

-- WARNING: gh_vk.gpu_is_extension_supported() returns a boolean...
VK_NV_mesh_shader_OK = gh_vk.gpu_is_extension_supported(gpu_index, "VK_NV_mesh_shader")
--VK_NV_mesh_shader_OK = false


vk_renderer = gh_vk.gpu_get_name(gpu_index)
vk_version_major, vk_version_minor, vk_version_patch = gh_vk.gpu_get_api_version(gpu_index)

print("vk_renderer: " ..  vk_renderer)





--------------------------------------------------------------------
-- Storage buffer for vertices.
--

--[[
struct s_vertex
{
	vec4 position; // 16 bytes
	vec4 color; // 16 bytes
};

layout (std430, binding = 1) buffer _vertices
{
	s_vertex vertices[];
} vb;

--]]

function UpdateVertexBuffer(num_vertices)
	gh_gpu_buffer.map(vertex_ub)
	local buffer_offset_bytes = 0
	for v=0, num_vertices-1 do
		local x, y, z, w = gh_mesh.get_vertex_position(mesh, v)
		--print(string.format("vertex[%d - %d]: <%.1f ; %.1f ; %.1f>", v, buffer_offset_bytes, x, y, z))
		gh_gpu_buffer.set_value_4f(vertex_ub, buffer_offset_bytes, x, y, z, 1.0)
		buffer_offset_bytes = buffer_offset_bytes + 16
		gh_gpu_buffer.set_value_4f(vertex_ub, buffer_offset_bytes,1.0, 1.0, 1.0, 1.0)
		buffer_offset_bytes = buffer_offset_bytes + 16
	end
	gh_gpu_buffer.unmap(vertex_ub)
end

num_vertices = gh_object.get_num_vertices(mesh)
num_faces = gh_object.get_num_faces(mesh)
print("num_vertices: " .. num_vertices)
ub_size = 16*2 * num_vertices
vertex_ub = gh_gpu_buffer.create("STORAGE", "NONE", ub_size, "")
gh_gpu_buffer.bind(vertex_ub)
UpdateVertexBuffer(num_vertices)






--------------------------------------------------------------------
-- Storage buffer for meshlets.
--

--[[
struct s_meshlet
{
	uint vertices[64];
	uint indices[378]; // up to 126 triangles
	uint vertex_count;
	uint index_count;
};
--]]


function UpdateMeshletBuffer()
	gh_gpu_buffer.map(meshlet_ub)
	local buffer_offset_bytes = 0
	local base_offset_bytes = 0
	local meshlet_size = meshlet_max_vertices*4 + meshlet_max_indices*4 + 4 + 4 -- 768

	for m=0, num_meshlets-1 do
		--print(string.format("meshlet[%d]", m))

		base_offset_bytes = meshlet_size * m
		buffer_offset_bytes = base_offset_bytes

		--print(string.format("meshlet[%d] - base offset: %d", m, base_offset_bytes))

		local nv = gh_mesh.meshlet_get_vertex_count(mesh, m)


		-- updating: uint vertices[64];
		--
		for v=0, nv-1 do
			local x = gh_mesh.meshlet_get_vertex(mesh, m, v)
			gh_gpu_buffer.set_value_1ui(meshlet_ub, buffer_offset_bytes, x)
			buffer_offset_bytes = buffer_offset_bytes + 4
		end

		
		buffer_offset_bytes = base_offset_bytes + meshlet_max_vertices*4


		local ni = gh_mesh.meshlet_get_index_count(mesh, m)

		-- updating: uint indices[64];
		--
		for v=0, ni-1 do
			local x = gh_mesh.meshlet_get_index(mesh, m, v) 
			gh_gpu_buffer.set_value_1ui(meshlet_ub, buffer_offset_bytes, x)
			buffer_offset_bytes = buffer_offset_bytes + 4
		end



		-- updating: vertex_count
		--
		buffer_offset_bytes = base_offset_bytes + meshlet_max_vertices*4 + meshlet_max_indices*4
		gh_gpu_buffer.set_value_1ui(meshlet_ub, buffer_offset_bytes, nv)

		-- updating: index_count
		--
		buffer_offset_bytes = buffer_offset_bytes + 4
		gh_gpu_buffer.set_value_1ui(meshlet_ub, buffer_offset_bytes, ni)
	end

	gh_gpu_buffer.unmap(meshlet_ub)
end


num_meshlets = gh_mesh.meshlet_get_count(mesh)
print("num_meshlets: " .. num_meshlets)
local meshlet_size = 4 + meshlet_max_vertices*4 + 4 + meshlet_max_indices*4
ub_size = meshlet_size * num_meshlets
meshlet_ub = gh_gpu_buffer.create("STORAGE", "NONE", ub_size, "")
gh_gpu_buffer.bind(meshlet_ub)
UpdateMeshletBuffer()


num_meshlets_render = num_meshlets






--------------------------------------------------------------------
--
meshlet_prog = 0
meshlet_ds = 0
meshlet_pipeline_wireframe = 0
meshlet_pipeline_solid = 0
meshlet_pipeline_valid = 0

nv_ms_props = 
{
	maxDrawMeshTasksCount = 0,
	maxTaskWorkGroupInvocations = 0,
	maxTaskWorkGroupSize = {x=0, y=0, z=0},
	maxTaskTotalMemorySize = 0,
	maxTaskOutputCount = 0,
	maxMeshWorkGroupInvocations = 0,
	maxMeshWorkGroupSize = {x=0, y=0, z=0},
	maxMeshTotalMemorySize = 0,
	maxMeshOutputVertices = 0,
	maxMeshOutputPrimitives = 0,
	maxMeshMultiviewViewCount = 0,
	meshOutputPerVertexGranularity = 0,
	meshOutputPerPrimitiveGranularity = 0,
}

if (VK_NV_mesh_shader_OK) then

	-- Mesh shader properties
	--
	nv_ms_props.maxDrawMeshTasksCount = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxDrawMeshTasksCount")
	nv_ms_props.maxTaskWorkGroupInvocations = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxTaskWorkGroupInvocations")
	nv_ms_props.maxTaskWorkGroupSize.x, nv_ms_props.maxTaskWorkGroupSize.y, nv_ms_props.maxTaskWorkGroupSize.z = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxTaskWorkGroupSize")
	nv_ms_props.maxTaskTotalMemorySize = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxTaskTotalMemorySize")
	nv_ms_props.maxTaskOutputCount = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxTaskOutputCount")
	nv_ms_props.maxMeshWorkGroupInvocations = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshWorkGroupInvocations")
	nv_ms_props.maxMeshWorkGroupSize.x, nv_ms_props.maxMeshWorkGroupSize.y, nv_ms_props.maxMeshWorkGroupSize.z = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshWorkGroupSize")
	nv_ms_props.maxMeshTotalMemorySize = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshTotalMemorySize")
	nv_ms_props.maxMeshOutputVertices = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshOutputVertices")
	nv_ms_props.maxMeshOutputPrimitives = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshOutputPrimitives")
	nv_ms_props.maxMeshMultiviewViewCount = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "maxMeshMultiviewViewCount")
	nv_ms_props.meshOutputPerVertexGranularity = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "meshOutputPerVertexGranularity")
	nv_ms_props.meshOutputPerPrimitiveGranularity = gh_vk.mesh_shader_get_property_value_nv(gpu_index, "meshOutputPerPrimitiveGranularity")




	-- mesh-shader program
	-- The mesh-shader program has the same pixel shader than the color program.
	--
	local mesh_shader = demo_dir .. "spirv/ms.spv"
	meshlet_prog = gh_gpu_program.vk_create_mesh_task_from_spirv_module_file("meshlet_prog",   mesh_shader, "main",   task_shader, "",  pixel_shader, "main") 
	print("meshlet_prog => id:" ..  meshlet_prog)
	
	
	
	-- Descriptor set.
	--
	meshlet_ds = gh_vk.descriptorset_create()
	-- The binding point is very important because it is used in the mesh shader to reference
	-- GPU buffers.
	--
	local binding_point = 0
	gh_vk.descriptorset_add_resource_gpu_buffer(meshlet_ds, transform_ub, binding_point, SHADER_STAGE_MESH)
	binding_point = 1
	gh_vk.descriptorset_add_resource_gpu_buffer(meshlet_ds, vertex_ub, binding_point, SHADER_STAGE_MESH)
	binding_point = 2
	gh_vk.descriptorset_add_resource_gpu_buffer(meshlet_ds, meshlet_ub, binding_point, SHADER_STAGE_MESH)
	gh_vk.descriptorset_build(meshlet_ds)
	gh_vk.descriptorset_update(meshlet_ds)



	-- Pipeline objects: one pipeline for wireframe rendering and a second one fpr solid rendering.
	--
	local pipeline = 0

	meshlet_pipeline_wireframe = gh_vk.pipeline_create("meshlet_pipeline_wireframe", meshlet_prog, "")
	pipeline = meshlet_pipeline_wireframe
	gh_vk.pipeline_set_attrib_4i(pipeline, "DEPTH_TEST", 1, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "FILL_MODE", POLYGON_MODE_LINE, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "PRIMITIVE_TYPE", PRIMITIVE_TRIANGLE, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "HAS_VERTEX_BINDING", 0, 0, 0, 0)
	meshlet_pipeline_wireframe_valid = gh_vk.pipeline_build(pipeline, meshlet_ds)
	if (meshlet_pipeline_wireframe_valid == 1) then
		print("meshlet_pipeline_wireframe => id:" ..  pipeline)
	else	
		print("ERROR: meshlet_pipeline_wireframe is not valid.")
	end
	
	
	meshlet_pipeline_solid = gh_vk.pipeline_create("meshlet_pipeline_solid", meshlet_prog, "")
	pipeline = meshlet_pipeline_solid
	gh_vk.pipeline_set_attrib_4i(pipeline, "DEPTH_TEST", 1, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "FILL_MODE", POLYGON_MODE_SOLID, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "PRIMITIVE_TYPE", PRIMITIVE_TRIANGLE, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
	gh_vk.pipeline_set_attrib_4i(pipeline, "HAS_VERTEX_BINDING", 0, 0, 0, 0)
	meshlet_pipeline_solid_valid = gh_vk.pipeline_build(pipeline, meshlet_ds)
	if (meshlet_pipeline_solid_valid == 1) then
		print("meshlet_pipeline_solid => id:" ..  pipeline)
	else	
		print("ERROR: meshlet_pipeline_solid is not valid.")
	end
	
	
	if ((meshlet_pipeline_wireframe_valid == 1) and (meshlet_pipeline_solid_valid == 1)) then
		meshlet_pipeline_valid = 1
	end
	


end







wireframe = 1

display_imgui = 1

use_vertex_shader = 0


-----------------------------------------------------------------------
-- 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.1, 0.2, 0.3, 1.0, 1.0)
	gh_vk.frame_command_buffer_begin()

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



	--------------------------
	if ((use_vertex_shader == 0) and VK_NV_mesh_shader_OK and (meshlet_pipeline_valid == 1)) then

		-- Mesh shader -------------------------
		
		gh_vk.descriptorset_bind(meshlet_ds)

		local pipeline = meshlet_pipeline_solid
		if (wireframe == 1) then
			pipeline = meshlet_pipeline_wireframe
		end
		gh_vk.pipeline_bind(pipeline)
		
		local first = 0
		local num_workgroups = num_meshlets_render
		gh_vk.draw_mesh_tasks(first, num_workgroups)

	else

		-- Color shader -------------------------

		if (color_pipeline_valid == 1) then
			gh_vk.descriptorset_bind(ds)
			gh_vk.pipeline_bind(color_pipeline)
			gh_object.render(mesh)
		end
	
	end



	--vklibfont_render()




	if (display_imgui == 1) then
		imgui_frame_begin()

    gh_imgui.set_color(IMGUI_WINDOW_BG_COLOR, 0.2, 0.2, 0.2, 0.5)


		local is_open = imgui_window_begin_pos_size_always("Control panel", 300, winH, 0, 0)
		if (is_open == 1) then
		
			gh_imgui.text("Turing Mesh Shader (VK_NV_mesh_shader)")

			gh_imgui.spacing()
			gh_imgui.spacing()

			if (VK_NV_mesh_shader_OK) then
				gh_imgui.text_rgba("- VK_NV_mesh_shader supported.", 0.2, 1.0, 0.1, 1.0)
			else
				gh_imgui.text_rgba("- VK_NV_mesh_shader NOT supported.", 1.0, 0.7, 0.1, 1.0)
			end

			gh_imgui.spacing()
			gh_imgui.spacing()

			gh_imgui.text(string.format("- Vulkan device: %s", vk_renderer))
			gh_imgui.text(string.format("- Vulkan version: %d.%d.%d", vk_version_major, vk_version_minor, vk_version_patch))



			if (VK_NV_mesh_shader_OK) then
				gh_imgui.spacing()
				gh_imgui.spacing()

				gh_imgui.text("- VK_NV_mesh_shader properties:")
				
				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxDrawMeshTasksCount: %d", nv_ms_props.maxDrawMeshTasksCount))
				
				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxTaskWorkGroupInvocations: %d", nv_ms_props.maxTaskWorkGroupInvocations))
				
				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxTaskWorkGroupSize: [%d ; %d ; %d]", nv_ms_props.maxTaskWorkGroupSize.x, nv_ms_props.maxTaskWorkGroupSize.y, nv_ms_props.maxTaskWorkGroupSize.z))
				
				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxTaskTotalMemorySize: %d", nv_ms_props.maxTaskTotalMemorySize))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxTaskOutputCount: %d", nv_ms_props.maxTaskOutputCount))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshWorkGroupInvocations: %d", nv_ms_props.maxMeshWorkGroupInvocations))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshWorkGroupSize: [%d ; %d ; %d]", nv_ms_props.maxMeshWorkGroupSize.x, nv_ms_props.maxMeshWorkGroupSize.y, nv_ms_props.maxMeshWorkGroupSize.z))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshTotalMemorySize: %d", nv_ms_props.maxMeshTotalMemorySize))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshOutputVertices: %d", nv_ms_props.maxMeshOutputVertices))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshOutputPrimitives: %d", nv_ms_props.maxMeshOutputPrimitives))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("maxMeshMultiviewViewCount: %d", nv_ms_props.maxMeshMultiviewViewCount))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("meshOutputPerVertexGranularity: %d", nv_ms_props.meshOutputPerVertexGranularity))

				gh_imgui.bullet()
				gh_imgui.same_line(0, 5)
				gh_imgui.text(string.format("meshOutputPerPrimitiveGranularity: %d", nv_ms_props.meshOutputPerPrimitiveGranularity))
			end


			
			gh_imgui.spacing()
			gh_imgui.spacing()

			gh_imgui.text("- Mesh info:")
			gh_imgui.bullet()
			gh_imgui.same_line(0, 5)
			gh_imgui.text(string.format("%d vertices / %d faces", num_vertices, num_faces))
			gh_imgui.bullet()
			gh_imgui.same_line(0, 5)
			gh_imgui.text(string.format("%d meshlets", num_meshlets))
			gh_imgui.bullet()
			gh_imgui.same_line(0, 5)
			gh_imgui.text(string.format("%d triangles per meshlet", meshlet_triangles))
			-- gh_imgui.bullet()
			-- gh_imgui.same_line(0, 5)
			-- gh_imgui.text(string.format("max vertices: %d - max indices: %d", meshlet_max_vertices, meshlet_max_indices))
			

			gh_imgui.spacing()
			gh_imgui.spacing()

			local elapsed_time = gh_utils.get_elapsed_time()
			gh_imgui.text(string.format("Elasped time: %.2f sec", elapsed_time))
			

			if (VK_NV_mesh_shader_OK) then
				gh_imgui.spacing()
				gh_imgui.spacing()
				use_vertex_shader = gh_imgui.checkbox("Use vertex shader", use_vertex_shader)

				if (use_vertex_shader == 0) then
					gh_imgui.spacing()
					gh_imgui.spacing()
					wireframe = gh_imgui.checkbox("Wireframe", wireframe)
				end

				gh_imgui.spacing()
				gh_imgui.spacing()
				gh_imgui.text("Num meshlets: [0; " .. num_meshlets .. "]")
				num_meshlets_render = gh_imgui.slider_1i("##num_meshlets_render", num_meshlets_render, 0, num_meshlets)
			end



			local mode3Axes = 1
			local modeDirection = 2
			local modeDirPlane = 4
			local modeDual = 8
			local modePanDolly = 16
			local modeMask = 255
			local cubeAtOrigin = 256
			local sphereAtOrigin = 512
			local noSolidAtOrigin = 1024
			local modeFullAxes = 2048
			local axesModeMask = 65280
	
			gh_imgui.spacing()
			gh_imgui.spacing()
			gh_imgui.text("Mesh orientation:")
			gh_imgui.imguizmoquat_gizmo3d_v1("##gizmo01", 100, mode3Axes + sphereAtOrigin, mesh)

		
		end 
		
		imgui_window_end()
		imgui_frame_end()
	end
	


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



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

if (display_imgui == 0) then
	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)
end

