Code viewer for World: Complete Infinite World (c...

// Cloned by Leigh Reilly on 30 Nov 2022 from World "Complete Infinite World" by Enhanced 
// Please leave this clone trail here.
 
//==============================================================================
//  Welcome to the Infinite world !
//==============================================================================

// This program was made by Nathan Bonnard.
// In this world, you can generate an infinite world ! 
// But this isn't really infinite, it would be impossible, 
// the world do a simple loop when the player reach the border. Like in real life !
// This world isn't a kind of game with specific goal, just enjoy the landscapes and all objects !
// 
// The first purpose of this world was to create an exploration world to just enjoy good views and the fact that it is infinite 
// Finally it became a sort of Minecraft, I wanted to create that type of game but with complex 3D Objects, not cubes.
// I wanted to demonstrate the power of javascript and Three.js : we can create big world with a lot of objects even in a browser
// Also, the aim is to encourage people using the first person view on worlds or the sun that you can find on Enhanced World.
// If you want to change the world by yourself, it would be a bit hard to get into 2000 lines of code, 
// but you can simply change some letiables and see the effects. Here are those letiables :

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

const squaresize = 5 ; // The world is like a infinite grid of square. squaresize is the size of a square
var MOVESPEED = 7; // Speed of the player

var viewDistance = 2; // determinate the maximum distance to see ground (viewDistance * squaresize * groundMultiplier)
var groundMultiplier = 551; // The world is divided by zone (grounds) that size groundMultiplier*squaresize
var worldSize = 13; // dimension of the world, it is not really infinite but big and can loop. There is worldSize * worldSize Grounds 

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

//Where all textures and objects are
const PATHTEXTURES = "/uploads/meak/";

//Limit between rare and small objects (in term of size, obviously here a castle size is bigger than 4 but a rock is not)
//Care it depends on the squaresize letiable. If you increase squaresize, you should also decrease this letiable
const limitSizeForRareObjects = 2;

//Number of maximum element that can be pose in each ground. You can change this after running the world
var maxElementsForest = 300;
var maxElementsSnow = 90;
var maxElementsSand = 60;

//Determine if the world can or not generate different type of ground. You can change this after running the world
var enableSand = true;
var enableSnow = true;
var enableForest = true;

//Path of sounds that are played during the game depending on what type of ground you are walking on
// const SOUNDFOREST = "/uploads/meak/forestsound.mp3";
// const SOUNDSNOW = "/uploads/meak/snowsound.mp3";
// const SOUNDSAND = "/uploads/meak/sandsound.mp3";
// const SOUNDNIGHT = "/uploads/meak/nightsound.mp3";

//Objects that are loaded for each type of ground. Add some Objects that you found on the internet and see !
//For that it need to be an Object3D (.obj) with a material (.mtl).
//If the material need some texture, upload those textures too.
const ARRAYOBJECTSFOREST = {
    "tree2":40,
    "lowpolytree":30,
    "castle-tower":0.5,
    "WoodenCabinObj":1,
    "houseA_obj":1,
    "tree13":30
    };

const ARRAYOBJECTSSNOW = {
    "castle-tower":0.5,
    "Stone":15,
    "kardanadam":2,
    "WoodenCabinObj":1,
    "Rock2":1
    };
    
const ARRAYOBJECTSSAND = {
    "castle-tower":0.5,
    "Cactus":10,
    "Stone":15,
    "WoodenCabinObj":1,
    "houseA_obj":1,
    "Rock2":1
    };

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

var newviewDistance = viewDistance; // letiables to re-generate the world with new letiables 
var newGroundMultiplier = groundMultiplier;
var newworldSize = worldSize;

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 ;

//all type of Grounds
const TYPEGROUND = ["SNOW", "FOREST", "SAND"];

//used to manage the click and give back control to the user when you click on a button/text box 
//and don't want to enter into first person mode
var HUDEVENT = false;
var mouse; // vector2 : position of the mouse on the screen

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

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 objects; // Stock all the prefabs of objects
var groundTexture; // Texture of the ground
var snowTexture; // Texture of the ground
var sandTexture; // Texture of the ground
var transitionTextureSnow;
var transitionTextureSand;
var transitionTextureForest;
var loaded = false; // True when everything is loaded
var grounds; // Array2d : Stock all ground of the world, with objects on it (recurrentObjects...)
var ai, aj; // position in grounds of the player
var pai, paj; // past position in grounds of the player
var modeOfView = 0; //0 : first person --- 1 : third person
var timeRunning = 0; // time updated 
var raycaster; // to determine direction of a click

var camera, controls;

var moveForward = false;
var moveBackward = false;
var moveLeft = false;
var moveRight = false;
var canJump = false;

var prevTime = performance.now();
var velocity = new THREE.Vector3();
var direction = new THREE.Vector3();
var vertex = new THREE.Vector3();
var color = new THREE.Color();

//var sun;//sun and all functions with it (also stars)
var loadingManager;//loading manager to load everything and thenrun the program

//var soundManager;//Object that manage the sound depending of the position of the player
var saving; //Object that store all informations to save the world

var offsetGround = 0.001;//letiable to avoid that grounds "bug" when they to parcels are overlapping
var userObjects = [];//store all objects that were pose by the player in edit mode
var allObjects = [];//allTypeOfObjects tht can be created by the player in edit mode
var indexObjects = 0;//Usefull to manage userObjects

var rayToDestroy;
var selectionBox =  new THREE.Mesh();
var selectionObject = null;
var editMode = null;


this.endCondition = false;
}
//==============================================================================
//==============================================================================

//==============================================================================
//  All Class
//==============================================================================

//==============================================================================
//  Defines the THREE.PointerLockControls class, source at https://threejs.org/
//==============================================================================

THREE.PointerLockControls = function(camera) {

	let scope = this;

	camera.rotation.set( 0, 0, 0 );

	let pitchObject = new THREE.Object3D();
	pitchObject.add( camera );

	let yawObject = new THREE.Object3D();
	yawObject.position.y = 10;
	yawObject.add( pitchObject );
    
    let attachedObject = new THREE.Object3D();
    yawObject.add(attachedObject);
    attachedObject.position.set(0,-yawObject.position.y,-150);
    
    
	let PI_2 = Math.PI / 2;

	let onMouseMove = function ( event ) {
		if ( scope.enabled === false ) return;
        
        if(editMode == 1)
	    {
	        if(controls.getAttachedObject().children.length != 0)
            {
    	        controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
                controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);
            }
            DestroyObject(event);
	    }
	    
		let movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
		let movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;

		yawObject.rotation.y -= movementX * 0.002;
		pitchObject.rotation.x -= movementY * 0.002;

		pitchObject.rotation.x = Math.max( - PI_2, Math.min( PI_2, pitchObject.rotation.x ) );

	};
    
    this.getAttachedObject = function () {

		return attachedObject;

	};

	this.dispose = function () {

		document.removeEventListener( 'mousemove', onMouseMove, false );
	};

	document.addEventListener( 'mousemove', onMouseMove, false );

	this.enabled = false;

	this.getObject = function () {

		return yawObject;

	};

	this.getDirection = function () {

		// assumes the camera itself is not rotated

		let direction = new THREE.Vector3( 0, 0, - 1 );
		let rotation = new THREE.Euler( 0, 0, 0, 'YXZ' );

		return function ( v ) {

			rotation.set( pitchObject.rotation.x, yawObject.rotation.y, 0 );

			v.copy( direction ).applyEuler( rotation );

			return v;

		};

	}();

};

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

//Class to save the world
// class SaveWorld
// {
//   constructor(dim, mult, viewDistance) 
//   {
//       this.worldSize = dim;
//       this.groundMultiplier = mult;
//       this.viewDistance = viewDistance;
      
//       this.grounds = new Array(dim);
//       for(let i = 0; i < this.grounds.length; i++)
//       {
//           this.grounds[i] = new Array(dim);
//           for(let j = 0; j < this.grounds[i].length; j++)
//           {
//               this.grounds[i][j] = {biom: "", elements:[]};
//           }
//       }
      
//       this.userObjects = [];
//   }
// }

// Class to stock Each Objects that were loaded 
// with their combobox size to place them in space
// and to avoid collision ( objects at same place)
class Obj
{
  constructor(nameDoc, sX, sY, sZ) 
  {
      this.path = nameDoc;
      this.sizeX = sX;
      this.sizeY = sY;
      this.sizeZ = sZ;
      this.obj;
  }
}

//Class that determine if a ground is active or not
//And stock the ground with all the objects attached
class Ground
{
  constructor(act, pos) 
  {
      this.active = act;
      this.ground;
      this.type;
  }
}

//Class that stock all the objects of all types
class ObjectsConteneur
{
  constructor() 
  {
      this.objectsForest = new ObjectsOfType("FOREST");
      this.objectsSand = new ObjectsOfType("SAND");
      this.objectsSnow = new ObjectsOfType("SNOW");
  }
}

