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

<glsl_hacker>
	
  <window name="win3d01" title="MadShaders - Shadertoy/magica voxel" 
          width="800" height="400"
          gl_version_major="2" gl_version_minor="1" />
          
          
<gpu_program name="shadertoy_prog" >
	<raw_data_vs><![CDATA[	 
void main()
{	
	gl_TexCoord[0] = gl_MultiTexCoord0;
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;		
}
  ]]></raw_data_vs>
  
	<raw_data_ps><![CDATA[	 

// https://www.shadertoy.com/view/MdBGRm
  
uniform vec3      iResolution;     // viewport resolution (in pixels)
uniform float     iGlobalTime;     // shader playback time (in seconds)
uniform vec4      iMouse;          // mouse pixel coords. xy: current (if MLB down), zw: click
uniform sampler2D iChannel0;
uniform vec3 iChannelResolution0;

// math const
const float PI = 3.14159265359;
const float DEG_TO_RAD = PI / 180.0;

// height map
float voxel( vec3 pos ) {
	pos = floor( pos );
	float density = texture2D( iChannel0, pos.xz / 2048.0 ).x;
	return step( pos.y, floor( density * 32.0 ) );
}

// improvement based on fb39ca4's implementation to remove most of branches :
// https://www.shadertoy.com/view/4dX3zl
// min | x < y | y < z | z < x
//  x  |   1   |   -   |   0  
//  y  |   0   |   1   |   -  
//  z  |   -   |   0   |   1  
float ray_vs_world( vec3 pos, vec3 dir, out vec3 mask, out vec3 center ) {
	// grid space
	vec3 grid = floor( pos );
	vec3 grid_step = sign( dir );
	vec3 corner = max( grid_step, vec3( 0.0 ) );
	
	// ray space
	vec3 inv = vec3( 1.0 ) / dir;
	vec3 ratio = ( grid + corner - pos ) * inv;
	vec3 ratio_step = grid_step * inv;
	
	// dda
	float hit = -1.0;
	for ( int i = 0; i < 128; i++ ) {
		if ( voxel( grid ) > 0.5 ) {
			hit = 1.0;
			continue;
		}

		vec3 cp = step( ratio, ratio.yzx );

		mask = cp * ( vec3( 1.0 ) - cp.zxy );
		
		grid  += grid_step  * mask;		
		ratio += ratio_step * mask;
	}
	
	center = grid + vec3( 0.5 );
	return dot( ratio - ratio_step, mask ) * hit;
}

// improvement based on iq's implementation to remove lots of redundant texture accesses :
// https://www.shadertoy.com/view/4dfGzs
void occlusion( vec3 v, vec3 n, out vec4 side, out vec4 corner ) {
	vec3 s = n.yzx;
	vec3 t = n.zxy;

	side = vec4 (
		voxel( v - s ),
		voxel( v + s ),
		voxel( v - t ),
		voxel( v + t )
	);
	
	corner = vec4 (
		voxel( v - s - t ),
		voxel( v + s - t ),
		voxel( v - s + t ),
		voxel( v + s + t )
	);
}

float filter( vec4 side, vec4 corner, vec2 tc ) {
	vec4 v = side.xyxy + side.zzww + corner;

	return mix( mix( v.x, v.y, tc.y ), mix( v.z, v.w, tc.y ), tc.x ) * 0.25;
}

float ao( vec3 v, vec3 n, vec2 tc ) {
	vec4 side, corner;
	
	occlusion( v + n, abs( n ), side, corner );
	
	return 1.0 - filter( side, corner, tc );
}

float edge( vec3 v, vec3 n, vec2 tc ) {
	float scale = 1.0 / 12.0;
	tc = fract( tc / scale );
	n *= scale;

	v += abs( n.yzx ) * ( -tc.y + 0.5 );
	v += abs( n.zxy ) * ( -tc.x + 0.5 );

	vec4 side_l, side_h, corner_l, corner_h;
		
	occlusion( v - n, abs( n ), side_l, corner_l );
	occlusion( v + n, abs( n ), side_h, corner_h );

	return 1.0 - filter(
		vec4( 1.0 ) -   side_l * ( vec4( 1.0 ) -   side_h ),
		vec4( 1.0 ) - corner_l * ( vec4( 1.0 ) - corner_h ),
		tc
	);
}

float grid( vec2 tc ) {
	tc = abs( tc - vec2( 0.5 ) );

	return 1.0 - pow( max( tc.x, tc.y ) * 1.6, 10.0 );
}

// pitch, yaw
mat3 rot3xy( vec2 angle ) {
	vec2 c = cos( angle );
	vec2 s = sin( angle );
	
	return mat3(
		c.y      ,  0.0, -s.y,
		s.y * s.x,  c.x,  c.y * s.x,
		s.y * c.x, -s.x,  c.y * c.x
	);
}

// get ray direction
vec3 ray_dir( float fov, vec2 size, vec2 pos ) {
	vec2 xy = pos - size * 0.5;

	float cot_half_fov = tan( ( 90.0 - fov * 0.5 ) * DEG_TO_RAD );	
	float z = size.y * 0.5 * cot_half_fov;
	
	return normalize( vec3( xy, -z ) );
}

vec3 ray_dir_spherical( float fov, vec2 size, vec2 pos ) {
	vec2 angle = ( pos - vec2( 0.5 ) * size ) * ( fov / size.y * DEG_TO_RAD );

	vec2 c = cos( angle );
	vec2 s = sin( angle );
	
	return normalize( vec3( c.y * s.x, s.y, -c.y * c.x ) );
}

// phong shading
vec3 shading( vec3 v, vec3 n, vec3 eye ) {
	vec3 final = vec3( 0.0 );
	
	// light 0
	{
		vec3 light_pos = vec3( 100.0, 110.0, 150.0 );
		vec3 light_color = vec3( 1.0 );
		vec3 vl = normalize( light_pos - v );
		float diffuse  = max( 0.0, dot( vl, n ) );
		final += light_color * diffuse;
	}
	
	// light 1
	{
		vec3 light_pos = -vec3( 100.0, 110.0, 120.0 );
		vec3 light_color = vec3( 1.0 );
		vec3 vl = normalize( light_pos - v );
		float diffuse  = max( 0.0, dot( vl, n ) );
		final += light_color * diffuse;
	}

	return final;
}

void main(void)
{
	// default ray dir
	vec3 dir = ray_dir_spherical( 60.0, iResolution.xy, gl_FragCoord.xy );
	
	// default ray origin
	vec3 eye = vec3( 0.0, 0.0, 56.0 );

	// rotate camera
	mat3 rot = rot3xy( vec2( -DEG_TO_RAD * 34.0, iGlobalTime * 0.1 ) );
	dir = rot * dir;
	eye = rot * eye;
	
	dir = normalize( dir );
	
	// grid traversal
	vec3 mask;
	vec3 center;
	float depth = ray_vs_world( eye, dir, mask, center );

	vec3 p = eye + dir * depth;
	vec3 n = -mask * sign( dir );

	vec2 tc =
		( fract( p.yz ) * mask.x ) +
		( fract( p.zx ) * mask.y ) +
		( fract( p.xy ) * mask.z );
	
	// attenuation
	float k_att = min( 1.0, 600.0 / depth / depth );

	// ambient occlusion
	float k_ao = ao( center, n, tc );
	
	// grid
	float k_grid = grid( tc );
	
	// edge
	float k_edge = edge( p, n, tc );
	
	// color
	vec3 color = shading( p, n, eye ) * (
		k_att *
		k_ao *
		k_grid *
		k_edge * k_edge *
		1.8
		);
	
	gl_FragColor = vec4( color, 1.0 );
}  ]]></raw_data_ps>

