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

<!--
Reference: http://prideout.net/blog/?p=48
-->


<glsl_hacker>
	
  <window name="win3d01" title="Tessellation shaders (OpenGL 4.0)" 
          width="800" height="600" 
          gl_version_major="4" gl_version_minor="0" />
  
  
	<script name="init_scene" run_mode="INIT" >
		<raw_data><![CDATA[	
    
    
local lib_dir = gh_utils.get_scripting_libs_dir() 		
local framework_dir = lib_dir .. "lua/framework_v1/"
dofile(framework_dir .. "kx.lua") -- kx framework.


kx_init_begin(framework_dir)
    
kx_set_main_title("OpenGL 4.0 - Tessellation")
    

    
    
camera = kx_get_camera()
gh_camera.set_position(camera, 0, 15, 20)
gh_camera.set_lookat(camera, 0, 0, 0, 1)
    
    
    

-- mesh = gh_mesh.create_sphere(10, 10, 10)
mesh = gh_mesh.create_torus(10, 3, 20)
--mesh = gh_mesh.create_torus(10, 3, 30)

GL_ARB_tessellation_shader_ok = gh_renderer.check_opengl_extension("GL_ARB_tessellation_shader")

tess_prog = 0

if (GL_ARB_tessellation_shader_ok == 1) then
  tess_prog = gh_node.getid("tess_gs_wireframe_prog")
  gh_object.set_tessellation_state(mesh, 1)
end




kx_init_end()



		]]></raw_data>
	</script> 
  
  
  
	<script name="kill_scene" run_mode="TERMINATE" >
		<raw_data><![CDATA[	

kx_terminate()

		]]></raw_data>
	</script> 
  
  
  

 
	<script name="update_scene" run_mode="FRAME" >
		<raw_data><![CDATA[	

    
-----------------------------------------------------------------------
kx_frame_begin(0.3, 0.3, 0.3)
-----------------------------------------------------------------------




local elapsed_time = kx_gettime()



gh_camera.set_position(camera, 0, 0, 15)
gh_camera.setlookat(camera, 0, 0, 0, 1)
gh_camera.bind(camera)

gh_renderer.set_depth_test_state(1)


-- Useful for live coding...
outer_tess_level = 8
inner_tess_level = 8


gh_object.set_position(mesh, 0, 0, 0)
gh_object.set_euler_angles(mesh, elapsed_time*7.0, elapsed_time*11.0, elapsed_time*13.0)

if (GL_ARB_tessellation_shader_ok == 1) then
  gh_gpu_program.bind(tess_prog)
  gh_gpu_program.uniform1f(tess_prog, "tessLevelOuter", outer_tess_level)
  gh_gpu_program.uniform1f(tess_prog, "tessLevelInner", inner_tess_level)
  gh_gpu_program.uniform4f(tess_prog, "color", 1, 0, 0, 1)
  gh_gpu_program.uniform4f(tess_prog, "light_position", 50, 50, 20, 1)
end

gh_object.render(mesh)



-----------------------------------------------------------------------
local show_osi = kx_get_osi_state()
kx_frame_end(show_osi)
-----------------------------------------------------------------------
		]]></raw_data>
	</script> 
	

	<script name="resize_scene" run_mode="SIZE" >
		<raw_data><![CDATA[	

kx_resize()


		]]></raw_data>
	</script> 
  
  
  
  
  
  
  <gpu_program name="tess_gs_wireframe_prog"  >
    <raw_data_vs><![CDATA[	 
#version 400
in vec4 gxl3d_Position;
void main()
{
  gl_Position = gxl3d_Position;
}
  ]]></raw_data_vs>
  
    <raw_data_tcs><![CDATA[	 
#version 400
layout(vertices = 3) out;
uniform float tessLevelOuter;
uniform float tessLevelInner;
void main()
{
  gl_TessLevelOuter[0] = tessLevelOuter;
  gl_TessLevelOuter[1] = tessLevelOuter;
  gl_TessLevelOuter[2] = tessLevelOuter;
  gl_TessLevelInner[0] = tessLevelInner;
  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
  ]]></raw_data_tcs>
  
    <raw_data_tes><![CDATA[	 
#version 400

layout(triangles, equal_spacing, ccw) in;

uniform mat4 gxl3d_ViewMatrix;
uniform mat4 gxl3d_ProjectionMatrix;
uniform mat4 gxl3d_ModelViewProjectionMatrix;

out vec3 tePosition;
out vec3 tePatchDistance;

void main()
{
  float u = gl_TessCoord.x;
  float v = gl_TessCoord.y;
  float w = gl_TessCoord.z;

  tePatchDistance = gl_TessCoord;  
  
  vec4 pos = vec4(0);
  pos.xyz += u * gl_in[0].gl_Position.xyz;
  pos.xyz += v * gl_in[1].gl_Position.xyz;
  pos.xyz += w * gl_in[2].gl_Position.xyz;
  pos.w = 1.0;
  
  tePosition = pos.xyz;

  gl_Position = gxl3d_ModelViewProjectionMatrix * pos;
}
  ]]></raw_data_tes>
  
    <raw_data_gs><![CDATA[	 
#version 400
    
uniform mat4 gxl3d_ModelViewMatrix;
uniform mat4 gxl3d_ViewMatrix;
uniform vec4 light_position;

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

in vec3 tePosition[3];
in vec3 tePatchDistance[3];

out vec3 gFaceLight;
out vec3 gFacetNormal;
out vec3 gPatchDistance;
out vec3 gTriDistance;

void main()
{
    vec3 A = tePosition[2] - tePosition[0];
    vec3 B = tePosition[1] - tePosition[0];
    vec3 N = normalize(cross(A, B));
    gFacetNormal = vec3(gxl3d_ModelViewMatrix * vec4(N, 0.0));
    gFaceLight = vec3(gxl3d_ViewMatrix * light_position);
    
    gPatchDistance = tePatchDistance[0];
    gTriDistance = vec3(1, 0, 0);
    gl_Position = gl_in[0].gl_Position; EmitVertex();
   
    gPatchDistance = tePatchDistance[1];
    gTriDistance = vec3(0, 1, 0);
    gl_Position = gl_in[1].gl_Position; EmitVertex();

    gPatchDistance = tePatchDistance[2];
    gTriDistance = vec3(0, 0, 1);
    gl_Position = gl_in[2].gl_Position; EmitVertex();
   
    EndPrimitive();
}    
  ]]></raw_data_gs>
  
  
    <raw_data_ps><![CDATA[	 
#version 400
precision highp float;
uniform mat4 gxl3d_ViewMatrix;
uniform vec4 color;
in vec3 gFaceLight;
in vec3 gFacetNormal;
in vec3 gTriDistance;
in vec3 gPatchDistance;
in float gPrimitive;
out vec4 Out_Color;

float amplify(float d, float scale, float offset)
{
  d = scale * d + offset;
  d = clamp(d, 0, 1);
  d = 1 - exp2(-2*d*d);
  return d;
}

void main()
{
  vec3 N = normalize(gFacetNormal);
  vec3 L = normalize(gFaceLight);
  
  float df = dot(N, L);
  float diffuse =  max(df, 0.0);

  vec3 color = vec3(1.0, 0.4, 0.1) * (1.0-diffuse);
  //vec3 color = vec3(0.2, 0.4, 0.5);
 
  float d1 = min(min(gTriDistance.x, gTriDistance.y), gTriDistance.z);
  float d2 = min(min(gPatchDistance.x, gPatchDistance.y), gPatchDistance.z);
  color = amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5) * color;
   
  Out_Color = vec4(color, 1.0);
}
    ]]></raw_data_ps>
  
  </gpu_program>
  
  
  
</glsl_hacker>
