//inspirer et d'après http://alteredqualia.com/


var CANVAS;
var GL;
var X_OFFSET = 0.0;
var Y_OFFSET = 0.0;
var Z_OFFSET = 0.0;
var DR = 0.7, DG = 0.7, DB = 0.7;
var Light = [0, 0, 0];
var SPIN_ID = 0;
var LAST_UPDATE_TIME = 0;
var FRAME_DELAY = 1000/30; 
var DEFCON7 = true;

var TEXTURES = [];
var TSIZES = [];


var ROTATION_X = 0;
var ROTATION_C = 0;

var TMP1 = M4x4.$();
var TMP2 = M4x4.$();
var TMP3 = M4x4.$();

var PLANETE_SHADERS = {};
var SHADER_O = {};
var SHADER_IDC = {};

var RING;
var DATA_RING;
var SPHERE;
var DATA_SPHERE;
var ICO_SPHERE;
var RECTANGLE;

var SCREEN;
var CONVOLUTION_PASS_1, CONVOLUTION_PASS_2;
var FB_CONVO_WIDTH = 512, FB_CONVO_HEIGHT = 256;

var DIRECT_CAM = true;
var CAMERA_ORTHO, CAMERA_PERSPECTIVE;
var CAM_DEFAULT = {};
var CAMERAS = [];

var DRAG_ON = 0;
var DRAG_STARTX = 0;
var DRAG_STARTY = 0;

var DEBUG_MODE = true;

var reboursCamGo;
var reboursCamLo;
var activationManuel = false;
var activeGl = false;
function setMatrixUniforms(shader, camera) {
    GL.uniformMatrix4fv(shader["uProjectionMatrix"], false, camera["PROJECTION_MATRIX"]);
    GL.uniformMatrix4fv(shader["uModelViewMatrix"], false, camera["MV_MATRIX"]);
    if(shader["uNormalMatrix"] != undefined && camera["NORMAL_MATRIX"] != undefined)
        GL.uniformMatrix3fv(shader["uNormalMatrix"], false, camera["NORMAL_MATRIX"]);
}

function transpose3x3(m) {
    var tmp;
    
    tmp = m[1]; m[1] = m[3]; m[3] = tmp;
    tmp = m[2]; m[2] = m[6]; m[6] = tmp;
    tmp = m[5]; m[5] = m[7]; m[7] = tmp;
}


function initDataObject(type) {	
	if (type = 1)
		return {'vertices':[],'normals':[],'indices':[],'uvs':[],'colors':[]};
}



var So;
var listPlanet = new Array(7);


function execute3D(defaultScene){
	
		listPlanet = new Array(7);
		CAM_DEFAULT = {};
		So= new SceneElement();
		So.sizeElement = 1000000000;
		So.strateLumiere = "img3D/sky.jpg";
		So.strate4D = "img3D/nb.jpg";
	
	
	
		var p = new SceneElement();
		p.sizeElement = 200;
		p.center = [0,0,0];
		//Light=p.center;
		p.rotation = 1;
		p.typeElement = 3;
		p.blurColor = [1,0.3,1,1];
	
		p.strate4D = "img3D/r6.jpg";
		
		listPlanet[0] = p;
		
		p = new SceneElement();
		p.center = [-20,3992,0.0];
		p.sizeElement=8;
		p.rotation = 1;
		p.rotationV = 1;
		p.axeInclinaison=0.41;
		p.typeElement=1;
		
		p.strate3='img3D/pg1.jpg';
		p.strate4D='img3D/atmo2.jpg';
		p.blurColor=[0.3,0.2,0.2,1];
	
		listPlanet[1] = p;
		
		p = new SceneElement();
		p.center = [-20,3993,0.0];
		p.sizeElement=10;
		p.rotation = 0;
		p.axeInclinaison=0.41;
		p.typeElement=2;
		p.strate2='img3D/r5.jpg';
		p.blurColor=[0.3,0.2,0.2,1];
	
		listPlanet[2] = p;
		
		p = new SceneElement();
		p.center = [-20,3993,0.0];
		p.sizeElement=13.2;
		p.rotation = 0;
		p.axeInclinaison=0.41;
		p.typeElement=2;
		p.strate2='img3D/r3.jpg';
		p.blurColor=[0.3,0.2,0.2,1];
		listPlanet[3] = p;	
	
		p = new SceneElement();
		p.center = [-3,3998,0.700];
		p.sizeElement=0.5;
		p.rotation = 1;
		p.axeInclinaison=0.41;
		p.typeElement=1;
		p.rotationV = 1;
		p.strate3='img3D/pt1.jpg';
		p.strate4D='img3D/atmo5.jpg';
	
		p.blurColor=[0.1,0.15,0.5,1];
		listPlanet[4] = p;
		
		p = new SceneElement();
		p.center = [-3,3999,0];
		p.sizeElement=0.07;
		p.rotation = 1;
		p.rotationV = 1;
		p.revolution = 5;
		p.axeInclinaison=0.41;
		p.typeElement=1;
		p.strate3='img3D/C3planet7.jpg';
	
		p.blurColor=[1,1,1,1];
		listPlanet[5] = p;	
		
		p = new SceneElement();
		p.center = [-3000,-9998,0];
		p.sizeElement=0.5;
		p.rotation = 1;
		p.rotationV = 1;
		p.axeInclinaison=0.41;
		p.typeElement=1;
		p.strate3='img3D/C3planet3.jpg';
		p.strate4D='img3D/atmo5.jpg';
	
		p.blurColor=[0.9,0.9,1,1];
		
		
		
		
		listPlanet[6] = p;	
	
		CAM_DEFAULT["EYE"] =[6.1,8.36,3981.7];
		CAM_DEFAULT["CENTER"] = [3.94,7.5,3983.58];
		CAM_DEFAULT["DISTANCE"] = 5000;
	
	launch3D();

}

function SceneElement() {
	
	this.sizeElement = 0;
	this.center = [0,0,0];
	this.revolution = 0;
	this.rotation = 0;
	this.rotationV = 0;
	this.axeInclinaison = 0;
	this.typeElement = 0;
	this.strate1 = "img3D/default.jpg";
	this.strate2 = "img3D/default.jpg";
	this.strate3 = "img3D/default.jpg";
	this.strate4D = "img3D/default.jpg";
	this.strateLumiere = "img3D/default.jpg";
	this.blurColor = [0,0,0,1];

	
}


function initTextures(callback) {
    var partCallback = function() {
        if(callback) callback();
    }
    
    var loadAll = function() {
		So.strate1=loadTexture(GL, So.strate1, partCallback);
		So.strate2=loadTexture(GL, So.strate2, partCallback);
		So.strate3=loadTexture(GL, So.strate3, partCallback);
		So.strateLumiere=loadTexture(GL, So.strateLumiere, partCallback);
		So.strate4D=loadTexture(GL, So.strate4D, partCallback);
  
        var nbP = listPlanet.length;
		for(var p=0;p<nbP;p++){
			listPlanet[p].strate1=loadTexture(GL, listPlanet[p].strate1, partCallback);
			listPlanet[p].strate2=loadTexture(GL, listPlanet[p].strate2, partCallback);
			listPlanet[p].strate3=loadTexture(GL, listPlanet[p].strate3, partCallback);
			listPlanet[p].strateLumiere=loadTexture(GL, listPlanet[p].strateLumiere, partCallback);
			listPlanet[p].strate4D=loadTexture(GL, listPlanet[p].strate4D, partCallback);
		}
    }
    loadAll();
}

var TexturesLib=new Array();
function loadTexture(gl, url, i, callback) {
	var index=-1;
	if(index==-1){
		index=TexturesLib.length;
		TexturesLib[index]=url;
		var texture = gl.createTexture();
		var image = new Image();
		image.onload = function() { 
				handleTextureLoaded(image, texture); 
				TEXTURES[index] = texture;
				//TSIZES[index] = image.width+" x "+image.height;
				if(callback) callback(); 
		}
		image.src = url;
	}
	return index;
}

