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

<glsl_hacker>
	
  <window name="win3d01" title="MadShaders - Shadertoy/mobius balls" 
          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/XsX3R4
  
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 samplerCube iChannel0; // cubemap
uniform sampler2D iChannel1; // tex01.jpg
uniform sampler2D iChannel2; // tex09.jpg


float pi = 3.141592;

vec2 r(vec2 v,float y)
{
    return cos(y)*v+sin(y)*vec2(-v.y,v.x);
}
 
vec3 textureAVG(samplerCube tex, vec3 tc) {
    const float diff0 = 0.35;
    const float diff1 = 0.12;
 	vec3 s0 = textureCube(tex,tc).xyz;
    vec3 s1 = textureCube(tex,tc+vec3(diff0)).xyz;
    vec3 s2 = textureCube(tex,tc+vec3(-diff0)).xyz;
    vec3 s3 = textureCube(tex,tc+vec3(-diff0,diff0,-diff0)).xyz;
    vec3 s4 = textureCube(tex,tc+vec3(diff0,-diff0,diff0)).xyz;
    
    vec3 s5 = textureCube(tex,tc+vec3(diff1)).xyz;
    vec3 s6 = textureCube(tex,tc+vec3(-diff1)).xyz;
    vec3 s7 = textureCube(tex,tc+vec3(-diff1,diff1,-diff1)).xyz;
    vec3 s8 = textureCube(tex,tc+vec3(diff1,-diff1,diff1)).xyz;
    
    return (s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8) * 0.111111111;
}

float somestep(float t)
{
    return pow(t, 4.0);
}

vec3 smin(vec3 a, vec3 b)
{
    if (a.x < b.x)
        return a;
    
    return b;
}

vec3 smax(vec3 a, vec3 b)
{
	if (a.x > b.x)
        return a;
    
    return b;
}

vec3 sinv(vec3 a)
{
	return vec3(-a.x, a.y, a.z);    
}

vec3 textureBlured(samplerCube tex, vec3 tc) {
   	vec3 r = textureAVG(tex,vec3(1.0,0.0,0.0));
    vec3 t = textureAVG(tex,vec3(0.0,1.0,0.0));
    vec3 f = textureAVG(tex,vec3(0.0,0.0,1.0));
    vec3 l = textureAVG(tex,vec3(-1.0,0.0,0.0));
    vec3 b = textureAVG(tex,vec3(0.0,-1.0,0.0));
    vec3 a = textureAVG(tex,vec3(0.0,0.0,-1.0));
        
    float kr = dot(tc,vec3(1.0,0.0,0.0)) * 0.5 + 0.5; 
    float kt = dot(tc,vec3(0.0,1.0,0.0)) * 0.5 + 0.5;
    float kf = dot(tc,vec3(0.0,0.0,1.0)) * 0.5 + 0.5;
    float kl = 1.0 - kr;
    float kb = 1.0 - kt;
    float ka = 1.0 - kf;
    
    kr = somestep(kr);
    kt = somestep(kt);
    kf = somestep(kf);
    kl = somestep(kl);
    kb = somestep(kb);
    ka = somestep(ka);    
    
    float d;
    vec3 ret;
    ret  = f * kf; d  = kf;
    ret += a * ka; d += ka;
    ret += l * kl; d += kl;
    ret += r * kr; d += kr;
    ret += t * kt; d += kt;
    ret += b * kb; d += kb;
    
    return ret / d;
}

//repeat around y axis n times
void rp(inout vec3 p, float n) {
	float w = 2.0*pi/n;
	float a = atan(p.z, p.x);
	float r = length(p.xz);
	a = mod(a+pi*.5, w)+pi-pi/n;
	p.xz = r*vec2(cos(a),sin(a));
}

vec3 moebius(vec3 p, vec3 q)
{
  float a = atan(p.z,p.x);
  vec2 p2 = vec2(length(p.xz),p.y);
  p2.x -= q.z;
  p2 = r(p2, a*0.5);
  vec2 p3 = r(p2, pi/4.0);
  vec2 tc = vec2(p3.y,a);
  float d = abs(p2.y)-q.x;
  d = max(d,abs(p2.x)-q.y);
  return vec3(d, tc);
}
 
vec3 dualmoebius(vec3 p)
{
	float bandSize = 1.5;
	float radius = 5.0;
	float bandThickness = 0.75;
	return smax(moebius(p, vec3(bandSize, bandThickness, radius)), sinv(moebius(p, vec3(bandSize - bandThickness, bandThickness+0.1, radius))));
}
 
vec3 sphere(vec3 p, float r)
{
    vec3 n = normalize(p);
    vec2 tc = asin(n.xz)/pi + 0.5;
	return vec3(length(p) - r, tc * 2.0);
}

vec3 spheres(vec3 p)
{
	rp(p, 12.0);
	p.x += 5.0;
	return sphere(p, 0.75);	
}