//Class that stock all the objects of the different type
class ObjectsOfType
{
  constructor(type) 
  {
      this.type = type;
      this.recurrentObjects = [];
      this.rareObjects = [];
  }
}

//Class that deal with the sound
// class SoundManager
// {
//   constructor() 
//   {
//     let listener = new THREE.AudioListener();
//     threeworld.camera.add( listener );
        
//     // create a global audio source
//     this.soundForest = new THREE.Audio( listener );
//     this.soundSand = new THREE.Audio( listener );
//     this.soundSnow = new THREE.Audio( listener );
//     this.soundNight = new THREE.Audio( listener );

//     this.currentSound = null;
//     this.isNight = false;
//   }
  
//   playCurrentSound()
//   {
//       if(this.currentSound != null)
//         {
//             if(this.isNight)
//             {
//                 this.soundNight.setVolume(0);
//                 this.soundNight.play();
//             }
//             else if(this.currentSound == "FOREST")
//             {
//                 this.soundForest.setVolume(0);
//                 this.soundForest.play();
//             }
//             else if(this.currentSound == "SAND")
//             {
//                 this.soundSand.setVolume(0);
//                 this.soundSand.play();
//             }
//             else if(this.currentSound == "SNOW")
//             {
//                 this.soundSnow.setVolume(0);
//                 this.soundSnow.play();
//             }
//         }
//   }
  
//   updateSound()
//   {
//     if(this.currentSound != null)
//     {
//         if(this.isNight && this.soundNight.getVolume() < 0.5)
//         {
//             this.soundNight.setVolume(this.soundNight.getVolume() + 0.01);
//         }
//         else if(this.currentSound == "FOREST" && this.soundForest.getVolume() < 0.5)
//         {
//             this.soundForest.setVolume(this.soundForest.getVolume() + 0.01);
//         }
//         else if(this.currentSound == "SAND" && this.soundSand.getVolume() < 0.5)
//         {
//             this.soundSand.setVolume(this.soundSand.getVolume() + 0.01);
//         }
//         else if(this.currentSound == "SNOW" && this.soundSnow.getVolume() < 0.5)
//         {
//             this.soundSnow.setVolume(this.soundSnow.getVolume() + 0.01);
//         }
//         if((this.currentSound != "FOREST" || this.isNight) && this.soundForest.getVolume() > 0)
//         {
//             this.soundForest.setVolume(this.soundForest.getVolume() - 0.01);
//             if(this.soundForest.getVolume() <= 0)
//             {
//                 this.soundForest.stop();
//             }
//         }
//         if((this.currentSound != "SAND" || this.isNight) && this.soundSand.getVolume() > 0)
//         {
//             this.soundSand.setVolume(this.soundSand.getVolume() - 0.01);
//             if(this.soundSand.getVolume() <= 0)
//             {
//                 this.soundSand.stop();
//             }
//         }
//         if((this.currentSound != "SNOW" || this.isNight) && this.soundSnow.getVolume() > 0)
//         {
//             this.soundSnow.setVolume(this.soundSnow.getVolume() - 0.01);
//             if(this.soundSnow.getVolume() <= 0)
//             {
//                 this.soundSnow.stop();
//             }
//         }
//         if(!this.isNight && this.soundNight.getVolume() > 0)
//         {
//             this.soundNight.setVolume(this.soundNight.getVolume() - 0.01);
//             if(this.soundNight.getVolume() <= 0)
//             {
//                 this.soundNight.stop();
//             }
//         }
//     }
//   }
// }

//Sun, used like a class
// let Sun = function()
// {
//         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 = controls.getObject();
// 		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();
//         controls.getObject().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(controls.getObject().position.x, Math.cos(this.angle)*3000, Math.sin(this.angle)*3000 + controls.getObject().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(-controls.getObject().rotation.x, -controls.getObject().rotation.y, -controls.getObject().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);
//             }
//         }
// }

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

//==============================================================================
// Functions to create/generate infinite world
//==============================================================================

//return a random element of the argument type. If wantRareObject is true, it will return a rare Object
// function getRandomElement(type, wantRareObject)
// {
//     if(type === "FOREST")
//     {
//         if(wantRareObject)
//         {
//             return objects.objectsForest.rareObjects[AB.randomIntAtoB(0,objects.objectsForest.rareObjects.length - 1)];
//         }
//         else
//         {
//             return objects.objectsForest.recurrentObjects[AB.randomIntAtoB(0,objects.objectsForest.recurrentObjects.length - 1)];
//         }
        
//     }
//     else if(type === "SAND")
//     {
//         if(wantRareObject)
//         {
//             return objects.objectsSand.rareObjects[AB.randomIntAtoB(0,objects.objectsSand.rareObjects.length - 1)];
//         }
//         else
//         {
//             return objects.objectsSand.recurrentObjects[AB.randomIntAtoB(0,objects.objectsSand.recurrentObjects.length - 1)];
//         }
        
//     }
//     else if(type === "SNOW")
//     {
//         if(wantRareObject)
//         {
//             return objects.objectsSnow.rareObjects[AB.randomIntAtoB(0,objects.objectsSnow.rareObjects.length - 1)];
//         }
//         else
//         {
//             return objects.objectsSnow.recurrentObjects[AB.randomIntAtoB(0,objects.objectsSnow.recurrentObjects.length - 1)];
//         }
        
//     }
    
// }

// //Detect what type is in Position x,y. If those coordinates are not 
// //in the dimension of the world, it change so that it loop like in the infinite world
// function checkTypeGroundAround(x, y, type)
// {
//     if(x < 0) x = worldSize - 1;
//     if(y < 0) y = worldSize - 1;
//     if(x >= worldSize) x = 0;
//     if(y >= worldSize) y = 0;
//     return grounds[x][y].type == type;
// }

// //Everytime the player move to a ground that is not yet created, 
// //it calls this function to create a Ground in a specific position pos.
// //x and y are for the coordinates in the array2d grounds.
// //type is to determine the type of the ground.
// //elements is when we load a world that alrdy had a ground with elements at this position.
// function createGround(pos, type, x, y, elements = null) 
// {
//     let conteneur = new THREE.Mesh();
//     conteneur.name = "ground";
//     let texture;
//     let transitionTexture;
//     let numberElement = 0;
//     let hasRareObject = (AB.randomIntAtoB(0,20) > 18);
    
//     saving.grounds[x][y].biom = type;
    
//     if(type === "FOREST")
//     {
//         transitionTexture = transitionTextureForest;
//         texture = groundTexture;
//         numberElement = AB.randomIntAtoB(0,maxElementsForest);
//     }
//     else if(type === "SAND")
//     {
//         transitionTexture = transitionTextureSand;
//         texture = sandTexture;
//         numberElement = AB.randomIntAtoB(0,maxElementsSand);
//     }
//     else if(type === "SNOW")
//     {
//         transitionTexture = transitionTextureSnow;
//         texture = snowTexture;
//         numberElement = AB.randomIntAtoB(0,maxElementsSnow);
//     }
    
//     let gr = new THREE.Mesh (
//         new THREE.PlaneGeometry ( squaresize*groundMultiplier, squaresize*groundMultiplier ),
//         texture );
//     gr.receiveShadow = true;
    
//     gr.rotation.x = (Math.PI / 2) * 3;
//     gr.position = pos;
    

//     if(!checkTypeGroundAround(x - 1, y, type))
//     {
//         let a1 = new THREE.Mesh (
//         new THREE.PlaneGeometry ( squaresize*groundMultiplier, squaresize*groundMultiplier/8 ),transitionTexture );
//         conteneur.add(a1);
//         a1.position.set(-squaresize*groundMultiplier/2 , offsetGround, 0);
//         a1.rotation.x = (Math.PI / 2) * 3;
//         a1.rotation.z = Math.PI/2;
//         a1.receiveShadow = true;
//         offsetGround += 0.01;
//         a1.name = "ground";
//     }
    
//     if(!checkTypeGroundAround(x + 1, y, type))
//     {
//         let a2 = new THREE.Mesh (
//             new THREE.PlaneGeometry ( squaresize*groundMultiplier, squaresize*groundMultiplier/8 ),transitionTexture);
//         conteneur.add(a2);
//         a2.position.set(squaresize*groundMultiplier/2 , offsetGround, 0);
//         a2.rotation.z = Math.PI/2;
//         a2.rotation.x = (Math.PI / 2) * 3;
//         a2.receiveShadow = true;
//         offsetGround += 0.01;
//         a2.name = "ground";
//     }
    