function handleTextureLoaded(image, texture) {
    GL.bindTexture(GL.TEXTURE_2D, texture);
    GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, image);
    GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
    GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_NEAREST);
    GL.generateMipmap(GL.TEXTURE_2D);
    GL.bindTexture(GL.TEXTURE_2D, null);
}

function createRectangle(size) {
    function createRectangleData(size, data) {
        var half = size/2;
        
        data.vertices = [ 
            -half, -half, 0,
            half, -half, 0,
            half, half, 0,
            -half, half, 0
        ];
        
        data.indices = [
            2,1,0,
            0,3,2
        ];
        
        data.normals = [
            0,0,-1,
            0,0,-1,
            0,0,-1,
            0,0,-1
        ];
        
        data.uvs = [
            0,0,
            1,0,
            1,1,
            0,1
        ];
    }
    
    var data = {
        'vertices':[],
        'normals' :[],
        'indices' :[],
        'uvs'     :[]
    }
    
    createRectangleData(size, data);
    return initObject(data);
}


function createSphereGeodesic(radius, subdivision) {
    var X  = 0.525731112119133606;
    var Z  = 0.850650808352039932;

    var vdata = [    
        [-X, 0.0, Z], [X, 0.0, Z],  [-X, 0.0, -Z], [X, 0.0, -Z],    
        [0.0, Z, X],  [0.0, Z, -X], [0.0, -Z, X],  [0.0, -Z, -X],    
        [Z, X, 0.0],  [-Z, X, 0.0], [Z, -X, 0.0],  [-Z, -X, 0.0] 
    ];
    
    var tindices = [ 
        [0,4,1],  [0,9,4],  [9,5,4],  [4,5,8],  [4,8,1],    
        [8,10,1], [8,3,10], [5,3,8],  [5,2,3],  [2,7,3],    
        [7,10,3], [7,6,10], [7,11,6], [11,0,6], [0,1,6], 
        [6,1,10], [9,0,11], [9,11,2], [9,2,5],  [7,2,11] ];

    function normalize(a) {
        var d = Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
        a[0]/=d; a[1]/=d; a[2]/=d;
    }

    function epsilon(t,x) {
        return Math.abs(t-x)<0.001;
    }
    
    function drawtri(a, b, c, div, r, data) {
        var d,u1,u2,u3,v1,v2,v3;
        
        if(div <= 0) {
            // normals
            if(data.flat) {
                var n0 = (a[0]+b[0]+c[0])/3;
                var n1 = (a[1]+b[1]+c[1])/3;
                var n2 = (a[2]+b[2]+c[2])/3;
                data.normals.push(n0);
                data.normals.push(n1);
                data.normals.push(n2);
                
                data.normals.push(n0);
                data.normals.push(n1);
                data.normals.push(n2);
                
                data.normals.push(n0);
                data.normals.push(n1);
                data.normals.push(n2);
            }
            else {
                data.normals.push(a[0]);
                data.normals.push(a[1]);
                data.normals.push(a[2]);
                
                data.normals.push(b[0]);
                data.normals.push(b[1]);
                data.normals.push(b[2]);
                
                data.normals.push(c[0]);
                data.normals.push(c[1]);
                data.normals.push(c[2]);
            }
            
            // vertices
            data.vertices.push(a[0]*r);
            data.vertices.push(a[1]*r);
            data.vertices.push(a[2]*r);

            data.vertices.push(b[0]*r);
            data.vertices.push(b[1]*r);
            data.vertices.push(b[2]*r);
            
            data.vertices.push(c[0]*r);
            data.vertices.push(c[1]*r);
            data.vertices.push(c[2]*r);
                        
            // indices
            var n = data.indices.length;
            data.indices.push(n);
            data.indices.push(n+1);
            data.indices.push(n+2);
            
            // texture coordinates
            var scale = 1;
            var s = scale, t = scale;
            var tt = 0.75;
            var nn = 1 - tt;
            
            u1 = Math.atan2(a[0], a[2]) / (2*Math.PI) + 0.5;
            v1 = Math.asin(a[1]) / Math.PI + 0.5;
            
            u2 = Math.atan2(b[0], b[2]) / (2*Math.PI) + 0.5;
            v2 = Math.asin(b[1]) / Math.PI + 0.5;
            
            u3 = Math.atan2(c[0], c[2]) / (2*Math.PI) + 0.5;
            v3 = Math.asin(c[1]) / Math.PI + 0.5;
            
            // fix texture mapping at wrap boundary
            if(Math.abs(u1-u2) > tt) { 
                if(u1<nn) u1 += 1;
                if(u2<nn) u2 += 1;
                if(u3<nn) u3 += 1;
            }
            else if(Math.abs(u1-u3) > tt) { 
                if(u1<nn) u1 += 1;
                if(u2<nn) u2 += 1;
                if(u3<nn) u3 += 1;
            }
            else if(Math.abs(u2-u3) > tt) { 
                if(u1<nn) u1 += 1;
                if(u2<nn) u2 += 1;
                if(u3<nn) u3 += 1;
            }
            
            // fix texture mapping at poles
            if(epsilon(1,v1)) { u1 = 0.5*(u2+u3); }
            if(epsilon(1,v2)) { u2 = 0.5*(u1+u3); }
            if(epsilon(1,v3)) { u3 = 0.5*(u1+u2); }
            
            if(epsilon(0,v1)) { u1 = 0.5*(u2+u3); }
            if(epsilon(0,v2)) { u2 = 0.5*(u1+u3); }
            if(epsilon(0,v3)) { u3 = 0.5*(u1+u2); }
            
            data.uvs.push(s*u1);
            data.uvs.push(t*v1);
            
            data.uvs.push(s*u2);
            data.uvs.push(t*v2);
            
            data.uvs.push(s*u3);
            data.uvs.push(t*v3);
            
            // colors
            var rr = Math.random();
            var gg = Math.random();
            var bb = Math.random();
            var aa = 1.0;
            for(var i=0; i<3; ++i) {
                data.colors.push(rr);
                data.colors.push(gg);
                data.colors.push(bb);
                data.colors.push(aa);
            }
        } 
        else {
            var ab = [], ac = [], bc = [];
            for(var i=0; i<3; i++) {
                ab[i] = (a[i]+b[i])/2;
                ac[i] = (a[i]+c[i])/2;
                bc[i] = (b[i]+c[i])/2;
            }
            normalize(ab); normalize(ac); normalize(bc);
            drawtri(a, ab, ac, div-1, r, data);
            drawtri(b, bc, ab, div-1, r, data);
            drawtri(c, ac, bc, div-1, r, data);
            drawtri(ab, bc, ac, div-1, r, data);  //<--Comment this line and sphere looks really cool!
        }  
    }

    function createSphereGeodesicData(ndiv, radius, data) {
        for(var i=0; i<tindices.length; i++)
            drawtri(vdata[tindices[i][0]], vdata[tindices[i][1]], vdata[tindices[i][2]], ndiv, radius, data);
    }
    
    var data = {
        'vertices':[],
        'normals' :[],
        'indices' :[],
        'uvs'     :[],
        'colors'  :[],
        'flat'    :0
    }
    createSphereGeodesicData(subdivision, radius, data);
    
    return initObject(data);
}


