Code viewer for World: Sun

// Cloned by Nathan Bonnard on 9 Aug 2018 from World "Infinite World" by Nathan Bonnard 
// Please leave this clone trail here.
 
//==============================================================================
//  Sun Prefab
//==============================================================================


//------------------------------ TWEAKER BOX ------------------------------//

const SKYDISTANCE = 3000; // Distance of stars and sun
const NBSTARS = 100; //number of stars

//------------------------------ END OF TWEAKER BOX ------------------------------//


const MAXPOS                = 4000 ;                                 
const startRadiusConst	 	= MAXPOS * 0.5 ;		// distance from centre to start the camera at
const maxRadiusConst 		= MAXPOS * 5 ;		// maximum distance from camera we will render things  

const SKYCOLOR 	= 0x6495ED;
const LIGHTCOLOR = 0xffffff ;

threehandler.MAXCAMERAPOS = MAXPOS * 10 ;// allow camera go far away 

AB.clockTick       = 20;    

// Speed of run: Step every n milliseconds. Default 100.

AB.maxSteps        = 1000000;    

// Length of run: Maximum length of run in steps. Default 1000.

AB.screenshotStep  = 50;   

// Take screenshot on this step. (All resources should have finished loading.) Default 50.

/**
 * A linear interpolator for hexadecimal colors
 * @param {Int} a
 * @param {Int} b
 * @param {Number} amount
 * @example
 * // returns 0x7F7F7F
 * lerpColor(0x000000, 0xffffff, 0.5)
 * @returns {Int}
 */
function lerpColor(a, b, amount) { 

    let ah = a;
        ar = ah >> 16, ag = ah >> 8 & 0xff, ab = ah & 0xff,
        bh = b;
        br = bh >> 16, bg = bh >> 8 & 0xff, bb = bh & 0xff,
        rr = ar + amount * (br - ar),
        rg = ag + amount * (bg - ag),
        rb = ab + amount * (bb - ab);

    return  ((1 << 24) + (rr << 16) + (rg << 8) + rb | 0);
}

/**/
function map(n, start1, stop1, start2, stop2) 
{
    return ((n-start1)/(stop1-start1))*(stop2-start2)+start2;
}