//     if(!checkTypeGroundAround(x, y - 1, type))
//     {
//         let a3 = new THREE.Mesh (
//             new THREE.PlaneGeometry ( squaresize*groundMultiplier, squaresize*groundMultiplier/8 ), transitionTexture);
//         conteneur.add(a3);
//         a3.position.set(0 , offsetGround, -squaresize*groundMultiplier/2);
//         a3.rotation.x = (Math.PI / 2) * 3;
//         a3.receiveShadow = true;
//         offsetGround += 0.01;
//         a3.name = "ground";
//     }
    
//     if(!checkTypeGroundAround(x, y + 1, type))
//     {
//         let a4 = new THREE.Mesh (
//             new THREE.PlaneGeometry ( squaresize*groundMultiplier, squaresize*groundMultiplier/8 ), transitionTexture);
//         conteneur.add(a4);
//         a4.position.set(0, offsetGround , squaresize*groundMultiplier/2);
//         a4.rotation.x = (Math.PI / 2) * 3;
//         a4.receiveShadow = true;
//         offsetGround += 0.01;
//         a4.name = "ground";
//     }
    
//     if(offsetGround > 0.2)
//     {
//         offsetGround = 0.001;
//     }
    
//     gr.add(conteneur);
//     conteneur.rotation.x = -(Math.PI / 2) * 3;
//     if(elements == null)
//     {
//         //add all elements to a group, 
//         let placeAvailables = [];
//         let tmp = [];
//         for (let i = 0; i < groundMultiplier; i++) 
//         {
//             tmp[i] = [];
//             for (let j = 0; j < groundMultiplier; j++) 
//             {
//                 tmp[i][j] = false;
//             }
//         }
        
//         let numberOfTry = 0;
//         while(numberElement > 0 && numberOfTry != 500)
//         {
//             let randomX = AB.randomIntAtoB(0,groundMultiplier-1);
//             let randomY = AB.randomIntAtoB(0,groundMultiplier-1);
//             let wasPosed = false;
            
//             while(!wasPosed && numberOfTry != 500)
//             {
//                 numberOfTry++;
//                 if(tmp[randomX][randomY] === false)
//                 {
//                     let t = getRandomElement(type, hasRareObject);
//                     let randomScale = AB.randomFloatAtoB(0.5,1.5);
//                     if(t != null)
//                     {
//                         let canPoseObject = true;
//                         for(let i = randomX - Math.ceil(((t.sizeX * randomScale)-1)/2); i <= randomX + Math.ceil(((t.sizeX* randomScale)-1)/2); i++)
//                         {
//                             for(let j = randomY - Math.ceil(((t.sizeZ* randomScale)-1)/2); j <= randomY + Math.ceil(((t.sizeZ* randomScale)-1)/2); j++)
//                             {
//                                 if(i >= 0 && j >= 0 && i < groundMultiplier && j < groundMultiplier)
//                                 {
//                                     if(tmp[i][j])
//                                     {
//                                         canPoseObject = false;
//                                         break;
//                                     }
//                                 }
//                                 else
//                                 {
//                                     canPoseObject = false;
//                                     break;
//                                 }
//                             }
//                         }
//                         if(canPoseObject)
//                         {
//                             let obj = t.obj.clone();
//                             if(!hasRareObject) obj.rotation.y = AB.randomIntAtoB(0,360);
//                             obj.scale.multiplyScalar(randomScale);
//                             obj.position.set((randomX - parseInt(groundMultiplier/2)) * squaresize, t.sizeY* randomScale, (randomY - parseInt(groundMultiplier/2)) * squaresize);
//                             conteneur.add(obj);
//                             for(let i = randomX - Math.ceil(((t.sizeX* randomScale)-1)/2); i <= randomX + Math.ceil(((t.sizeX* randomScale)-1)/2); i++)
//                             {
//                                 for(let j = randomY - Math.ceil(((t.sizeZ* randomScale)-1)/2); j <= randomY + Math.ceil(((t.sizeZ* randomScale)-1)/2); j++)
//                                 {
//                                     if(i >= 0 && j >= 0 && i < groundMultiplier && j < groundMultiplier)
//                                     {
//                                         tmp[i][j] = true;
//                                     }
//                                 }
//                             }
//                             if(hasRareObject)
//                             {
//                                 hasRareObject = false;
//                             }
                            
//                             let o = 
//                             {
//                                 s: Number((randomScale).toFixed(1)),
//                                 x: Number(((randomX - parseInt(groundMultiplier/2)) * squaresize).toFixed(1)),
//                                 y: Number((t.sizeY* randomScale).toFixed(1)),
//                                 z: Number(((randomY - parseInt(groundMultiplier/2)) * squaresize).toFixed(1)),
//                                 o: t.path,
//                             }
//                             saving.grounds[x][y].elements.push(o);
                            
//                             wasPosed = true;
//                             numberElement--;
//                             numberOfTry = 0;
//                         }
//                         else
//                         {
//                             randomX = AB.randomIntAtoB(0,groundMultiplier-1);
//                             randomY = AB.randomIntAtoB(0,groundMultiplier-1);
//                         }
//                     }
//                     else
//                     {
//                         if(hasRareObject)
//                         {
//                             hasRareObject = false;
//                         }
//                     }
//                 }
//                 else
//                 {
//                     randomX = AB.randomIntAtoB(0,groundMultiplier-1);
//                     randomY = AB.randomIntAtoB(0,groundMultiplier-1);
//                 }
//             }
//         }
//     }
//     else
//     {
//         for(let i = 0; i < elements.length; i++)
//         {
//             let t = findObjectLoad(elements[i].o);
//             if(t !== null)
//             {
//                 let obj = t.obj.clone();
//                 obj.scale.multiplyScalar(elements[i].s);
//                 obj.position.set(elements[i].x, elements[i].y, elements[i].z);
//                 conteneur.add(obj);
//             }
//         }
//     }
//     gr.name = "ground";
//     return gr;
// }

// //With the name of an object, it find the object to recreate it.
// //If it wasn't loaded(code changed) it returns null
// function findObjectLoad(path)
// {
//     for(let i = 0; i < allObjects.length; i++)
//     {
//         if(path == allObjects[i].path) return allObjects[i];
//     }
//     console.log("The Object", path, "was not find in allObjects array that stock all objects that have been loaded");
//     return null;
// }

// //Return the type that is the most present around the current position.
// function getTypeAround(array,x,y)
// {
//     let sand = 0;
//     let snow = 0;
//     let forest = 0;
    
//     if(x - 1 >= 0 && array[x - 1][y] !== null)
//     {
//         if(array[x - 1][y] == "SAND") sand++;
//         if(array[x - 1][y] == "FOREST") forest++;
//         if(array[x - 1][y] == "SNOW") snow++;
//     }
//     if(y - 1 >= 0 && array[x][y - 1] !== null)
//     {
//         if(array[x][y - 1] == "SAND") sand++;
//         if(array[x][y - 1] == "FOREST") forest++;
//         if(array[x][y - 1] == "SNOW") snow++;
//     }
//     if(x + 1 < array.length && array[x + 1][y] !== null)
//     {
//         if(array[x + 1][y] == "SAND") sand++;
//         if(array[x + 1][y] == "FOREST") forest++;
//         if(array[x + 1][y] == "SNOW") snow++;
//     }
//     if(y + 1 < array.length && array[x][y + 1] !== null)
//     {
//         if(array[x][y + 1] == "SAND") sand++;
//         if(array[x][y + 1] == "FOREST") forest++;
//         if(array[x][y + 1] == "SNOW") snow++;
//     }
//     if(sand == 0 && snow == 0 && forest == 0)
//     {
//         return null;
//     }
//     else if(sand > forest && sand > snow && enableSand)
//     {
//         return "SAND";
//     }
//     else if(snow > forest && snow > sand && enableSnow)
//     {
//         return "SNOW";
//     }
//     else if(forest > snow && forest > sand && enableForest)
//     {
//         return "FOREST";
//     }
//     else
//     {
//         return null;
//     }
// }

// //initialize the ground of the world, to determine all type nd create fake grounds
// //around the world to fake a loop
// function initGround()
// {
//     let tmp = new Array(worldSize);
//     for (let i = 0; i < worldSize; i++) 
//     {
//         tmp[i] = new Array(worldSize);
//         for (let j = 0; j < worldSize; j++) 
//         {
//             tmp[i][j] = null;
//         }
//     }
//     for(let i = 0; i < worldSize; i++)
//     {
//         for(let j = 0; j < worldSize; j++)
//         {
//             let typeAround = getTypeAround(tmp,i,j);
            
//             let rand = AB.randomIntAtoB(0,5);
//             if(rand < 3 && typeAround !== null)
//             {
//                 tmp[i][j] = typeAround;
//             }
//             else
//             {
//                 let t = TYPEGROUND[AB.randomIntAtoB(0,TYPEGROUND.length-1)];
//                 while(!((t == "FOREST" && enableForest) || (t == "SAND" && enableSand) || (t == "SNOW" && enableSnow)))
//                 {
//                     t = TYPEGROUND[AB.randomIntAtoB(0,TYPEGROUND.length-1)];
//                 }
//                 tmp[i][j] = t;
//             }
//         }
//     }
   