function genSphere(rad, lat, lon) {
	DATA_SPHERE = initDataObject(1);   
    for (var latNumber = 0; latNumber <= lat; latNumber++) {
        var theta = latNumber * Math.PI / lat;
        var sinTheta = Math.sin(theta);
        var cosTheta = Math.cos(theta);

        for (var longNumber = 0; longNumber <= lon; longNumber++) {
            var phi = longNumber * 2 * Math.PI / lon;
            var sinPhi = Math.sin(phi);
            var cosPhi = Math.cos(phi);

            var x = cosPhi * sinTheta;
            var y = cosTheta;
            var z = sinPhi * sinTheta;
            var u = 1 - (longNumber / lon);
            var v = 1 - (latNumber / lat);
            var r = Math.random();
            var g = Math.random();
            var b = Math.random();
            var a = 1.0;
            for(var i=0; i<3; ++i) {
                DATA_SPHERE.colors.push(r);
                DATA_SPHERE.colors.push(g);
                DATA_SPHERE.colors.push(b);
                DATA_SPHERE.colors.push(a);
            }
            DATA_SPHERE.normals.push(x);
            DATA_SPHERE.normals.push(y);
            DATA_SPHERE.normals.push(z);
            DATA_SPHERE.uvs.push(u);
            DATA_SPHERE.uvs.push(v);
            DATA_SPHERE.vertices.push(rad * x);
            DATA_SPHERE.vertices.push(rad * y);
            DATA_SPHERE.vertices.push(rad * z);
        }
    }

    for (var latNumber = 0; latNumber < lat; latNumber++) {
        for (var longNumber = 0; longNumber < lon; longNumber++) {
            var first = (latNumber * (lon + 1)) + longNumber;
            var second = first + lon + 1;
            DATA_SPHERE.indices.push(second);
			DATA_SPHERE.indices.push(first);
			DATA_SPHERE.indices.push(first + 1);

			DATA_SPHERE.indices.push(second+1);
			DATA_SPHERE.indices.push(second);
			DATA_SPHERE.indices.push(first + 1);               
        }
    }

    return initObject(DATA_SPHERE);
}

function genRing(r1, r2, lat) {
	DATA_RING = initDataObject(1);
    for (var latNumber = 0; latNumber <= lat; latNumber++) {
        var theta = 2*latNumber * Math.PI / lat;
        var sinTheta = Math.sin(theta);
        var cosTheta = Math.cos(theta);

		var x = sinTheta;
		var y = 0;
		var z = cosTheta;
		var r = Math.random();
		var g = Math.random();
		var b = Math.random();
		var a = 1.0;
		
		
		for(var i=0; i<6; ++i) {
			DATA_RING.colors.push(r);
			DATA_RING.colors.push(g);
			DATA_RING.colors.push(b);
			DATA_RING.colors.push(a);
		}
		DATA_RING.normals.push(x);
		DATA_RING.normals.push(y);
		DATA_RING.normals.push(z);
		DATA_RING.uvs.push(10*latNumber / lat);
		DATA_RING.uvs.push(1);
		DATA_RING.vertices.push(r1 * x);
		DATA_RING.vertices.push(r1 * y);
		DATA_RING.vertices.push(r1 * z);
		
		DATA_RING.normals.push(x);
		DATA_RING.normals.push(y);
		DATA_RING.normals.push(z);
		DATA_RING.uvs.push(10*latNumber / lat);
		DATA_RING.uvs.push(0);
		DATA_RING.vertices.push(r2 * x);
		DATA_RING.vertices.push(r2 * y);
		DATA_RING.vertices.push(r2 * z);

		
    }

    for (var latNumber = 0; latNumber < lat; latNumber++) {
		var first = 2*latNumber;
		var second = 2*(latNumber+1);
		DATA_RING.indices.push(first);
		DATA_RING.indices.push(first+1);
		DATA_RING.indices.push(second+1);

		DATA_RING.indices.push(second+1);
		DATA_RING.indices.push(second);
		DATA_RING.indices.push(first);
		
		DATA_RING.indices.push(first+1);
		DATA_RING.indices.push(first);
		DATA_RING.indices.push(second+1);

		DATA_RING.indices.push(second);
		DATA_RING.indices.push(second+1);
		DATA_RING.indices.push(first);
    }

    return initObject(DATA_RING);
}


function initObject(data) {
    var object = {};   
    for (d in data) {
    	object[d+"buffer"] = GL.createBuffer();
        GL.bindBuffer(GL.ARRAY_BUFFER, object[d+"buffer"]);
        GL.bufferData(GL.ARRAY_BUFFER, new Float32Array(data[d]), GL.STATIC_DRAW);
    }	

    if(data["indices"]) {
        object["indicesbuffer"] = GL.createBuffer();
        GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, object["indicesbuffer"]);
        GL.bufferData(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(data["indices"]), GL.STATIC_DRAW);      
        object["nbIndex"] = data.indices.length;
    }

    return object;
}

function Shader() {
	
	this.gl = null;
	this.program = null;
	this.id = "";
	this.vertex = "";
	this.fragment = "";
	this.parametres = new Array();
	
	this.getShader = function () {
		var id = this.id;
		var gl = this.gl;
	    var shaderScript = document.getElementById(id);
	    if(!shaderScript) return null;
	  
	    var theSource = "";
	    var currentChild = shaderScript.firstChild;
	    
	    while(currentChild) {
	        if(currentChild.nodeType == 3)
	            theSource += currentChild.textContent;
	        currentChild = currentChild.nextSibling;
	    }  
	  
	    var shader; 
	    if(shaderScript.type == "x-shader/x-fragment")
	        shader = GL.createShader(GL.FRAGMENT_SHADER);
	    else if(shaderScript.type == "x-shader/x-vertex")
	        shader = GL.createShader(GL.VERTEX_SHADER);
	    else
	        return null;   
	    GL.shaderSource(shader, theSource);
	    GL.compileShader(shader); 
	    if(!GL.getShaderParameter(shader, GL.COMPILE_STATUS)) {
	        alert("Erreur de compilation du shader " + GL.getShaderInfoLog(shader));
	        return null;
	    }
	      return shader;
	}
	
	this.createShaderProgram = function () {
		var gl = this.gl;
	    var fShader = getShader(gl, this.fragment);
	    var vShader = getShader(gl, this.vertex);
	    
	    var shaderProgram = gl.createProgram();
	    gl.attachShader(shaderProgram, vShader);
	    gl.attachShader(shaderProgram, fShader);
	    gl.linkProgram(shaderProgram);
	    
	    if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
	        alert("Impossible d'initialiser les shaders_program");
	    
	    return shaderProgram;
	}
	
	this.configShaders = function () {
		var nbP = this.parametres.length;
	    for(var i=0; i<nbP; ++i) {
	    	this.parametres[i] = GL.getAttribLocation(this.program, this.parametres[i]);
	        GL.enableVertexAttribArray(this.parametres[i]);
	    }
	}
	
	this.hiULocations = function () {
		var nbP = this.parameters.length;
	    for(var i=0; i<nbP; ++i)
	    	this.parametres[i] = GL.getUniformLocation(this.program,this.parametres[i]);
	}

}


//Tout ce qui concerne les shaders est issu de nombreux exemples parmi lesquels :
//http://jsperf.com/dom-style-performance/2
//http://www.rozengain.com/blog/2010/08/10/using-webgl-glsl-shaders-to-create-a-tunnel-effect/
//Kernel : http://code.google.com/p/webglsamples/source/browse/hdr/hdr.js?r=64d706bbbafc5b5173f02bfb69cc9899b15799f2
//http://www.oampo.co.uk/2010/11/webglet-0-1-tutorial-pt-1/

//(Blurization) Produit convolution :  http://o3d.googlecode.com/svn/trunk/samples/convolution.html

function gauss(x, sigma) {
	return Math.exp(- (x * x) / (2.0 * sigma * sigma));
}

//
function buildKernel(sigma) {
	var kMaxKernelSize = 25;
	var kernelSize = 2 * Math.ceil(sigma * 3.0) + 1;
	if(kernelSize > kMaxKernelSize) kernelSize = kMaxKernelSize;
	var halfWidth = (kernelSize - 1) * 0.5
	
	var values = new Array(kernelSize);
	var sum = 0.0;
	for(var i=0; i<kernelSize; ++i) {
	  values[i] = gauss(i - halfWidth, sigma);
	  sum += values[i];
	}
	for(var i=0; i<kernelSize; ++i) values[i] /= sum;
	return values;
}