vec3 f( vec3 p )
{
	vec2 mouse = vec2(sin(iGlobalTime), cos(iGlobalTime));//iMouse.xy / iResolution.xy;
	//p.xz = r(p.xz, mouse.x);
	p.yz = r(p.yz, 0.1 * iGlobalTime);
    
    vec3 q = p;
	q.xz = r(q.xz, 0.5 * iGlobalTime);
    
	return smin(sphere(p, 3.0), smin(spheres(q), dualmoebius(q)));
}

vec4 getcolor(vec3 hit, vec3 ray, vec3 normal, float t, vec3 d) 
{
    vec4 background = vec4(textureCube(iChannel0, ray).xyz, 0.0);
    if( t < 26.0 )
    {
        // material
        float fresnel_pow = 2.0;
        float fresnel_bias = 0.125;
        float color_intensity = 1.5;
        float roughness_bias = 1.5;
        float roughness_coverage = 0.2;
        float shininess = 0.6;
        
        vec3 color_mod = (0.5+0.5*texture2D(iChannel1, d.yz).rgb) * color_intensity;
                
        // IBL
        vec3 ibl_diffuse = textureBlured(iChannel0,normal);
        
        // fresnel
        float fresnel = fresnel_bias + (1.0 - fresnel_bias) * max(1.0 - dot(normal,-ray), 0.0);
        fresnel = pow(fresnel,fresnel_pow);
        
        // surface roughness
        float rough = (1.0 - roughness_bias) + roughness_bias * length(texture2D(iChannel2, d.yz * 0.1).rgb);
        rough = 1.0 - ((1.0-rough) * smoothstep(0.4, 0.6, length(ibl_diffuse)));
        rough *= min(1.0, pow(length(color_mod), 2.0));
        
        vec4 foreground = vec4(((1.0 - roughness_coverage) + roughness_coverage * rough) * ibl_diffuse * color_mod, max(0.0, min(1.0, shininess * fresnel * rough)));
        return mix(foreground, background, smoothstep(0.0, 0.005, dot(normal, ray)));
    } 
    else 
    {   
        return background;
    }
}

// ao
float ao(vec3 v, vec3 n) 
{
    const int ao_iterations = 10;
    const float ao_step = 0.2;
    const float ao_scale = 0.75;
    
	float sum = 0.0;
	float att = 1.0;
	float len = ao_step;
    
	for (int i = 0; i < ao_iterations; i++)
    {
		sum += (len - f(v + n * len).x) * att;		
		len += ao_step;		
		att *= 0.5;
	}
	
	return 1.0 - max(sum * ao_scale, 0.0);
}

void main()
{
    gl_FragColor.xyz = vec3(0);
    
    vec3 q = vec3((gl_FragCoord.xy / iResolution.xy - 0.5), 1.0); 
    q.x *= iResolution.x / iResolution.y;
    vec3 p = vec3(0, 0.0, -10.0);
    q = normalize(q);

    p.xz = r(p.xz, 0.05*iGlobalTime);
    q.xz = r(q.xz, 0.05*iGlobalTime);

    const int reflectionCount = 3;
    const int raymarchingSteps = 80;
    vec3 colors[reflectionCount];
    float factors[reflectionCount];
    int reflections = 0;
    for (int iter = 0; iter < reflectionCount; ++iter)
    {
        float t=0.;
        vec3 d = vec3(0);
        float steps = 0.0;
        for (int tt=0; tt < raymarchingSteps; ++tt )
        {
            d = f(p+q*t);
            t += d.x * 0.95;
            if( !(t<=26.0)||d.x<=0.000001)
            {
                break;
            }
            steps = float(tt);
        }

        vec3 hit = p+q*t;

        vec2 e = vec2(0.001, 0.00);
        vec3 normal= vec3( f(hit + e.xyy).x - f(hit - e.xyy).x, f(hit + e.yxy).x - f(hit - e.yxy).x, f(hit + e.yyx).x - f(hit - e.yyx).x);
        normal= normalize(normal);
        
        vec4 color = getcolor(hit, q, normal, t, d);
        colors[iter] = color.rgb * (1.0 - color.w) * ao(hit, normal);
        factors[iter] = color.w;
        if (t >= 26.0)
            break;

        ++reflections;
        q = reflect(q, normal);
        p = hit + q * 0.001;   
    }

    float factor = 1.0;
    for (int i = 0; i < reflectionCount; ++i)
    {
        gl_FragColor.xyz += factor * colors[i];
        factor *= factors[i] * 1.5;

        if (i >= reflections)
            break;        
    }
}
]]></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")

cubemap = moon3d.image.loadCubeMap("./data/cubemap01_posx.jpg", "./data/cubemap01_negx.jpg", "./data/cubemap01_posy.jpg", "./data/cubemap01_negy.jpg", "./data/cubemap01_posz.jpg", "./data/cubemap01_negz.jpg")
tex1 = moon3d.image.load2d("./data/tex01.jpg")
tex2 = moon3d.image.load2d("./data/tex09.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, cubemap, 0)
moon3d.madshaders.setShadertoyTexture(shadertoy_prog, tex1, 1)
moon3d.madshaders.setShadertoyTexture(shadertoy_prog, tex2, 2)

moon3d.graphics.draw(quad)

moon3d.madshaders.displayBenchmarkInfoV2("Shadertoy/mobius balls", 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>
