From f7b8365847893d9675a2e2c83713366b270db006 Mon Sep 17 00:00:00 2001
From: "jorge.josegonc" <jorge.jose-goncalves@etu.hesge.ch>
Date: Wed, 16 Dec 2020 10:22:10 +0100
Subject: [PATCH] rotation and shadow with ponct light good but have not
 directionnal and ambient and a good method for select hourglass

---
 lab4/src/lab4.js | 696 +++++++++++++++++++++++------------------------
 1 file changed, 348 insertions(+), 348 deletions(-)

diff --git a/lab4/src/lab4.js b/lab4/src/lab4.js
index 14aadf2..cdd4abf 100644
--- a/lab4/src/lab4.js
+++ b/lab4/src/lab4.js
@@ -2,167 +2,145 @@
 Author : Jorge José Goncalves
 */
 
-// variable for camera and light
-var eyeX = 2;
-var eyeY = 4;
-var eyeZ = 6;
-const STEP = 0.1;
-var lightDirectionnalX = 0.5;
-var lightDirectionnalY = 3.0;
-var lightDirectionnalZ = 4.0;
-var lightPositionX = 0.0;
-var lightPositionY = 5.0;
-var lightPositionZ = 0.0;
-var OFFSCREEN_WIDTH = 2048;
-var OFFSCREEN_HEIGHT = 2048;
-var clicked_canvas = false;
-var x_clicked = 0;
-var y_clicked = 0;
-var VSHADER_SOURCE_DIRECTIONNAL_LIGHT =
+// Vertex shader program for generating a shadow map
+var SHADOW_VSHADER_SOURCE =
   'attribute vec4 a_Position;\n' +
-  'attribute vec4 a_Color;\n' +
-  'attribute vec4 a_Normal;\n' +
-  'uniform mat4 mMVP;\n' +
-  'uniform mat4 mNormal;\n' +
-  'uniform vec3 vLightDirection;\n' +
-  'varying vec4 v_Color;\n' +
+  'uniform mat4 u_MvpMatrix;\n' +
   'void main() {\n' +
-  '  gl_Position = mMVP * a_Position;\n' +
-  '  vec4 normal = mNormal * a_Normal;\n' +
-  '  float nDotL = max(dot(normalize(normal.xyz), vLightDirection), 0.0);\n' +
-  '  v_Color = vec4(a_Color.xyz * nDotL, a_Color.a);\n' +
+  '  gl_Position = u_MvpMatrix * a_Position;\n' +
   '}\n';
 
-var FSHADER_SOURCE_DIRECTIONNAL_LIGHT =
+// Fragment shader program for generating a shadow map
+var SHADOW_FSHADER_SOURCE =
   '#ifdef GL_ES\n' +
   'precision mediump float;\n' +
   '#endif\n' +
-  'varying vec4 v_Color;\n' +
   'void main() {\n' +
-  '  gl_FragColor = v_Color;\n' +
+  '  gl_FragColor = vec4(gl_FragCoord.z, 0.0, 0.0, 0.0);\n' + // Write the z-value in R
   '}\n';
 
-  var VSHADER_SOURCE_PONCTUAL_LIGHT =
+// Vertex shader program for regular drawing
+var VSHADER_SOURCE =
   'attribute vec4 a_Position;\n' +
   'attribute vec4 a_Color;\n' +
   'attribute vec4 a_Normal;\n' +
-  'uniform mat4 mMVP;\n' +
-  'uniform mat4 mModel;\n' +
-  'uniform mat4 mNormal;\n' +
-  'varying vec4 v_Color;\n' +
-  'varying vec3 normal;\n' +
-  'varying vec4 vertexPosition;\n' +
-  'uniform bool u_Clicked;\n' +
-  'uniform bool u_is_hourglass;\n' +
+  'uniform mat4 u_MvpMatrix;\n' +
   'uniform mat4 u_MvpMatrixFromLight;\n' +
   'varying vec4 v_PositionFromLight;\n' +
+  'varying vec4 v_Color;\n' +
+  'varying vec3 v_normal;\n' +
+  'uniform mat4 u_NormalMatrix;\n' +
+  'uniform bool u_Clicked;\n' +
+  'varying vec4 v_VertexPosition;\n' +
+  'uniform mat4 u_ModelMatrix;\n' +
   'void main() {\n' +
-  '  gl_Position = mMVP * a_Position;\n' +
-  '  normal = normalize(vec3(mNormal * a_Normal));\n' +
-  '  vertexPosition = mModel * a_Position;\n' +
-  '  if(u_Clicked && u_is_hourglass) {\n' +
+  '  gl_Position = u_MvpMatrix * a_Position;\n' +
+  '  v_normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
+  '  v_VertexPosition = u_ModelMatrix * a_Position;\n' +
+  '  v_PositionFromLight = u_MvpMatrixFromLight * a_Position;\n' +
+  '  if(u_Clicked && a_Color != vec4(1.0, 1.0, 1.0, 1.0)) {\n' +
   '    v_Color = vec4(0.0, 1.0, 0.0, 1.0);\n' +
   '  } else {\n' +
   '    v_Color = a_Color;\n' +
   '  }\n' +
   '}\n';
 