function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if(!shaderScript) return null;
  
    var theSource = "";
    var currentChild = shaderScript.firstChild;
    
    while(currentChild) {
        if(currentChild.nodeType == 3)
            theSource += currentChild.textContent;
        currentChild = currentChild.nextSibling;
    }  
  
    var shader; 
    if(shaderScript.type == "x-shader/x-fragment")
        shader = GL.createShader(GL.FRAGMENT_SHADER);
    else if(shaderScript.type == "x-shader/x-vertex")
        shader = GL.createShader(GL.VERTEX_SHADER);
    else
        return null;   
    GL.shaderSource(shader, theSource);
    GL.compileShader(shader); 
    if(!GL.getShaderParameter(shader, GL.COMPILE_STATUS)) {
        alert("Erreur de compilation du shader " + GL.getShaderInfoLog(shader));
        return null;
    }
      return shader;
}

function createShaderProgram(gl, vertex, fragment) {
    var fShader = getShader(gl, fragment);
    var vShader = getShader(gl, vertex);
    
    var shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vShader);
    gl.attachShader(shaderProgram, fShader);
    gl.linkProgram(shaderProgram);
    
    if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
        alert("Impossible d'initialiser les shaders_program");
    
    return shaderProgram;
}

function configShaders(shader, parameters) {
	var nbP = parameters.length;
    for(var i=0; i<nbP; ++i) {
        shader[parameters[i]] = GL.getAttribLocation(shader["shader_program"], parameters[i]);
        GL.enableVertexAttribArray(shader[parameters[i]]);
    }
}
function hiULocations(shader, parameters) {
	var nbP = parameters.length;
    for(var i=0; i<nbP; ++i)
        shader[parameters[i]] = GL.getUniformLocation(shader["shader_program"],parameters[i]);
}


function initShaders() {
	PLANETE_SHADERS["shader_program"] = createShaderProgram(GL, "vertexshader_planete", "fragmentshader-planete");
    GL.useProgram(PLANETE_SHADERS["shader_program"]);
    configShaders(PLANETE_SHADERS, ["aVertexNormal", "aVertexColor", "aTextureCoord","aVertexPosition"]);
    hiULocations(PLANETE_SHADERS, ["uProjectionMatrix", "uModelViewMatrix", "uNormalMatrix", "uRotation", "lumierePositon", "lumiereCouleur", "strate1", "strate2","strate3","strate4D","strateLumiere", "blurColor", "typeElement", "uTX", "uTY" ]);
    GL.uniform1i(PLANETE_SHADERS["strate1"],  0);
    GL.uniform1i(PLANETE_SHADERS["strate2"],1);
    GL.uniform1i(PLANETE_SHADERS["strate3"],2);
    GL.uniform1i(PLANETE_SHADERS["strateLumiere"],3);
	GL.uniform1i(PLANETE_SHADERS["strate4D"],4);
	
	
	
	SHADER_O["shader_program"] = createShaderProgram(GL, "vertexshader_produitConv", "fragmentshader_produitConv");
    GL.useProgram(SHADER_O["shader_program"]);
    configShaders(SHADER_O, ["aTextureCoord", "aVertexPosition"]);
    hiULocations(SHADER_O, ["uProjectionMatrix", "uModelViewMatrix", "FGlow","kernel"]);


    var kernel = buildKernel(4.0);
    GL.uniform1fv(SHADER_O["kernel"], kernel);
    
    // plain texture shader
    SHADER_IDC["shader_program"] = createShaderProgram(GL, "vertexshader_IDC", "fragmentshader_IDC");
    GL.useProgram(SHADER_IDC["shader_program"]);
    configShaders(SHADER_IDC, ["aTextureCoord", "aVertexPosition"]);
    hiULocations(SHADER_IDC, ["uProjectionMatrix", "uModelViewMatrix", "ugBlend"]);    
}

function initWebGL(canvas) {
	
	try{
		
    GL = canvas.getContext("experimental-webgl", {antialias : true});
	}catch(e) {
		
	}	
}

function setNormalTexture() {
    setOpaque();
    GL.useProgram(PLANETE_SHADERS["shader_program"]);
    
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[0]);
    GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
    GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_NEAREST);
}

function setTransparent() {
    GL.enable(GL.BLEND);
    GL.blendFunc(GL.ONE, GL.ONE);
    GL.disable(GL.CULL_FACE);
    GL.enable(GL.DEPTH_TEST);
}


function createTextureFrameBuffer(gl, width, height) {
    var framebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
    gl.generateMipmap(gl.TEXTURE_2D);

    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    
    var renderbuffer = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);

    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);

    gl.bindTexture(gl.TEXTURE_2D, null);
    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    
    return { "framebuffer":framebuffer, "texture":texture, 'width':width, 'height':height }
}

function createCameraOrtho(left, right, bottom, top, znear, zfar) {
    var camera = {};
        
    camera["MV_MATRIX"] = M4x4.$(1.0, 0.0, 0.0, 0.0,
                       0.0, 1.0, 0.0, 0.0,
                       0.0, 0.0, 1.0, 0.0,
                       0.0, 0.0, 0.0, 1.0 );
    
    camera["PROJECTION_MATRIX"] = M4x4.makeOrtho(left, right, bottom, top, znear, zfar);
    
    camera["TMP"] = M4x4.$();
        
    return camera;
}

function createCameraPerspective(fovy, aspect, znear, zfar, theta, phi, distance) {
    var camera = {};
        
    camera["MV_MATRIX"] = M4x4.$(1.0, 0.0, 0.0, 0.0,
                       0.0, 1.0, 0.0, 0.0,
                       0.0, 0.0, 1.0, 0.0,
                       0.0, 0.0, 0.0, 1.0 );
    
    camera["PROJECTION_MATRIX"] = M4x4.makePerspective(fovy, aspect, znear, zfar);
    
    camera["TMP"] = M4x4.$();
    
    camera["eye"]    = V3.$(0,0,distance);
    camera["center"] = V3.$(0,0,0);
    camera["up"]     = V3.$(0,1,0);
        
    camera["theta"]    = theta;
    camera["phi"]      = phi;
    camera["alpha"]    = 0;
    camera["distance"] = distance;
        
    return camera;
}

function updateCamera(camera) {
    if(camera["theta"] < 0.01) camera["theta"] = 0.01;
    if(camera["theta"] > 3.14) camera["theta"] = 3.14;
    
    var sinTheta = Math.sin(camera["theta"]);
    var cosTheta = Math.cos(camera["theta"]);

    var sinPhi = Math.sin(camera["phi"]);
    var cosPhi = Math.cos(camera["phi"]);
	
	camera["center"][0] = camera["eye"][0]+camera["distance"] * cosPhi * sinTheta;
    camera["center"][1] = camera["eye"][1]+camera["distance"] * cosTheta;
    camera["center"][2] = camera["eye"][2]+camera["distance"] * sinPhi * sinTheta;

}

function updateCameraE(camera,d) {
    if(camera["theta"] < 0.01) camera["theta"] = 0.01;
    if(camera["theta"] > 3.14) camera["theta"] = 3.14;
    
    var sinTheta = Math.sin(camera["theta"]);
    var cosTheta = Math.cos(camera["theta"]);

    var sinPhi = Math.sin(camera["phi"]);
    var cosPhi = Math.cos(camera["phi"]);
	

    camera["eye"][0] = camera["eye"][0]+d * cosPhi * sinTheta;
    camera["eye"][1] = camera["eye"][1]+d * cosTheta;
    camera["eye"][2] = camera["eye"][2]+d * sinPhi * sinTheta;
    updateCamera(camera);
}


function toggleSpin() {
    if(SPIN_ID) {
        clearTimeout(SPIN_ID);
        SPIN_ID = 0;
    }
    else {
        LAST_UPDATE_TIME = 0;
        SPIN_ID = setInterval(function() { animate() }, FRAME_DELAY);
    }
}