//     for(let i = 0; i < worldSize; i++)
//     {
//         for(let j = 0; j < worldSize; j++)
//         {
//             grounds[i][j] = new Ground(false, new THREE.Vector3(0,0,0));
//             grounds[i][j].type = tmp[i][j];
//             grounds[i][j].active = false;
//             saving.grounds[i][j].biom = tmp[i][j];
//         }
//     }
//     for(let i = 0; i < worldSize; i++)
//     {
//         for(let j = 0; j < worldSize; j++)
//         {
//             if(i < viewDistance + 1 || i >= worldSize - viewDistance || j >= worldSize - viewDistance || j < viewDistance + 1)
//             {
//                 grounds[i][j].ground = createGround(new THREE.Vector3(0,0,0), grounds[i][j].type, i, j);
//                 grounds[i][j].ground.position.set((i- Math.trunc(worldSize/2)) * squaresize * groundMultiplier,0, (j- Math.trunc(worldSize/2)) * squaresize*groundMultiplier)
//             }
//         }
//     }
//     for(let i = - viewDistance; i < worldSize + viewDistance; i++)
//     {
//         for(let j = - viewDistance; j < worldSize + viewDistance; j++)
//         {
//             let b = (worldSize + viewDistance);
            
//             if(i < 0 || j < 0 || i >= worldSize || j >= worldSize)
//             {
//                 let tmp;
//                 if( i < 0)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[worldSize + i][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[worldSize + i][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[worldSize + i][j].ground.clone();
//         			}
        			
//         		}
//         		else if(i >= worldSize)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[i - worldSize][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[i - worldSize][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[i - worldSize][j].ground.clone();
//         			}
//         		}
//         		else if(i >= worldSize)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[i - worldSize][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[i - worldSize][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[i - worldSize][j].ground.clone();
//         			}
//         		}
//         		else if( j < 0)
//         		{
//         			tmp = grounds[i][worldSize + j].ground.clone();
//         		}
//         		else if(j >= worldSize)
//         		{
//         			tmp = grounds[i][j - worldSize].ground.clone();
//         		}
//         		tmp.position.set((i - Math.trunc(worldSize/2)) * squaresize * groundMultiplier,0, (j - Math.trunc(worldSize/2)) * squaresize*groundMultiplier);
//                 threeworld.scene.add(tmp);
//             }
//         }
//     }
// }

// //This function is called each time the player moves to another ground to check if 
// //there is a need to create a ground depending on the viewDistance
// function updateGround()
// {
//     for(let i = ai - viewDistance - 1; i < ai + viewDistance + 2; i++)
//     {
//         for(let j = aj - viewDistance - 1; j < aj + viewDistance + 2; j++)
//         {
//             if(!(i < 0 || i >= worldSize || j >= worldSize || j < 0))
//             {
//               if(i == ai - viewDistance - 1 || j == aj - viewDistance - 1 || i == ai + viewDistance + 1 || j == aj + viewDistance + 1)
//                 {
//                     if(grounds[i][j] !== null && grounds[i][j].active)
//                     {
//                         grounds[i][j].active = false;            
//                     }
//                 }
//                 else
//                 {
//                   if(typeof grounds[i][j].ground == 'undefined' || grounds[i][j].ground === null)
//                     {
//                         grounds[i][j].ground = createGround(new THREE.Vector3(0,0,0), grounds[i][j].type, i, j);
//                         grounds[i][j].ground.position.set((i- Math.trunc(worldSize/2)) * squaresize * groundMultiplier,0, (j- Math.trunc(worldSize/2)) * squaresize*groundMultiplier);
//                         grounds[i][j].active = true;
//                         threeworld.scene.add(grounds[i][j].ground);
//                     }
//                     else if(!grounds[i][j].active)
//                     {
//                         grounds[i][j].active = true;
//                         threeworld.scene.add(grounds[i][j].ground);
//                     }
//                 } 
//             }
//         }
//     }
// }

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

// //==============================================================================
// // Functions link to an event
// //==============================================================================

// //Create a new infinite world. First destroy the previous one and then recreate one.
// function createNewInfiniteWorld()  
// {
//     viewDistance =  newviewDistance;
//     worldSize = newworldSize;
//     groundMultiplier = newGroundMultiplier;
    
//     saving = new SaveWorld(worldSize,groundMultiplier, viewDistance);
    
//     while (threeworld.scene.children.length)
//     {
//         threeworld.scene.remove(threeworld.scene.children[0]);
//     }
//     threeworld.scene.add(controls.getObject());
//     threeworld.scene.fog = new THREE.Fog(SKYCOLOR, 0, SKYDISTANCE);
//     // LIGHTS
// 	let hemiLight = new THREE.HemisphereLight( SKYCOLOR, SKYCOLOR, 0.4 );
// 	hemiLight.position.set( 0, 50, 0 );
// 	threeworld.scene.add( hemiLight );
//     init();
// }

// function onDocumentTouchStart( event ) 
// {
//     console.log("onDocumentTouchStart");
// 	event.preventDefault();

// 	event.clientX = event.touches[0].clientX;
//     event.clientY = event.touches[0].clientY;
// 	onDocumentMouseDown( event );
// }

// //Called when a key is up
// function handleKeyUp (e)
// {
//     if((e.keyCode == 38) || (e.keyCode == 40))
//     {
//         velocity = 0;
//     }
//     if(e.keyCode == 37 || e.keyCode == 39)
//     {
//         speedRotation = 0;
//     }
//     if(e.keyCode == 37 || e.keyCode == 39)
//     {
//         speedRotation = 0;
//     }
// }

// //Called on scrool of the wheel's mouse
// function onScroll(e)
// {
//     if(controls.getAttachedObject().children.length !== 0)
//     {
//         controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
//         controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);
//         let delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
//         if(delta == 1 && indexObjects + 1 < allObjects.length)
//         {
//             indexObjects++;
//         }
//         else if(delta == 1)
//         {
//             indexObjects = 0;
//         }
//         else if(delta == -1 && indexObjects - 1 >= 0)
//         {
//             indexObjects--;
//         }
//         else if(delta == -1)
//         {
//             indexObjects = allObjects.length-1;
//         }
//         let t = allObjects[indexObjects];
//         let o = t.obj.clone();
        
//         let bbox = getBoundingBoxObject(o, 0x008000);
//         controls.getAttachedObject().add(bbox);
        
//         controls.getAttachedObject().add(o);
//         o.position.y = t.sizeY;
//     }
// }

// function OnClick(e)
// {
//     if(editMode !== null)
//     {
//         if(editMode === 0)
//         {
//             selectionObject = null;
//             CreateObject(e);
//         }
//         else if(editMode == 1)
//         {
            
//             if(controls.getAttachedObject().children.length != 0)
//             {
//                 controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
//                 controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);
//             }
//             if(e != null && e.which == 3)
//             {
//                 editMode = null;
//             }
//             if(selectionObject !== null)
//             {
//                 removeObject(threeworld.scene, selectionObject);
//                 while (selectionBox.children.length)
//                 {
//                     selectionBox.remove(selectionBox.children[0]);
//                 }
//             }
//         }
//     }
// }

// function DestroyObject(e)
// {
//     if(e.type !== 'click')
//     {
//         rayToDestroy = new THREE.Raycaster( controls.getObject().position, threeworld.camera.getWorldDirection(), 0, 800);
//         let inter = rayToDestroy.intersectObjects(threeworld.scene.children, true);
//         if(inter.length > 0)
//         {
//             let i = 0;
//             while(i < inter.length && (inter[i].object.name == "ground" || inter[i].object == selectionBox)) i++;
//             if(i < inter.length && inter[i].object != selectionObject)
//             {   
//                 let o = getParent(inter[0].object);
                
//                 if(selectionObject != o && o != selectionBox)
//                 {
//                     while (selectionBox.children.length)
//                     {
//                         selectionBox.remove(selectionBox.children[0]);
//                     }
//                     let bbox = getBoundingBoxObject(o, 0xFF0000);
//                     selectionBox.add(bbox);
//                     bbox.position.x = o.getWorldPosition().x;
//                     bbox.position.z = o.getWorldPosition().z;
                    
//                     selectionObject = o;
//                 }
                
                
//             }
//         }
//     }
// }

// function removeObject(objConteneur, objToDestroy)
// {
//     for(let i = 0; i < objConteneur.children.length; i++)
//     {
//         if(objConteneur.children[i] == objToDestroy)
//         {
//             objConteneur.remove(objToDestroy);
//         }
//         else
//         {
//             removeObject(objConteneur.children[i], objToDestroy);
//         }
//     }
    