-var FSHADER_SOURCE_PONCTUAL_LIGHT =
+// Fragment shader program for regular drawing
+var FSHADER_SOURCE =
   '#ifdef GL_ES\n' +
   'precision mediump float;\n' +
   '#endif\n' +
-  'varying vec4 v_Color;\n' +
-  'uniform vec3 vLightColor;\n' +
-  'uniform vec3 vLightPosition;\n' +
-  'varying vec3 normal;\n' +
-  'varying vec4 vertexPosition;\n' +
+  'uniform sampler2D u_ShadowMap;\n' +
   'varying vec4 v_PositionFromLight;\n' +
+  'varying vec4 v_Color;\n' +
+  'varying vec3 v_normal;\n' +
+  'varying vec4 v_VertexPosition;\n' +
+  'uniform vec3 u_LightPosition;\n' +
+  'uniform vec3 u_LightColor;\n' +
   'void main() {\n' +
-  '  vec3 vLightDirection = normalize(vLightPosition - vec3(vertexPosition));\n' +
-  '  float nDotL = max(dot(normal, vLightDirection), 0.0);\n' +
-  '  vec3 diffuse = vLightColor * v_Color.rgb * nDotL;\n' +
-  '  gl_FragColor =  vec4(diffuse, v_Color.a);\n' +
+  '  vec3 lightDirection = normalize(u_LightPosition - vec3(v_VertexPosition));\n' +
+  '  float nDotL = max(dot(v_normal, lightDirection), 0.0);\n' +
+  '  vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;\n' +
+  '  vec3 shadowCoord = (v_PositionFromLight.xyz/v_PositionFromLight.w)/2.0 + 0.5;\n' +
+  '  vec4 rgbaDepth = texture2D(u_ShadowMap, shadowCoord.xy);\n' +
+  '  float depth = rgbaDepth.r;\n' + // Retrieve the z-value from R
+  '  float visibility = (shadowCoord.z > depth + 0.005) ? 0.0 : 1.0;\n' +
+  '  gl_FragColor = vec4(diffuse * visibility, v_Color.a);\n' +
   '}\n';
 
-var SHADOW_VSHADER_SOURCE =
-  'attribute vec4 a_Position;\n' +
-  'uniform mat4 u_MvpMatrix;\n' +
-  'void main() {\n' +
-  '  gl_Position = u_MvpMatrix * a_Position;\n' +
-  '}\n';
+const PERSPECTIVE_WIDTH_FROM_LIGHT = 2048
+const PERSPECTIVE_HEIGHT_FROM_LIGHT = 2048
 
-var SHADOW_FSHADER_SOURCE =
-'#ifdef GL_ES\n' +
-'precision mediump float;\n' +
-'#endif\n' +
-'void main() {\n' +
-'  gl_FragColor = vec4(gl_FragCoord.z, 0.0, 0.0, 0.0);\n' + // Write the z-value in R
-'}\n';
+// Step when change with keys
+const STEP = 0.1;
 
-function main() {
-  //directionnal_light();
-  ponctual_light();
-  // Control camera or lights
-  document.addEventListener("keydown", (event) => {
-    switch (event.key) {
-      case 'a':
-        eyeX -= STEP;
-        break;
-      case 'd':
-        eyeX += STEP;
-        break;
-      case 's':
-        eyeY -= STEP;
-        break;
-      case 'w':
-        eyeY += STEP;
-        break;
-      case 'r':
-        eyeZ -= STEP;
-        break;
-      case 'f':
-        eyeZ += STEP;
-        break;
-      case 'ArrowRight':
-        lightDirectionnalX += STEP;
-        lightPositionX += STEP;
-        break;
-      case 'ArrowLeft':
-        lightDirectionnalX -= STEP;
-        lightPositionX -= STEP;
-        break;
-      case 'ArrowDown':
-        lightDirectionnalY -= STEP;
-        lightPositionY -= STEP;
-        break;
-      case 'ArrowUp':
-        lightDirectionnalY += STEP;
-        lightPositionY += STEP;
-        break;
-      case 'z':
-        lightDirectionnalZ += STEP;
-        lightPositionZ += STEP;
-        break;
-      case 'h':
-        lightDirectionnalZ -= STEP;
-        lightPositionZ -= STEP;
-        break;
-      default:
-        break;
-    }
+// For light position
+var light_x = 0
+var light_y = 1
+var light_z = 2;
+
+// For camera position
+var eye_x = 2;
+var eye_y = 4;
+var eye_z = 6;
+
+// Coordinate transformation matrix
+var tmp_modelMatrix = new Matrix4();
+var tmp_mvpMatrix = new Matrix4();
+var tmp_normalMatrix = new Matrix4();
+var rotationSecFrustrumMatrix = new Matrix4();
+var translateFrustrumMatrix = new Matrix4();
+
+// Event of key down, move camera or light positions
+document.addEventListener("keydown", (event) => {
+  switch (event.key) {
+    case 'a':
+      eye_x -= STEP;
+      break;
+    case 'd':
+      eye_x += STEP;
+      break;
+    case 's':
+      eye_y -= STEP;
+      break;
+    case 'w':
+      eye_y += STEP;
+      break;
+    case 'r':
+      eye_z -= STEP;
+      break;
+    case 'f':
+      eye_z += STEP;
+      break;
+    case 'ArrowRight':
+      light_x += STEP;
+      break;
+    case 'ArrowLeft':
+      light_x -= STEP;
+      break;
+    case 'ArrowDown':
+      light_y -= STEP;
+      break;
+    case 'ArrowUp':
+      light_y += STEP;
+      break;
+    case 'z':
+      light_z += STEP;
+      break;
+    case 'h':
+      light_z -= STEP;
+      break;
+    default:
+      break;
+  }
 
-    // update html
-    document.getElementById("light_x_dir").textContent = "Light X directionnal : " + lightDirectionnalX
-    document.getElementById("light_y_dir").textContent = "Light Y directionnal : " + lightDirectionnalY
-    document.getElementById("light_z_dir").textContent = "Light Z directionnal : : " + lightDirectionnalZ
-  
-    document.getElementById("light_x_point").textContent = "Light X point : " + lightPositionX
-    document.getElementById("light_y_point").textContent = "Light Y point : " + lightPositionY
-    document.getElementById("light_z_point").textContent = "Light Z point : " + lightPositionZ
-  });
-}
+  document.getElementById("light_x_point").textContent = "Light X point : " + light_x
+  document.getElementById("light_y_point").textContent = "Light Y point : " + light_y
+  document.getElementById("light_z_point").textContent = "Light Z point : " + light_z
+});
 