function animate() {
    drawScene();   
    var currentTime = (new Date).getTime();
    if (LAST_UPDATE_TIME) {
        var delta = currentTime - LAST_UPDATE_TIME;		
		animateCam(delta);
        ROTATION_X += (0.5 * delta) / 50000.0;
        ROTATION_C -= (0.1*delta) / 50000.0;
        ELAPSED_TIME += delta/1000.0;
    }
    else
        ELAPSED_TIME = 0;
    LAST_UPDATE_TIME = currentTime;
}

var currentlyPressedKeys = {};
var up=0;
var rotationS=0;
var speed=10;
function handleKeyDown(event) {
	currentlyPressedKeys[event.keyCode] = true;
	
}
function handleKeyUp(event) {
	currentlyPressedKeys[event.keyCode] = false;
}

function handleKeys() {
	if (currentlyPressedKeys[37])
		rotationS = -speed;
	else if (currentlyPressedKeys[39])
		rotationS = speed;
	else {
		if (DEBUG_MODE && currentlyPressedKeys[90])
			alert(printCam());
		rotationS = 0;
	}	
	if (currentlyPressedKeys[38]) {
		up = 1;
		DEFCON7=false;
	} else if (currentlyPressedKeys[40]) {
		up = -1;
		DEFCON7=false;
	}
	else
		up=0;
}
var de=0;
var sensMouv=true;
function wheel(e,d) {   
	//alert(CAMERA_PERSPECTIVE["distance"]);
	if (d<0 && sensMouv) {
		sensMouv=false;
		de=0;
	}
	else if (d>0 && !sensMouv) {
		sensMouv=true;
		de=0;
	}	
		
			
    de += 0.1*d;

    
    updateCameraE(CAMERA_PERSPECTIVE,de);
    
    drawScene();
    e.stopPropagation();
}

function animateCam(elapsed){
	handleKeys();
	if(up==1){
		if(speed>=0 && speed<0.00005){
			speed=0.00005;
		}
		else if(speed>0){
			speed=Math.min(2,speed*(Math.pow(1.1,elapsed/100)));
		}
		else{
			speed=speed/(Math.pow(1.1,elapsed/100));
			if(speed>-0.00005)speed=-speed;
		}
	}
	else if(up==-1){
		if(speed<=0 && speed>-0.00005){
			speed=-0.00005;
		}
		else if(speed<0){
			speed=Math.max(-2,speed*(Math.pow(1.1,elapsed/100)));
		}
		else{
			speed=speed/(Math.pow(1.1,elapsed/100));
			if(speed<0.00005)speed=-speed;
		}
	}
	if (speed != 0) {
		var vect=[Math.sin(CAMERA_PERSPECTIVE["theta"])*Math.cos(CAMERA_PERSPECTIVE["phi"])*speed * elapsed,Math.cos(CAMERA_PERSPECTIVE["theta"])*speed * elapsed,Math.sin(CAMERA_PERSPECTIVE["theta"])*Math.sin(CAMERA_PERSPECTIVE["phi"])*speed * elapsed];
	
		CAMERA_PERSPECTIVE["eye"][0] += vect[0];
		CAMERA_PERSPECTIVE["eye"][1] += vect[1];
		CAMERA_PERSPECTIVE["eye"][2] += vect[2];
		
		CAMERA_PERSPECTIVE["center"][0] += vect[0];
		CAMERA_PERSPECTIVE["center"][1] += vect[1];
		CAMERA_PERSPECTIVE["center"][2] += vect[2];
	}
	
	if(DEFCON7){
		CAMERA_PERSPECTIVE["phi"]=CAMERA_PERSPECTIVE["phi"]+0.00002*elapsed;
		CAMERA_PERSPECTIVE["eye"][0] = CAMERA_PERSPECTIVE["center"][0]- CAMERA_PERSPECTIVE["distance"]*Math.cos(CAMERA_PERSPECTIVE["phi"]);
		CAMERA_PERSPECTIVE["eye"][2] = CAMERA_PERSPECTIVE["center"][2]- CAMERA_PERSPECTIVE["distance"]*Math.sin(CAMERA_PERSPECTIVE["phi"]);
	}
	
	CAMERA_PERSPECTIVE["alpha"] += rotationS * elapsed;
}

function printCam(){
	var c="Distance:"+CAMERA_PERSPECTIVE["distance"]+"\nEye:\n"+CAMERA_PERSPECTIVE["eye"][0]+"\n"+CAMERA_PERSPECTIVE["eye"][1]+"\n"+CAMERA_PERSPECTIVE["eye"][2]+"\nCenter :\n"+CAMERA_PERSPECTIVE["center"][0]+"\n"+CAMERA_PERSPECTIVE["center"][1]+"\n"+CAMERA_PERSPECTIVE["center"][2];
	return c;
}
function updateCameraNormal(camera) {
    camera["NORMAL_MATRIX"] = M4x4.inverseTo3x3(camera["MV_MATRIX"], camera["NORMAL_MATRIX"]);
    transpose3x3(camera["NORMAL_MATRIX"]);    
}

function applyCamera(transform, camera) {
    lookAt(camera["eye"], camera["center"], camera["up"], camera["TMP"]);
    M4x4.mul(camera["TMP"], transform, camera["MV_MATRIX"]);   
}


function CamLook(xE,yE,zE,xC,yC,zC){
	CAMERA_PERSPECTIVE["eye"]=[xE,yE,zE];
	CAMERA_PERSPECTIVE["center"]=[xC,yC,zC];
    lookAt(CAMERA_PERSPECTIVE["eye"], CAMERA_PERSPECTIVE["center"], CAMERA_PERSPECTIVE["up"], CAMERA_PERSPECTIVE["TMP"]);
}
var CylceB=false;
var MaxSpeed=500;
var CxE=0;
var CyE=0;
var CzE=0;
var CxC=0;
var CyC=0;
var CzC=0;
function CamGoToStart(xE,yE,zE,xC,yC,zC){
	DEFCON7 = false;
	CxE=xE;
	CyE=yE;
	CzE=zE;
	CxC=xC;
	CyC=yC;
	CzC=zC;

	clearTimeout(reboursCamGo);
	clearTimeout(reboursCamLo);
	CamGoTo();
	
}