//==============================================================================
//  World Definition
//==============================================================================
function World() { 

//==============================================================================
//  All variables
//==============================================================================

var sun; //sun and all functions with it (also stars)

this.endCondition = false;

//==============================================================================
//==============================================================================

//==============================================================================
//  Sun Class
//==============================================================================

function Sun(target)
{
        this.angle = 0;

    	this.object = new THREE.DirectionalLight( 0xffffff, 0.1 );
        this.object.position.set(0, Math.cos(this.angle)*3000, Math.sin(this.angle)*3000);
        this.object.castShadow = true;
		this.object.shadow.mapSize.width = 1024;
		this.object.shadow.mapSize.height = 1024;
		this.object.shadow.camera.near = 10;
		this.object.shadow.camera.far = 4000;
        
		let d = 1000;

		this.object.shadow.camera.left = -d;
		this.object.shadow.camera.right = d;
		this.object.shadow.camera.top = d;
		this.object.shadow.camera.bottom = -d;
		this.object.shadow.bias = -0.0001;
		
		this.object.target = target;
		threeworld.scene.add(this.object);
        
        this.stars = [];
        this.starMaterial = new THREE.MeshBasicMaterial({color : "white", fog: false}) ;
        this.starMaterial.transparent = true;
        this.starMaterial.opacity = 0;
        
        let sunball = new THREE.Mesh( new THREE.SphereGeometry(100,32,32), new THREE.MeshBasicMaterial({color : "yellow", fog: false}) );
        this.object.add( sunball );
        this.starGyroscope = new THREE.Mesh();
        target.add( this.starGyroscope );
    
        
        for (let i = 0; i<NBSTARS; i++)
        {
            let radius = AB.randomFloatAtoB ( 5, 20 );
            let star = new THREE.Mesh( new THREE.SphereGeometry(radius,8,8), this.starMaterial);
            let s = AB.randomFloatAtoB ( 0, Math.PI*2 );
            let t = AB.randomFloatAtoB ( 0, Math.PI/2 );
            star.position.set(SKYDISTANCE*Math.cos(s)*Math.sin(t), SKYDISTANCE*Math.cos(t), SKYDISTANCE*Math.sin(s)*Math.sin(t));
            this.stars.push(star);
            this.starGyroscope.add(star);
        }
        
        //Use this in nextStep to make the sun move
        this.animate = function()
        {
            this.angle+=0.001;
            
            //normalize angle between -PI and PI
            while (this.angle <= -Math.PI) this.angle += Math.PI*2;
            while (this.angle > Math.PI) this.angle -= Math.PI*2;
            
            this.object.position.set(target.position.x, Math.cos(this.angle)*3000, Math.sin(this.angle)*3000 + target.position.z);
            
            this.object.intensity = this.getSunIntensity();
            
            let c = new THREE.Color(this.getSkyColor());
		    threeworld.scene.background = c;
		    threeworld.scene.fog.color = c;
		    
		    this.setStarsOpacityAndFog();
		    this.starGyroscope.rotation.set(-target.rotation.x, -target.rotation.y, -target.rotation.z);
        }
    
        //change star opacity and fog depending of the position of the sun
        this.setStarsOpacityAndFog = function()
        {
            if (this.angle > Math.PI/2  &&  this.angle < Math.PI*3/4)
            {
                soundManager.isNight = true;
                soundManager.playCurrentSound();
                this.starMaterial.opacity = map(this.angle, Math.PI/2, Math.PI*3/4, 0, 0.8);
                threeworld.scene.fog.far = 1000 + SKYDISTANCE * (1 - map(this.angle, Math.PI/2, Math.PI*3/4, 0, 0.8));
            }
            else if (this.angle > -Math.PI*3/4  &&  this.angle < -Math.PI/2)
            {
                soundManager.isNight = false;
                this.starMaterial.opacity = map(this.angle, -Math.PI*3/4, -Math.PI/2, 0.8, 0);
                threeworld.scene.fog.far = 1000 + SKYDISTANCE * (1 - map(this.angle, -Math.PI*3/4, -Math.PI/2, 0.8, 0));
            }
        }
        
        //return the color of the sky depending of the position of the sun (to get the sunrise)
        this.getSkyColor = function()
        {
            if (this.angle > -Math.PI*3/8  &&  this.angle < Math.PI*3/8)
            {
                // console.log("day");
                return 0x7ec0ee;
            }
            else if (this.angle > Math.PI*3/8  &&  this.angle < Math.PI/2)
            {
                // console.log("Sunset 1");
                return lerpColor(0x7ec0ee, 0xfd5e53, map(this.angle, Math.PI*3/8,Math.PI/2,0,1));
            }
            else if (this.angle > Math.PI/2  &&  this.angle < Math.PI*5/8)
            {
                // console.log("Sunset 2");
                return lerpColor(0xfd5e53, 0x0c3166, map(this.angle, Math.PI/2,Math.PI*5/8,0,1));
            }
            else if (this.angle > Math.PI*5/8  ||  this.angle < -Math.PI*3/4)
            {
                // console.log("night");
                return 0x0c3166;
            }
            else if (this.angle > -Math.PI*3/4  &&  this.angle < -Math.PI/2)
            {
                // console.log("Sunrise 1");
                return lerpColor(0x0c3166, 0xfd5e53, map(this.angle, -Math.PI*3/4,-Math.PI/2,0,1));
            }
            else if (this.angle > -Math.PI/2  &&  this.angle < -Math.PI*3/8)
            {
                // console.log("Sunrise 2");
                return lerpColor(0xfd5e53, 0x7ec0ee, map(this.angle, -Math.PI/2, -Math.PI*3/8, 0, 1));
            }
        }
        
        //return intensity of the sun
        this.getSunIntensity = function()
        {
            
            if (this.angle > -Math.PI*3/8  &&  this.angle < Math.PI*3/8)
            {
                return 2;
            }
            else if (this.angle > Math.PI*3/8  &&  this.angle < Math.PI/2)
            {
                return map(this.angle, Math.PI*3/8,Math.PI/2,2,1);
            }
            else if (this.angle > Math.PI/2  &&  this.angle < Math.PI*3/4)
            {
                return map(this.angle, Math.PI/2,Math.PI*3/4,1,0);
            }
            else if (this.angle > Math.PI*3/4  ||  this.angle < -Math.PI*3/4)
            {
                return 0;
            }
            else if (this.angle > -Math.PI*3/4  &&  this.angle < -Math.PI/2)
            {
                return map(this.angle, -Math.PI*3/4,-Math.PI/2,0,1);
            }
            else if (this.angle > -Math.PI/2  &&  this.angle < -Math.PI*3/8)
            {
                return map(this.angle, -Math.PI/2, -Math.PI*3/8, 1, 2);
            }
        }
}

//==============================================================================
// Function newRun ,init and endRun
//==============================================================================

this.newRun = function() 
{
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, SKYDISTANCE );
    threeworld.camera = camera;
    
    threeworld.init3d ( 0, 0, SKYCOLOR  ); 
    
    // can adjust renderer:
	threeworld.renderer.shadowMap.enabled = true;
	threeworld.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
	
	threeworld.scene.fog = new THREE.Fog(SKYCOLOR, 0, SKYDISTANCE);
	
	var geometry = new THREE.BoxGeometry( 10, 10, 10 );
    var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
    var cube = new THREE.Mesh( geometry, material );
    threeworld.scene.add( cube );

	sun = new Sun(cube);
};




this.nextStep = function()
{
    sun.animate();
};

this.endRun = function()
{
};


}