// }


// //Called when you click left with the nosue after having entered the edit mode with a left click.
// function CreateObject(e = null)
// {
//     editMode = 0;
//     if(e != null && e.which == 3 && controls.getAttachedObject().children.length !== 0)
//     {
//         controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
//         controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);
//         editMode = null;
//     }
//     else if(e != null && e.which == 3)
//     {
//         //TODO Maybe ?
//     }
//     else
//     {
//         if(controls.getAttachedObject().children.length !== 0)
//         {
//             let o = controls.getAttachedObject().children[1].clone();
//             userObjects.push(o);
//             threeworld.scene.add(o);
//             let pos = controls.getAttachedObject().children[1].getWorldPosition();
//             let rot = controls.getAttachedObject().children[1].getWorldRotation();
//             o.rotation.set();
//             o.position.set(pos.x, pos.y, pos.z);
//             o.rotation.set(rot.x, rot.y, rot.z);
            
//             let t = allObjects[indexObjects];
            
//             let s = 
//             {
//                 s: 1,
//                 x: Number((pos.x).toFixed(1)),
//                 y: Number((pos.y).toFixed(1)),
//                 z: Number((pos.z).toFixed(1)),
//                 o: t.path,
//             }
//             saving.userObjects.push(s);
//         }
//         else
//         {
//             let t = allObjects[indexObjects];
//             let o = t.obj.clone();
            
//             let bbox = getBoundingBoxObject(o, 0x008000);
//             controls.getAttachedObject().add(bbox);
            
//             controls.getAttachedObject().add(o);
//             o.position.y = t.sizeY;
//         }
//     }
// }

// //Fonction that return an cube that determine the bouding box of an object
// function getBoundingBoxObject(object, colorBox)
// {
//     let bbox = new THREE.Box3().setFromObject(object);

//     let cube = new THREE.Mesh(
//         new THREE.BoxGeometry(bbox.size().x,bbox.size().y,bbox.size().z),
//         new THREE.MeshBasicMaterial({
//             color: colorBox,
//             transparent: true,
//             opacity: 0.5
//     }));
//     cube.position.y = bbox.size().y/2 ;
//     return cube;
// }

// //Return highest parent in the hierarchy that is not a ground or the scene.
// //Useful for models that were not well designed.
// function getParent(object)
// {
//     if(object.parent !== null && object.parent.name != "ground" && object.parent != threeworld.scene)
//     {
//         return getParent(object.parent);
//     }
//     return object;
// }
// //==============================================================================
// //==============================================================================

// //==============================================================================
// // Function that load Initialize the world
// //==============================================================================

// //Load all objects3D and textures before initialazing the world
// // function loaderObjects()
// // {
// //     soundManager = new SoundManager();
    
// //     // load a sound and set it as the Audio object's buffer
// //     let audioLoaderForest = new THREE.AudioLoader(loadingManager);
    
// //     audioLoaderForest.load( SOUNDFOREST, function(buffer) {
// //         	soundManager.soundForest.setBuffer(buffer);
// //         	soundManager.soundForest.setLoop(true);
// //         	soundManager.soundForest.setVolume(0);
// //     });
    
// //     let audioLoaderSand = new THREE.AudioLoader(loadingManager);
    
// //     audioLoaderSand.load( SOUNDSAND, function( buffer ) {
// //         	soundManager.soundSand.setBuffer( buffer );
// //         	soundManager.soundSand.setLoop( true );
// //         	soundManager.soundSand.setVolume(0);
// //     });
    
// //     let audioLoaderSnow = new THREE.AudioLoader(loadingManager);
    
// //     audioLoaderSnow.load( SOUNDSNOW, function( buffer ) {
// //         	soundManager.soundSnow.setBuffer( buffer );
// //         	soundManager.soundSnow.setLoop( true );
// //         	soundManager.soundSnow.setVolume(0);
// //     });
    
// //     let audioLoaderNight = new THREE.AudioLoader(loadingManager);
    
// //     audioLoaderNight.load( SOUNDSNOW, function( buffer ) {
// //         	soundManager.soundNight.setBuffer( buffer );
// //         	soundManager.soundNight.setLoop( true );
// //         	soundManager.soundNight.setVolume(0);
// //     });
    
//     let planeTex = THREE.ImageUtils.loadTexture( "/uploads/meak/transitionsnow.png" );
//     planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
//     planeTex.repeat.set( 8, 8 );
    
//     transitionTextureSnow = new THREE.MeshPhongMaterial({map: planeTex, transparent: true, dithering: true });
//     transitionTextureSnow.wrapAround = true;
//     transitionTextureSnow.receiveShadow = true;
    
//     planeTex = THREE.ImageUtils.loadTexture( "/uploads/meak/transitionsand.png" );
//     planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
//     planeTex.repeat.set( 8, 8 );
    
//     transitionTextureSand = new THREE.MeshPhongMaterial({map: planeTex, transparent: true, dithering: true });
//     transitionTextureSand.wrapAround = true;
//     transitionTextureSand.receiveShadow = true;
    
//     planeTex = THREE.ImageUtils.loadTexture( "/uploads/meak/transitiongrass.png" );
//     planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
//     planeTex.repeat.set( 8, 8 );
    
//     transitionTextureForest = new THREE.MeshPhongMaterial({map: planeTex, transparent: true, dithering: true });
//     transitionTextureForest.wrapAround = true;
//     transitionTextureForest.receiveShadow = true;
    
//     planeTex = THREE.ImageUtils.loadTexture( "/uploads/meak/grass.jpg" );
//     planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
//     planeTex.repeat.set( 8, 8 );
    
//     groundTexture = new THREE.MeshPhongMaterial({map: planeTex, dithering: true });
//     groundTexture.wrapAround = true;
//     groundTexture.castShadow = true;
//     groundTexture.receiveShadow = true;
    
//     planeTex = THREE.ImageUtils.loadTexture( "/uploads/meak/sand.jpg" );
//     planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
//     planeTex.repeat.set( 8, 8 );
    
//     sandTexture = new THREE.MeshPhongMaterial({map: planeTex, dithering: true });
//     sandTexture.wrapAround = true;
//     sandTexture.castShadow = true;
//     sandTexture.receiveShadow = true;
    
//     snowTexture = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture( "/uploads/meak/snow.png" ), dithering: true });
//     snowTexture.wrapAround = true;
//     snowTexture.castShadow = true;
//     snowTexture.receiveShadow = true;
    
//     console.log("loading " + Object.keys(ARRAYOBJECTSFOREST).length + " elements ");
    
//     for (let key in ARRAYOBJECTSFOREST) 
//     {
//         let loaderMat = new THREE.MTLLoader(loadingManager);
//         let loaderObj = new THREE.OBJLoader(loadingManager);
//         loaderMat.setTexturePath(PATHTEXTURES);
//         let pathMat = PATHTEXTURES + key + '.mtl';
//         let pathObj = PATHTEXTURES + key + '.obj';
//         let value = ARRAYOBJECTSFOREST[key];
//         let nameObj = key;
//         console.log("loading " + pathMat + " and " + pathObj);
//         loaderMat.load
//         (
//         	// resource URL
//         	pathMat,
//         	// called when resource is loaded
//         	function (materials) 
//             {
//         	    materials.preload();
        	    
//         	    loaderObj.setMaterials(materials);
//         	    // load a resource
//                 loaderObj.load
//                 (
//                 	// resource URL
//                 	pathObj,
//                 	// called when resource is loaded
//                 	function ( object ) 
//                     {
//                         let boundingBox = new THREE.Box3().setFromObject(object);
                        
//                         object.traverse( function ( child ) {
//                             if ( child instanceof THREE.Mesh ) {
//                                 child.castShadow = true;
//                                 object.receiveShadow = true;
//                             }
//                         } );
                        
//                 	    object.position.set(0,0,0);
                	    
//                 	    let sizeX = Math.abs(boundingBox.min.x)+Math.abs(boundingBox.max.x);
//                 	    let sizeY = Math.abs(boundingBox.min.y)+Math.abs(boundingBox.max.y);
//                 	    let sizeZ = Math.abs(boundingBox.min.z)+Math.abs(boundingBox.max.z);
                	    
//                         let tmp  = new Obj(nameObj, 1 + Math.ceil((value * sizeX / squaresize) * 2),Math.abs(boundingBox.min.y)*value, 1 + Math.ceil((value * sizeZ / squaresize) * 2));
//                         object.scale.multiplyScalar(value);
//                         tmp.obj = object;
//                         if( Math.ceil((sizeZ-1)/2) < limitSizeForRareObjects && Math.ceil((sizeX-1)/2) < limitSizeForRareObjects )
//                         {
//                             objects.objectsForest.recurrentObjects.push(tmp);
//                         }
//                         else
//                         {
//                             objects.objectsForest.rareObjects.push(tmp);
//                         }
//                         allObjects.push(tmp);
//                 	}
//                 );
//         	}
//         );
//     }
//     console.log("loading " + Object.keys(ARRAYOBJECTSSAND).length + " elements ");
    