function CamGoTo(){
	speed=0;
	DEFCON7 = false;
	
	if (DIRECT_CAM){
		CAMERA_PERSPECTIVE["eye"][0]=CxE;
		CAMERA_PERSPECTIVE["eye"][1]=CyE;
		CAMERA_PERSPECTIVE["eye"][2]=CzE;
	}
	else {
		CAMERA_PERSPECTIVE["eye"][0]=CAMERA_PERSPECTIVE["eye"][0]+ Math.max(Math.min((CxE-CAMERA_PERSPECTIVE["eye"][0])/2,MaxSpeed),-0.5*MaxSpeed);
		CAMERA_PERSPECTIVE["eye"][1]=CAMERA_PERSPECTIVE["eye"][1]+ Math.max(Math.min((CyE-CAMERA_PERSPECTIVE["eye"][1])/2,MaxSpeed),-0.5*MaxSpeed);
		CAMERA_PERSPECTIVE["eye"][2]=CAMERA_PERSPECTIVE["eye"][2]+ Math.max(Math.min((CzE-CAMERA_PERSPECTIVE["eye"][2])/2,MaxSpeed),-0.5*MaxSpeed);	
	}
    lookAt(CAMERA_PERSPECTIVE["eye"], CAMERA_PERSPECTIVE["center"], CAMERA_PERSPECTIVE["up"], CAMERA_PERSPECTIVE["TMP"]);
	if(Math.abs(CAMERA_PERSPECTIVE["eye"][0]-CxE)>0.05 || Math.abs(CAMERA_PERSPECTIVE["eye"][1]-CyE)>0.05 || Math.abs(CAMERA_PERSPECTIVE["eye"][2]-CzE)>0.05){
		reboursCamGo = setTimeout('CamGoTo()',50);
		CylceB=true;
	}
	else{
		reboursCamLo = setTimeout('CamLookAt()',50);
		CylceB=false;
	}
}
function CamLookAt(){
	DEFCON7 = false;
	if (DIRECT_CAM){
		CAMERA_PERSPECTIVE["center"][0]=CxC;
		CAMERA_PERSPECTIVE["center"][1]=CyC;
		CAMERA_PERSPECTIVE["center"][2]=CzC;
	}
	else {
		CAMERA_PERSPECTIVE["center"][0]=CAMERA_PERSPECTIVE["center"][0]+ Math.max(Math.min((CxC-CAMERA_PERSPECTIVE["center"][0])/5,MaxSpeed),-0.5*MaxSpeed);
		CAMERA_PERSPECTIVE["center"][1]=CAMERA_PERSPECTIVE["center"][1]+ Math.max(Math.min((CyC-CAMERA_PERSPECTIVE["center"][1])/5,MaxSpeed),-0.5*MaxSpeed);
		CAMERA_PERSPECTIVE["center"][2]=CAMERA_PERSPECTIVE["center"][2]+ Math.max(Math.min((CzC-CAMERA_PERSPECTIVE["center"][2])/5,MaxSpeed),-0.5*MaxSpeed);
	}
	CAMERA_PERSPECTIVE["distance"]=Math.pow(Math.pow(CAMERA_PERSPECTIVE["eye"][0]-CAMERA_PERSPECTIVE["center"][0],2)+Math.pow(CAMERA_PERSPECTIVE["eye"][1]-CAMERA_PERSPECTIVE["center"][1],2)+Math.pow(CAMERA_PERSPECTIVE["eye"][2]-CAMERA_PERSPECTIVE["center"][2],2),0.5);
	
	CAMERA_PERSPECTIVE["theta"]=Math.acos((CAMERA_PERSPECTIVE["center"][1]- CAMERA_PERSPECTIVE["eye"][1])/CAMERA_PERSPECTIVE["distance"]);
	var cosPhi=(CAMERA_PERSPECTIVE["center"][0]-CAMERA_PERSPECTIVE["eye"][0])/CAMERA_PERSPECTIVE["distance"]/Math.sin(CAMERA_PERSPECTIVE["theta"]);
	var sinPhi=(CAMERA_PERSPECTIVE["center"][2]-CAMERA_PERSPECTIVE["eye"][2])/CAMERA_PERSPECTIVE["distance"]/Math.sin(CAMERA_PERSPECTIVE["theta"]);
	if(sinPhi>=0)CAMERA_PERSPECTIVE["phi"]=Math.acos(cosPhi);
	if(sinPhi<0)CAMERA_PERSPECTIVE["phi"]=-1*Math.acos(cosPhi);

	lookAt(CAMERA_PERSPECTIVE["eye"], CAMERA_PERSPECTIVE["center"], CAMERA_PERSPECTIVE["up"], CAMERA_PERSPECTIVE["TMP"]);
	if(Math.abs(CAMERA_PERSPECTIVE["center"][0]-CxC)>0.01 || Math.abs(CAMERA_PERSPECTIVE["center"][1]-CyC)>0.01 || Math.abs(CAMERA_PERSPECTIVE["center"][2]-CzC)>0.01){
		reboursCamLo = setTimeout('CamLookAt()',50);
		CylceB=true;
	}
	else{
		CylceB=false;
		DEFCON7=false;
	}
}







function lookAt(eye, center, up, dest) {
	var eyex = eye[0],
		eyey = eye[1],
		eyez = eye[2],
		upx = up[0],
		upy = up[1],
		upz = up[2],
		centerx = center[0],
		centery = center[1],
		centerz = center[2];

	if(eyex == centerx && eyey == centery && eyez == centerz) {
        loadIdentity(dest);
        return;
	}
	
	var z0,z1,z2,x0,x1,x2,y0,y1,y2,len;
	
	//vec3.direction(eye, center, z);
	z0 = eyex - center[0];
	z1 = eyey - center[1];
	z2 = eyez - center[2];
	
	// normalize (no check needed for 0 because of early return)
	len = Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
	z0 = z0/len;
	z1 = z1/len;
	z2 = z2/len;
	
	//vec3.normalize(vec3.cross(up, z, x));
	x0 = upy * z2 - upz * z1;
	x1 = upz * z0 - upx * z2;
	x2 = upx * z1 - upy * z0;
	len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
	if (!len) {
		x0 = 0;
		x1 = 0;
		x2 = 0;
	} else {
		x0 = x0/len;
		x1 = x1/len;
		x2 = x2/len;
	};
	
	//vec3.normalize(vec3.cross(z, x, y));
	y0 = z1 * x2 - z2 * x1;
	y1 = z2 * x0 - z0 * x2;
	y2 = z0 * x1 - z1 * x0;
	
	len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
	if (!len) {
		y0 = 0;
		y1 = 0;
		y2 = 0;
	} else {
		y0 = y0/len;
		y1 = y1/len;
		y2 = y2/len;
	}
	
	dest[0] = x0;
	dest[1] = y0;
	dest[2] = z0;
	dest[3] = 0;
	dest[4] = x1;
	dest[5] = y1;
	dest[6] = z1;
	dest[7] = 0;
	dest[8] = x2;
	dest[9] = y2;
	dest[10] = z2;
	dest[11] = 0;
	dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
	dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
	dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
	dest[15] = 1;
	//M4x4.rotate(CAMERA_PERSPECTIVE["alpha"], [0,0,1], dest, dest);
}

function setRenderTarget(target) {
    GL.bindFramebuffer(GL.FRAMEBUFFER, target.framebuffer);
    GL.viewport(0, 0, target.width, target.height);
    GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);
}

function drag_start(e) {
    DRAG_ON = 1;
    DRAG_STARTX = e.pageX;
    DRAG_STARTY = e.pageY;
    e.stopPropagation();
}

function drag_end(e) {
    DRAG_ON = 0;
    e.stopPropagation();
}

function drag(e) {
    if(DRAG_ON) {
        var deltaX = DRAG_STARTX - e.pageX;
        var deltaY = DRAG_STARTY - e.pageY;
        
        CAMERA_PERSPECTIVE["phi"]   -= 0.002*deltaX;
        CAMERA_PERSPECTIVE["theta"] -= 0.002*deltaY;
        updateCamera(CAMERA_PERSPECTIVE);

        DRAG_STARTX = e.pageX;
        DRAG_STARTY = e.pageY;
        if(!SPIN_ID) drawScene();
        DEFCON7=false;
    }
    e.stopPropagation();
}


function setOpaque() {
    GL.disable(GL.BLEND);
    GL.enable(GL.CULL_FACE);
    GL.enable(GL.DEPTH_TEST);
}

function loadIdentity(m) {
    m[0]  = 1.0;  m[1]  = 0.0; m[2]  = 0.0; m[3]  = 0.0;
    m[4]  = 0.0;  m[5]  = 1.0; m[6]  = 0.0; m[7]  = 0.0;
    m[8]  = 0.0;  m[9]  = 0.0; m[10] = 1.0; m[11] = 0.0;
    m[12] = 0.0;  m[13] = 0.0; m[14] = 0.0; m[15] = 1.0;
}

