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

<glsl_hacker>
	
  <window name="win3d01" title="MadShaders - GLSLSandbox/#2902.4" 
          width="800" height="400"
          gl_version_major="2" gl_version_minor="1" />
          
         
<gpu_program name="glslsandbox_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[	 

// http://glsl.heroku.com/e#2902.4

// too many damn distance fields on glsl sandbox,
// how about some volume rendering?!
// @simesgreen

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;
uniform float time;
//uniform vec2 mouse;
//uniform float zoom;

uniform vec2 surfaceSize;
//uniform vec2 surfacePosition;

const int _VolumeSteps = 64;
const float _StepSize = 0.05; 
const float _Density = 0.2;

const float _SphereRadius = 3.0;
const float _NoiseFreq = 3.0;
const float _NoiseAmp = 6.0;
const vec3 _NoiseAnim = vec3(0, 0.0, 0);

// iq's nice integer-less noise function

// matrix to rotate the noise octaves
mat3 m = mat3( 0.00,  0.80,  0.60,
              -0.80,  0.36, -0.48,
              -0.60, -0.48,  0.64 );

float hash( float n )
{
    return fract(sin(n)*43758.5453);
}


float noise( in vec3 x )
{
    vec3 p = floor(x);
    vec3 f = fract(x);

    f = f*f*(3.0-2.0*f);

    float n = p.x + p.y*57.0 + 113.0*p.z;

    float res = mix(mix(mix( hash(n+  0.0), hash(n+  1.0),f.x),
                        mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y),
                    mix(mix( hash(n+113.0), hash(n+114.0),f.x),
                        mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
    return res;
}

float fbm( vec3 p )
{
    float f;
    f = 0.5000*noise( p ); p = m*p*2.02;
    f += 0.2500*noise( p ); p = m*p*2.03;
    f += 0.1250*noise( p ); p = m*p*2.01;
    f += 0.0625*noise( p );
    //p = m*p*2.02; f += 0.03125*abs(noise( p ));  
    return f;
}

// returns signed distance to surface
float distanceFunc(vec3 p)
{  
  float d = length(p) - _SphereRadius;  // distance to sphere
  
  // offset distance with pyroclastic noise
  //p = normalize(p) * _SphereRadius;  // project noise point to sphere surface
  d += fbm(p*_NoiseFreq) * _NoiseAmp;
  return d;
}

// color gradient 
// this should be in a 1D texture really
vec4 gradient(float x)
{
  // no constant array initializers allowed in GLES SL!
  const vec4 c0 = vec4(2, 2, 1, 1);  // yellow
  const vec4 c1 = vec4(1, 0, 0, 1);  // red
  const vec4 c2 = vec4(0, 0, 0, 0);   // black
  const vec4 c3 = vec4(0, 0.5, 1, 0.5);   // blue
  const vec4 c4 = vec4(0, 0, 0, 0);   // black
  
  x = clamp(x, 0.0, 0.999);
  float t = fract(x*4.0);
  vec4 c;
  if (x < 0.25) {
    c =  mix(c0, c1, t);
  } else if (x < 0.5) {
    c = mix(c1, c2, t);
  } else if (x < 0.75) {
    c = mix(c2, c3, t);
  } else {
    c = mix(c3, c4, t);    
  }
  //return vec4(x);
  //return vec4(t);
  return c;
}

// shade a point based on distance
vec4 shade(float d)
{  
  // lookup in color gradient
  //vec4 c = gradient(d);
  //return c;
  //return  gradient(d);
  //return mix(vec4(1, 1, 1, 1), vec4(0, 0, 0, 0), smoothstep(0.9, 1.4, d));

  vec4 c = gradient(d)*0.6 +  mix(vec4(1, 1, 1, 1), vec4(0, 0, 0, 0), smoothstep(0.9, 1.4, d))*0.4;
  return c;


}

// procedural volume
// maps position to color
vec4 volumeFunc(vec3 p)
{
  float d = distanceFunc(p);
  return shade(d);
}

// ray march volume from front to back
// returns color
vec4 rayMarch(vec3 rayOrigin, vec3 rayStep, out vec3 pos)
{
  vec4 sum = vec4(0, 0, 0, 0);
  pos = rayOrigin;
  for(int i=0; i<_VolumeSteps; i++) {
    vec4 col = volumeFunc(pos);
    col.a *= _Density;
    //col.a = min(col.a, 1.0);
    
    // pre-multiply alpha
    col.rgb *= col.a;
    sum = sum + col*(1.0 - sum.a);  
#if 0
    // exit early if opaque
          if (sum.a > _OpacityThreshold)
                break;
#endif    
    pos += rayStep;
  }
  return sum;
}

void main(void)
{
    //vec2 q = gl_FragCoord.xy / resolution.xy;
    //vec2 p = -1.0 + 2.0 * q;

    vec2 q = gl_TexCoord[0].xy *2.0 - 1.0;
    vec2 p = q;
    
    p.x *= resolution.x/resolution.y;
  
    //float rotx = mouse.y*4.0;
    //float roty = - mouse.x*4.0;
    float rotx = time*0.3;
    float roty = time * 0.5;

    //float zoom = 5.0*surfaceSize.y;
    float zoom = 5.0;

    // camera
    vec3 ro = zoom*normalize(vec3(cos(roty), cos(rotx), sin(roty)));
    vec3 ww = normalize(vec3(0.0,0.0,0.0) - ro);
    vec3 uu = normalize(cross( vec3(0.0,1.0,0.0), ww ));
    vec3 vv = normalize(cross(ww,uu));
    vec3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww );

    ro += rd*2.0;
  
    // volume render
    vec3 hitPos;
    vec4 col = rayMarch(ro, rd*_StepSize, hitPos);
    //vec4 col = gradient(p.x);
      
    gl_FragColor = col;
}  ]]></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)
glslsandbox_prog = moon3d.graphics.getGpuProgram("glslsandbox_prog")

local cam = moon3d.camera.getDefaultPersp()
moon3d.camera.setPosition(cam, 0, 0, 400)

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.bindPersp()

moon3d.graphics.bindGpuProgram(glslsandbox_prog)
moon3d.madshaders.updateGLSLSandboxCommonParams(glslsandbox_prog, global_time)
moon3d.graphics.draw(quad)

moon3d.madshaders.displayBenchmarkInfoV2("GLSLSandbox/#2902.4", 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>
