
<body onload="onLoad();">
<script src="https://portsmouth.github.io/snelly/js/compiled/snelly.min.js"></script>

<?/* ------------------------------------------------------------------*/?>
<?/*                         scene definition                          */?>
<?/* ------------------------------------------------------------------*/?>

<script type="text/javascript">

function Scene() {}
Scene.prototype.init = function(snelly)
{
	/******* copy-pasted console output on 'O', begin *******/

	let renderer  = snelly.getRenderer();
	let camera    = snelly.getCamera();
	let controls  = snelly.getControls();
	let materials = snelly.getMaterials();
		
	this.par = {};
	this.par.Iterations = 9.0169133192389;
	this.par.rotation = [71.72399755750051,74.11764705882354,69.03114186851211];
	this.par.Scale = 2.818886539816772;
	this.par.MinRad2 = 0.27061310782241016;
		
	snelly.showGUI(true);

	/** Camera settings **/
	camera.fov = 45;
	camera.aperture = -10;
	camera.focalDistance = 0.45995806856170385;
	camera.up.set(0, 1, 0);
	camera.position.set(-3.317792688241468, 2.573886057965879, -2.3232869810621244);
	controls.target.set(0.22293316198773833, 0.27007237081735647, 0.9248158372417498);

	/** Renderer settings **/
	renderer.renderMode = 'pt';
	renderer.dispersive = false;
	renderer.maxSamplesPerFrame = 1;
	renderer.maxSpp = 1024;
	renderer.maxBounces = 1;
	renderer.maxScatters = 2;
	renderer.maxMarchSteps = 100;
	renderer.maxVolumeSteps = 256;
	renderer.maxStepsIsMiss = false;
	renderer.interactive = true;
	renderer.goalFPS = 10;
	renderer.minsSPPToRedraw = 0;
	renderer.radianceClamp = 3;
	renderer.wavelengthSamples = 256;
	renderer.exposure = 0.5;
	renderer.gamma = 2.1649048625792813;
	renderer.contrast = 1;
	renderer.saturation = 1;
	renderer.skyPower = 1.024075823291703;
	renderer.skyTint = [1, 1, 1];
	renderer.envMapRotation = 0;
	renderer.envMapVisible = false;
	renderer.sunPower = 1;
	renderer.sunColor = [1, 0.8, 0.5];
	renderer.sunAngularSize = 5;
	renderer.sunLatitude = 50;
	renderer.sunLongitude = 0;
	renderer.sunVisibleDirectly = true;
	renderer.shadowStrength = 1;

	/** Material settings **/
	let surface = materials.loadSurface();
	surface.roughness = 0.020295983086680763;
	surface.ior = 2.7061310782241015;
	surface.diffuseAlbedo = [0.7842972051937939, 0.46556641231842244, 0.1075968087178024];
	surface.specAlbedo = [0.7646878602114116, 0.7646878602114116, 0.7646878602114116];

	/******* copy-pasted console output on 'O', end *******/
}


Scene.prototype.getName = function() { return 'Mandelbox'; }

Scene.prototype.getURL = function() { return "https://github.com/portsmouth/snelly/blob/master/exampleScenes/fractals/mandelbox.html"; }

Scene.prototype.initGenerator = function()
{
    return `
this.par = {};
this.par.Iterations = ${this.par.Iterations};
this.par.rotation = [${this.par.rotation}];
this.par.Scale = ${this.par.Scale};
this.par.MinRad2 = ${this.par.MinRad2};
    `;
}

Scene.prototype.shader = function()
{
	let Iterations = this.par.Iterations;
	let ColorIterations = this.par.ColorIterations;

    return `
	uniform vec3 RotVector;
	uniform float Scale;
	uniform float MinRad2;

	mat3 rot;
	vec4 scale;
	float absScalem1;
	float AbsScaleRaisedTo1mIters;
	vec3 L;

	mat3 rotationMatrix3(vec3 v, float angle)
	{
		float c = cos(radians(angle));
		float s = sin(radians(angle));
		return mat3(c + (1.0-c)*v.x*v.x,             (1.0-c)*v.x*v.y - s*v.z,     (1.0-c)*v.x*v.z + s*v.y,
			            (1.0-c)*v.x*v.y + s*v.z, c + (1.0-c)*v.y*v.y,             (1.0-c)*v.y*v.z - s*v.x,
			            (1.0-c)*v.x*v.z - s*v.y,     (1.0-c)*v.y*v.z + s*v.x, c + (1.0-c)*v.z*v.z );
	}

	void INIT()
	{
		float angle = length(RotVector);
		vec3 axis = vec3(0.0, 1.0, 0.0);
		if (angle>0.0) axis = normalize(RotVector);
		rot = rotationMatrix3(axis, angle);
		scale = vec4(Scale, Scale, Scale, abs(Scale)) / MinRad2;
		absScalem1 = abs(Scale - 1.0);
		const int Iterations = int(${Iterations});
		AbsScaleRaisedTo1mIters = pow(abs(Scale), float(1-Iterations));
	}

	float mandelbox(vec3 pos)
	{
		vec4 p = vec4(pos,1);
		vec4 p0 = p;  // p.w is the distance estimate
		const int Iterations = int(${Iterations});
		for (int i=0; i<Iterations; i++)
		{
			p.xyz *= rot;
			p.xyz = clamp(p.xyz, -1.0, 1.0)*2.0 - p.xyz;
			float r2 = dot(p.xyz, p.xyz);
			p *= clamp(max(MinRad2/r2, MinRad2), 0.0, 1.0);
			p = p*scale + p0;
	        if (r2>1000.0) break;
		}
		return ((length(p.xyz) - absScalem1) / p.w - AbsScaleRaisedTo1mIters);
	}

    float SDF_SURFACE(in vec3 X)
    {
        return mandelbox(X);
    }


    `;
}

Scene.prototype.getLengthScale = function()    { return 1.0; }
Scene.prototype.getMinLengthScale = function() { return 1.0e-4 * this.getLengthScale(); }
Scene.prototype.getMaxLengthScale = function() { return 1.0e2 * this.getLengthScale(); }

Scene.prototype.envMap = function()
{ return 'https://portsmouth.github.io/envmaps/HDR_112_River_Road_2_Bg.jpg'; }

Scene.prototype.initGui = function(gui)
{
    gui.addSlider(this.par, {name: 'Iterations', min: 1, max: 10, step: 1, recompile: true});
    gui.addSlider(this.par, {name: 'Scale', min: 0.0, max: 10.0});
    gui.addSlider(this.par, {name: 'MinRad2', min: 0.0, max: 1.0});
	gui.addColor(this.par, "rotation", 180.0);
}

Scene.prototype.syncShader = function(snelly, shader)
{
	shader.uniformF("Scale", this.par.Scale);
	shader.uniformF("MinRad2", this.par.MinRad2);
	shader.uniform3Fv("RotVector", this.par.rotation);
}

</script>

<?/* ------------------------------------------------------------------*/?>
<?/*                            main loop                              */?>
<?/* ------------------------------------------------------------------*/?>

<script type="text/javascript">
function onLoad() { snelly = new Snelly(new Scene()); animateLoop(); }
function animateLoop() { snelly.render(); window.requestAnimationFrame(animateLoop); }
</script>

</body>