//     for (let key in ARRAYOBJECTSSAND) 
//     {
//         let loaderMat = new THREE.MTLLoader(loadingManager);
//         let loaderObj = new THREE.OBJLoader(loadingManager);
//         loaderMat.setTexturePath(PATHTEXTURES);
//         let pathMat = PATHTEXTURES + key + '.mtl';
//         let pathObj = PATHTEXTURES + key + '.obj';
//         let value = ARRAYOBJECTSSAND[key];
//         let nameObj = key;
//         console.log("loading " + pathMat + " and " + pathObj);
//         loaderMat.load
//         (
//         	// resource URL
//         	pathMat,
//         	// called when resource is loaded
//         	function ( materials ) 
//             {
//         	    materials.preload();
//         	    loaderObj.setMaterials(materials);
//         	    // load a resource
//                 loaderObj.load
//                 (
//                 	// resource URL
//                 	pathObj,
//                 	// called when resource is loaded
//                 	function ( object ) 
//                     {
//                         let boundingBox = new THREE.Box3().setFromObject(object);
                        
//                         object.traverse( function ( child ) {
//                             if ( child instanceof THREE.Mesh ) {
//                                 child.castShadow = true;
//                                 object.receiveShadow = true;
//                             }
//                         } );
                        
//                 	    object.position.set(0,0,0);
                	    
//                 	    let sizeX = Math.abs(boundingBox.min.x)+Math.abs(boundingBox.max.x);
//                 	    let sizeY = Math.abs(boundingBox.min.y)+Math.abs(boundingBox.max.y);
//                 	    let sizeZ = Math.abs(boundingBox.min.z)+Math.abs(boundingBox.max.z);
                	    
//                         let tmp  = new Obj(nameObj, 1 + Math.ceil((value * sizeX / squaresize) * 2),Math.abs(boundingBox.min.y)*value, 1 + Math.ceil((value * sizeZ / squaresize) * 2));
//                         object.scale.multiplyScalar(value);
//                         tmp.obj = object;
                	    
//                 	    if( Math.ceil((sizeZ-1)/2) < limitSizeForRareObjects && Math.ceil((sizeX-1)/2) < limitSizeForRareObjects )
//                         {
//                             objects.objectsSand.recurrentObjects.push(tmp);
//                         }
//                         else
//                         {
//                             objects.objectsSand.rareObjects.push(tmp);
//                         }
//                         allObjects.push(tmp);
//                 	}
//                 );
//         	}
//         );
//     }
//     console.log("loading " + Object.keys(ARRAYOBJECTSSNOW).length + " elements ");
    
//     for (let key in ARRAYOBJECTSSNOW) 
//     {
//         let loaderMat = new THREE.MTLLoader(loadingManager);
//         let loaderObj = new THREE.OBJLoader(loadingManager);
//         loaderMat.setTexturePath(PATHTEXTURES);
//         let pathMat = PATHTEXTURES + key + '.mtl';
//         let pathObj = PATHTEXTURES + key + '.obj';
//         let value = ARRAYOBJECTSSNOW[key];
//         let nameObj = key;
//         console.log("loading " + pathMat + " and " + pathObj);
//         loaderMat.load
//         (
//         	// resource URL
//         	pathMat,
//         	// called when resource is loaded
//         	function ( materials ) 
//             {
//         	    materials.preload();
//         	    loaderObj.setMaterials(materials);
//         	    // load a resource
//                 loaderObj.load
//                 (
//                 	// resource URL
//                 	pathObj,
//                 	// called when resource is loaded
//                 	function ( object ) 
//                     {
//                         let boundingBox = new THREE.Box3().setFromObject(object);
                        
//                         object.traverse( function ( child ) {
//                             if ( child instanceof THREE.Mesh ) {
//                                 child.castShadow = true;
//                                 object.receiveShadow = true;
//                             }
//                         } );
                        
//                 	    object.position.set(0,0,0);
                	    
//                 	    let sizeX = Math.abs(boundingBox.min.x)+Math.abs(boundingBox.max.x);
//                 	    let sizeY = Math.abs(boundingBox.min.y)+Math.abs(boundingBox.max.y);
//                 	    let sizeZ = Math.abs(boundingBox.min.z)+Math.abs(boundingBox.max.z);
                	    
//                         let tmp  = new Obj(nameObj, 1 + Math.ceil((value * sizeX / squaresize) * 2),Math.abs(boundingBox.min.y)*value, 1 + Math.ceil((value * sizeZ / squaresize) * 2));
//                         object.scale.multiplyScalar(value);
//                         tmp.obj = object;
                	    
//                 	    if( Math.ceil((sizeZ-1)/2) < limitSizeForRareObjects && Math.ceil((sizeX-1)/2) < limitSizeForRareObjects )
//                         {
//                             objects.objectsSnow.recurrentObjects.push(tmp);
//                         }
//                         else
//                         {
//                             objects.objectsSnow.rareObjects.push(tmp);
//                         }
//                         allObjects.push(tmp);
//                 	}
//                 );
//         	}
//         );
//     }
// }

// //Initalization before running the world
// function init()		 
// {
//     grounds = new Array(worldSize);
//     for (let i = 0; i < worldSize; i++) 
//     {
//         grounds[i] = new Array(worldSize);
//         for (let j = 0; j < worldSize; j++) 
//         {
//             grounds[i][j] = null;
//         }
//     }
//     ai = parseInt(worldSize/2 + camera.getWorldPosition().x/(squaresize*groundMultiplier));
//     aj = parseInt(worldSize/2 + camera.getWorldPosition().z/(squaresize*groundMultiplier));

//     pai = ai;
//     paj = aj;
//     initGround();
//     updateGround();
//     // soundManager.currentSound = grounds[ai][aj].type;
//     // soundManager.playCurrentSound();
//     threeworld.scene.add(selectionBox);

// }

// //Initialization of the loading Manager. When everything is loaded, create all HUD elements and start to initialize the world
// function initLoadingManager() 
// {
//   loadingManager = new THREE.LoadingManager();
//   AB.loadingScreen();
  
//   loadingManager.onLoad = function () {
//     	console.log( 'Loading complete!');
    	
//     	if ( AB.onDesktop() )
//         {
//                 $("#user_span1").html("<p>Use WASD or Arrows to move, mouse to look around and space to jump.</p>"+
//                 "<p>Tap '1' to enter first edit mode, then click left to create Objects</p>"+
//                 "<p>You can change the object by scrolling !</p>"+
//                 "<p>Tap '2' to enter second edit mode, then click left to destroy objects</p>"+
//                 "<p>click right to cancel each edit mode. (Creation or Destruction)</p>"+
//                 "<p> If you want to re-generate the world, you can press R !</p>");
//                 if (AB.runloggedin)
//                 {
//                         // Definitely can save, not sure if can restore:
//                         $("#user_span2").html ( " <button onclick='AB.saveData();' >Save your work</button> " );
                        
//                         // Check if any data exists, if so make restore button:
//                         AB.queryDataExists();           // will call World.queryDataExists when done 
//                 }       
//                 else    
//                 {
//                     $("#user_span2").html(  " <p> <b> To save your work, go to the World page and run this \"logged in\". </b> </p> " );
//                 }
                
                
//                 $("#user_span10").html("<p><b>Click screen to enable mouse controls</b></p>");
                
//                 $("#user_span4").html("<p> Size of each parcel of the world (1 to 1000) <input type=\"number\" min=\"1\" max=\"1000\" value=\""+ newGroundMultiplier +"\" class=\"slider\" id=\"groundMultiplierHtml\"></p>");
                
//                 document.getElementById("groundMultiplierHtml").onchange = function() {
//                     newGroundMultiplier = +this.value ;
//                     console.log("groundMultiplierHtml " + newGroundMultiplier);
//                     HUDEVENT = true;
//                 }
//                 document.getElementById("groundMultiplierHtml").onkeypress = function() {
//                     newGroundMultiplier = +this.value ;
//                     console.log("groundMultiplierHtml " + newGroundMultiplier);
//                     HUDEVENT = true;
//                 }
                
                
//                 $("#user_span5").html("<p> Size of the world (1 to 50) <input type=\"number\" min=\"1\" max=\"50\" value=\""+ newworldSize +"\" class=\"slider\" id=\"worldSizeHtml\"></p>");
                