-function directionnal_light() {
+function main() {
+  // Retrieve <canvas> element
   var canvas = document.getElementById('my-canvas');
 
   // Get the rendering context for WebGL
@@ -172,67 +150,40 @@ function directionnal_light() {
     return;
   }
 
-  // Initialize shaders for light directionnal
-  if (!initShaders(gl, VSHADER_SOURCE_DIRECTIONNAL_LIGHT, FSHADER_SOURCE_DIRECTIONNAL_LIGHT)) {
-    console.log('Failed to intialize shaders.');
-    return;
-  }
-
-  // Set the clear color and enable the depth test
-  gl.clearColor(0, 0, 0, 1);
-  gl.enable(gl.DEPTH_TEST);
-
-  // Get the storage locations
-  var mMVP = gl.getUniformLocation(gl.program, 'mMVP');
-  var mNormal = gl.getUniformLocation(gl.program, 'mNormal');
-  var vLightDirection = gl.getUniformLocation(gl.program, 'vLightDirection');
-  if (!mMVP || !mNormal || !vLightDirection) {
-    console.log('Failed to get the storage location');
-    return;
-  }
-
-  var vpMatrix = new Matrix4();   // View projection matrix
-
-  var tick = function () {
-    // Set perspective and camera
-    vpMatrix.setPerspective(50, canvas.width / canvas.height, 1, 100);
-    vpMatrix.lookAt(eyeX, eyeY, eyeZ, 0, 0, 0, 0, 1, 0);
-
-    // Set the light direction
-    var lightDirection = new Vector3([lightDirectionnalX, lightDirectionnalY, lightDirectionnalZ]);
-    lightDirection.normalize();     // Normalize
-    gl.uniform3fv(vLightDirection, lightDirection.elements);
-
-    // Clear color and depth buffer
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
-    // Draw
-    drawHourGlass(gl, vpMatrix, mMVP, mNormal, null, false);
-    drawPlaneBase(gl, vpMatrix, mMVP, mNormal, null, false);
-
-    requestAnimationFrame(tick, canvas);
-  };
-  tick();
-}
-
-function ponctual_light() {
-  var canvas = document.getElementById('my-canvas2');
-  // Get the rendering context for WebGL
-  var gl = getWebGLContext(canvas);
-  if (!gl) {
-    console.log('Failed to get the rendering context for WebGL');
+  // Create a program for generating a shadow map
+  var shadowProgram = createProgram(gl, SHADOW_VSHADER_SOURCE, SHADOW_FSHADER_SOURCE);
+  shadowProgram.a_Position = gl.getAttribLocation(shadowProgram, 'a_Position');
+  shadowProgram.u_MvpMatrix = gl.getUniformLocation(shadowProgram, 'u_MvpMatrix');
+  if (shadowProgram.a_Position < 0 || !shadowProgram.u_MvpMatrix) {
+    console.log('Failed to get the storage location of attribute or uniform variable from shadowProgram'); 
     return;
   }
 
-  // Initialize shaders shadow
-  if (!initShaders(gl, SHADOW_VSHADER_SOURCE, SHADOW_FSHADER_SOURCE)) {
-    console.log('Failed to intialize shaders.');
+  // Create the normal program
+  var normalProgram = createProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE);
+  normalProgram.a_Position = gl.getAttribLocation(normalProgram, 'a_Position');
+  normalProgram.a_Color = gl.getAttribLocation(normalProgram, 'a_Color');
+  normalProgram.a_Normal = gl.getAttribLocation(normalProgram, 'a_Normal');
+  normalProgram.u_MvpMatrix = gl.getUniformLocation(normalProgram, 'u_MvpMatrix');
+  normalProgram.u_MvpMatrixFromLight = gl.getUniformLocation(normalProgram, 'u_MvpMatrixFromLight');
+  normalProgram.u_ShadowMap = gl.getUniformLocation(normalProgram, 'u_ShadowMap');
+  normalProgram.u_Clicked = gl.getUniformLocation(normalProgram, 'u_Clicked');
+  normalProgram.u_NormalMatrix = gl.getUniformLocation(normalProgram, 'u_NormalMatrix');
+  normalProgram.u_ModelMatrix = gl.getUniformLocation(normalProgram, 'u_ModelMatrix');
+  normalProgram.u_LightPosition = gl.getUniformLocation(normalProgram, 'u_LightPosition');
+  normalProgram.u_LightColor = gl.getUniformLocation(normalProgram, 'u_LightColor');
+  if (normalProgram.a_Position < 0 || normalProgram.a_Color < 0 || normalProgram.a_Normal < 0 || !normalProgram.u_MvpMatrix ||
+      !normalProgram.u_MvpMatrixFromLight || !normalProgram.u_ShadowMap || !normalProgram.u_Clicked || !normalProgram.u_NormalMatrix ||
+      !normalProgram.u_ModelMatrix || !normalProgram.u_LightPosition || !normalProgram.u_LightColor) {
+    console.log('Failed to get the storage location of attribute or uniform variable from normalProgram'); 
     return;
   }
 
-  // Initialize shaders
-  if (!initShaders(gl, VSHADER_SOURCE_PONCTUAL_LIGHT, FSHADER_SOURCE_PONCTUAL_LIGHT)) {
-    console.log('Failed to intialize shaders.');
+  // Set the vertex information of objects for the draw
+  var frustrum = initVertexBuffersForFrustrum(gl);
+  var plane = initVertexBuffersForPlane(gl);
+  if (!frustrum || !plane) {
+    console.log('Failed to set the vertex information');
     return;
   }
 
@@ -242,27 +193,42 @@ function ponctual_light() {
     console.log('Failed to initialize frame buffer object');
     return;
   }
-  gl.activeTexture(gl.TEXTURE0); // Set a texture object to the texture unit
+
+  // Set a texture object to the texture unit
+  gl.activeTexture(gl.TEXTURE0); 
   gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
 
   // Set the clear color and enable the depth test
   gl.clearColor(0, 0, 0, 1);
   gl.enable(gl.DEPTH_TEST);
 
-  // Get the storage locations
-  var mModel = gl.getUniformLocation(gl.program, 'mModel');
-  var mMVP = gl.getUniformLocation(gl.program, 'mMVP');
-  var mNormal = gl.getUniformLocation(gl.program, 'mNormal');
-  var vLightColor = gl.getUniformLocation(gl.program, 'vLightColor');
-  var vLightPosition = gl.getUniformLocation(gl.program, 'vLightPosition');
-  var u_Clicked = gl.getUniformLocation(gl.program, 'u_Clicked');
-  var u_is_hourglass = gl.getUniformLocation(gl.program, 'u_is_hourglass');
-  if (!mMVP || !mNormal || !vLightColor || !vLightPosition || !mModel || !u_Clicked) { 
-    console.log('Failed to get the storage location');
-    return;
-  }
-
-  canvas.onmousedown = function(ev) {   // Mouse is pressed
+  // View project for shadow map
+  var viewProjMatrixFromLight = new Matrix4(); 
+  viewProjMatrixFromLight.setPerspective(200.0, PERSPECTIVE_WIDTH_FROM_LIGHT/PERSPECTIVE_HEIGHT_FROM_LIGHT, 1.0, 100.0);
+  viewProjMatrixFromLight.lookAt(light_x, light_y, light_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+
+  // View project for normal program
+  var viewProjMatrix = new Matrix4();
+  viewProjMatrix.setPerspective(45, canvas.width/canvas.height, 1.0, 100.0);
+  viewProjMatrix.lookAt(eye_x, eye_y, eye_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+
+  // For the animation of hourglass
+  var animateHourGlass = false;
+  var currentAngle = 0.0;
+  var oldAngle = 0.0;
+
+  // A mvp for the 3 objects (2 frustrum and 1 plane)
+  var mvpMatrixFromLight_f = new Matrix4(); 
+  var mvpMatrixFromLight_f2 = new Matrix4();
+  var mvpMatrixFromLight_p = new Matrix4();
+
+  // Save data when event mouse clicked is active
+  var clicked_canvas = false;
+  var x_clicked = 0;
+  var y_clicked = 0;
+
+  // Event when mouse is clicked
+  canvas.onmousedown = function(ev) {
     var x = ev.clientX, y = ev.clientY;
     var rect = ev.target.getBoundingClientRect();
     if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
@@ -272,162 +238,184 @@ function ponctual_light() {
     }
   }
 
-  var vpMatrix = new Matrix4();   // View projection matrix
+  // Tick for create a shadow map and drawing 
+  var tick = function() {
+
+    // View project for light
+    viewProjMatrixFromLight.setPerspective(200.0, PERSPECTIVE_WIDTH_FROM_LIGHT/PERSPECTIVE_HEIGHT_FROM_LIGHT, 1.0, 100.0);
+    viewProjMatrixFromLight.lookAt(light_x, light_y, light_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+
+    // View project for camera
+    viewProjMatrix.setPerspective(45, canvas.width/canvas.height, 1.0, 100.0);
+    viewProjMatrix.lookAt(eye_x, eye_y, eye_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+
+    // Animate 180 degrees and change color of hourglass
+    if(animateHourGlass){
+      oldAngle = currentAngle
+      currentAngle += 1.0;
+      if(oldAngle >= 359 && gl.getUniform(normalProgram, normalProgram.u_Clicked) == 0){
+        animateHourGlass = false;
+        currentAngle = 0;
+      } else if(oldAngle >= 179 && gl.getUniform(normalProgram, normalProgram.u_Clicked) == 1){
+        animateHourGlass = false;
+        currentAngle = 180;
+      }
+    }
+    
+    // Use of framebuffer object for shadow map
+    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+    gl.viewport(0, 0, PERSPECTIVE_WIDTH_FROM_LIGHT, PERSPECTIVE_HEIGHT_FROM_LIGHT);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 
-  var tick = function () {
-    // Set perspective and camera
-    vpMatrix.setPerspective(50, canvas.width / canvas.height, 1, 100);
-    vpMatrix.lookAt(eyeX, eyeY, eyeZ, 0, 0, 0, 0, 1, 0);
+    // Use the programm shadow for generating a shadow map
+    gl.useProgram(shadowProgram);
 
-    // Set the light color (white)
-    gl.uniform3f(vLightColor, 1.0, 1.0, 1.0);
-    // Set the light position
-    gl.uniform3f(vLightPosition, lightPositionX, lightPositionY, lightPositionZ);
+    // Draw the two frustrum and plane for the shadow map
+    drawFrustrum(gl, shadowProgram, frustrum, currentAngle, viewProjMatrixFromLight, false);
+    mvpMatrixFromLight_f.set(tmp_mvpMatrix);
+    drawFrustrum(gl, shadowProgram, frustrum, currentAngle, viewProjMatrixFromLight, true);
+    mvpMatrixFromLight_f2.set(tmp_mvpMatrix);
+    drawPlane(gl, shadowProgram, plane, viewProjMatrixFromLight);
+    mvpMatrixFromLight_p.set(tmp_mvpMatrix);
 
-    // Clear color and depth buffer
+    // Use the normal program and the default framebuffer
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+    gl.viewport(0, 0, canvas.width, canvas.height);
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 
-    drawHourGlass(gl, vpMatrix, mMVP, mNormal, mModel, true, u_Clicked, u_is_hourglass);
-    drawPlaneBase(gl, vpMatrix, mMVP, mNormal, mModel, true, u_is_hourglass);
+    gl.useProgram(normalProgram);
+    gl.uniform3f(normalProgram.u_LightColor, 1.0, 1.0, 1.0); // The light is white
+    gl.uniform3f(normalProgram.u_LightPosition, light_x, light_y, light_z);
+    gl.uniform1i(normalProgram.u_ShadowMap, 0);  // Pass 0 because gl.TEXTURE0 is enabled
+
+    // Draw the two frustrum and plane for the normal program
+    gl.uniformMatrix4fv(normalProgram.u_MvpMatrixFromLight, false, mvpMatrixFromLight_f.elements);
+    drawFrustrum(gl, normalProgram, frustrum, currentAngle, viewProjMatrix, false);
+    gl.uniformMatrix4fv(normalProgram.u_MvpMatrixFromLight, false, mvpMatrixFromLight_f2.elements);
+    drawFrustrum(gl, normalProgram, frustrum, currentAngle, viewProjMatrix, true);
+    gl.uniformMatrix4fv(normalProgram.u_MvpMatrixFromLight, false, mvpMatrixFromLight_p.elements);
+    drawPlane(gl, normalProgram, plane, viewProjMatrix);
+
+    // Change color and animate when clicked
+    if(clicked_canvas && animateHourGlass == false){
+      var pixels = new Uint8Array(4);
+      gl.readPixels(x_clicked, y_clicked, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+      if(pixels[0] > 0 && pixels[1] == 0 && pixels[2] == 0){
+        gl.uniform1i(normalProgram.u_Clicked, 1);
+        animateHourGlass = true;
+      }
+      else if(pixels[0] == 0 && pixels[1] > 0 && pixels[2] == 0){
+        gl.uniform1i(normalProgram.u_Clicked, 0);
+        animateHourGlass = true;
+      }
+      clicked_canvas = false;
+    }
 
-    requestAnimationFrame(tick, canvas);
+    window.requestAnimationFrame(tick, canvas);
   };
-  tick();
+  tick(); 
 }
 
-function drawPlaneBase(gl, vpMatrix, mMVP, mNormal, mModel, isPonct, u_is_hourglass) {
-  gl.uniform1i(u_is_hourglass, 0);
-  var n = initVertexBuffersPlaneBase(gl);
-  if (n < 0) {
-    console.log('Failed to set the vertex information');
-    return;
+function drawFrustrum(gl, program, frustrum, angle, viewProjMatrix, is_second) {
+  // Rotate for the animation
+  tmp_modelMatrix.setRotate(angle, 1, 0, 0);
+  
+  // Rotate the second frustrum
+  if(is_second){
+    rotationSecFrustrumMatrix.setRotate(180, 1, 0, 0)
+    tmp_modelMatrix.multiply(rotationSecFrustrumMatrix);
   }
 
-  var modelMatrixTranslate = new Matrix4();
-  var mvpMatrix = new Matrix4();
-  var normalMatrix = new Matrix4();
-
-  modelMatrixTranslate.setTranslate(0, -0.001, 0);
-  if (isPonct) {
-    gl.uniformMatrix4fv(mModel, false, modelMatrixTranslate.elements);
-  }
-  mvpMatrix.set(vpMatrix).multiply(modelMatrixTranslate);
-  gl.uniformMatrix4fv(mMVP, false, mvpMatrix.elements);
-  normalMatrix.setInverseOf(modelMatrixTranslate);
-  normalMatrix.transpose();
-  gl.uniformMatrix4fv(mNormal, false, normalMatrix.elements);
+  // Change translate to have a good rotate animation
+  translateFrustrumMatrix.setTranslate(0, -1, 0);
+  tmp_modelMatrix.multiply(translateFrustrumMatrix);
+  draw(gl, program, frustrum, viewProjMatrix);
+}
 
-  gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
+function drawPlane(gl, program, plane, viewProjMatrix) {
+  // translate the plane to be good with the hourglass
+  tmp_modelMatrix.setTranslate(0, -1, 0);
+  draw(gl, program, plane, viewProjMatrix);
 }
 
-var angle = 0;
-var trans = 0;
-function drawHourGlass(gl, vpMatrix, mMVP, mNormal, mModel, isPonct, u_Clicked, u_is_hourglass) {
-  //angle += 1;
-  gl.uniform1i(u_is_hourglass, 1);
-  var n = initVertexBuffersHourglass(gl);
-  if (n < 0) {
-    console.log('Failed to set the vertex information');
-    return;
+function draw(gl, program, o, viewProjMatrix) {
+  initAttributeVariable(gl, program.a_Position, o.vertexBuffer);
+
+  // If programm shadow, he can't have the color buffer or normal buffer
+  if (program.a_Color != undefined){
+    initAttributeVariable(gl, program.a_Color, o.colorBuffer);
   }
 
-  var modelMatrixRotate = new Matrix4();  // Model matrix
-  var modelMatrixTranslate = new Matrix4();
-  var modelMatrixScale = new Matrix4();
-  var mvpMatrix = new Matrix4();    // Model view projection matrix
-  var normalMatrix = new Matrix4(); // Transformation matrix for normals
-
-  // First frustrum
-  modelMatrixRotate.setRotate(0 + angle, 1, 0, 0); // Rotate around the y-axis
-  modelMatrixTranslate.setTranslate(0, 0.0 - trans, 0);
-  var finalModelMatrix = modelMatrixRotate.multiply(modelMatrixTranslate).multiply(modelMatrixScale);
-  if (isPonct) {
-    gl.uniformMatrix4fv(mModel, false, finalModelMatrix.elements);
+  if (program.a_Normal != undefined){
+    initAttributeVariable(gl, program.a_Normal, o.normalsBuffer);
   }
+  
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, o.indexBuffer);
 
-  mvpMatrix.set(vpMatrix).multiply(modelMatrixRotate);
-  gl.uniformMatrix4fv(mMVP, false, mvpMatrix.elements);
-  normalMatrix.setInverseOf(modelMatrixRotate);
-  normalMatrix.transpose();
-  gl.uniformMatrix4fv(mNormal, false, normalMatrix.elements);
+  // Calculate the mvp matrix and pass it to u_MvpMatrix
+  tmp_mvpMatrix.set(viewProjMatrix);
+  tmp_mvpMatrix.multiply(tmp_modelMatrix);
+  gl.uniformMatrix4fv(program.u_MvpMatrix, false, tmp_mvpMatrix.elements);
 
-  
-  gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
-
-  // Second frustrum
-  modelMatrixRotate.setRotate(180 + angle, 1, 0, 0);
-  modelMatrixTranslate.setTranslate(0, -2.0 + trans, 0);
-  modelMatrixScale.setScale(-1, 1, -1);
-  var finalModelMatrix = modelMatrixRotate.multiply(modelMatrixTranslate).multiply(modelMatrixScale);
-  if (isPonct) {
-    gl.uniformMatrix4fv(mModel, false, finalModelMatrix.elements);
-  }
-  mvpMatrix.set(vpMatrix).multiply(finalModelMatrix)
-  gl.uniformMatrix4fv(mMVP, false, mvpMatrix.elements);
-  normalMatrix.setInverseOf(finalModelMatrix);
-  normalMatrix.transpose();
-  gl.uniformMatrix4fv(mNormal, false, normalMatrix.elements);
-  gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
-
-  if(clicked_canvas){
-    var pixels = new Uint8Array(4); // Array for storing the pixel value
-    gl.readPixels(x_clicked, y_clicked, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
-    console.log(pixels);
-    if(pixels[0] > 0){
-      console.log("Rouge");
-      if(isPonct){
-        gl.getUniform(gl.program, u_Clicked);
-      }
-      gl.uniform1i(u_Clicked, 1);
-    }
-    else if(pixels[1] > 0){
-      console.log("Vert");
-      gl.uniform1i(u_Clicked, 0);
-    }
-    clicked_canvas = false;
-  }
+  // Calculate normals
+  tmp_normalMatrix.setInverseOf(tmp_modelMatrix);
+  tmp_normalMatrix.transpose();
+  gl.uniformMatrix4fv(program.u_NormalMatrix, false, tmp_normalMatrix.elements);
+
+  // Stock the model matrix
+  gl.uniformMatrix4fv(program.u_ModelMatrix, false, tmp_modelMatrix.elements);
+
+  gl.drawElements(gl.TRIANGLES, o.numIndices, gl.UNSIGNED_BYTE, 0);
 }
 
-function initVertexBuffersPlaneBase(gl) {
-  var vertices_position = new Float32Array([
-    -2.0, -0.5, -2.0, 2.0, -0.5, 2.0, -2.0, -0.5, 2.0, 2.0, -0.5, -2.0
+// Assign the buffer objects and enable the assignment
+function initAttributeVariable(gl, a_attribute, buffer) {
+  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+  gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
+  gl.enableVertexAttribArray(a_attribute);
+}
+
+function initVertexBuffersForPlane(gl) {
+
+  // Vertex coordinates
+  var vertices = new Float32Array([
+    -5.0, -0.5, -5.0, 5.0, -0.5, 5.0, -5.0, -0.5, 5.0, 5.0, -0.5, -5.0
   ]);
 
-  // Colors only white for this tp
+  // Colors
   var colors = new Float32Array([
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+    1.0, 1.0, 1.0,    1.0, 1.0, 1.0,  1.0, 1.0, 1.0,   1.0, 1.0, 1.0
   ]);
 
+  // Normals
   var normals = new Float32Array([
     0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0
   ]);
 
-  var indices = new Uint8Array([
-    0, 1, 2, 0, 1, 3
-  ]);
+  // Indices of the vertices
+  var indices = new Uint8Array([0, 1, 2, 0, 1, 3]);
+
+  var o = new Object(); // Utilize Object object to return multiple buffer objects together
 
-  // Write the vertex property to buffers (positions, colors and normals)
-  if (!initArrayBuffer(gl, 'a_Position', vertices_position, 3, gl.FLOAT)) return -1;
-  if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
-  if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
+  // Write vertex information to buffer object
+  o.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
+  o.colorBuffer = initArrayBufferForLaterUse(gl, colors, 3, gl.FLOAT);
+  o.normalsBuffer = initArrayBufferForLaterUse(gl, normals, 3, gl.FLOAT);
+  o.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
+  if (!o.vertexBuffer || !o.colorBuffer || !o.indexBuffer || !o.normalsBuffer) return null; 
+
+  o.numIndices = indices.length;
 
   // Unbind the buffer object
   gl.bindBuffer(gl.ARRAY_BUFFER, null);
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
 
-  // Write the indices to the buffer object
-  var indexBuffer = gl.createBuffer();
-  if (!indexBuffer) {
-    console.log('Failed to create the buffer object');
-    return false;
-  }
-  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
-  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
-
-  return indices.length;
+  return o;
 }
 
-function initVertexBuffersHourglass(gl) {
-  var vertices_position = new Float32Array([
+function initVertexBuffersForFrustrum(gl) {
+  // Vertex coordinates
+  var vertices = new Float32Array([
     -0.25, 1.0, 0.25, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.25, 1.0, 0.25, // front face
     0.25, 1.0, 0.25, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.25, 1.0, -0.25,// right face
     -0.25, 1.0, -0.25, 0.25, 1.0, 0.25, -0.25, 1.0, 0.25, 0.25, 1.0, -0.25, // Up face 
@@ -436,7 +424,7 @@ function initVertexBuffersHourglass(gl) {
     0.25, 1.0, -0.25, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.25, 1.0, -0.25 // back face
   ]);
 
-  // Colors only red for this tp
+  // Colors
   var colors = new Float32Array([
     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
@@ -445,17 +433,18 @@ function initVertexBuffersHourglass(gl) {
     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0
   ]);
-
+    
   var normals = new Float32Array([
     0.0, 1.0, 1.0,  0.0, 1.0, 1.0,  0.0, 1.0, 1.0,  0.0, 1.0, 1.0, // front face
     1.0, 1.0, 0.0,  1.0, 1.0, 0.0,  1.0, 1.0, 0.0,  1.0, 1.0, 0.0, // right face
     0.0, 1.0, 0.0,  0.0, 1.0, 0.0,  0.0, 1.0, 0.0,   0.0, 1.0, 0.0, // up face
     -1.0, 1.0, 0.0,  -1.0, 1.0, 0.0,  -1.0, 1.0, 0.0,  -1.0, 1.0, 0.0, // left face
     0.0, -1.0, 0.0,  0.0, -1.0, 0.0,  0.0, -1.0, 0.0,   0.0, -1.0, 0.0,  // down face
-    0.0, 1.0, -1.0,  0.0, 1.0, -1.0,  0.0, 1.0, -1.0,  0.0, 1.0, -1.0,  // back face
+    0.0, 1.0, -1.0,  0.0, 1.0, -1.0,  0.0, 1.0, -1.0,  0.0, 1.0, -1.0  // back face
   ]);
 
-  var indices = new Uint8Array([
+  // Indices of the vertices
+  var indices = new Uint8Array([ 
     0, 1, 2, 0, 1, 3,    // front Face
     4, 5, 6, 4, 5, 7,	// right face
     8, 9, 10, 8, 9, 11,	// up face
@@ -464,49 +453,59 @@ function initVertexBuffersHourglass(gl) {
     20, 21, 22, 20, 21, 23 // back face
   ]);
 
-  // Write the vertex property to buffers (positions, colors and normals)
-  if (!initArrayBuffer(gl, 'a_Position', vertices_position, 3, gl.FLOAT)) return -1;
-  if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
-  if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
+  var o = new Object();  // Utilize Object object to return multiple buffer objects together
+
+  // Write vertex information to buffer object
+  o.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
+  o.colorBuffer = initArrayBufferForLaterUse(gl, colors, 3, gl.FLOAT);
+  o.normalsBuffer = initArrayBufferForLaterUse(gl, normals, 3, gl.FLOAT);
+  o.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
+  if (!o.vertexBuffer || !o.colorBuffer || !o.indexBuffer || !o.normalsBuffer) return null; 
+
+  o.numIndices = indices.length;
 
   // Unbind the buffer object
   gl.bindBuffer(gl.ARRAY_BUFFER, null);
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
 
-  // Write the indices to the buffer object
-  var indexBuffer = gl.createBuffer();
-  if (!indexBuffer) {
-    console.log('Failed to create the buffer object');
-    return false;
-  }
-  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
-  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
-
-  return indices.length;
+  return o;
 }
 
-function initArrayBuffer(gl, attribute, data, num, type) {
+function initArrayBufferForLaterUse(gl, data, num, type) {
   // Create a buffer object
   var buffer = gl.createBuffer();
   if (!buffer) {
     console.log('Failed to create the buffer object');
-    return false;
+    return null;
   }
   // Write date into the buffer object
   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
   gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
-  // Assign the buffer object to the attribute variable
-  var a_attribute = gl.getAttribLocation(gl.program, attribute);
-  if (a_attribute < 0) {
-    console.log('Failed to get the storage location of ' + attribute);
-    return false;
+
+  // Store the necessary information to assign the object to the attribute variable later
+  buffer.num = num;
+  buffer.type = type;
+
+  return buffer;
+}
+
+function initElementArrayBufferForLaterUse(gl, data, type) {
+  // Create a buffer object
+  var buffer = gl.createBuffer();
+  if (!buffer) {
+    console.log('Failed to create the buffer object');
+    return null;
   }
-  gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
-  // Enable the assignment of the buffer object to the attribute variable
-  gl.enableVertexAttribArray(a_attribute);
+  // Write date into the buffer object
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
+
+  buffer.type = type;
 
-  return true;
+  return buffer;
 }
 
+// Create the framebuffer fbo for shadow map
 function initFramebufferObject(gl) {
   var framebuffer, texture, depthBuffer;
 
@@ -531,8 +530,9 @@ function initFramebufferObject(gl) {
     console.log('Failed to create texture object');
     return error();
   }
+  
   gl.bindTexture(gl.TEXTURE_2D, texture);
-  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, PERSPECTIVE_WIDTH_FROM_LIGHT, PERSPECTIVE_HEIGHT_FROM_LIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 
   // Create a renderbuffer object and Set its size and parameters
@@ -542,7 +542,7 @@ function initFramebufferObject(gl) {
     return error();
   }
   gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
-  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
+  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, PERSPECTIVE_WIDTH_FROM_LIGHT, PERSPECTIVE_HEIGHT_FROM_LIGHT);
 
   // Attach the texture and the renderbuffer object to the FBO
   gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
-- 
GitLab