</gpu_program>

 
	<script name="init_scene" run_mode="INIT" >
		<raw_data><![CDATA[	

app_dir = gh_utils.get_scripting_libs_dir() 		
dofile(app_dir .. "lua/Moon3D_v2.lua")

moon3d.init(2, 1)
moon3d.graphics.vsync(0)

bmfont = moon3d.font.create("trebuchet_20px.fnt", "data/")
bmfont_texture = moon3d.font.getTexture(bmfont)
moon3d.madshaders.setBmFontData(bmfont, bmfont_texture)

winW, winH = moon3d.window.getSize()

quad = moon3d.graphics.newQuad(winW, winH)
shadertoy_prog = moon3d.graphics.getGpuProgram("shadertoy_prog")

tex0 = moon3d.image.load2d("./data/tex01.jpg")

moon3d.madshaders.resetBenchmarkData()

		]]></raw_data>
	</script> 

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

moon3d.startFrame(0, 0, 0, 1)

local global_time = moon3d.getTime()

moon3d.madshaders.updateBenchmarkData(global_time)

moon3d.camera.bindOrtho()

moon3d.graphics.bindGpuProgram(shadertoy_prog)
moon3d.madshaders.updateShadertoyCommonParams(shadertoy_prog, global_time)
moon3d.madshaders.setShadertoyTexture(shadertoy_prog, tex0, 0)
moon3d.graphics.draw(quad)

moon3d.madshaders.displayBenchmarkInfoV2("Shadertoy/magica voxel", global_time, 1, 1, 1, 1)

moon3d.endFrame()

		]]></raw_data>
	</script> 
	

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

moon3d.window.resize()
winW, winH = moon3d.window.getSize()
moon3d.graphics.resizeQuad(quad, winW, winH)

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