function drawSR(object, shader, camera, p) {   
    GL.useProgram(shader["shader_program"]);
    GL.uniform1i(shader["typeElement"], p.typeElement);
    GL.uniform4fv(shader["blurColor"], p.blurColor);

    loadIdentity(TMP1);
	if(p.typeElement!=0){
		M4x4.translate3(X_OFFSET, Y_OFFSET, Z_OFFSET, TMP1, TMP2);
		M4x4.rotate(ROTATION_X*p.rotationV, [0,1,0], TMP2, TMP1);
	}
    M4x4.rotate(p.axeInclinaison, [1,0,0], TMP1, TMP3);
    M4x4.scale1(p.sizeElement, TMP3, TMP2);

    applyCamera(TMP2, camera);
    updateCameraNormal(camera);

	var vec=[1,1,1];
	var mvMat=M4x4.clone(camera["MV_MATRIX"]);
    M4x4.rotate(-p.axeInclinaison, [1,0,0], mvMat, TMP1);
	M4x4.rotate(-ROTATION_X*p.rotationV, [0,1,0], TMP1, TMP2);
    M4x4.translate3(X_OFFSET, Y_OFFSET, Z_OFFSET, TMP2, mvMat);

    //Calcul Position lumière
	vec[0]=mvMat[0]*Light[0]+mvMat[4]*Light[1]+mvMat[8]*Light[2]+mvMat[12];
	vec[1]=mvMat[1]*Light[0]+mvMat[5]*Light[1]+mvMat[9]*Light[2]+mvMat[13];
	vec[2]=mvMat[2]*Light[0]+mvMat[6]*Light[1]+mvMat[10]*Light[2]+mvMat[14];
	
    GL.uniform1f(shader["uRotation"], ROTATION_C);
    GL.uniform3f(shader["lumierePositon"], vec[0], vec[1], vec[2]);
    GL.uniform3f(shader["lumiereCouleur"], DR, DG, DB);
	
	if(p.typeElement==0){
		GL.uniform1f(shader["uTX"], 8);
	    GL.uniform1f(shader["uTY"], 8);
	}
	else if(p.typeElement==2){
		GL.uniform1f(shader["uTX"], 20);
	    GL.uniform1f(shader["uTY"], 1);
	}
	else{
		GL.uniform1f(shader["uTX"], 1);
	    GL.uniform1f(shader["uTY"], 1);
	}
    // Set vertices
    GL.bindBuffer(GL.ARRAY_BUFFER, object["verticesbuffer"]);
    GL.vertexAttribPointer(shader["aVertexPosition"], 3, GL.FLOAT, false, 0, 0);

    // Set colors
    GL.bindBuffer(GL.ARRAY_BUFFER, object["colorsbuffer"]);
    GL.vertexAttribPointer(shader["aVertexColor"], 4, GL.FLOAT, false, 0, 0); 

    // Set texture coordinates
    GL.bindBuffer(GL.ARRAY_BUFFER, object["uvsbuffer"]);
    GL.vertexAttribPointer(shader["aTextureCoord"], 2, GL.FLOAT, false, 0, 0);
	
    // Set diffuse texture
    GL.activeTexture(GL.TEXTURE0);
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[p.strate1]);
	
	// Set diffuse texture
    GL.activeTexture(GL.TEXTURE1);
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[p.strate2]);
   
    // Set decal texture
    GL.activeTexture(GL.TEXTURE2);
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[p.strate3]);
	
	 // Set light texture
    GL.activeTexture(GL.TEXTURE3);
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[p.strateLumiere]);
	
	 // Set decal texture
    GL.activeTexture(GL.TEXTURE4);
    GL.bindTexture(GL.TEXTURE_2D, TEXTURES[p.strate4D]);
	
    // Set mesh normals
    GL.bindBuffer(GL.ARRAY_BUFFER, object["normalsbuffer"]);
    GL.vertexAttribPointer(shader["aVertexNormal"], 3, GL.FLOAT, false, 0, 0); 
  
    // Draw mesh
    GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, object["indicesbuffer"]);
    setMatrixUniforms(shader, camera);
    GL.drawElements(GL.TRIANGLES, object["nbIndex"], GL.UNSIGNED_SHORT, 0);

	GL.flush();
}

function drawSolidAstre() {
	if (!SPHERE)
		SPHERE = genSphere(1.0, 30, 30);
	drawSR(SPHERE, PLANETE_SHADERS, CAMERA_PERSPECTIVE, So);
	var nbP = listPlanet.length;
    for(var p=0;p<nbP;p++){
		var t = ROTATION_X;
		var dx = listPlanet[p].center[0]+listPlanet[p].rotation*Math.sin(listPlanet[p].revolution*t);
		var dy = listPlanet[p].center[1]+listPlanet[p].rotation*Math.cos(listPlanet[p].revolution*t);
		X_OFFSET += dx;
		Z_OFFSET += dy;
		ROTATION_X += t;
		if(listPlanet[p].typeElement==2){
			if (!RING)
				RING = genRing(1.0, 1.3, 160);  
			setTransparent();
			drawSR(RING, PLANETE_SHADERS, CAMERA_PERSPECTIVE, listPlanet[p]);
			setOpaque();
		}
		else {
			if (!ICO_SPHERE)
				ICO_SPHERE = createSphereGeodesic(1.0, 4);
			drawSR(ICO_SPHERE, PLANETE_SHADERS, CAMERA_PERSPECTIVE, listPlanet[p]);
		}

		ROTATION_X -= t;
		X_OFFSET -= dx;
		Z_OFFSET -= dy;
	}
}

function drawRectangle(object, shader, camera, texture, dx,dy,dz) {
    GL.useProgram(shader["shader_program"]);
        
    loadIdentity(TMP1);
    M4x4.translate3(dx,dy,dz, TMP1, camera["MV_MATRIX"]);
    
    // Set vertices
    GL.bindBuffer(GL.ARRAY_BUFFER, object["verticesbuffer"]);
    GL.vertexAttribPointer(shader["aVertexPosition"], 3, GL.FLOAT, false, 0, 0);
    
    // Set texture coordinates
    GL.bindBuffer(GL.ARRAY_BUFFER, object["uvsbuffer"]);
    GL.vertexAttribPointer(shader["aTextureCoord"], 2, GL.FLOAT, false, 0, 0);
    
    // Set diffuse texture
    GL.activeTexture(GL.TEXTURE0);
    GL.bindTexture(GL.TEXTURE_2D, texture);
        
    // Draw mesh
    GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, object["indicesbuffer"]);
    setMatrixUniforms(shader, camera);
    GL.drawElements(GL.TRIANGLES, object["nbIndex"], GL.UNSIGNED_SHORT, 0);
}

function updateBufferMipmap(target) {
    GL.bindTexture(GL.TEXTURE_2D, target.texture);
    GL.generateMipmap(GL.TEXTURE_2D);
}

function drawScene() {
    setRenderTarget(CONVOLUTION_PASS_1);
    drawSolidAstre();
    updateBufferMipmap(CONVOLUTION_PASS_1);   
    setRenderTarget(CONVOLUTION_PASS_2);
    GL.useProgram(SHADER_O["shader_program"]);
    GL.uniform2fv(SHADER_O["FGlow"], [0.002, 0]);   
    if (!RECTANGLE)
    	RECTANGLE = createRectangle(2.0);
    drawRectangle(RECTANGLE, SHADER_O, CAMERA_ORTHO, CONVOLUTION_PASS_1.texture, 0,0,0);
    updateBufferMipmap(CONVOLUTION_PASS_2); 
    setRenderTarget(CONVOLUTION_PASS_1);
    GL.useProgram(SHADER_O["shader_program"]);
    GL.uniform2fv(SHADER_O["FGlow"], [0, 0.005]);
    drawRectangle(RECTANGLE, SHADER_O, CAMERA_ORTHO, CONVOLUTION_PASS_2.texture, 0,0,0);
    updateBufferMipmap(CONVOLUTION_PASS_1);   
    setRenderTarget(SCREEN);        
    drawSolidAstre();   
    setBlend();
    GL.useProgram(SHADER_IDC["shader_program"]);
    GL.uniform1f(SHADER_IDC["ugBlend"], 1.1);
    drawRectangle(RECTANGLE, SHADER_IDC, CAMERA_ORTHO, CONVOLUTION_PASS_1.texture, 0,0,0);
    setOpaque();
}