//                 document.getElementById("worldSizeHtml").onchange = function() {
//                     newworldSize = +this.value;
//                     if((newworldSize - 1) /2 < newviewDistance)
//                     {
//                         newviewDistance = 0;
//                         document.getElementById("viewDistanceHtml").value = 0;
//                     }
//                     HUDEVENT = true;
//                     console.log("worldSizeHtml " + newworldSize);
//                 }
//                 document.getElementById("worldSizeHtml").onkeypress = function() {
//                     newworldSize = +this.value;
//                     if((newworldSize - 1) /2 < newviewDistance)
//                     {
//                         newviewDistance = 0;
//                         document.getElementById("viewDistanceHtml").value = 0;
//                     }
//                     HUDEVENT = true;
//                     console.log("worldSizeHtml " + newworldSize);
//                 }
                
//                 $("#user_span6").html("<p> viewDistance in term of parcel (0 to 10) <input type=\"number\" min=\"0\" max=\"10\" value=\""+ newviewDistance +"\" class=\"slider\" id=\"viewDistanceHtml\"></p>");
                
//                 document.getElementById("viewDistanceHtml").onchange = function() {
//                     if(newworldSize/2 >= +this.value)
//                     {
//                         newviewDistance = +this.value ;
//                     }
//                     console.log("viewDistanceHtml " + newviewDistance);
//                     HUDEVENT = true;
//                 }
//                 document.getElementById("viewDistanceHtml").onkeypress = function() {
//                     if(newworldSize/2 >= +this.value)
//                     {
//                         newviewDistance = +this.value ;
//                     }
//                     console.log("viewDistanceHtml " + newviewDistance);
//                     HUDEVENT = true;
//                 }
                
//                 $("#user_span7").html("<p>Enable snow <input type=\"checkBox\" id=\"enableSnowHtml\" checked> Max element for one section <input type=\"number\" id=\"maxElementsSnowHtml\" min=\"0\" max=\"300\" value=\"" + maxElementsSnow + "\"></p>");
                
//                 document.getElementById("maxElementsSnowHtml").onchange = function() {
//                     maxElementsSnow = this.value;
//                     HUDEVENT = true;
//                 }
//                 document.getElementById("maxElementsSnowHtml").onkeypress = function() {
//                     maxElementsSnow = this.value;
//                     HUDEVENT = true;
//                 }
                
//                 document.getElementById("enableSnowHtml").onchange = function() {
//                     if(!enableSand && !enableForest)
//                     {
//                         this.checked = true;
//                     }
//                     else
//                     {
//                         enableSnow = !enableSnow;
//                     }
//                     this.releasePointerCapture();
//                     HUDEVENT = true;
//                 }
                
//                 $("#user_span8").html("<p>Enable sand <input type=\"checkBox\" id=\"enableSandHtml\" checked> Max element for one section <input type=\"number\" id=\"maxElementsSandHtml\" min=\"0\" max=\"300\" value=\"" + maxElementsSand + "\"></p>");
                
//                 document.getElementById("maxElementsSandHtml").onchange = function() {
//                     maxElementsSand = this.value;
//                     HUDEVENT = true;
//                 }
//                 document.getElementById("maxElementsSandHtml").onkeypress = function() {
//                     maxElementsSand = this.value;
//                     HUDEVENT = true;
//                 }
                
//                 document.getElementById("enableSandHtml").onchange = function() {
//                     if(!enableSnow && !enableForest)
//                     {
//                         this.checked = true;
//                     }
//                     else
//                     {
//                         enableSand = !enableSand;
//                     }
//                     HUDEVENT = true;
//                 }
                
//                 $("#user_span9").html("<p>Enable forest <input type=\"checkBox\" id=\"enableForestHtml\" checked> Max element for one section <input type=\"number\" id=\"maxElementsForestHtml\" min=\"0\" max=\"300\" value=\"" + maxElementsForest + "\"></p>");
                
//                 document.getElementById("maxElementsForestHtml").onchange = function() {
//                     maxElementsForest = this.value;
//                     HUDEVENT = true;
//                 }
//                 document.getElementById("maxElementsForestHtml").onkeypress = function() {
//                     maxElementsForest = this.value;
//                     HUDEVENT = true;
//                 }
                
//                 document.getElementById("enableForestHtml").onchange = function() {
//                     if(!enableSnow && !enableSand)
//                     {
//                         this.checked = true;
//                     }
//                     else
//                     {
//                         enableForest = !enableForest;
//                     }
//                     HUDEVENT = true;
//                 }
//         }
//         else 
//         {
//             $("#user_span1").html( "<p> <b> This World currently only works on desktop. </b> </p>" );
//         }
//  	    loaded = true;
//  	    AB.removeLoading();
//  	    createNewInfiniteWorld();
//  	   // sun = new Sun();
//     };

//     loadingManager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
//     	let s = 'Loading file: ' + itemsLoaded + ' of ' + itemsTotal + ' files.';
//  	    $("#user_span1").html( s );
//     };
// }

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

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

// this.newRun = function() 
// {
//     camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, SKYDISTANCE );
//     threeworld.camera = camera;
    
//     let vector = new THREE.Vector3(0, 0, -1);
//     vector = camera.localToWorld(vector);
//     vector.sub(camera.position); // Now vector is a unit vector with the same direction as the camera
    

//     rayToDestroy = new THREE.Raycaster( camera.position, vector);
    
//     threeworld.init3d ( 0, 0, SKYCOLOR  ); 
//     // can adjust renderer:
// 	threeworld.renderer.shadowMap.enabled = true;
// 	threeworld.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
	
// 	//Initialize the Object that will contain all possible 3D Objects in the world
//     objects = new ObjectsConteneur();
    
//     //position of mouse in the canvas
//     mouse = new THREE.Vector2();
    
//     //First person controller
//     controls = new THREE.PointerLockControls( camera );
    
//     //Start loading objects
//     initLoadingManager();
//     loaderObjects();

//  	 //This will handle key presses
    
//         let onKeyDown = function ( event ) {

// 	    	switch ( event.keyCode ) {

// 				case 38: // up
// 				case 87: // w
// 					moveForward = true;
// 					break;

// 				case 37: // left
// 				case 65: // a
// 					moveLeft = true; break;

// 				case 40: // down
// 				case 83: // s
// 					moveBackward = true;
// 					break;

// 				case 39: // right
// 				case 68: // d
// 					moveRight = true;
// 					break;

// 				case 32: // space
// 					if ( canJump === true || true ) velocity.y += 350;
// 					canJump = false; 
// 					break;
// 				case 49:
// 				case 97: // Create Object (1)
// 				    CreateObject();
// 				    break;
				    
// 			    case 50:
// 				case 98: // Destroy Object (2)
// 				    editMode = 1;
// 				    break;    
				    
// // 				case 82: //Re-generateTheworld (R)
// // 				    createNewInfiniteWorld();
// // 				    threeworld.scene.add(sun.object);
// // 				    break;
// // 			}

// 		};

// 		let onKeyUp = function ( event ) {

// 			switch( event.keyCode ) {

// 				case 38: // up
// 				case 87: // w
// 					moveForward = false;
// 					break;

// 				case 37: // left
// 				case 65: // a
// 					moveLeft = false;
// 					break;

// 				case 40: // down
// 				case 83: // s
// 					moveBackward = false;
//                     break;

// 				case 39: // right
// 				case 68: // d
// 					moveRight = false;
// 					break;

// 			}

// 		};
 	
//  	document.addEventListener('keydown', onKeyDown, false );
// 	document.addEventListener('keyup', onKeyUp, false );
// 	document.addEventListener('click', OnClick, false);
// 	document.addEventListener('mousewheel', onScroll, false);
// 	document.addEventListener('DOMMouseScroll', onScroll, false);
// 	document.addEventListener('onmousewheel', onScroll, false);
	
// 	raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );

//     //The following handles pointer locking when clicking the window
	    
// 	let havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
//     console.log(havePointerLock);
//     if ( havePointerLock ) {

// 		let element = document.body;

// 		let pointerlockchange = function ( event ) {

// 			if ( document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element ) 
// 			{
// 			    if(HUDEVENT)
// 			    {
// 			        document.exitPointerLock();
// 			        HUDEVENT = false;
// 			    }
// 			    else
// 			    {
// 			        if(!controls.enabled && controls.getAttachedObject().children.length !== 0)
//                     {
//                         controls.getAttachedObject().remove(controls.getAttachedObject().children[1]);
//                         controls.getAttachedObject().remove(controls.getAttachedObject().children[0]);
//                     }
// 			        if(!controls.enabled)
//                     {
//                         controls.enabled = true;
//                         $("#user_span10").html("");
//                     }
// 			    }
// 			} else
// 			{
// 				controls.enabled = false;
// 				$("#user_span10").html("<p><b>Click screen to enable mouse controls</b></p>");

// 			}

// 		};
// 	let pointerlockerror = function ( event ) {

// 				console.error("pointerlockerror");
// 			};

