<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>


<!--
This demo shows how to render a mesh with a PN Triangle tesselation shader.
-->


<glsl_hacker>
	
  <window name="win3d01" title="Vulkan - Tessellation / PN Triangles" 
          width="1280" height="720" resizable="1" menubar="1" 
          separate_render_thread="1" gpu_index="0"
          renderer_type="Vulkan" vsync="0" />
  
  
	<script name="init_scene" run_mode="INIT" >
		<raw_data><![CDATA[	
    
local demo_dir = gh_utils.get_demo_dir() 		
dofile(demo_dir .. "./common.lua")
    
local lib_dir = gh_utils.get_scripting_libs_dir()
dofile(lib_dir .. "lua/imgui.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, 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

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, 6.0, 6.0)
UpdateLightPosition(ub1, -20, 10, 30)
UpdateTessellationParams(ub1, 8.0, 8.0, 0.5, 1.1)




-----------------------------------------------------------------------
--
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 .. "data/1596-diffuse.jpg", PF_U8_RGBA)
tex1 = gh_texture.create_from_file_v5(demo_dir .. "data/1596-normal.jpg", PF_U8_RGBA)
tex2 = gh_texture.create_from_file_v5(demo_dir .. "data/1596-bump.jpg", PF_U8_RGBA)


-----------------------------------------------------------------------
--
local anisotropy = 1.0
sampler = gh_renderer.texture_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
--]]



ds = gh_renderer.vk_descriptorset_create()
ub_binding_point = 0
local shader_stages = VK_SHADER_STAGE_TESSELLATION_CONTROL + VK_SHADER_STAGE_TESSELLATION_EVALUATION + VK_SHADER_STAGE_FRAGMENT
gh_renderer.vk_descriptorset_add_resource_gpu_buffer(ds, ub1, ub_binding_point, shader_stages)
tex_binding_point = 1
tex_res_index = gh_renderer.vk_descriptorset_add_resource_texture(ds, tex0, sampler, tex_binding_point, VK_SHADER_STAGE_FRAGMENT)
tex_binding_point = 2
tex_res_index = gh_renderer.vk_descriptorset_add_resource_texture(ds, tex1, sampler, tex_binding_point, VK_SHADER_STAGE_FRAGMENT)
tex_binding_point = 3
tex_res_index = gh_renderer.vk_descriptorset_add_resource_texture(ds, tex2, sampler, tex_binding_point, VK_SHADER_STAGE_TESSELLATION_EVALUATION)

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




-----------------------------------------------------------------------
--
pso01 = gh_renderer.pipeline_state_create("pso01", tess_shader, "")
gh_renderer.pipeline_state_set_attrib_4i(pso01, "DEPTH_TEST", 1, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "FILL_MODE", POLYGON_MODE_SOLID, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "PRIMITIVE_TYPE", PRIMITIVE_PATCH, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01, "CCW", 0, 0, 0, 0)

pso_valid = gh_renderer.vk_pipeline_state_build(pso01, ds)
if (pso_valid == 0) then
	print("ERROR: pipeline state pso01 is not valid.")
end


pso01_wireframe = gh_renderer.pipeline_state_create("pso01_wireframe", tess_shader, "")
gh_renderer.pipeline_state_set_attrib_4i(pso01_wireframe, "DEPTH_TEST", 1, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01_wireframe, "FILL_MODE", POLYGON_MODE_LINE, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01_wireframe, "PRIMITIVE_TYPE", PRIMITIVE_PATCH, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01_wireframe, "CULL_MODE", POLYGON_FACE_NONE, 0, 0, 0)
gh_renderer.pipeline_state_set_attrib_4i(pso01_wireframe, "CCW", 0, 0, 0, 0)

pso_valid = gh_renderer.vk_pipeline_state_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, 20, 20)


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

UpdateObjectTransform(ub1, mesh)



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

cmd = gh_renderer.command_list_create(0)






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}


		]]></raw_data>
	</script> 
	
	

	
	<script name="terminate_scene" run_mode="TERMINATE" >
		<raw_data><![CDATA[	

gh_renderer.wait_for_gpu()

gh_gpu_buffer.unmap(ub1)
gh_imgui.terminate()


		]]></raw_data>
	</script> 
	
	
	
  
	<script name="update_scene" run_mode="FRAME" >
		<raw_data><![CDATA[	
   
    
    
local elapsed_time = gh_utils.get_elapsed_time()
gh_object.set_euler_angles(mesh, 90 + 10*math.cos(elapsed_time), 20*math.sin(elapsed_time),  10*math.sin(elapsed_time))
UpdateObjectTransform(ub1, mesh)

UpdateTessellationParams(ub1, g_tess_params.tess_level, g_tess_params.tess_level, 0.5, g_tess_params.bump_scale)



    
    
gh_renderer.command_list_open(cmd)

gh_renderer.clear_color_depth_buffers(bkg_color.r, bkg_color.g, bkg_color.b, bkg_color.a, 1.0)

gh_renderer.vk_command_list_render_pass_begin(cmd, 0)
   


gh_renderer.set_viewport_scissor(0, 0, winW, winH)

if (g_wireframe == 1) then
  gh_renderer.pipeline_state_bind(pso01_wireframe)
else  
  gh_renderer.pipeline_state_bind(pso01)
end

gh_renderer.vk_descriptorset_bind(ds)

gh_object.render(mesh)















----------------------------------------------------------------------------
-- ImGui begin -------------------------------------------------------------
--
imgui_frame_begin()

local is_open = imgui_window_begin_v1("Control panel", 300, 200, 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()
--
-- ImGui end ---------------------------------------------------------------
----------------------------------------------------------------------------





gh_renderer.vk_command_list_render_pass_end(cmd)
gh_renderer.command_list_close(cmd)
gh_renderer.command_list_execute(cmd)





		]]></raw_data>
	</script> 
	

	<script name="resize_scene" run_mode="SIZE" >
		<raw_data><![CDATA[	
winW, winH = gh_window.getsize(0)


local aspect = winW / winH
gh_camera.update_persp(camera, camera_params.fov, aspect, camera_params.znear, camera_params.zfar)
gh_camera.set_viewport(camera, 0, 0, winW, winH)
UpdateCameraTransform(ub1, camera)


		]]></raw_data>
	</script> 
  
  
</glsl_hacker>