function setBlend() {
    GL.enable(GL.BLEND);
    GL.blendFunc(GL.ONE, GL.ONE);
    GL.disable(GL.CULL_FACE);
    GL.disable(GL.DEPTH_TEST);
}

function clear3D() {
	clearTimeout(SPIN_ID);
	GL = null;
	X_OFFSET = 0.0;
	Y_OFFSET = 0.0;
	Z_OFFSET = 0.0;
	DR = 0.7, DG = 0.7, DB = 0.7;
	Light = [0, 0, 0];
	
	SPIN_ID = 0;
	LAST_UPDATE_TIME = 0;
	FRAME_DELAY = 1000/30; 
	DEFCON7 = true;

	TEXTURES = [];
	TSIZES = [];


	ROTATION_X = 0;
	ROTATION_C = 0;

	TMP1 = M4x4.$();
	TMP2 = M4x4.$();
	TMP3 = M4x4.$();

	PLANETE_SHADERS = {};
	SHADER_O = {};
	SHADER_IDC = {};

	RING = null;
	DATA_RING = null;
	SPHERE = null;
	DATA_SPHERE = null;
	ICO_SPHERE = null;
    RECTANGLE = null;

	 SCREEN = null;
	 CONVOLUTION_PASS_1, CONVOLUTION_PASS_2;
	 FB_CONVO_WIDTH = 512, FB_CONVO_HEIGHT = 256;


	 CAMERA_ORTHO = null;
	 CAMERA_PERSPECTIVE = null;
	 
	 CAMERAS = [];

	 DRAG_ON = 0;
	 DRAG_STARTX = 0;
	 DRAG_STARTY = 0;
	 listPlanet = new Array();
	DEBUG_MODE = true;


	
	
}

function launch3D() {
	
    CANVAS = document.getElementById("glcanvas");
 
	initWebGL(CANVAS);
	
    if(GL) {
    	
        GL.clearColor(0.0, 0.0, 0.0, 0.0);  // Set clear color to black, fully opaque
        GL.clearDepth(1.0);                 // Clear everything
        GL.enable(GL.DEPTH_TEST);           // Enable depth testing
        GL.depthFunc(GL.LEQUAL);            // Near things obscure far things
        
        GL.frontFace(GL.CW);
        GL.cullFace(GL.BACK);
        GL.enable(GL.CULL_FACE);
		initShaders();
		
		SCREEN = { "framebuffer":null, "width":CANVAS.width, "height":CANVAS.height, "texture":null };
		
		CONVOLUTION_PASS_1 = createTextureFrameBuffer(GL, FB_CONVO_WIDTH, FB_CONVO_HEIGHT);
		CONVOLUTION_PASS_2 = createTextureFrameBuffer(GL, FB_CONVO_WIDTH, FB_CONVO_HEIGHT);
		CAMERA_ORTHO = createCameraOrtho(-1, 1, -1, 1, -1000, 1);
		
        CAMERAS[0] = createCameraPerspective(45, CANVAS.width/CANVAS.height, 0.01, 10000000.0, 1.57, -1.57, 2000);
        for(var i=0; i<CAMERAS.length; ++i) updateCamera(CAMERAS[i]);
       
        CAMERA_PERSPECTIVE = CAMERAS[0];
        
        CamGoToStart(CAM_DEFAULT["EYE"][0], CAM_DEFAULT["EYE"][1], CAM_DEFAULT["EYE"][2],CAM_DEFAULT["CENTER"][0], CAM_DEFAULT["CENTER"][1], CAM_DEFAULT["CENTER"][2]);
        
        initTextures(function() { drawScene(); });
        
		toggleSpin();
	
		document.onkeydown = handleKeyDown;
		document.onkeyup = handleKeyUp;
    }
	else{
		errorWebGl();
	}
}

function errorWebGl() {
	if (activationManuel)
			alert(nCompatible);
	activationManuel = false;
	activeGl = false;
	$("interface3D").style.display = "none";
	if ($('checkBox3D') && $('checkBox3D').checked) 
		$('checkBox3D').checked = false;
}



function active3D() {
	if (!$('checkBox3D').checked) {
		activeGl = false;
		$('glcanvas').style.display = "none";
		$("interface3D").style.display = "none";
		if (!resetO)
			loadGraphics();
	}
	else {
		activationManuel = true;
		activeGl = true;
		if (!GL && !graphicPlanet)
			execute3D();
		else if (!GL && graphicPlanet && !resetO)
			loadGraphics();
		
		if (GL) {
			clearGraphics();
		}
			
	}
	if (!resetO)
		anim3DDesactive();
}

function changeVue() {
	DIRECT_CAM=false;
	var v = $('vueCha').getValue();
	v = v.split(',');
	CamGoToStart(v[0], v[1], v[2], v[3], v[4], v[5]);
}

function animation3DFocus() {
	var vueS = $('vueCha').getValue();
	if ($('animation3DFocus').checked) {
		$('glcanvas').style.zIndex = 3000;
	
		$('iContainer').style.display = "";
		
		$('iContainer').innerHTML = $('interface3D').innerHTML;
		
		$('interface3D').innerHTML = "";
		$('animation3DFocus').checked = true;
		$('vueCha').setValue(vueS);
		if ($('skycraperAd'))
			$('skycraperAd').style.display = "none";
		if ($('accueilAd'))
			$('accueilAd').style.display = "none";
		if ($('bannAd'))
			$('bannAd').style.display = "none";
		if ($('vuePersoCheckDiv'))
			$('vuePersoCheckDiv').style.display="";
		jQuery(document).ready(function(){
			jQuery("#glcanvas").mousedown(function(e) { drag_start(e);de=0; } ); 
		
			jQuery(document).mouseup(function(e) { drag_end(e) } );
			jQuery(document).mousemove(function(e) { drag(e) } ) ;
			jQuery('#glcanvas').mousewheel(function(e, d) { wheel(e,d); });});
	}	
	else {
		if ($('vuePersoCheckDiv'))
			$('vuePersoCheckDiv').style.display="none";
		$('glcanvas').style.zIndex=0;
		$('interface3D').innerHTML = $('iContainer').innerHTML;
		$('iContainer').innerHTML = "";
		$('iContainer').style.display = "none";
		$('animation3DFocus').checked = false;
		$('vueCha').setValue(vueS);
		if ($('skycraperAd'))
			$('skycraperAd').style.display = "";
		if ($('accueilAd'))
			$('accueilAd').style.display = "";
		if ($('bannAd'))
			$('bannAd').style.display = "";		
		jQuery(document).ready(function(){
			
			jQuery("#glcanvas").unbind("mousedown");
			jQuery(document).unbind("mouseup");
			jQuery(document).unbind("mousemove");
			jQuery('#glcanvas').unbind("mousewheel");});
	}	
}


function savePerso3D() {
	var xhr = getXhr();
	if (GL) {
		$('infoSave3D').style.display="none";
		
		var compileCam = Math.round(CAMERA_PERSPECTIVE["eye"][0]*100)/100+','+Math.round(CAMERA_PERSPECTIVE["eye"][1]*100)/100+','+Math.round(CAMERA_PERSPECTIVE["eye"][2]*100)/100+','+Math.round(CAMERA_PERSPECTIVE["center"][0]*100)/100+','+Math.round(CAMERA_PERSPECTIVE["center"][1]*100)/100+','+Math.round(CAMERA_PERSPECTIVE["center"][2]*100)/100;
		chargementKeeper('vuePersoCheck');
		new Ajax.Request('options/saveVue3D.php', {	
			method: 'post',
			parameters: {compileCam:compileCam},		
			onSuccess: function(response) {	
				if ($('vue3Dp')) {
					$('vue3Dp').remove();
				}	
				$('infoSave3D').style.display="";
				chargementKeeper('vuePersoCheck');
				$('vueCha').insert("<option  id=\"vue3Dp\" value=\""+compileCam+"\">"+f3d_vuPerso+"</option>");
				
			}
		});	
	}
}