// 			// Hook pointer lock state change events
// 			document.addEventListener( 'pointerlockchange', pointerlockchange, false );
// 			document.addEventListener( 'mozpointerlockchange', pointerlockchange, false );
// 			document.addEventListener( 'webkitpointerlockchange', pointerlockchange, false );

// 			document.addEventListener( 'pointerlockerror', pointerlockerror, false );
// 			document.addEventListener( 'mozpointerlockerror', pointerlockerror, false );
// 			document.addEventListener( 'webkitpointerlockerror', pointerlockerror, false );

// 			document.addEventListener( 'click', function ( event ) {

// 				// Ask the browser to lock the pointer
// 				element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock;
// 				element.requestPointerLock();

// 			}, false );

// 		} else {

// 			$("#user_span1").html('<p>Your browser doesn\'t seem to support Pointer Lock API</p>');

// 		}
		
// };




// this.nextStep = function()
// {
    
//     if(!loaded)
//     {
//         console.warn( 'Charging' );
//     }
//     else
//     {
//         //======================================================================
//         //This will handle moving the player and the camera
//         //======================================================================
        
//             // sun.animate();

// 			let time = performance.now();
// 			let delta = ( time - prevTime ) / 1000;

// 			velocity.x -= velocity.x * 10.0 * delta;
// 	    	velocity.z -= velocity.z * 10.0 * delta;

// 			velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass

// 			direction.z = Number( moveForward ) - Number( moveBackward );
// 			direction.x = Number( moveLeft ) - Number( moveRight );
// 			direction.normalize(); // this ensures consistent movements in all directions

// 			if ( moveForward || moveBackward ) velocity.z -= direction.z * 400.0 * MOVESPEED * delta;
// 			if ( moveLeft || moveRight ) velocity.x -= direction.x * 400.0 * MOVESPEED * delta;

// 			controls.getObject().translateX( velocity.x * delta );
// 			controls.getObject().translateY( velocity.y * delta );
// 			controls.getObject().translateZ( velocity.z * delta );

// 			if ( controls.getObject().position.y < 10 ) {

// 				velocity.y = 0;
// 				controls.getObject().position.y = 10;

// 				canJump = true;

// 			}

// 			prevTime = time;
			
// 		//Update the position of the payer in the world so that it can generate ground around the player, depending on the viewDistance
//         if(worldSize/2 + camera.getWorldPosition().x/(squaresize*groundMultiplier) < 0)
//         {
//             ai = -Math.ceil(-(worldSize/2 + camera.getWorldPosition().x/(squaresize*groundMultiplier)));
//         }
//         else
//         {
//             ai = Math.trunc(worldSize/2 + camera.getWorldPosition().x/(squaresize*groundMultiplier));
//         }
//         if(worldSize/2 + camera.getWorldPosition().z/(squaresize*groundMultiplier) < 0)
//         {
//             aj = -Math.ceil(-(worldSize/2 + camera.getWorldPosition().z/(squaresize*groundMultiplier)));
//         }
//         else
//         {
//             aj = Math.trunc(worldSize/2 + camera.getWorldPosition().z/(squaresize*groundMultiplier));
//         }
        
//         if(ai < 0)
//         {
//             controls.getObject().position.x = (worldSize/2) * groundMultiplier * squaresize - 0.01;
//         }
//         if(ai >= worldSize)
//         {
//             controls.getObject().position.x = - worldSize/2 * groundMultiplier * squaresize;
//         }
//         if(aj >= worldSize)
//         {
//             controls.getObject().position.z = - worldSize/2 * groundMultiplier * squaresize;
//         }
//         if(aj < 0)
//         {
//           controls.getObject().position.z = (worldSize/2) * groundMultiplier * squaresize - 0.01;
//         }
//         // if(ai != pai || aj != paj)
//         // {
//         //     pai = ai;
//         //     paj = aj;
//         //     updateGround();
//         //     if(grounds[ai][aj].type != soundManager.currentSound)
//         //     {
//         //         soundManager.currentSound = grounds[ai][aj].type;
//         //         soundManager.playCurrentSound();
//         //     }
//         }
//         ///
        
//         //Update of the sound depending of the actual zone where the player is.
//       // soundManager.updateSound();
//     }
// };

// this.endRun = function()
// {
// };

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



// //==============================================================================
// // Functions to store/restore data
// //==============================================================================

// this.restoreData = function ( a )          // process object returned from server  
// {
//     console.log ( "Restore Data");
    
//     //We store saving data so that the player can update his save
//     saving = a;
    
//     //We re-generate the world that was saved
//     RecreateInfiniteWorld(a);
// };
 
 
//  this.queryDataExists = function ( exists )
//  {
//         if ( exists ) 
//           $("#user_span3").html ( "<p> <button onclick='AB.restoreData();' >Restore your work</button> </p>" );
//  };


// this.saveData = function()                 // defines what object to save to server
// {
//     HUDEVENT = true;
//     return (saving);  
// };

// //Function to recreate a world that was saved on the server.
// //a 
// function RecreateInfiniteWorld(data)
// {
//     worldSize = data.worldSize;
//     groundMultiplier = data.groundMultiplier;
//     viewDistance = data.viewDistance;
    
//     while (threeworld.scene.children.length)
//     {
//         threeworld.scene.remove(threeworld.scene.children[0]);
//     }
//     threeworld.scene.add(controls.getObject());
//     // threeworld.scene.add(sun.object);
//     threeworld.scene.fog = new THREE.Fog(SKYCOLOR, 0, SKYDISTANCE);
    
//     // LIGHTS
// 	let hemiLight = new THREE.HemisphereLight( SKYCOLOR, SKYCOLOR, 0.4 );
// 	hemiLight.position.set( 0, 50, 0 );
// 	threeworld.scene.add( hemiLight );
    
//     for(let i = 0; i < worldSize; i++)
//     {
//         for(let j = 0; j < worldSize; j++)
//         {
//             grounds[i][j] = new Ground(false, new THREE.Vector3(0,0,0));
//             grounds[i][j].type = data.grounds[i][j].biom;
//             grounds[i][j].active = false;
//             saving.grounds[i][j].biom = data.grounds[i][j].biom;
//         }
//     }
//     for(let i = 0; i < worldSize; i++)
//     {
//         for(let j = 0; j < worldSize; j++)
//         {
//             if(data.grounds[i][j].elements.length !== 0)
//             {
//                 grounds[i][j].ground = createGround(new THREE.Vector3(0,0,0), grounds[i][j].type, i, j, data.grounds[i][j].elements);
//                 grounds[i][j].ground.position.set((i- Math.trunc(worldSize/2)) * squaresize * groundMultiplier,0, (j- Math.trunc(worldSize/2)) * squaresize*groundMultiplier)
//                 threeworld.scene.add(grounds[i][j].ground);
//             }
//         }
//     }
//     for(let i = 0; i < data.userObjects.length; i++)
//     {
//         let t = findObjectLoad(data.userObjects[i].o);
//         if(t !== null)
//         {
//                 let obj = t.obj.clone();
//                 obj.scale.multiplyScalar(data.userObjects[i].s);
//                 obj.position.set(data.userObjects[i].x, data.userObjects[i].y, data.userObjects[i].z);
//                 threeworld.scene.add(obj);
//         } 
//     }
//     for(let i = - viewDistance; i < worldSize + viewDistance; i++)
//     {
//         for(let j = - viewDistance; j < worldSize + viewDistance; j++)
//         {
//             let b = (worldSize + viewDistance);
            
//             if(i < 0 || j < 0 || i >= worldSize || j >= worldSize)
//             {
//                 let tmp;
//                 if( i < 0)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[worldSize + i][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[worldSize + i][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[worldSize + i][j].ground.clone();
//         			}
        			
//         		}
//         		else if(i >= worldSize)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[i - worldSize][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[i - worldSize][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[i - worldSize][j].ground.clone();
//         			}
//         		}
//         		else if(i >= worldSize)
//         		{
//         			if(j < 0)
//         			{
//         				tmp = grounds[i - worldSize][worldSize + j].ground.clone();
//         			}
//         			else if(j >= worldSize)
//         			{
//         				tmp = grounds[i - worldSize][j - worldSize].ground.clone();
//         			}
//         			else
//         			{
//         				tmp = grounds[i - worldSize][j].ground.clone();
//         			}
//         		}
//         		else if( j < 0)
//         		{
//         			tmp = grounds[i][worldSize + j].ground.clone();
//         		}
//         		else if(j >= worldSize)
//         		{
//         			tmp = grounds[i][j - worldSize].ground.clone();
//         		}
//         		tmp.position.set((i - Math.trunc(worldSize/2)) * squaresize * groundMultiplier,0, (j - Math.trunc(worldSize/2)) * squaresize*groundMultiplier);
//                 threeworld.scene.add(tmp);
//             }
//         }
//     }
// }

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

// }