From de2927b54f0b7b4c00d981902d4dd600451c3ef6 Mon Sep 17 00:00:00 2001 From: "quentin.berthet1" <quentin.berthet@etu.hesge.ch> Date: Fri, 18 Dec 2020 09:08:55 +0100 Subject: [PATCH] labo3+4 --- lab3.0/README.md | 6 - lab3.0/docs/Cours 3D Labo 3.pdf | Bin 32952 -> 0 bytes lab3.0/src/lab3.html | 20 - lab3.0/src/lab3.js | 293 ----------- lab3.1/README.md | 6 - lab3.1/docs/Cours 3D Labo 3.pdf | Bin 32952 -> 0 bytes lab3.1/lib/cuon-utils.js | 113 ----- lab3.1/lib/webgl-debug.js | 677 ------------------------- lab3.1/lib/webgl-utils.js | 197 -------- lab3.1/src/lab3.html | 20 - lab3.1/src/lab3.js | 470 ------------------ lab3/README.md | 6 +- lab3/src/lab3.html | 11 + lab3/src/lab3.js | 666 +++++++++---------------- lab3Bis/README.md | 6 - lab3Bis/docs/Cours 3D Labo 3.pdf | Bin 32952 -> 0 bytes lab3Bis/lib/cuon-matrix.js | 741 ---------------------------- lab3Bis/lib/cuon-utils.js | 113 ----- lab3Bis/lib/webgl-debug.js | 677 ------------------------- lab3Bis/lib/webgl-utils.js | 197 -------- lab3Bis/src/lab3.html | 20 - lab3Bis/src/lab3.js | 458 ----------------- lab4/README.md | 6 + lab4/docs/Cours 3D Labo 4.pdf | Bin 0 -> 74144 bytes {lab3.0 => lab4}/lib/cuon-utils.js | 0 {lab3.0 => lab4}/lib/webgl-debug.js | 0 {lab3.0 => lab4}/lib/webgl-utils.js | 0 lab4/src/lab4.html | 16 + lab4/src/lab4.js | 18 + 29 files changed, 290 insertions(+), 4447 deletions(-) delete mode 100644 lab3.0/README.md delete mode 100644 lab3.0/docs/Cours 3D Labo 3.pdf delete mode 100644 lab3.0/src/lab3.html delete mode 100644 lab3.0/src/lab3.js delete mode 100644 lab3.1/README.md delete mode 100644 lab3.1/docs/Cours 3D Labo 3.pdf delete mode 100644 lab3.1/lib/cuon-utils.js delete mode 100644 lab3.1/lib/webgl-debug.js delete mode 100644 lab3.1/lib/webgl-utils.js delete mode 100644 lab3.1/src/lab3.html delete mode 100644 lab3.1/src/lab3.js delete mode 100644 lab3Bis/README.md delete mode 100644 lab3Bis/docs/Cours 3D Labo 3.pdf delete mode 100644 lab3Bis/lib/cuon-matrix.js delete mode 100644 lab3Bis/lib/cuon-utils.js delete mode 100644 lab3Bis/lib/webgl-debug.js delete mode 100644 lab3Bis/lib/webgl-utils.js delete mode 100644 lab3Bis/src/lab3.html delete mode 100644 lab3Bis/src/lab3.js create mode 100644 lab4/README.md create mode 100644 lab4/docs/Cours 3D Labo 4.pdf rename {lab3.0 => lab4}/lib/cuon-utils.js (100%) rename {lab3.0 => lab4}/lib/webgl-debug.js (100%) rename {lab3.0 => lab4}/lib/webgl-utils.js (100%) create mode 100644 lab4/src/lab4.html create mode 100644 lab4/src/lab4.js diff --git a/lab3.0/README.md b/lab3.0/README.md deleted file mode 100644 index 37ef2aa..0000000 --- a/lab3.0/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Lab3 IHM - -* **docs**: contains the lab's statement -* **libs**: contains WebGL libraries and utilities -* **src**: contains the source code of the lab2 that you should complete (`main()` function in **lab3.js** file) -* **DO NOT CHANGE** the name of the file `lab3.html`, however, you are free to change its content. diff --git a/lab3.0/docs/Cours 3D Labo 3.pdf b/lab3.0/docs/Cours 3D Labo 3.pdf deleted file mode 100644 index 95be1783746c753299fd5ae3d412b90a2c39ad9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32952 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ðKXPd*Dt1?%l0ho3+mF3;VtLfW<lMj}B5M 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 diff --git a/lab3.0/src/lab3.html b/lab3.0/src/lab3.html deleted file mode 100644 index eb19ba3..0000000 --- a/lab3.0/src/lab3.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <title>Lab 3</title> -</head> - -<body onload="main()"> - <canvas width="400" height="600" id="my-canvas"> - Please use a browser that supports "canvas" -</canvas> - <script src="../lib/webgl-utils.js"></script> - <script src="../lib/webgl-debug.js"></script> - <script src="../lib/cuon-matrix.js"></script> - <script src="../lib/cuon-utils.js"></script> - <script src="lab3.js"></script> -</body> - -</html> \ No newline at end of file diff --git a/lab3.0/src/lab3.js b/lab3.0/src/lab3.js deleted file mode 100644 index 24f9a23..0000000 --- a/lab3.0/src/lab3.js +++ /dev/null @@ -1,293 +0,0 @@ -//author : QUentin Berthet -const VSHADER_SOURCE = - 'attribute vec4 a_Position;\n' + - 'attribute vec3 a_normal;\n' + - 'attribute vec4 a_Color;\n' + - - 'uniform mat4 u_worldViewProjection;\n' + - 'uniform mat4 u_worldInverseTranspose;\n' + - - 'varying vec3 v_normal;\n' + - 'varying vec4 v_Color;\n' + - - - 'void main() {\n' + - ' gl_Position = u_worldViewProjection * a_Position ;\n' + - ' v_normal = mat3(u_worldInverseTranspose) * a_normal;\n' + - ' v_Color = a_Color;\n' + - '}\n'; - - -const FSHADER_SOURCE = - 'precision mediump float;\n' + - - 'varying vec4 v_Color;\n' + - 'varying vec3 v_normal;\n' + - 'uniform vec3 u_reverseLightDirection;\n' + - - 'void main() {\n' + - ' vec3 normal = normalize(v_normal);\n' + - ' float light = dot(normal, u_reverseLightDirection);\n' + - - ' gl_FragColor = v_Color;\n' + - ' gl_FragColor.rgb *= light;\n' + - '}\n' - -function main() { - - const canvas = document.getElementById('my-canvas'); - - - const gl = getWebGLContext(canvas); - if (!gl) { - console.log('Failed to get the displaying context for WebGL'); - return; - } - - - if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { - console.log('Failed to intialize shaders.'); - return; - } - - - const len = initVertexBuffers(gl); - if (len < 0) { - console.log('Failed to set the positions of the vertices'); - return; - } - - gl.clearColor(0.75, 0.85, 0.8, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.enable(gl.DEPTH_TEST); - gl.frontFace(gl.CCW); - gl.cullFace(gl.BACK); - - - var u_mat = gl.getUniformLocation(gl.program, 'u_mat'); - - var mat = new Matrix4(); - - - var viewProjMatrix = new Matrix4(); - viewProjMatrix.setPerspective(100.0, 1.0, 1.0, 1000.0); - viewProjMatrix.lookAt(1.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - - var vals = [0.0, 0.0]; - ObjectManager(vals); - - var display = function() { - mat.set(viewProjMatrix); - mat.rotate(vals[0], 1.0, 0.0, 0.0); - mat.rotate(vals[1], 0.0, 1.0, 0.0); - gl.uniformMatrix4fv(u_mat, false, mat.elements); - - - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.drawArrays(gl.TRIANGLES, 0, len); - - mat.translate(0, 3.0, -4) - mat.rotate(180, 1.0, 0.0, 0.0); - gl.uniformMatrix4fv(u_mat, false, mat.elements); - gl.drawArrays(gl.TRIANGLES, 0, len); - - - requestAnimationFrame(display); - }; - display(); -} - -function ObjectManager(values) { - document.onkeydown = (ev) => { - v = 10; - switch (ev.key) { - case 'ArrowDown': - values[0] += v; - break; - case 'ArrowUp': - values[0] -= v; - break; - case 'ArrowRight': - values[1] += v; - break; - case 'ArrowLeft': - values[1] -= v; - break; - } - }; -} - - -function CreateNormals(gl) { - var normales = new Float32Array( - [ //front - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - - // back - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - - - // left - -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, - - // right - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - - // top - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - - // ground - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - ]); - gl.bufferData(gl.ARRAY_BUFFER, normales, gl.STATIC_DRAW); - -} - - -function initVertexBuffers(gl) { - - let vertices = new Float32Array([ - - // Front - -2, -1.5, 0, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - - -1, 1.5, -1, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - 0, -1.5, 0, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - 2, -1.5, 0, 0, 1, 0, - - // Back - -2, -1.5, -4, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, - 0, -1.5, -4, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, - 0, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - - 0, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - - // Left - -2, -1.5, -4, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, -2, -1.5, -2, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, -2, -1.5, -2, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, - - -2, -1.5, -2, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, -2, -1.5, 0, 0, 1, 0, - - // Right - 2, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -2, 0, 1, 0, - - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -2, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - 2, -1.5, -2, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - 2, -1.5, -0, 0, 1, 0, - - // top - -1, 1.5, -1, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, - 0, 1.5, -1, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, - 0, 1.5, -1, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - - 0, 1.5, -1, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - // ground - -2, -1.5, 0, 0, 1, 0, -2, -1.5, -4, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - - -2, -1.5, -4, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - - 0, -1.5, 0, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - 2, -1.5, 0, 0, 1, 0 - - ]); - - const len = vertices.length / 6; - - const vertexBuffer = gl.createBuffer(); - if (!vertexBuffer) { - console.log('Failed to create the buffer object'); - return -1; - } - - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - - - const a_Position = gl.getAttribLocation(gl.program, 'a_Position'); - if (a_Position < 0) { - console.log('Failed to get the storage location of a_Position'); - return -1; - } - gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 24, 0); - gl.enableVertexAttribArray(a_Position); - - var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); - if (a_Color < 0) { - console.log('Failed to get the storage location of a_Color'); - return -1; - } - - gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12); - gl.enableVertexAttribArray(a_Color); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - return len; -} \ No newline at end of file diff --git a/lab3.1/README.md b/lab3.1/README.md deleted file mode 100644 index 37ef2aa..0000000 --- a/lab3.1/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Lab3 IHM - -* **docs**: contains the lab's statement -* **libs**: contains WebGL libraries and utilities -* **src**: contains the source code of the lab2 that you should complete (`main()` function in **lab3.js** file) -* **DO NOT CHANGE** the name of the file `lab3.html`, however, you are free to change its content. diff --git a/lab3.1/docs/Cours 3D Labo 3.pdf b/lab3.1/docs/Cours 3D Labo 3.pdf deleted file mode 100644 index 95be1783746c753299fd5ae3d412b90a2c39ad9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32952 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ðKXPd*Dt1?%l0ho3+mF3;VtLfW<lMj}B5M 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 diff --git a/lab3.1/lib/cuon-utils.js b/lab3.1/lib/cuon-utils.js deleted file mode 100644 index dc08b2e..0000000 --- a/lab3.1/lib/cuon-utils.js +++ /dev/null @@ -1,113 +0,0 @@ -// cuon-utils.js (c) 2012 kanda and matsuda -/** - * Create a program object and make current - * @param gl GL context - * @param vshader a vertex shader program (string) - * @param fshader a fragment shader program (string) - * @return true, if the program object was created and successfully made current - */ -function initShaders(gl, vshader, fshader) { - var program = createProgram(gl, vshader, fshader); - if (!program) { - console.log('Failed to create program'); - return false; - } - - gl.useProgram(program); - gl.program = program; - - return true; -} - -/** - * Create the linked program object - * @param gl GL context - * @param vshader a vertex shader program (string) - * @param fshader a fragment shader program (string) - * @return created program object, or null if the creation has failed - */ -function createProgram(gl, vshader, fshader) { - // Create shader object - var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader); - var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader); - if (!vertexShader || !fragmentShader) { - return null; - } - - // Create a program object - var program = gl.createProgram(); - if (!program) { - return null; - } - - // Attach the shader objects - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - - // Link the program object - gl.linkProgram(program); - - // Check the result of linking - var linked = gl.getProgramParameter(program, gl.LINK_STATUS); - if (!linked) { - var error = gl.getProgramInfoLog(program); - console.log('Failed to link program: ' + error); - gl.deleteProgram(program); - gl.deleteShader(fragmentShader); - gl.deleteShader(vertexShader); - return null; - } - return program; -} - -/** - * Create a shader object - * @param gl GL context - * @param type the type of the shader object to be created - * @param source shader program (string) - * @return created shader object, or null if the creation has failed. - */ -function loadShader(gl, type, source) { - // Create shader object - var shader = gl.createShader(type); - if (shader == null) { - console.log('unable to create shader'); - return null; - } - - // Set the shader program - gl.shaderSource(shader, source); - - // Compile the shader - gl.compileShader(shader); - - // Check the result of compilation - var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); - if (!compiled) { - var error = gl.getShaderInfoLog(shader); - console.log('Failed to compile shader: ' + error); - gl.deleteShader(shader); - return null; - } - - return shader; -} - -/** - * Initialize and get the rendering for WebglInstance - * @param canvas <cavnas> element - * @param opt_debug flag to initialize the context for debugging - * @return the rendering context for WebglInstance - */ -function getWebGLContext(canvas, opt_debug) { - // Get the rendering context for WebglInstance - var gl = WebGLUtils.setupWebGL(canvas); - if (!gl) return null; - - // if opt_debug is explicitly false, create the context for debugging - if (arguments.length < 2 || opt_debug) { - gl = WebGLDebugUtils.makeDebugContext(gl); - } - - return gl; -} diff --git a/lab3.1/lib/webgl-debug.js b/lab3.1/lib/webgl-debug.js deleted file mode 100644 index 685868d..0000000 --- a/lab3.1/lib/webgl-debug.js +++ /dev/null @@ -1,677 +0,0 @@ -//Copyright (c) 2009 The Chromium Authors. All rights reserved. -//Use of this source code is governed by a BSD-style license that can be -//found in the LICENSE file. - -// Various functions for helping debug WebglInstance apps. - -WebGLDebugUtils = function() { - -/** - * Wrapped logging function. - * @param {string} msg Message to log. - */ -var log = function(msg) { - if (window.console && window.console.log) { - window.console.log(msg); - } -}; - -/** - * Which arguements are enums. - * @type {!Object.<number, string>} - */ -var glValidEnumContexts = { - - // Generic setters and getters - - 'enable': { 0:true }, - 'disable': { 0:true }, - 'getParameter': { 0:true }, - - // Rendering - - 'drawArrays': { 0:true }, - 'drawElements': { 0:true, 2:true }, - - // Shaders - - 'createShader': { 0:true }, - 'getShaderParameter': { 1:true }, - 'getProgramParameter': { 1:true }, - - // Vertex attributes - - 'getVertexAttrib': { 1:true }, - 'vertexAttribPointer': { 2:true }, - - // Textures - - 'bindTexture': { 0:true }, - 'activeTexture': { 0:true }, - 'getTexParameter': { 0:true, 1:true }, - 'texParameterf': { 0:true, 1:true }, - 'texParameteri': { 0:true, 1:true, 2:true }, - 'texImage2D': { 0:true, 2:true, 6:true, 7:true }, - 'texSubImage2D': { 0:true, 6:true, 7:true }, - 'copyTexImage2D': { 0:true, 2:true }, - 'copyTexSubImage2D': { 0:true }, - 'generateMipmap': { 0:true }, - - // Buffer objects - - 'bindBuffer': { 0:true }, - 'bufferData': { 0:true, 2:true }, - 'bufferSubData': { 0:true }, - 'getBufferParameter': { 0:true, 1:true }, - - // Renderbuffers and framebuffers - - 'pixelStorei': { 0:true, 1:true }, - 'readPixels': { 4:true, 5:true }, - 'bindRenderbuffer': { 0:true }, - 'bindFramebuffer': { 0:true }, - 'checkFramebufferStatus': { 0:true }, - 'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, - 'framebufferTexture2D': { 0:true, 1:true, 2:true }, - 'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, - 'getRenderbufferParameter': { 0:true, 1:true }, - 'renderbufferStorage': { 0:true, 1:true }, - - // Frame buffer operations (clear, blend, depth test, stencil) - - 'clear': { 0:true }, - 'depthFunc': { 0:true }, - 'blendFunc': { 0:true, 1:true }, - 'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, - 'blendEquation': { 0:true }, - 'blendEquationSeparate': { 0:true, 1:true }, - 'stencilFunc': { 0:true }, - 'stencilFuncSeparate': { 0:true, 1:true }, - 'stencilMaskSeparate': { 0:true }, - 'stencilOp': { 0:true, 1:true, 2:true }, - 'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, - - // Culling - - 'cullFace': { 0:true }, - 'frontFace': { 0:true }, -}; - -/** - * Map of numbers to names. - * @type {Object} - */ -var glEnums = null; - -/** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebglInstance context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ -function init(ctx) { - if (glEnums == null) { - glEnums = { }; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'number') { - glEnums[ctx[propertyName]] = propertyName; - } - } - } -} - -/** - * Checks the utils have been initialized. - */ -function checkInit() { - if (glEnums == null) { - throw 'WebGLDebugUtils.init(ctx) not called'; - } -} - -/** - * Returns true or false if value matches any WebglInstance enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebglInstance defined enums - */ -function mightBeEnum(value) { - checkInit(); - return (glEnums[value] !== undefined); -} - -/** - * Gets an string version of an WebglInstance enum. - * - * Example: - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ -function glEnumToString(value) { - checkInit(); - var name = glEnums[value]; - return (name !== undefined) ? name : - ("*UNKNOWN WebglInstance ENUM (0x" + value.toString(16) + ")"); -} - -/** - * Returns the string version of a WebglInstance argument. - * Attempts to convert enum arguments to strings. - * @param {string} functionName the name of the WebglInstance function. - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ -function glFunctionArgToString(functionName, argumentIndex, value) { - var funcInfo = glValidEnumContexts[functionName]; - if (funcInfo !== undefined) { - if (funcInfo[argumentIndex]) { - return glEnumToString(value); - } - } - return value.toString(); -} - -/** - * Given a WebglInstance context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not gl.NO_ERROR. - * - * @param {!WebGLRenderingContext} ctx The webgl context to - * wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc - * The function to call when gl.getError returns an - * error. If not specified the default function calls - * console.log with a message. - */ -function makeDebugContext(ctx, opt_onErrorFunc) { - init(ctx); - opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { - // apparently we can't do args.join(","); - var argStr = ""; - for (var ii = 0; ii < args.length; ++ii) { - argStr += ((ii == 0) ? '' : ', ') + - glFunctionArgToString(functionName, ii, args[ii]); - } - log("WebglInstance error "+ glEnumToString(err) + " in "+ functionName + - "(" + argStr + ")"); - }; - - // Holds booleans for each GL error so after we get the error ourselves - // we can still return it to the client app. - var glErrorShadow = { }; - - // Makes a function that calls a WebglInstance function and then calls getError. - function makeErrorWrapper(ctx, functionName) { - return function() { - var result = ctx[functionName].apply(ctx, arguments); - var err = ctx.getError(); - if (err != 0) { - glErrorShadow[err] = true; - opt_onErrorFunc(err, functionName, arguments); - } - return result; - }; - } - - // Make a an object that has a copy of every property of the WebglInstance context - // but wraps all functions. - var wrapper = {}; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); - } else { - wrapper[propertyName] = ctx[propertyName]; - } - } - - // Override the getError function with one that returns our saved results. - wrapper.getError = function() { - for (var err in glErrorShadow) { - if (glErrorShadow[err]) { - glErrorShadow[err] = false; - return err; - } - } - return ctx.NO_ERROR; - }; - - return wrapper; -} - -function resetToInitialState(ctx) { - var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); - var tmp = ctx.createBuffer(); - ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp); - for (var ii = 0; ii < numAttribs; ++ii) { - ctx.disableVertexAttribArray(ii); - ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0); - ctx.vertexAttrib1f(ii, 0); - } - ctx.deleteBuffer(tmp); - - var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); - for (var ii = 0; ii < numTextureUnits; ++ii) { - ctx.activeTexture(ctx.TEXTURE0 + ii); - ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null); - ctx.bindTexture(ctx.TEXTURE_2D, null); - } - - ctx.activeTexture(ctx.TEXTURE0); - ctx.useProgram(null); - ctx.bindBuffer(ctx.ARRAY_BUFFER, null); - ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); - ctx.disable(ctx.BLEND); - ctx.disable(ctx.CULL_FACE); - ctx.disable(ctx.DEPTH_TEST); - ctx.disable(ctx.DITHER); - ctx.disable(ctx.SCISSOR_TEST); - ctx.blendColor(0, 0, 0, 0); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ZERO); - ctx.clearColor(0, 0, 0, 0); - ctx.clearDepth(1); - ctx.clearStencil(-1); - ctx.colorMask(true, true, true, true); - ctx.cullFace(ctx.BACK); - ctx.depthFunc(ctx.LESS); - ctx.depthMask(true); - ctx.depthRange(0, 1); - ctx.frontFace(ctx.CCW); - ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE); - ctx.lineWidth(1); - ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false); - ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); - // TODO: Delete this IF. - if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) { - ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL); - } - ctx.polygonOffset(0, 0); - ctx.sampleCoverage(1, false); - ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height); - ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF); - ctx.stencilMask(0xFFFFFFFF); - ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP); - ctx.viewport(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight); - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT); - - // TODO: This should NOT be needed but Firefox fails with 'hint' - while(ctx.getError()); -} - -function makeLostContextSimulatingContext(ctx) { - var wrapper_ = {}; - var contextId_ = 1; - var contextLost_ = false; - var resourceId_ = 0; - var resourceDb_ = []; - var onLost_ = undefined; - var onRestored_ = undefined; - var nextOnRestored_ = undefined; - - // Holds booleans for each GL error so can simulate errors. - var glErrorShadow_ = { }; - - function isWebGLObject(obj) { - //return false; - return (obj instanceof WebGLBuffer || - obj instanceof WebGLFramebuffer || - obj instanceof WebGLProgram || - obj instanceof WebGLRenderbuffer || - obj instanceof WebGLShader || - obj instanceof WebGLTexture); - } - - function checkResources(args) { - for (var ii = 0; ii < args.length; ++ii) { - var arg = args[ii]; - if (isWebGLObject(arg)) { - return arg.__webglDebugContextLostId__ == contextId_; - } - } - return true; - } - - function clearErrors() { - var k = Object.keys(glErrorShadow_); - for (var ii = 0; ii < k.length; ++ii) { - delete glErrorShdow_[k]; - } - } - - // Makes a function that simulates WebglInstance when out of context. - function makeLostContextWrapper(ctx, functionName) { - var f = ctx[functionName]; - return function() { - // Only call the functions if the context is not lost. - if (!contextLost_) { - if (!checkResources(arguments)) { - glErrorShadow_[ctx.INVALID_OPERATION] = true; - return; - } - var result = f.apply(ctx, arguments); - return result; - } - }; - } - - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - wrapper_[propertyName] = makeLostContextWrapper(ctx, propertyName); - } else { - wrapper_[propertyName] = ctx[propertyName]; - } - } - - function makeWebGLContextEvent(statusMessage) { - return {statusMessage: statusMessage}; - } - - function freeResources() { - for (var ii = 0; ii < resourceDb_.length; ++ii) { - var resource = resourceDb_[ii]; - if (resource instanceof WebGLBuffer) { - ctx.deleteBuffer(resource); - } else if (resource instanceof WebctxFramebuffer) { - ctx.deleteFramebuffer(resource); - } else if (resource instanceof WebctxProgram) { - ctx.deleteProgram(resource); - } else if (resource instanceof WebctxRenderbuffer) { - ctx.deleteRenderbuffer(resource); - } else if (resource instanceof WebctxShader) { - ctx.deleteShader(resource); - } else if (resource instanceof WebctxTexture) { - ctx.deleteTexture(resource); - } - } - } - - wrapper_.loseContext = function() { - if (!contextLost_) { - contextLost_ = true; - ++contextId_; - while (ctx.getError()); - clearErrors(); - glErrorShadow_[ctx.CONTEXT_LOST_WEBGL] = true; - setTimeout(function() { - if (onLost_) { - onLost_(makeWebGLContextEvent("context lost")); - } - }, 0); - } - }; - - wrapper_.restoreContext = function() { - if (contextLost_) { - if (onRestored_) { - setTimeout(function() { - freeResources(); - resetToInitialState(ctx); - contextLost_ = false; - if (onRestored_) { - var callback = onRestored_; - onRestored_ = nextOnRestored_; - nextOnRestored_ = undefined; - callback(makeWebGLContextEvent("context restored")); - } - }, 0); - } else { - throw "You can not restore the context without a listener" - } - } - }; - - // Wrap a few functions specially. - wrapper_.getError = function() { - if (!contextLost_) { - var err; - while (err = ctx.getError()) { - glErrorShadow_[err] = true; - } - } - for (var err in glErrorShadow_) { - if (glErrorShadow_[err]) { - delete glErrorShadow_[err]; - return err; - } - } - return ctx.NO_ERROR; - }; - - var creationFunctions = [ - "createBuffer", - "createFramebuffer", - "createProgram", - "createRenderbuffer", - "createShader", - "createTexture" - ]; - for (var ii = 0; ii < creationFunctions.length; ++ii) { - var functionName = creationFunctions[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return null; - } - var obj = f.apply(ctx, arguments); - obj.__webglDebugContextLostId__ = contextId_; - resourceDb_.push(obj); - return obj; - }; - }(ctx[functionName]); - } - - var functionsThatShouldReturnNull = [ - "getActiveAttrib", - "getActiveUniform", - "getBufferParameter", - "getContextAttributes", - "getAttachedShaders", - "getFramebufferAttachmentParameter", - "getParameter", - "getProgramParameter", - "getProgramInfoLog", - "getRenderbufferParameter", - "getShaderParameter", - "getShaderInfoLog", - "getShaderSource", - "getTexParameter", - "getUniform", - "getUniformLocation", - "getVertexAttrib" - ]; - for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) { - var functionName = functionsThatShouldReturnNull[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return null; - } - return f.apply(ctx, arguments); - } - }(wrapper_[functionName]); - } - - var isFunctions = [ - "isBuffer", - "isEnabled", - "isFramebuffer", - "isProgram", - "isRenderbuffer", - "isShader", - "isTexture" - ]; - for (var ii = 0; ii < isFunctions.length; ++ii) { - var functionName = isFunctions[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return false; - } - return f.apply(ctx, arguments); - } - }(wrapper_[functionName]); - } - - wrapper_.checkFramebufferStatus = function(f) { - return function() { - if (contextLost_) { - return ctx.FRAMEBUFFER_UNSUPPORTED; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.checkFramebufferStatus); - - wrapper_.getAttribLocation = function(f) { - return function() { - if (contextLost_) { - return -1; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.getAttribLocation); - - wrapper_.getVertexAttribOffset = function(f) { - return function() { - if (contextLost_) { - return 0; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.getVertexAttribOffset); - - wrapper_.isContextLost = function() { - return contextLost_; - }; - - function wrapEvent(listener) { - if (typeof(listener) == "function") { - return listener; - } else { - return function(info) { - listener.handleEvent(info); - } - } - } - - wrapper_.registerOnContextLostListener = function(listener) { - onLost_ = wrapEvent(listener); - }; - - wrapper_.registerOnContextRestoredListener = function(listener) { - if (contextLost_) { - nextOnRestored_ = wrapEvent(listener); - } else { - onRestored_ = wrapEvent(listener); - } - } - - return wrapper_; -} - -return { - /** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebglInstance context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ - 'init': init, - - /** - * Returns true or false if value matches any WebglInstance enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebglInstance defined enums - */ - 'mightBeEnum': mightBeEnum, - - /** - * Gets an string version of an WebglInstance enum. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ - 'glEnumToString': glEnumToString, - - /** - * Converts the argument of a WebglInstance function to a string. - * Attempts to convert enum arguments to strings. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D); - * - * would return 'TEXTURE_2D' - * - * @param {string} functionName the name of the WebglInstance function. - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ - 'glFunctionArgToString': glFunctionArgToString, - - /** - * Given a WebglInstance context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not NO_ERROR. - * - * You can supply your own function if you want. For example, if you'd like - * an exception thrown on any GL error you could do this - * - * function throwOnGLError(err, funcName, args) { - * throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" + - * funcName; - * }; - * - * ctx = WebGLDebugUtils.makeDebugContext( - * canvas.getContext("webgl"), throwOnGLError); - * - * @param {!WebGLRenderingContext} ctx The webgl context to wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc The function - * to call when gl.getError returns an error. If not specified the default - * function calls console.log with a message. - */ - 'makeDebugContext': makeDebugContext, - - /** - * Given a WebglInstance context returns a wrapped context that adds 4 - * functions. - * - * ctx.loseContext: - * simulates a lost context event. - * - * ctx.restoreContext: - * simulates the context being restored. - * - * ctx.registerOnContextLostListener(listener): - * lets you register a listener for context lost. Use instead - * of addEventListener('webglcontextlostevent', listener); - * - * ctx.registerOnContextRestoredListener(listener): - * lets you register a listener for context restored. Use - * instead of addEventListener('webglcontextrestored', - * listener); - * - * @param {!WebGLRenderingContext} ctx The webgl context to wrap. - */ - 'makeLostContextSimulatingContext': makeLostContextSimulatingContext, - - /** - * Resets a context to the initial state. - * @param {!WebGLRenderingContext} ctx The webgl context to - * reset. - */ - 'resetToInitialState': resetToInitialState -}; - -}(); - diff --git a/lab3.1/lib/webgl-utils.js b/lab3.1/lib/webgl-utils.js deleted file mode 100644 index 26ed37e..0000000 --- a/lab3.1/lib/webgl-utils.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2010, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/** - * @fileoverview This file contains functions every webgl program will need - * a version of one way or another. - * - * Instead of setting up a context manually it is recommended to - * use. This will check for success or failure. On failure it - * will attempt to present an approriate message to the user. - * - * gl = WebGLUtils.setupWebGL(canvas); - * - * For animated WebglInstance apps use of setTimeout or setInterval are - * discouraged. It is recommended you structure your rendering - * loop like this. - * - * function render() { - * window.requestAnimationFrame(render, canvas); - * - * // do rendering - * ... - * } - * render(); - * - * This will call your rendering function up to the refresh rate - * of your display but will stop rendering if your app is not - * visible. - */ - -WebGLUtils = function() { - -/** - * Creates the HTLM for a failure message - * @param {string} canvasContainerId id of container of th - * canvas. - * @return {string} The html. - */ -var makeFailHTML = function(msg) { - return '' + - '<div style="margin: auto; width:500px;z-index:10000;margin-top:20em;text-align:center;">' + msg + '</div>'; - return '' + - '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' + - '<td align="center">' + - '<div style="display: table-cell; vertical-align: middle;">' + - '<div style="">' + msg + '</div>' + - '</div>' + - '</td></tr></table>'; -}; - -/** - * Mesasge for getting a webgl browser - * @type {string} - */ -var GET_A_WEBGL_BROWSER = '' + - 'This page requires a browser that supports WebglInstance.<br/>' + - '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>'; - -/** - * Mesasge for need better hardware - * @type {string} - */ -var OTHER_PROBLEM = '' + - "It doesn't appear your computer can support WebglInstance.<br/>" + - '<a href="http://get.webgl.org">Click here for more information.</a>'; - -/** - * Creates a webgl context. If creation fails it will - * change the contents of the container of the <canvas> - * tag to an error message with the correct links for WebglInstance. - * @param {Element} canvas. The canvas element to create a - * context from. - * @param {WebGLContextCreationAttirbutes} opt_attribs Any - * creation attributes you want to pass in. - * @param {function:(msg)} opt_onError An function to call - * if there is an error during creation. - * @return {WebGLRenderingContext} The created context. - */ -var setupWebGL = function(canvas, opt_attribs, opt_onError) { - function handleCreationError(msg) { - var container = document.getElementsByTagName("body")[0]; - //var container = canvas.parentNode; - if (container) { - var str = window.WebGLRenderingContext ? - OTHER_PROBLEM : - GET_A_WEBGL_BROWSER; - if (msg) { - str += "<br/><br/>Status: " + msg; - } - container.innerHTML = makeFailHTML(str); - } - }; - - opt_onError = opt_onError || handleCreationError; - - if (canvas.addEventListener) { - canvas.addEventListener("webglcontextcreationerror", function(event) { - opt_onError(event.statusMessage); - }, false); - } - var context = create3DContext(canvas, opt_attribs); - if (!context) { - if (!window.WebGLRenderingContext) { - opt_onError(""); - } else { - opt_onError(""); - } - } - - return context; -}; - -/** - * Creates a webgl context. - * @param {!Canvas} canvas The canvas tag to get context - * from. If one is not passed in one will be created. - * @return {!WebGLContext} The created context. - */ -var create3DContext = function(canvas, opt_attribs) { - var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; - var context = null; - for (var ii = 0; ii < names.length; ++ii) { - try { - context = canvas.getContext(names[ii], opt_attribs); - } catch(e) {} - if (context) { - break; - } - } - return context; -} - -return { - create3DContext: create3DContext, - setupWebGL: setupWebGL -}; -}(); - -/** - * Provides requestAnimationFrame in a cross browser - * way. - */ -if (!window.requestAnimationFrame) { - window.requestAnimationFrame = (function() { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { - window.setTimeout(callback, 1000/60); - }; - })(); -} - -/** * ERRATA: 'cancelRequestAnimationFrame' renamed to 'cancelAnimationFrame' to reflect an update to the W3C Animation-Timing Spec. - * - * Cancels an animation frame request. - * Checks for cross-browser support, falls back to clearTimeout. - * @param {number} Animation frame request. */ -if (!window.cancelAnimationFrame) { - window.cancelAnimationFrame = (window.cancelRequestAnimationFrame || - window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame || - window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame || - window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame || - window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame || - window.clearTimeout); -} \ No newline at end of file diff --git a/lab3.1/src/lab3.html b/lab3.1/src/lab3.html deleted file mode 100644 index defa2c6..0000000 --- a/lab3.1/src/lab3.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <title>Lab 3</title> -</head> - -<body onload="main()"> - <canvas width="400" height="600" id="my-canvas"> -Please use a browser that supports "canvas" -</canvas> - <script src="../lib/webgl-utils.js"></script> - <script src="../lib/webgl-debug.js"></script> - <script src="../lib/cuon-matrix.js"></script> - <script src="../lib/cuon-utils.js"></script> - <script src="lab3.js"></script> -</body> - -</html> \ No newline at end of file diff --git a/lab3.1/src/lab3.js b/lab3.1/src/lab3.js deleted file mode 100644 index 08d08df..0000000 --- a/lab3.1/src/lab3.js +++ /dev/null @@ -1,470 +0,0 @@ -//author : QUentin Berthet -const VSHADER_SOURCE = - 'attribute vec4 a_position;\n' + - 'attribute vec4 a_Color;\n' + - 'attribute vec3 a_normal;\n' + - - - 'uniform vec3 u_lightWorldPosition;\n' + - 'uniform vec3 u_viewWorldPosition;\n' + - - - 'uniform mat4 u_world;\n' + - 'uniform mat4 u_worldViewProjection;\n' + - 'uniform mat4 u_worldInverseTranspose;\n' + - - 'varying vec3 v_normal;\n' + - - 'varying vec3 v_surfaceToLight;\n' + - 'varying vec3 v_surfaceToView;\n' + - - 'void main() {\n' + - ' gl_Position = u_worldViewProjection * a_position ;\n' + - ' v_normal = mat3(u_worldInverseTranspose) * a_normal;\n' + - ' vec3 surfaceWorldPosition = (u_world * a_position).xyz;\n' + - ' v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;\n' + - ' v_surfaceToView = u_viewWorldPosition - surfaceWorldPosition;\n' + - '}\n'; - - -const FSHADER_SOURCE = - 'precision mediump float;\n' + - 'varying vec3 v_normal;\n' + - 'varying vec3 v_surfaceToLight;\n' + - 'varying vec3 v_surfaceToView;\n' + - 'uniform vec4 u_Color;\n' + - 'uniform float u_shininess;\n' + - - 'void main() {\n' + - ' vec3 normal = normalize(v_normal);\n' + - ' vec3 surfaceToLightDirection = normalize(v_surfaceToLight);\n' + - ' vec3 surfaceToViewDirection = normalize(v_surfaceToView);\n' + - ' vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);\n' + - ' float light = dot(normal, surfaceToLightDirection);\n' + - ' float specular = 0.0;\n' + - ' if (light > 0.0) {specular = pow(dot(normal, halfVector), u_shininess);}\n' + - ' gl_FragColor = u_Color;\n' + - ' gl_FragColor.rgb *= light;\n' + - ' gl_FragColor.rgb += specular;\n' + - '}\n'; - - - -function main() { - - console.log("hello<"); - const canvas = document.getElementById('my-canvas'); - - - const gl = canvas.getContext('webgl'); - if (!gl) { - console.log('Failed to get the displaying context for WebGL'); - return; - } - - - if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { - console.log('Failed to intialize shaders.'); - return; - } - - // look up where the vertex data needs to go. - var positionLocation = gl.getAttribLocation(gl.program, "a_position"); - var normalLocation = gl.getAttribLocation(gl.program, "a_normal"); - - // lookup uniforms - var worldViewProjectionLocation = gl.getUniformLocation(gl.program, "u_worldViewProjection"); - var worldInverseTransposeLocation = gl.getUniformLocation(gl.program, "u_worldInverseTranspose"); - var colorLocation = gl.getUniformLocation(gl.program, "u_Color"); - var shininessLocation = gl.getUniformLocation(gl.program, "u_shininess"); - var lightWorldPositionLocation = - gl.getUniformLocation(gl.program, "u_lightWorldPosition"); - var viewWorldPositionLocation = - gl.getUniformLocation(gl.program, "u_viewWorldPosition"); - var worldLocation = - gl.getUniformLocation(gl.program, "u_world"); - - - - // Create a buffer to put positions in - var positionBuffer = gl.createBuffer(); - // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - // Put geometry data into buffer - - const len = initVertexBuffers(gl); - - if (len < 0) { - console.log('Failed to set the positions of the vertices'); - return; - } - - // Create a buffer to put normals in - var normalBuffer = gl.createBuffer(); - // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = normalBuffer) - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - // Put normals data into buffer - - - CreateNormals(gl); - var shininess = 150; - - function updateShininess(event, ui) { - shininess = ui.value; - drawScene(); - } - - - - - function drawScene() { - - gl.clearColor(0.75, 0.85, 0.8, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.enable(gl.DEPTH_TEST); - gl.frontFace(gl.CCW); - gl.cullFace(gl.BACK); - // Turn on the position attribute - - const projMatrix = new Matrix4(); - projMatrix.setPerspective(45, gl.canvas.clientWidth / gl.canvas.clientHeight, 1, 100); - - const cameraMatrix = new Matrix4(); - let angle = 1; - let X = 5 * Math.cos(angle); - let Y = 0; - let Z = 5 * Math.sin(angle); - - cameraMatrix.setLookAt(X, Y, Z, 0, 0, 0, 0, 1, 0); - const viewMatrix = new Matrix4(cameraMatrix); - - const viewProjectionMatrix = new Matrix4(projMatrix).multiply(new Matrix4(viewMatrix)); - - const worldMatrix = new Matrix4(); - - - const worldViewProjectionMatrix = new Matrix4(viewProjectionMatrix).multiply(worldMatrix); - const worldInverseMatrix = new Matrix4(worldMatrix).invert(); - const worldInverseTransposeMatrix = new Matrix4(worldInverseMatrix).transpose(); - - - - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - gl.enableVertexAttribArray(positionLocation); - var size = 3; // 3 components per iteration - var type = gl.FLOAT; // the data is 32bit floats - var normalize = false; // don't normalize the data - var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position - var offset = 0; // start at the beginning of the buffer - gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset); - - - - - - // Turn on the normal attribute - gl.enableVertexAttribArray(normalLocation); - // Bind the normal buffer. - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - // Tell the attribute how to get data out of normalBuffer (ARRAY_BUFFER) - var size = 3; // 3 components per iteration - var type = gl.FLOAT; // the data is 32bit floating point values - var normalize = false; // normalize the data (convert from 0-255 to 0-1) - var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position - var offset = 0; // start at the beginning of the buffer - gl.vertexAttribPointer( - normalLocation, size, type, normalize, stride, offset); - - - // Set the matrices - gl.uniformMatrix4fv(worldViewProjectionLocation, false, worldViewProjectionMatrix); - gl.uniformMatrix4fv(worldInverseTransposeLocation, false, worldInverseTransposeMatrix); - gl.uniformMatrix4fv(worldLocation, false, worldMatrix); - // Set the color to use - gl.uniform4fv(colorLocation, [0.2, 1, 0.2, 1]); // green - // set the light position - gl.uniform3fv(lightWorldPositionLocation, [20, 30, 60]); - // set the camera/view position - gl.uniform3fv(viewWorldPositionLocation, camera); - // set the shininess - gl.uniform1f(shininessLocation, shininess); - - - - - - - // var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); - // if (a_Color < 0) { - // console.log('Failed to get the storage location of a_Color'); - // return -1; - // } - - // gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12); - // gl.enableVertexAttribArray(a_Color); - // gl.bindBuffer(gl.ARRAY_BUFFER, null); - - - - - var viewProjMatrix = new Matrix4(); - viewProjMatrix.setPerspective(100.0, 1.0, 1.0, 1000.0); - viewProjMatrix.lookAt(1.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - - var vals = [0.0, 0.0]; - ObjectManager(vals); - - var display = function() { - let count = 42; - // Don't render the upper surface because we duplicate frustum + surface - if (i === 1) { - count -= 6; - } - cameraMatrix.set(viewProjMatrix); - cameraMatrix.rotate(vals[0], 1.0, 0.0, 0.0); - cameraMatrix.rotate(vals[1], 0.0, 1.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); - - - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0); - - cameraMatrix.translate(0, 3.0, -4) - cameraMatrix.rotate(180, 1.0, 0.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); - - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0); - - - requestAnimationFrame(display); - }; - display(); - } - -} - -function ObjectManager(values) { - document.onkeydown = (ev) => { - v = 10; - switch (ev.key) { - case 'ArrowDown': - values[0] += v; - break; - case 'ArrowUp': - values[0] -= v; - break; - case 'ArrowRight': - values[1] += v; - break; - case 'ArrowLeft': - values[1] -= v; - break; - } - }; -} - - - -function initVertexBuffers(gl) { - - let vertices = new Float32Array([ - - // Front - -2, -1.5, 0, -1, 1.5, -1, - 0, -1.5, 0, - - -1, 1.5, -1, - 0, -1.5, 0, - 1, 1.5, -1, - - 0, -1.5, 0, - 1, 1.5, -1, - 2, -1.5, 0, - - // Back - -2, -1.5, -4, -1, 1.5, -3, - 0, -1.5, -4, - - -1, 1.5, -3, - 0, -1.5, -4, - 1, 1.5, -3, - - 0, -1.5, -4, - 1, 1.5, -3, - 2, -1.5, -4, - - // Left - -2, -1.5, -4, -1, 1.5, -3, -2, -1.5, -2, - - -1, 1.5, -3, -2, -1.5, -2, -1, 1.5, -1, - - -2, -1.5, -2, -1, 1.5, -1, -2, -1.5, 0, - - // Right - 2, -1.5, -4, - 1, 1.5, -3, - 2, -1.5, -2, - - 1, 1.5, -3, - 2, -1.5, -2, - 1, 1.5, -1, - - 2, -1.5, -2, - 1, 1.5, -1, - 2, -1.5, -0, - - // top - -1, 1.5, -1, -1, 1.5, -3, - 0, 1.5, -1, - - -1, 1.5, -3, - 0, 1.5, -1, - 1, 1.5, -3, - - 0, 1.5, -1, - 1, 1.5, -3, - 1, 1.5, -1, - - // ground - -2, -1.5, 0, -2, -1.5, -4, - 0, -1.5, 0, - - -2, -1.5, -4, - 0, -1.5, 0, - 2, -1.5, -4, - - 0, -1.5, 0, - 2, -1.5, -4, - 2, -1.5, 0, - - - ]); - - const len = vertices.length / 6; - const vertexBuffer = gl.createBuffer(); - if (!vertexBuffer) { - console.log('Failed to create the buffer object'); - return -1; - } - - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - - return len; -} - -function normalizedCrossWith3Points(a0, a1, a2, b0, b1, b2, c0, c1, c2) { - const u = [b0 - a0, b1 - a1, b2 - a2]; - const v = [c0 - a0, c1 - a1, c2 - a2]; - const rawNormal = [ - u[1] * v[2] - u[2] * v[1], - u[2] * v[0] - u[0] * v[2], - u[0] * v[1] - u[1] * v[0] - ]; - const norm = Math.hypot(...rawNormal); - return rawNormal.map((n) => n / norm); -} - -const Normal_f = normalizedCrossWith3Points(-1, 1.5, -1, - 0, -1.5, 0, - 1, 1.5, -1 - -); -const Normal_b = normalizedCrossWith3Points(-1, 1.5, -3, - 0, -1.5, -4, - 1, 1.5, -3 -); -const Normal_t = normalizedCrossWith3Points(-1, 1.5, -3, - 0, 1.5, -1, - 1, 1.5, -3 -); -const Normal_g = normalizedCrossWith3Points(-2, -1.5, -4, - 0, -1.5, 0, - 2, -1.5, -4 -); -const Normal_r = normalizedCrossWith3Points( - 1, 1.5, -3, - 2, -1.5, -2, - 1, 1.5, -1 -); - -const leftNormal = normalizedCrossWith3Points(-1, 1.5, -3, -2, -1.5, -2, -1, 1.5, -1); - -// const surfaceNormal = normalizedCrossWith3Points(-2.5, -0.501, -2.5, -// 2.5, -0.501, -2.5, -// 2.5, -0.501, 2.5 -// ); - - -function CreateNormals(gl, bottomNormal) { - var vertexNormals = new Float32Array( - [ //front - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - - - // back - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - - - // left - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - // right - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - - // top - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - - // ground - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2] - ]); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals), gl.STATIC_DRAW); -} \ No newline at end of file diff --git a/lab3/README.md b/lab3/README.md index 073809a..37ef2aa 100644 --- a/lab3/README.md +++ b/lab3/README.md @@ -1,6 +1,6 @@ -# Lab2 IHM +# Lab3 IHM * **docs**: contains the lab's statement * **libs**: contains WebGL libraries and utilities -* **src**: contains the source code of the lab2 that you should complete (`main()` function in **lab2.js** file) -* **DO NOT CHANGE** the name of the file `lab2.html`, however, you are free to change its content. +* **src**: contains the source code of the lab2 that you should complete (`main()` function in **lab3.js** file) +* **DO NOT CHANGE** the name of the file `lab3.html`, however, you are free to change its content. diff --git a/lab3/src/lab3.html b/lab3/src/lab3.html index eb19ba3..f7b6c12 100644 --- a/lab3/src/lab3.html +++ b/lab3/src/lab3.html @@ -7,9 +7,20 @@ </head> <body onload="main()"> + <canvas width="400" height="600" id="my-canvas"> Please use a browser that supports "canvas" </canvas> + <p>Point light position:</p> + <p id="pLX">x: 0</p> + <p id="pLY">y: 2</p> + <p id="pLZ">z: 0</p> + + <p>Directional light direction:</p> + <p id="dLX">x: 0</p> + <p id="dLY">y: 2</p> + <p id="dLZ">z: 0</p> + <script src="../lib/webgl-utils.js"></script> <script src="../lib/webgl-debug.js"></script> <script src="../lib/cuon-matrix.js"></script> diff --git a/lab3/src/lab3.js b/lab3/src/lab3.js index f65bab9..d5d72d4 100644 --- a/lab3/src/lab3.js +++ b/lab3/src/lab3.js @@ -1,20 +1,29 @@ -//author : QUentin Berthet -const VSHADER_SOURCE = +/** + * title : LABO3 + * author : Quentin Berthet + */ + + +var VSHADER_SOURCE = + 'attribute vec3 a_Normal;\n' + // Normal 'attribute vec4 a_Position;\n' + - 'attribute vec3 a_normal;\n' + 'attribute vec4 a_Color;\n' + - 'uniform mat4 u_worldViewProjection;\n' + - 'uniform mat4 u_worldInverseTranspose;\n' + + 'uniform mat4 u_viewMatrix;\n' + + 'uniform mat4 u_Matrix;\n' + + 'uniform mat4 u_MatrixInverseTransposee;\n' + - 'varying vec3 v_normal;\n' + + 'uniform vec3 u_LightPosition;\n' + 'varying vec4 v_Color;\n' + - + 'varying vec3 v_Normal;\n' + + 'varying vec3 v_LightDirection;\n' + 'void main() {\n' + - ' gl_Position = u_worldViewProjection * a_Position ;\n' + - ' v_normal = mat3(u_worldInverseTranspose) * a_normal;\n' + + ' gl_Position = u_viewMatrix * a_Position ;\n' + ' v_Color = a_Color;\n' + + ' v_Normal = mat3(u_MatrixInverseTransposee) * a_Normal;\n' + + ' vec3 currentPosition = (u_Matrix * a_Position).xyz;\n' + + ' v_LightDirection = u_LightPosition - currentPosition;\n' + '}\n'; @@ -22,480 +31,277 @@ const FSHADER_SOURCE = 'precision mediump float;\n' + 'varying vec4 v_Color;\n' + - 'varying vec3 v_normal;\n' + - 'uniform vec3 u_reverseLightDirection;\n' + - - 'void main() {\n' + - ' vec3 normal = normalize(v_normal);\n' + - ' float light = dot(normal, u_reverseLightDirection);\n' + - - ' gl_FragColor = v_Color;\n' + - ' gl_FragColor.rgb *= light;\n' + - '}\n'; - + 'varying vec3 v_Normal;\n' + + 'varying vec3 v_LightDirection;\n' + -let angleLight = 1; -let angle = 1; -let onOff = true; -let lightWorldPositionX = 1 * Math.cos(angleLight); -let lightWorldPositionY = 1; -let lightWorldPositionZ = 1 * Math.sin(angleLight); -let X = 15 * Math.cos(angle); -let Y = 0; -let Z = 15 * Math.sin(angle); - -function main() { - - const canvas = document.getElementById('my-canvas'); - - - const gl = canvas.getContext('webgl'); - if (!gl) { - console.log('Failed to get the displaying context for WebGL'); - return; - } + 'uniform vec3 u_LightDirection;\n' + + 'uniform vec3 u_LightDirectional;\n' + + 'uniform vec3 u_LightPoint;\n' + + 'void main() {\n' + + ' vec3 normal = normalize(v_Normal.xyz);\n' + - if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { - console.log('Failed to intialize shaders.'); - return; - } + ' float lightDirectional = dot(normal, u_LightDirection);\n' + + ' float lightPoint = dot(normal, normalize(v_LightDirection));\n' + + ' gl_FragColor = vec4((u_LightPoint * v_Color.rgb * lightPoint) + (u_LightDirectional * v_Color.rgb * lightDirectional), v_Color.a);\n' + + '}\n'; - const retour = initVertexBuffers(gl); - const len = retour[0] - const vertices = retour[1] - if (len < 0) { - console.log('Failed to set the positions of the vertices'); - return; - } +function initVertexBuffers(gl) { + // This is the model + let normals = new Float32Array([ + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ]); + const colors = new Float32Array([ + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ]); + let vertices = new Float32Array([-0.4, -0.4, -0.4, -0.4, -0.4, 0.4, 0.4, -0.4, -0.4, 0.4, -0.4, 0.4, -0.2, 0.4, -0.2, -0.2, 0.4, 0.2, 0.2, 0.4, -0.2, 0.2, 0.4, 0.2, -0.4, -0.4, 0.4, -0.2, 0.4, 0.2, 0.0, -0.4, 0.4, 0.2, 0.4, 0.2, + 0.4, -0.4, 0.4, -0.4, -0.4, 0.4, -0.2, 0.4, 0.2, -0.4, -0.4, 0.0, -0.2, 0.4, -0.2, -0.4, -0.4, -0.4, 0.4, -0.4, -0.4, 0.2, 0.4, -0.2, + 0.4, -0.4, 0.0, 0.2, 0.4, 0.2, 0.4, -0.4, 0.4, -0.4, -0.4, -0.4, -0.2, 0.4, -0.2, 0.0, -0.4, -0.4, 0.2, 0.4, -0.2, 0.4, -0.4, -0.4, -2.0, -0.5, -2.0, -2.0, -0.5, 2.0, 2.0, -0.5, -2.0, 2.0, -0.5, 2.0 + ]); + let indices = new Uint8Array([ + 0, 2, 1, 2, 3, 1, 4, 5, 6, 5, 7, 6, + 8, 10, 9, 10, 11, 9, 10, 12, 11, 13, 14, 15, + 14, 16, 15, 16, 17, 15, 18, 19, 20, 19, 21, 20, + 21, 22, 20, 23, 24, 25, 24, 26, 25, 26, 27, 25, + 28, 29, 30, 29, 31, 30 + ]); const vertexBuffer = gl.createBuffer(); - if (!vertexBuffer) { - console.log('Failed to create the buffer object'); - return -1; - } - - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + calculeNormal(vertices, normals, indices); + // copie les info coordonnée, color et normal au buffer + var bufferV = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, bufferV); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - var worldViewProjectionLocation = gl.getUniformLocation(gl.program, "u_worldViewProjection"); - - const a_Position = gl.getAttribLocation(gl.program, 'a_Position'); - if (a_Position < 0) { - console.log('Failed to get the storage location of a_Position'); - return -1; - } - gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 24, 0); - gl.enableVertexAttribArray(a_Position); + var a_attrV = gl.getAttribLocation(gl.program, 'a_Position'); + gl.vertexAttribPointer(a_attrV, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(a_attrV); + var bufferC = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, bufferC); + gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); + var c_attrC = gl.getAttribLocation(gl.program, 'a_Color'); + gl.vertexAttribPointer(c_attrC, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(c_attrC); + var bufferN = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, bufferN); + gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW); + var c_attrN = gl.getAttribLocation(gl.program, 'a_Normal'); + gl.vertexAttribPointer(c_attrN, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(c_attrN); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + + return indices.length; +} - var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); - if (a_Color < 0) { - console.log('Failed to get the storage location of a_Color'); - return -1; +function computeNormal(array1, array2, norm, indices, i) { + for (let j = 0; j < 3; j++) { + norm[indices[i + j] * 3] = (array1[1] * array2[2] - array1[2] * array2[1]); + norm[indices[i + j] * 3 + 1] = (array1[2] * array2[0] - array1[0] * array2[2]); + norm[indices[i + j] * 3 + 2] = (array1[0] * array2[1] - array1[1] * array2[0]); } +} - gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12); - gl.enableVertexAttribArray(a_Color); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - var normalLocation = gl.getAttribLocation(gl.program, "a_normal"); - var worldInverseTransposeLocation = gl.getUniformLocation(gl.program, "u_worldInverseTranspose"); - var reverseLightDirectionLocation = gl.getUniformLocation(gl.program, "u_reverseLightDirection"); - - // Create a buffer to put normals in - var normalBuffer = gl.createBuffer(); - // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = normalBuffer) - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - // Put normals data into buffer - Createnormals(gl); - // Turn on the normal attribute - gl.enableVertexAttribArray(normalLocation); - - // Bind the normal buffer. - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - - // Tell the attribute how to get data out of normalBuffer (ARRAY_BUFFER) - var size = 3; // 3 components per iteration - var type = gl.FLOAT; // the data is 32bit floating point values - var normalize = false; // normalize the data (convert from 0-255 to 0-1) - var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position - var offset = 0; // start at the beginning of the buffer - gl.vertexAttribPointer(normalLocation, size, type, normalize, stride, offset); +function calculeNormal(vert, norm, indice) { + for (let i = 0; i < indice.length; i += 3) { + let index1 = 3 * indice[i] + let index2 = 3 * indice[i + 1] + let index3 = 3 * indice[i + 2] + let el1 = [vert[index1], vert[index1 + 1], vert[index1 + 2]]; + let el2 = [vert[index2], vert[index2 + 1], vert[index2 + 2]]; + let el3 = [vert[index3], vert[index3 + 1], vert[index3 + 2]]; - function radToDeg(r) { - return r * 180 / Math.PI; - } + let result1 = []; + for (let i = 0; i < el2.length; i++) { + result1.push(el2[i] - el1[i]); + } + let result2 = []; + for (let i = 0; i < el3.length; i++) { + result2.push(el3[i] - el1[i]); + } + computeNormal(result1, result2, norm, indice, i) - function degToRad(d) { - return d * Math.PI / 180; } - var fieldOfViewRadians = degToRad(60); - - +} - gl.clearColor(0.75, 0.85, 0.8, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); +function main() { + const canvas = document.getElementById('my-canvas'); + const gl = getWebGLContext(canvas); + initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE) + gl.clearColor(0, 0, 0, 1); gl.enable(gl.DEPTH_TEST); - gl.frontFace(gl.CCW); - gl.cullFace(gl.BACK); - - - - var u_worldViewProjection = gl.getUniformLocation(gl.program, 'u_worldViewProjection'); - + const n = initVertexBuffers(gl); + let u_viewMatrix = gl.getUniformLocation(gl.program, 'u_viewMatrix') + let u_LightDirectional = gl.getUniformLocation(gl.program, 'u_LightDirectional') + let u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection') + let u_LightPoint = gl.getUniformLocation(gl.program, 'u_LightPoint') + let u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition') + let u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix') + let u_MatrixInverseTransposee = gl.getUniformLocation(gl.program, 'u_MatrixInverseTransposee') + + //positionne light + let Light1Pos = [0.0, 2.0, 0.0]; + let Light2Pos = [0.0, 2.0, 0.0]; + gl.uniform3f(u_LightDirectional, 0.0, 0.0, 0.0); + let lightDirection = new Vector3(Light2Pos); + gl.uniform3fv(u_LightDirection, lightDirection.normalize().elements); + gl.uniform3f(u_LightPoint, 1.0, 1.0, 1.0); + gl.uniform3fv(u_LightPosition, Light1Pos); + + var viewProjMat = new Matrix4(); + viewProjMat.setPerspective(30.0, canvas.width / canvas.height, 1.0, 10.0); + viewProjMat.lookAt(3.0, 3.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //pos, pt vis, Dir + + var viewMat = new Matrix4(); // Model view projection matrix var mat = new Matrix4(); + var matInverseTransposee = new Matrix4(); - - var viewProjMatrix = new Matrix4(); - var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; - - - viewProjMatrix.setPerspective(1000.0, aspect, 1.0, 2000.0); - const cameraMatrix = new Matrix4(); - viewProjMatrix.lookAt(X, Y, Z, 0, 0, 0, 0, 1, 100); - - const viewMatrix = new Matrix4(); - - - - // Make a view matrix from the camera matrix. - - // Compute a view projection matrix - var viewProjectionMatrix = new Matrix4(viewProjMatrix).multiply(viewMatrix); - - - const worldMatrix = new Matrix4(); - - const worldViewProjectionMatrix = new Matrix4(viewProjectionMatrix).multiply(worldMatrix); - const worldInverseMatrix = new Matrix4(worldMatrix).invert(); - const worldInverseTransposeMatrix = new Matrix4(worldInverseMatrix).transpose();; - // Set the matrices - console.log("------------------------------------------------------------"); - console.log(worldViewProjectionMatrix); - console.log("------------------------------------------------------------"); - gl.uniformMatrix4fv(worldViewProjectionLocation, false, worldViewProjectionMatrix.elements); - gl.uniformMatrix4fv(worldInverseTransposeLocation, false, worldInverseTransposeMatrix.elements); - - // set the light direction. - //gl.uniform3fv(reverseLightDirectionLocation, m4.normalize([0.5, 0.7, 1])); - - - var vals = [0.0, 0.0]; - ObjectManager(vals); - - - - gl.uniform3fv(reverseLightDirectionLocation, new Vector3([lightWorldPositionX, lightWorldPositionY, lightWorldPositionZ]).normalize().elements); - + var keysMove = [0.0, 0.0]; + actionsManager(document, gl, keysMove, u_LightPoint, u_LightDirectional, Light1Pos, Light2Pos); + var render = function() { + gl.uniform3fv(u_LightPosition, Light1Pos); + //Directional light direction + lightDirection = new Vector3(Light2Pos); + gl.uniform3fv(u_LightDirection, lightDirection.normalize().elements); - var display = function() { - cameraMatrix.set(viewProjMatrix); - cameraMatrix.rotate(vals[0], 1.0, 0.0, 0.0); - cameraMatrix.rotate(vals[1], 0.0, 1.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); + mat.setRotate(keysMove[0], 1.0, 0.0, 0.0); + mat.rotate(keysMove[1], 0.0, 1.0, 0.0); + viewMat.set(viewProjMat).multiply(mat); + gl.uniformMatrix4fv(u_viewMatrix, false, viewMat.elements); + gl.uniformMatrix4fv(u_Matrix, false, mat.elements); + matInverseTransposee.setInverseOf(mat).transpose() + gl.uniformMatrix4fv(u_MatrixInverseTransposee, false, matInverseTransposee.elements); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.drawArrays(gl.TRIANGLES, 0, len); + gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); + mat.translate(0, 0.80, 0); + mat.rotate(180, 1.0, 0.0, 0.0); + viewMat.set(viewProjMat).multiply(mat) + gl.uniformMatrix4fv(u_viewMatrix, false, viewMat.elements); + gl.uniformMatrix4fv(u_Matrix, false, mat.elements); - cameraMatrix.translate(0, 3.0, -4) - cameraMatrix.rotate(180, 1.0, 0.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); + matInverseTransposee.setInverseOf(mat).transpose() + gl.uniformMatrix4fv(u_MatrixInverseTransposee, false, matInverseTransposee.elements); + gl.drawElements(gl.TRIANGLES, n - 6, gl.UNSIGNED_BYTE, 0); - gl.drawArrays(gl.TRIANGLES, 0, len); - - - requestAnimationFrame(display); + requestAnimationFrame(render); }; - display(); -} -let i = 0; - -function normalizedCrossWith3Points(a0, a1, a2, b0, b1, b2, c0, c1, c2) { - const u = [b0 - a0, b1 - a1, b2 - a2]; - const v = [c0 - a0, c1 - a1, c2 - a2]; - const rawnormal = [ - u[1] * v[2] - u[2] * v[1], - u[2] * v[0] - u[0] * v[2], - u[0] * v[1] - u[1] * v[0] - ]; - const norm = Math.hypot(...rawnormal); - return rawnormal.map((n) => n / norm); + render(); } -function ObjectManager(values) { - document.onkeydown = (event) => { - v = 1; +let on = true; + +function actionsManager(document, gl, keysMove, u_LightPoint, u_LightDirectional, Light1Pos, Light2Pos) { + switchLight = true; + + document.onkeydown = function(event) { switch (event.code) { - case "KeyA": - angle += 0.1; - onOff = true; + case "KeyJ": + if (on) { + { + console.log("1"); + gl.uniform3f(u_LightPoint, 0.0, 0.0, 0.0); + gl.uniform3f(u_LightDirectional, 1.0, 1.0, 1.0); + switchLight = false; + on = false; + } + + } else { + + console.log("2"); + gl.uniform3f(u_LightPoint, 1.0, 1.0, 1.0); + gl.uniform3f(u_LightDirectional, 0.0, 0.0, 0.0); + switchLight = true; + on = true; + } break; - case "KeyD": - angle -= 0.1; - onOff = true; + case "KeyE": + if (switchLight) { + Light1Pos[0] += 0.1; + } else { + Light2Pos[0] += 0.1; + } break; - case "KeyW": - Y -= 0.1; - X -= 0.1; - onOff = true; + case "KeyQ": + if (switchLight) { + Light1Pos[0] -= 0.1; + } else { + Light2Pos[0] -= 0.1; + } break; case "KeyS": - Y += 0.1; - X += 0.1; - onOff = true; - break; - case "KeyC": - i += 0.1; - if (i % 2 == 0) { - onOff = true; - console.log(onOff); + if (switchLight) { + Light1Pos[1] += 0.1; } else { - onOff = false; - console.log(onOff); + Light2Pos[1] += 0.1; } break; - - case "KeyJ": - console.log("on"); - lightWorldPositionX -= 0.1; - angleLight += 0.1; - onOff = true; - break; - case "KeyL": - lightWorldPositionX += 0.1; - angleLight -= 0.1; - onOff = true; + case "KeyW": + if (switchLight) { + Light1Pos[1] -= 0.1; + } else { + Light2Pos[1] -= 0.1; + } break; - case "KeyI": - lightWorldPositionY += 0.1; - onOff = true; + case "KeyA": + if (switchLight) { + Light1Pos[2] -= 0.1; + } else { + Light2Pos[2] -= 0.1; + } break; - case "KeyK": - lightWorldPositionY -= 0.1; - onOff = true; + case "KeyD": + if (switchLight) { + Light1Pos[2] += 0.1; + } else { + Light2Pos[2] += 0.1; + } break; - case 'ArrowDown': - values[0] += v; - onOff = false; + case "KeyF": + keysMove[1] += 1; break; - case 'ArrowUp': - onOff = false; - values[0] -= v; + case "KeyH": + keysMove[1] -= 1; break; - case 'ArrowRight': - onOff = false; - values[1] += v; + case "KeyT": + keysMove[0] += 1; break; - case 'ArrowLeft': - onOff = false; - values[1] -= v; + case "KeyG": + keysMove[0] -= 1; break; } - if (onOff) { - - requestAnimationFrame(main); - event.preventDefault(); - } - - + document.getElementById("pLX").innerHTML = "x: " + Math.round(Light1Pos[0] * 10); + document.getElementById("pLY").innerHTML = "y: " + Math.round(Light1Pos[1] * 10); + document.getElementById("pLZ").innerHTML = "z: " + Math.round(Light1Pos[2] * 10); + document.getElementById("dLX").innerHTML = "x: " + Math.round(Light2Pos[0] * 10); + document.getElementById("dLY").innerHTML = "y: " + Math.round(Light2Pos[1] * 10); + document.getElementById("dLZ").innerHTML = "z: " + Math.round(Light2Pos[2] * 10); } -}; - - - -function initVertexBuffers(gl) { - - let vertices = new Float32Array([ - - // Front - // Front - -2, -1.5, 0, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - - -1, 1.5, -1, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - 0, -1.5, 0, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - 2, -1.5, 0, 0, 1, 0, - - // Back - -2, -1.5, -4, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, - 0, -1.5, -4, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, - 0, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - - 0, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - - // Left - -2, -1.5, -4, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, -2, -1.5, -2, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, -2, -1.5, -2, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, - - -2, -1.5, -2, 0, 1, 0, -1, 1.5, -1, 0, 1, 0, -2, -1.5, 0, 0, 1, 0, - - // Right - 2, -1.5, -4, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -2, 0, 1, 0, - - 1, 1.5, -3, 0, 1, 0, - 2, -1.5, -2, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - 2, -1.5, -2, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - 2, -1.5, -0, 0, 1, 0, - - // top - -1, 1.5, -1, 0, 1, 0, -1, 1.5, -3, 0, 1, 0, - 0, 1.5, -1, 0, 1, 0, - - -1, 1.5, -3, 0, 1, 0, - 0, 1.5, -1, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - - 0, 1.5, -1, 0, 1, 0, - 1, 1.5, -3, 0, 1, 0, - 1, 1.5, -1, 0, 1, 0, - - // ground - -2, -1.5, 0, 0, 1, 0, -2, -1.5, -4, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - - -2, -1.5, -4, 0, 1, 0, - 0, -1.5, 0, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - - 0, -1.5, 0, 0, 1, 0, - 2, -1.5, -4, 0, 1, 0, - 2, -1.5, 0, 0, 1, 0 - - ]); - - const len = vertices.length / 6; - return [len, vertices]; -} - - -const normal_f = normalizedCrossWith3Points(-1, 1.5, -1, - 0, -1.5, 0, - 1, 1.5, -1, - -); -const normal_b = normalizedCrossWith3Points(-1, 1.5, -3, - 0, -1.5, -4, - 1, 1.5, -3, -); -const normal_t = normalizedCrossWith3Points(-1, 1.5, -3, - 0, 1.5, -1, - 1, 1.5, -3, -); -const normal_g = normalizedCrossWith3Points(-2, -1.5, -4, - 0, -1.5, 0, - 2, -1.5, -4, -); -const normal_r = normalizedCrossWith3Points( - 1, 1.5, -3, - 2, -1.5, -2, - 1, 1.5, -1, -); - -const normal_l = normalizedCrossWith3Points(-1, 1.5, -3, -2, -1.5, -2, -1, 1.5, -1); - -// const surfacenormal = normalizedCrossWith3Points(-2.5, -0.501, -2.5, -// 2.5, -0.501, -2.5, -// 2.5, -0.501, 2.5 -// ); - - -function Createnormals(gl) { - var normales = new Float32Array( - [ //front - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - - - // back - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - normal_b[0], normal_b[1], normal_b[2], - - - // left - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - normal_f[0], normal_f[1], normal_f[2], - // right - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - normal_r[0], normal_r[1], normal_r[2], - - // top - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - normal_t[0], normal_t[1], normal_t[2], - - // ground - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2], - normal_g[0], normal_g[1], normal_g[2] - ]); - gl.bufferData(gl.ARRAY_BUFFER, normales, gl.STATIC_DRAW); - -} \ No newline at end of file +}; \ No newline at end of file diff --git a/lab3Bis/README.md b/lab3Bis/README.md deleted file mode 100644 index 073809a..0000000 --- a/lab3Bis/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Lab2 IHM - -* **docs**: contains the lab's statement -* **libs**: contains WebGL libraries and utilities -* **src**: contains the source code of the lab2 that you should complete (`main()` function in **lab2.js** file) -* **DO NOT CHANGE** the name of the file `lab2.html`, however, you are free to change its content. diff --git a/lab3Bis/docs/Cours 3D Labo 3.pdf b/lab3Bis/docs/Cours 3D Labo 3.pdf deleted file mode 100644 index 95be1783746c753299fd5ae3d412b90a2c39ad9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32952 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ðKXPd*Dt1?%l0ho3+mF3;VtLfW<lMj}B5M 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 diff --git a/lab3Bis/lib/cuon-matrix.js b/lab3Bis/lib/cuon-matrix.js deleted file mode 100644 index b67a5dd..0000000 --- a/lab3Bis/lib/cuon-matrix.js +++ /dev/null @@ -1,741 +0,0 @@ -// cuon-matrix.js (c) 2012 kanda and matsuda -/** - * This is a class treating 4x4 matrix. - * This class contains the function that is equivalent to OpenGL matrix stack. - * The matrix after conversion is calculated by multiplying a conversion matrix from the right. - * The matrix is replaced by the calculated result. - */ - -/** - * Constructor of Matrix4 - * If opt_src is specified, new matrix is initialized by opt_src. - * Otherwise, new matrix is initialized by identity matrix. - * @param opt_src source matrix(option) - */ -var Matrix4 = function(opt_src) { - var i, s, d; - if (opt_src && typeof opt_src === 'object' && opt_src.hasOwnProperty('elements')) { - s = opt_src.elements; - d = new Float32Array(16); - for (i = 0; i < 16; ++i) { - d[i] = s[i]; - } - this.elements = d; - } else { - this.elements = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]); - } -}; - -/** - * Set the identity matrix. - * @return this - */ -Matrix4.prototype.setIdentity = function() { - var e = this.elements; - e[0] = 1; e[4] = 0; e[8] = 0; e[12] = 0; - e[1] = 0; e[5] = 1; e[9] = 0; e[13] = 0; - e[2] = 0; e[6] = 0; e[10] = 1; e[14] = 0; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - return this; -}; - -/** - * Copy matrix. - * @param src source matrix - * @return this - */ -Matrix4.prototype.set = function(src) { - var i, s, d; - - s = src.elements; - d = this.elements; - - if (s === d) { - return; - } - - for (i = 0; i < 16; ++i) { - d[i] = s[i]; - } - - return this; -}; - -/** - * Multiply the matrix from the right. - * @param other The multiply matrix - * @return this - */ -Matrix4.prototype.concat = function(other) { - var i, e, a, b, ai0, ai1, ai2, ai3; - - // Calculate e = a * b - e = this.elements; - a = this.elements; - b = other.elements; - - // If e equals b, copy b to temporary matrix. - if (e === b) { - b = new Float32Array(16); - for (i = 0; i < 16; ++i) { - b[i] = e[i]; - } - } - - for (i = 0; i < 4; i++) { - ai0=a[i]; ai1=a[i+4]; ai2=a[i+8]; ai3=a[i+12]; - e[i] = ai0 * b[0] + ai1 * b[1] + ai2 * b[2] + ai3 * b[3]; - e[i+4] = ai0 * b[4] + ai1 * b[5] + ai2 * b[6] + ai3 * b[7]; - e[i+8] = ai0 * b[8] + ai1 * b[9] + ai2 * b[10] + ai3 * b[11]; - e[i+12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15]; - } - - return this; -}; -Matrix4.prototype.multiply = Matrix4.prototype.concat; - -/** - * Multiply the three-dimensional vector. - * @param pos The multiply vector - * @return The result of multiplication(Float32Array) - */ -Matrix4.prototype.multiplyVector3 = function(pos) { - var e = this.elements; - var p = pos.elements; - var v = new Vector3(); - var result = v.elements; - - result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + e[12]; - result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + e[13]; - result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + e[14]; - - return v; -}; - -/** - * Multiply the four-dimensional vector. - * @param pos The multiply vector - * @return The result of multiplication(Float32Array) - */ -Matrix4.prototype.multiplyVector4 = function(pos) { - var e = this.elements; - var p = pos.elements; - var v = new Vector4(); - var result = v.elements; - - result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + p[3] * e[12]; - result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + p[3] * e[13]; - result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + p[3] * e[14]; - result[3] = p[0] * e[3] + p[1] * e[7] + p[2] * e[11] + p[3] * e[15]; - - return v; -}; - -/** - * Transpose the matrix. - * @return this - */ -Matrix4.prototype.transpose = function() { - var e, t; - - e = this.elements; - - t = e[ 1]; e[ 1] = e[ 4]; e[ 4] = t; - t = e[ 2]; e[ 2] = e[ 8]; e[ 8] = t; - t = e[ 3]; e[ 3] = e[12]; e[12] = t; - t = e[ 6]; e[ 6] = e[ 9]; e[ 9] = t; - t = e[ 7]; e[ 7] = e[13]; e[13] = t; - t = e[11]; e[11] = e[14]; e[14] = t; - - return this; -}; - -/** - * Calculate the inverse matrix of specified matrix, and set to this. - * @param other The source matrix - * @return this - */ -Matrix4.prototype.setInverseOf = function(other) { - var i, s, d, inv, det; - - s = other.elements; - d = this.elements; - inv = new Float32Array(16); - - inv[0] = s[5]*s[10]*s[15] - s[5] *s[11]*s[14] - s[9] *s[6]*s[15] - + s[9]*s[7] *s[14] + s[13]*s[6] *s[11] - s[13]*s[7]*s[10]; - inv[4] = - s[4]*s[10]*s[15] + s[4] *s[11]*s[14] + s[8] *s[6]*s[15] - - s[8]*s[7] *s[14] - s[12]*s[6] *s[11] + s[12]*s[7]*s[10]; - inv[8] = s[4]*s[9] *s[15] - s[4] *s[11]*s[13] - s[8] *s[5]*s[15] - + s[8]*s[7] *s[13] + s[12]*s[5] *s[11] - s[12]*s[7]*s[9]; - inv[12] = - s[4]*s[9] *s[14] + s[4] *s[10]*s[13] + s[8] *s[5]*s[14] - - s[8]*s[6] *s[13] - s[12]*s[5] *s[10] + s[12]*s[6]*s[9]; - - inv[1] = - s[1]*s[10]*s[15] + s[1] *s[11]*s[14] + s[9] *s[2]*s[15] - - s[9]*s[3] *s[14] - s[13]*s[2] *s[11] + s[13]*s[3]*s[10]; - inv[5] = s[0]*s[10]*s[15] - s[0] *s[11]*s[14] - s[8] *s[2]*s[15] - + s[8]*s[3] *s[14] + s[12]*s[2] *s[11] - s[12]*s[3]*s[10]; - inv[9] = - s[0]*s[9] *s[15] + s[0] *s[11]*s[13] + s[8] *s[1]*s[15] - - s[8]*s[3] *s[13] - s[12]*s[1] *s[11] + s[12]*s[3]*s[9]; - inv[13] = s[0]*s[9] *s[14] - s[0] *s[10]*s[13] - s[8] *s[1]*s[14] - + s[8]*s[2] *s[13] + s[12]*s[1] *s[10] - s[12]*s[2]*s[9]; - - inv[2] = s[1]*s[6]*s[15] - s[1] *s[7]*s[14] - s[5] *s[2]*s[15] - + s[5]*s[3]*s[14] + s[13]*s[2]*s[7] - s[13]*s[3]*s[6]; - inv[6] = - s[0]*s[6]*s[15] + s[0] *s[7]*s[14] + s[4] *s[2]*s[15] - - s[4]*s[3]*s[14] - s[12]*s[2]*s[7] + s[12]*s[3]*s[6]; - inv[10] = s[0]*s[5]*s[15] - s[0] *s[7]*s[13] - s[4] *s[1]*s[15] - + s[4]*s[3]*s[13] + s[12]*s[1]*s[7] - s[12]*s[3]*s[5]; - inv[14] = - s[0]*s[5]*s[14] + s[0] *s[6]*s[13] + s[4] *s[1]*s[14] - - s[4]*s[2]*s[13] - s[12]*s[1]*s[6] + s[12]*s[2]*s[5]; - - inv[3] = - s[1]*s[6]*s[11] + s[1]*s[7]*s[10] + s[5]*s[2]*s[11] - - s[5]*s[3]*s[10] - s[9]*s[2]*s[7] + s[9]*s[3]*s[6]; - inv[7] = s[0]*s[6]*s[11] - s[0]*s[7]*s[10] - s[4]*s[2]*s[11] - + s[4]*s[3]*s[10] + s[8]*s[2]*s[7] - s[8]*s[3]*s[6]; - inv[11] = - s[0]*s[5]*s[11] + s[0]*s[7]*s[9] + s[4]*s[1]*s[11] - - s[4]*s[3]*s[9] - s[8]*s[1]*s[7] + s[8]*s[3]*s[5]; - inv[15] = s[0]*s[5]*s[10] - s[0]*s[6]*s[9] - s[4]*s[1]*s[10] - + s[4]*s[2]*s[9] + s[8]*s[1]*s[6] - s[8]*s[2]*s[5]; - - det = s[0]*inv[0] + s[1]*inv[4] + s[2]*inv[8] + s[3]*inv[12]; - if (det === 0) { - return this; - } - - det = 1 / det; - for (i = 0; i < 16; i++) { - d[i] = inv[i] * det; - } - - return this; -}; - -/** - * Calculate the inverse matrix of this, and set to this. - * @return this - */ -Matrix4.prototype.invert = function() { - return this.setInverseOf(this); -}; - -/** - * Set the orthographic projection matrix. - * @param left The coordinate of the left of clipping plane. - * @param right The coordinate of the right of clipping plane. - * @param bottom The coordinate of the bottom of clipping plane. - * @param top The coordinate of the top top clipping plane. - * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer. - * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer. - * @return this - */ -Matrix4.prototype.setOrtho = function(left, right, bottom, top, near, far) { - var e, rw, rh, rd; - - if (left === right || bottom === top || near === far) { - throw 'null frustum'; - } - - rw = 1 / (right - left); - rh = 1 / (top - bottom); - rd = 1 / (far - near); - - e = this.elements; - - e[0] = 2 * rw; - e[1] = 0; - e[2] = 0; - e[3] = 0; - - e[4] = 0; - e[5] = 2 * rh; - e[6] = 0; - e[7] = 0; - - e[8] = 0; - e[9] = 0; - e[10] = -2 * rd; - e[11] = 0; - - e[12] = -(right + left) * rw; - e[13] = -(top + bottom) * rh; - e[14] = -(far + near) * rd; - e[15] = 1; - - return this; -}; - -/** - * Multiply the orthographic projection matrix from the right. - * @param left The coordinate of the left of clipping plane. - * @param right The coordinate of the right of clipping plane. - * @param bottom The coordinate of the bottom of clipping plane. - * @param top The coordinate of the top top clipping plane. - * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer. - * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer. - * @return this - */ -Matrix4.prototype.ortho = function(left, right, bottom, top, near, far) { - return this.concat(new Matrix4().setOrtho(left, right, bottom, top, near, far)); -}; - -/** - * Set the perspective projection matrix. - * @param left The coordinate of the left of clipping plane. - * @param right The coordinate of the right of clipping plane. - * @param bottom The coordinate of the bottom of clipping plane. - * @param top The coordinate of the top top clipping plane. - * @param near The distances to the nearer depth clipping plane. This value must be plus value. - * @param far The distances to the farther depth clipping plane. This value must be plus value. - * @return this - */ -Matrix4.prototype.setFrustum = function(left, right, bottom, top, near, far) { - var e, rw, rh, rd; - - if (left === right || top === bottom || near === far) { - throw 'null frustum'; - } - if (near <= 0) { - throw 'near <= 0'; - } - if (far <= 0) { - throw 'far <= 0'; - } - - rw = 1 / (right - left); - rh = 1 / (top - bottom); - rd = 1 / (far - near); - - e = this.elements; - - e[ 0] = 2 * near * rw; - e[ 1] = 0; - e[ 2] = 0; - e[ 3] = 0; - - e[ 4] = 0; - e[ 5] = 2 * near * rh; - e[ 6] = 0; - e[ 7] = 0; - - e[ 8] = (right + left) * rw; - e[ 9] = (top + bottom) * rh; - e[10] = -(far + near) * rd; - e[11] = -1; - - e[12] = 0; - e[13] = 0; - e[14] = -2 * near * far * rd; - e[15] = 0; - - return this; -}; - -/** - * Multiply the perspective projection matrix from the right. - * @param left The coordinate of the left of clipping plane. - * @param right The coordinate of the right of clipping plane. - * @param bottom The coordinate of the bottom of clipping plane. - * @param top The coordinate of the top top clipping plane. - * @param near The distances to the nearer depth clipping plane. This value must be plus value. - * @param far The distances to the farther depth clipping plane. This value must be plus value. - * @return this - */ -Matrix4.prototype.frustum = function(left, right, bottom, top, near, far) { - return this.concat(new Matrix4().setFrustum(left, right, bottom, top, near, far)); -}; - -/** - * Set the perspective projection matrix by fovy and aspect. - * @param fovy The angle between the upper and lower sides of the frustum. - * @param aspect The aspect ratio of the frustum. (width/height) - * @param near The distances to the nearer depth clipping plane. This value must be plus value. - * @param far The distances to the farther depth clipping plane. This value must be plus value. - * @return this - */ -Matrix4.prototype.setPerspective = function(fovy, aspect, near, far) { - var e, rd, s, ct; - - if (near === far || aspect === 0) { - throw 'null frustum'; - } - if (near <= 0) { - throw 'near <= 0'; - } - if (far <= 0) { - throw 'far <= 0'; - } - - fovy = Math.PI * fovy / 180 / 2; - s = Math.sin(fovy); - if (s === 0) { - throw 'null frustum'; - } - - rd = 1 / (far - near); - ct = Math.cos(fovy) / s; - - e = this.elements; - - e[0] = ct / aspect; - e[1] = 0; - e[2] = 0; - e[3] = 0; - - e[4] = 0; - e[5] = ct; - e[6] = 0; - e[7] = 0; - - e[8] = 0; - e[9] = 0; - e[10] = -(far + near) * rd; - e[11] = -1; - - e[12] = 0; - e[13] = 0; - e[14] = -2 * near * far * rd; - e[15] = 0; - - return this; -}; - -/** - * Multiply the perspective projection matrix from the right. - * @param fovy The angle between the upper and lower sides of the frustum. - * @param aspect The aspect ratio of the frustum. (width/height) - * @param near The distances to the nearer depth clipping plane. This value must be plus value. - * @param far The distances to the farther depth clipping plane. This value must be plus value. - * @return this - */ -Matrix4.prototype.perspective = function(fovy, aspect, near, far) { - return this.concat(new Matrix4().setPerspective(fovy, aspect, near, far)); -}; - -/** - * Set the matrix for scaling. - * @param x The scale factor along the X axis - * @param y The scale factor along the Y axis - * @param z The scale factor along the Z axis - * @return this - */ -Matrix4.prototype.setScale = function(x, y, z) { - var e = this.elements; - e[0] = x; e[4] = 0; e[8] = 0; e[12] = 0; - e[1] = 0; e[5] = y; e[9] = 0; e[13] = 0; - e[2] = 0; e[6] = 0; e[10] = z; e[14] = 0; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - return this; -}; - -/** - * Multiply the matrix for scaling from the right. - * @param x The scale factor along the X axis - * @param y The scale factor along the Y axis - * @param z The scale factor along the Z axis - * @return this - */ -Matrix4.prototype.scale = function(x, y, z) { - var e = this.elements; - e[0] *= x; e[4] *= y; e[8] *= z; - e[1] *= x; e[5] *= y; e[9] *= z; - e[2] *= x; e[6] *= y; e[10] *= z; - e[3] *= x; e[7] *= y; e[11] *= z; - return this; -}; - -/** - * Set the matrix for translation. - * @param x The X value of a translation. - * @param y The Y value of a translation. - * @param z The Z value of a translation. - * @return this - */ -Matrix4.prototype.setTranslate = function(x, y, z) { - var e = this.elements; - e[0] = 1; e[4] = 0; e[8] = 0; e[12] = x; - e[1] = 0; e[5] = 1; e[9] = 0; e[13] = y; - e[2] = 0; e[6] = 0; e[10] = 1; e[14] = z; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - return this; -}; - -/** - * Multiply the matrix for translation from the right. - * @param x The X value of a translation. - * @param y The Y value of a translation. - * @param z The Z value of a translation. - * @return this - */ -Matrix4.prototype.translate = function(x, y, z) { - var e = this.elements; - e[12] += e[0] * x + e[4] * y + e[8] * z; - e[13] += e[1] * x + e[5] * y + e[9] * z; - e[14] += e[2] * x + e[6] * y + e[10] * z; - e[15] += e[3] * x + e[7] * y + e[11] * z; - return this; -}; - -/** - * Set the matrix for rotation. - * The vector of rotation axis may not be normalized. - * @param angle The angle of rotation (degrees) - * @param x The X coordinate of vector of rotation axis. - * @param y The Y coordinate of vector of rotation axis. - * @param z The Z coordinate of vector of rotation axis. - * @return this - */ -Matrix4.prototype.setRotate = function(angle, x, y, z) { - var e, s, c, len, rlen, nc, xy, yz, zx, xs, ys, zs; - - angle = Math.PI * angle / 180; - e = this.elements; - - s = Math.sin(angle); - c = Math.cos(angle); - - if (0 !== x && 0 === y && 0 === z) { - // Rotation around X axis - if (x < 0) { - s = -s; - } - e[0] = 1; e[4] = 0; e[ 8] = 0; e[12] = 0; - e[1] = 0; e[5] = c; e[ 9] =-s; e[13] = 0; - e[2] = 0; e[6] = s; e[10] = c; e[14] = 0; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - } else if (0 === x && 0 !== y && 0 === z) { - // Rotation around Y axis - if (y < 0) { - s = -s; - } - e[0] = c; e[4] = 0; e[ 8] = s; e[12] = 0; - e[1] = 0; e[5] = 1; e[ 9] = 0; e[13] = 0; - e[2] =-s; e[6] = 0; e[10] = c; e[14] = 0; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - } else if (0 === x && 0 === y && 0 !== z) { - // Rotation around Z axis - if (z < 0) { - s = -s; - } - e[0] = c; e[4] =-s; e[ 8] = 0; e[12] = 0; - e[1] = s; e[5] = c; e[ 9] = 0; e[13] = 0; - e[2] = 0; e[6] = 0; e[10] = 1; e[14] = 0; - e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; - } else { - // Rotation around another axis - len = Math.sqrt(x*x + y*y + z*z); - if (len !== 1) { - rlen = 1 / len; - x *= rlen; - y *= rlen; - z *= rlen; - } - nc = 1 - c; - xy = x * y; - yz = y * z; - zx = z * x; - xs = x * s; - ys = y * s; - zs = z * s; - - e[ 0] = x*x*nc + c; - e[ 1] = xy *nc + zs; - e[ 2] = zx *nc - ys; - e[ 3] = 0; - - e[ 4] = xy *nc - zs; - e[ 5] = y*y*nc + c; - e[ 6] = yz *nc + xs; - e[ 7] = 0; - - e[ 8] = zx *nc + ys; - e[ 9] = yz *nc - xs; - e[10] = z*z*nc + c; - e[11] = 0; - - e[12] = 0; - e[13] = 0; - e[14] = 0; - e[15] = 1; - } - - return this; -}; - -/** - * Multiply the matrix for rotation from the right. - * The vector of rotation axis may not be normalized. - * @param angle The angle of rotation (degrees) - * @param x The X coordinate of vector of rotation axis. - * @param y The Y coordinate of vector of rotation axis. - * @param z The Z coordinate of vector of rotation axis. - * @return this - */ -Matrix4.prototype.rotate = function(angle, x, y, z) { - return this.concat(new Matrix4().setRotate(angle, x, y, z)); -}; - -/** - * Set the viewing matrix. - * @param eyeX, eyeY, eyeZ The position of the eye point. - * @param centerX, centerY, centerZ The position of the reference point. - * @param upX, upY, upZ The direction of the up vector. - * @return this - */ -Matrix4.prototype.setLookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { - var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz; - - fx = centerX - eyeX; - fy = centerY - eyeY; - fz = centerZ - eyeZ; - - // Normalize f. - rlf = 1 / Math.sqrt(fx*fx + fy*fy + fz*fz); - fx *= rlf; - fy *= rlf; - fz *= rlf; - - // Calculate cross product of f and up. - sx = fy * upZ - fz * upY; - sy = fz * upX - fx * upZ; - sz = fx * upY - fy * upX; - - // Normalize s. - rls = 1 / Math.sqrt(sx*sx + sy*sy + sz*sz); - sx *= rls; - sy *= rls; - sz *= rls; - - // Calculate cross product of s and f. - ux = sy * fz - sz * fy; - uy = sz * fx - sx * fz; - uz = sx * fy - sy * fx; - - // Set to this. - e = this.elements; - e[0] = sx; - e[1] = ux; - e[2] = -fx; - e[3] = 0; - - e[4] = sy; - e[5] = uy; - e[6] = -fy; - e[7] = 0; - - e[8] = sz; - e[9] = uz; - e[10] = -fz; - e[11] = 0; - - e[12] = 0; - e[13] = 0; - e[14] = 0; - e[15] = 1; - - // Translate. - return this.translate(-eyeX, -eyeY, -eyeZ); -}; - -/** - * Multiply the viewing matrix from the right. - * @param eyeX, eyeY, eyeZ The position of the eye point. - * @param centerX, centerY, centerZ The position of the reference point. - * @param upX, upY, upZ The direction of the up vector. - * @return this - */ -Matrix4.prototype.lookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { - return this.concat(new Matrix4().setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)); -}; - -/** - * Multiply the matrix for project vertex to plane from the right. - * @param plane The array[A, B, C, D] of the equation of plane "Ax + By + Cz + D = 0". - * @param light The array which stored coordinates of the light. if light[3]=0, treated as parallel light. - * @return this - */ -Matrix4.prototype.dropShadow = function(plane, light) { - var mat = new Matrix4(); - var e = mat.elements; - - var dot = plane[0] * light[0] + plane[1] * light[1] + plane[2] * light[2] + plane[3] * light[3]; - - e[ 0] = dot - light[0] * plane[0]; - e[ 1] = - light[1] * plane[0]; - e[ 2] = - light[2] * plane[0]; - e[ 3] = - light[3] * plane[0]; - - e[ 4] = - light[0] * plane[1]; - e[ 5] = dot - light[1] * plane[1]; - e[ 6] = - light[2] * plane[1]; - e[ 7] = - light[3] * plane[1]; - - e[ 8] = - light[0] * plane[2]; - e[ 9] = - light[1] * plane[2]; - e[10] = dot - light[2] * plane[2]; - e[11] = - light[3] * plane[2]; - - e[12] = - light[0] * plane[3]; - e[13] = - light[1] * plane[3]; - e[14] = - light[2] * plane[3]; - e[15] = dot - light[3] * plane[3]; - - return this.concat(mat); -} - -/** - * Multiply the matrix for project vertex to plane from the right.(Projected by parallel light.) - * @param normX, normY, normZ The normal vector of the plane.(Not necessary to be normalized.) - * @param planeX, planeY, planeZ The coordinate of arbitrary points on a plane. - * @param lightX, lightY, lightZ The vector of the direction of light.(Not necessary to be normalized.) - * @return this - */ -Matrix4.prototype.dropShadowDirectionally = function(normX, normY, normZ, planeX, planeY, planeZ, lightX, lightY, lightZ) { - var a = planeX * normX + planeY * normY + planeZ * normZ; - return this.dropShadow([normX, normY, normZ, -a], [lightX, lightY, lightZ, 0]); -}; - -/** - * Constructor of Vector3 - * If opt_src is specified, new vector is initialized by opt_src. - * @param opt_src source vector(option) - */ -var Vector3 = function(opt_src) { - var v = new Float32Array(3); - if (opt_src && typeof opt_src === 'object') { - v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2]; - } - this.elements = v; -} - -/** - * Normalize. - * @return this - */ -Vector3.prototype.normalize = function() { - var v = this.elements; - var c = v[0], d = v[1], e = v[2], g = Math.sqrt(c*c+d*d+e*e); - if(g){ - if(g == 1) - return this; - } else { - v[0] = 0; v[1] = 0; v[2] = 0; - return this; - } - g = 1/g; - v[0] = c*g; v[1] = d*g; v[2] = e*g; - return this; -}; - -/** - * Constructor of Vector4 - * If opt_src is specified, new vector is initialized by opt_src. - * @param opt_src source vector(option) - */ -var Vector4 = function(opt_src) { - var v = new Float32Array(4); - if (opt_src && typeof opt_src === 'object') { - v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2]; v[3] = opt_src[3]; - } - this.elements = v; -} diff --git a/lab3Bis/lib/cuon-utils.js b/lab3Bis/lib/cuon-utils.js deleted file mode 100644 index dc08b2e..0000000 --- a/lab3Bis/lib/cuon-utils.js +++ /dev/null @@ -1,113 +0,0 @@ -// cuon-utils.js (c) 2012 kanda and matsuda -/** - * Create a program object and make current - * @param gl GL context - * @param vshader a vertex shader program (string) - * @param fshader a fragment shader program (string) - * @return true, if the program object was created and successfully made current - */ -function initShaders(gl, vshader, fshader) { - var program = createProgram(gl, vshader, fshader); - if (!program) { - console.log('Failed to create program'); - return false; - } - - gl.useProgram(program); - gl.program = program; - - return true; -} - -/** - * Create the linked program object - * @param gl GL context - * @param vshader a vertex shader program (string) - * @param fshader a fragment shader program (string) - * @return created program object, or null if the creation has failed - */ -function createProgram(gl, vshader, fshader) { - // Create shader object - var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader); - var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader); - if (!vertexShader || !fragmentShader) { - return null; - } - - // Create a program object - var program = gl.createProgram(); - if (!program) { - return null; - } - - // Attach the shader objects - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - - // Link the program object - gl.linkProgram(program); - - // Check the result of linking - var linked = gl.getProgramParameter(program, gl.LINK_STATUS); - if (!linked) { - var error = gl.getProgramInfoLog(program); - console.log('Failed to link program: ' + error); - gl.deleteProgram(program); - gl.deleteShader(fragmentShader); - gl.deleteShader(vertexShader); - return null; - } - return program; -} - -/** - * Create a shader object - * @param gl GL context - * @param type the type of the shader object to be created - * @param source shader program (string) - * @return created shader object, or null if the creation has failed. - */ -function loadShader(gl, type, source) { - // Create shader object - var shader = gl.createShader(type); - if (shader == null) { - console.log('unable to create shader'); - return null; - } - - // Set the shader program - gl.shaderSource(shader, source); - - // Compile the shader - gl.compileShader(shader); - - // Check the result of compilation - var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); - if (!compiled) { - var error = gl.getShaderInfoLog(shader); - console.log('Failed to compile shader: ' + error); - gl.deleteShader(shader); - return null; - } - - return shader; -} - -/** - * Initialize and get the rendering for WebglInstance - * @param canvas <cavnas> element - * @param opt_debug flag to initialize the context for debugging - * @return the rendering context for WebglInstance - */ -function getWebGLContext(canvas, opt_debug) { - // Get the rendering context for WebglInstance - var gl = WebGLUtils.setupWebGL(canvas); - if (!gl) return null; - - // if opt_debug is explicitly false, create the context for debugging - if (arguments.length < 2 || opt_debug) { - gl = WebGLDebugUtils.makeDebugContext(gl); - } - - return gl; -} diff --git a/lab3Bis/lib/webgl-debug.js b/lab3Bis/lib/webgl-debug.js deleted file mode 100644 index 685868d..0000000 --- a/lab3Bis/lib/webgl-debug.js +++ /dev/null @@ -1,677 +0,0 @@ -//Copyright (c) 2009 The Chromium Authors. All rights reserved. -//Use of this source code is governed by a BSD-style license that can be -//found in the LICENSE file. - -// Various functions for helping debug WebglInstance apps. - -WebGLDebugUtils = function() { - -/** - * Wrapped logging function. - * @param {string} msg Message to log. - */ -var log = function(msg) { - if (window.console && window.console.log) { - window.console.log(msg); - } -}; - -/** - * Which arguements are enums. - * @type {!Object.<number, string>} - */ -var glValidEnumContexts = { - - // Generic setters and getters - - 'enable': { 0:true }, - 'disable': { 0:true }, - 'getParameter': { 0:true }, - - // Rendering - - 'drawArrays': { 0:true }, - 'drawElements': { 0:true, 2:true }, - - // Shaders - - 'createShader': { 0:true }, - 'getShaderParameter': { 1:true }, - 'getProgramParameter': { 1:true }, - - // Vertex attributes - - 'getVertexAttrib': { 1:true }, - 'vertexAttribPointer': { 2:true }, - - // Textures - - 'bindTexture': { 0:true }, - 'activeTexture': { 0:true }, - 'getTexParameter': { 0:true, 1:true }, - 'texParameterf': { 0:true, 1:true }, - 'texParameteri': { 0:true, 1:true, 2:true }, - 'texImage2D': { 0:true, 2:true, 6:true, 7:true }, - 'texSubImage2D': { 0:true, 6:true, 7:true }, - 'copyTexImage2D': { 0:true, 2:true }, - 'copyTexSubImage2D': { 0:true }, - 'generateMipmap': { 0:true }, - - // Buffer objects - - 'bindBuffer': { 0:true }, - 'bufferData': { 0:true, 2:true }, - 'bufferSubData': { 0:true }, - 'getBufferParameter': { 0:true, 1:true }, - - // Renderbuffers and framebuffers - - 'pixelStorei': { 0:true, 1:true }, - 'readPixels': { 4:true, 5:true }, - 'bindRenderbuffer': { 0:true }, - 'bindFramebuffer': { 0:true }, - 'checkFramebufferStatus': { 0:true }, - 'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, - 'framebufferTexture2D': { 0:true, 1:true, 2:true }, - 'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, - 'getRenderbufferParameter': { 0:true, 1:true }, - 'renderbufferStorage': { 0:true, 1:true }, - - // Frame buffer operations (clear, blend, depth test, stencil) - - 'clear': { 0:true }, - 'depthFunc': { 0:true }, - 'blendFunc': { 0:true, 1:true }, - 'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, - 'blendEquation': { 0:true }, - 'blendEquationSeparate': { 0:true, 1:true }, - 'stencilFunc': { 0:true }, - 'stencilFuncSeparate': { 0:true, 1:true }, - 'stencilMaskSeparate': { 0:true }, - 'stencilOp': { 0:true, 1:true, 2:true }, - 'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, - - // Culling - - 'cullFace': { 0:true }, - 'frontFace': { 0:true }, -}; - -/** - * Map of numbers to names. - * @type {Object} - */ -var glEnums = null; - -/** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebglInstance context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ -function init(ctx) { - if (glEnums == null) { - glEnums = { }; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'number') { - glEnums[ctx[propertyName]] = propertyName; - } - } - } -} - -/** - * Checks the utils have been initialized. - */ -function checkInit() { - if (glEnums == null) { - throw 'WebGLDebugUtils.init(ctx) not called'; - } -} - -/** - * Returns true or false if value matches any WebglInstance enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebglInstance defined enums - */ -function mightBeEnum(value) { - checkInit(); - return (glEnums[value] !== undefined); -} - -/** - * Gets an string version of an WebglInstance enum. - * - * Example: - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ -function glEnumToString(value) { - checkInit(); - var name = glEnums[value]; - return (name !== undefined) ? name : - ("*UNKNOWN WebglInstance ENUM (0x" + value.toString(16) + ")"); -} - -/** - * Returns the string version of a WebglInstance argument. - * Attempts to convert enum arguments to strings. - * @param {string} functionName the name of the WebglInstance function. - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ -function glFunctionArgToString(functionName, argumentIndex, value) { - var funcInfo = glValidEnumContexts[functionName]; - if (funcInfo !== undefined) { - if (funcInfo[argumentIndex]) { - return glEnumToString(value); - } - } - return value.toString(); -} - -/** - * Given a WebglInstance context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not gl.NO_ERROR. - * - * @param {!WebGLRenderingContext} ctx The webgl context to - * wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc - * The function to call when gl.getError returns an - * error. If not specified the default function calls - * console.log with a message. - */ -function makeDebugContext(ctx, opt_onErrorFunc) { - init(ctx); - opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { - // apparently we can't do args.join(","); - var argStr = ""; - for (var ii = 0; ii < args.length; ++ii) { - argStr += ((ii == 0) ? '' : ', ') + - glFunctionArgToString(functionName, ii, args[ii]); - } - log("WebglInstance error "+ glEnumToString(err) + " in "+ functionName + - "(" + argStr + ")"); - }; - - // Holds booleans for each GL error so after we get the error ourselves - // we can still return it to the client app. - var glErrorShadow = { }; - - // Makes a function that calls a WebglInstance function and then calls getError. - function makeErrorWrapper(ctx, functionName) { - return function() { - var result = ctx[functionName].apply(ctx, arguments); - var err = ctx.getError(); - if (err != 0) { - glErrorShadow[err] = true; - opt_onErrorFunc(err, functionName, arguments); - } - return result; - }; - } - - // Make a an object that has a copy of every property of the WebglInstance context - // but wraps all functions. - var wrapper = {}; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); - } else { - wrapper[propertyName] = ctx[propertyName]; - } - } - - // Override the getError function with one that returns our saved results. - wrapper.getError = function() { - for (var err in glErrorShadow) { - if (glErrorShadow[err]) { - glErrorShadow[err] = false; - return err; - } - } - return ctx.NO_ERROR; - }; - - return wrapper; -} - -function resetToInitialState(ctx) { - var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); - var tmp = ctx.createBuffer(); - ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp); - for (var ii = 0; ii < numAttribs; ++ii) { - ctx.disableVertexAttribArray(ii); - ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0); - ctx.vertexAttrib1f(ii, 0); - } - ctx.deleteBuffer(tmp); - - var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); - for (var ii = 0; ii < numTextureUnits; ++ii) { - ctx.activeTexture(ctx.TEXTURE0 + ii); - ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null); - ctx.bindTexture(ctx.TEXTURE_2D, null); - } - - ctx.activeTexture(ctx.TEXTURE0); - ctx.useProgram(null); - ctx.bindBuffer(ctx.ARRAY_BUFFER, null); - ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); - ctx.disable(ctx.BLEND); - ctx.disable(ctx.CULL_FACE); - ctx.disable(ctx.DEPTH_TEST); - ctx.disable(ctx.DITHER); - ctx.disable(ctx.SCISSOR_TEST); - ctx.blendColor(0, 0, 0, 0); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ZERO); - ctx.clearColor(0, 0, 0, 0); - ctx.clearDepth(1); - ctx.clearStencil(-1); - ctx.colorMask(true, true, true, true); - ctx.cullFace(ctx.BACK); - ctx.depthFunc(ctx.LESS); - ctx.depthMask(true); - ctx.depthRange(0, 1); - ctx.frontFace(ctx.CCW); - ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE); - ctx.lineWidth(1); - ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false); - ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); - // TODO: Delete this IF. - if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) { - ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL); - } - ctx.polygonOffset(0, 0); - ctx.sampleCoverage(1, false); - ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height); - ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF); - ctx.stencilMask(0xFFFFFFFF); - ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP); - ctx.viewport(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight); - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT); - - // TODO: This should NOT be needed but Firefox fails with 'hint' - while(ctx.getError()); -} - -function makeLostContextSimulatingContext(ctx) { - var wrapper_ = {}; - var contextId_ = 1; - var contextLost_ = false; - var resourceId_ = 0; - var resourceDb_ = []; - var onLost_ = undefined; - var onRestored_ = undefined; - var nextOnRestored_ = undefined; - - // Holds booleans for each GL error so can simulate errors. - var glErrorShadow_ = { }; - - function isWebGLObject(obj) { - //return false; - return (obj instanceof WebGLBuffer || - obj instanceof WebGLFramebuffer || - obj instanceof WebGLProgram || - obj instanceof WebGLRenderbuffer || - obj instanceof WebGLShader || - obj instanceof WebGLTexture); - } - - function checkResources(args) { - for (var ii = 0; ii < args.length; ++ii) { - var arg = args[ii]; - if (isWebGLObject(arg)) { - return arg.__webglDebugContextLostId__ == contextId_; - } - } - return true; - } - - function clearErrors() { - var k = Object.keys(glErrorShadow_); - for (var ii = 0; ii < k.length; ++ii) { - delete glErrorShdow_[k]; - } - } - - // Makes a function that simulates WebglInstance when out of context. - function makeLostContextWrapper(ctx, functionName) { - var f = ctx[functionName]; - return function() { - // Only call the functions if the context is not lost. - if (!contextLost_) { - if (!checkResources(arguments)) { - glErrorShadow_[ctx.INVALID_OPERATION] = true; - return; - } - var result = f.apply(ctx, arguments); - return result; - } - }; - } - - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - wrapper_[propertyName] = makeLostContextWrapper(ctx, propertyName); - } else { - wrapper_[propertyName] = ctx[propertyName]; - } - } - - function makeWebGLContextEvent(statusMessage) { - return {statusMessage: statusMessage}; - } - - function freeResources() { - for (var ii = 0; ii < resourceDb_.length; ++ii) { - var resource = resourceDb_[ii]; - if (resource instanceof WebGLBuffer) { - ctx.deleteBuffer(resource); - } else if (resource instanceof WebctxFramebuffer) { - ctx.deleteFramebuffer(resource); - } else if (resource instanceof WebctxProgram) { - ctx.deleteProgram(resource); - } else if (resource instanceof WebctxRenderbuffer) { - ctx.deleteRenderbuffer(resource); - } else if (resource instanceof WebctxShader) { - ctx.deleteShader(resource); - } else if (resource instanceof WebctxTexture) { - ctx.deleteTexture(resource); - } - } - } - - wrapper_.loseContext = function() { - if (!contextLost_) { - contextLost_ = true; - ++contextId_; - while (ctx.getError()); - clearErrors(); - glErrorShadow_[ctx.CONTEXT_LOST_WEBGL] = true; - setTimeout(function() { - if (onLost_) { - onLost_(makeWebGLContextEvent("context lost")); - } - }, 0); - } - }; - - wrapper_.restoreContext = function() { - if (contextLost_) { - if (onRestored_) { - setTimeout(function() { - freeResources(); - resetToInitialState(ctx); - contextLost_ = false; - if (onRestored_) { - var callback = onRestored_; - onRestored_ = nextOnRestored_; - nextOnRestored_ = undefined; - callback(makeWebGLContextEvent("context restored")); - } - }, 0); - } else { - throw "You can not restore the context without a listener" - } - } - }; - - // Wrap a few functions specially. - wrapper_.getError = function() { - if (!contextLost_) { - var err; - while (err = ctx.getError()) { - glErrorShadow_[err] = true; - } - } - for (var err in glErrorShadow_) { - if (glErrorShadow_[err]) { - delete glErrorShadow_[err]; - return err; - } - } - return ctx.NO_ERROR; - }; - - var creationFunctions = [ - "createBuffer", - "createFramebuffer", - "createProgram", - "createRenderbuffer", - "createShader", - "createTexture" - ]; - for (var ii = 0; ii < creationFunctions.length; ++ii) { - var functionName = creationFunctions[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return null; - } - var obj = f.apply(ctx, arguments); - obj.__webglDebugContextLostId__ = contextId_; - resourceDb_.push(obj); - return obj; - }; - }(ctx[functionName]); - } - - var functionsThatShouldReturnNull = [ - "getActiveAttrib", - "getActiveUniform", - "getBufferParameter", - "getContextAttributes", - "getAttachedShaders", - "getFramebufferAttachmentParameter", - "getParameter", - "getProgramParameter", - "getProgramInfoLog", - "getRenderbufferParameter", - "getShaderParameter", - "getShaderInfoLog", - "getShaderSource", - "getTexParameter", - "getUniform", - "getUniformLocation", - "getVertexAttrib" - ]; - for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) { - var functionName = functionsThatShouldReturnNull[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return null; - } - return f.apply(ctx, arguments); - } - }(wrapper_[functionName]); - } - - var isFunctions = [ - "isBuffer", - "isEnabled", - "isFramebuffer", - "isProgram", - "isRenderbuffer", - "isShader", - "isTexture" - ]; - for (var ii = 0; ii < isFunctions.length; ++ii) { - var functionName = isFunctions[ii]; - wrapper_[functionName] = function(f) { - return function() { - if (contextLost_) { - return false; - } - return f.apply(ctx, arguments); - } - }(wrapper_[functionName]); - } - - wrapper_.checkFramebufferStatus = function(f) { - return function() { - if (contextLost_) { - return ctx.FRAMEBUFFER_UNSUPPORTED; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.checkFramebufferStatus); - - wrapper_.getAttribLocation = function(f) { - return function() { - if (contextLost_) { - return -1; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.getAttribLocation); - - wrapper_.getVertexAttribOffset = function(f) { - return function() { - if (contextLost_) { - return 0; - } - return f.apply(ctx, arguments); - }; - }(wrapper_.getVertexAttribOffset); - - wrapper_.isContextLost = function() { - return contextLost_; - }; - - function wrapEvent(listener) { - if (typeof(listener) == "function") { - return listener; - } else { - return function(info) { - listener.handleEvent(info); - } - } - } - - wrapper_.registerOnContextLostListener = function(listener) { - onLost_ = wrapEvent(listener); - }; - - wrapper_.registerOnContextRestoredListener = function(listener) { - if (contextLost_) { - nextOnRestored_ = wrapEvent(listener); - } else { - onRestored_ = wrapEvent(listener); - } - } - - return wrapper_; -} - -return { - /** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebglInstance context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ - 'init': init, - - /** - * Returns true or false if value matches any WebglInstance enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebglInstance defined enums - */ - 'mightBeEnum': mightBeEnum, - - /** - * Gets an string version of an WebglInstance enum. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ - 'glEnumToString': glEnumToString, - - /** - * Converts the argument of a WebglInstance function to a string. - * Attempts to convert enum arguments to strings. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D); - * - * would return 'TEXTURE_2D' - * - * @param {string} functionName the name of the WebglInstance function. - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ - 'glFunctionArgToString': glFunctionArgToString, - - /** - * Given a WebglInstance context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not NO_ERROR. - * - * You can supply your own function if you want. For example, if you'd like - * an exception thrown on any GL error you could do this - * - * function throwOnGLError(err, funcName, args) { - * throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" + - * funcName; - * }; - * - * ctx = WebGLDebugUtils.makeDebugContext( - * canvas.getContext("webgl"), throwOnGLError); - * - * @param {!WebGLRenderingContext} ctx The webgl context to wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc The function - * to call when gl.getError returns an error. If not specified the default - * function calls console.log with a message. - */ - 'makeDebugContext': makeDebugContext, - - /** - * Given a WebglInstance context returns a wrapped context that adds 4 - * functions. - * - * ctx.loseContext: - * simulates a lost context event. - * - * ctx.restoreContext: - * simulates the context being restored. - * - * ctx.registerOnContextLostListener(listener): - * lets you register a listener for context lost. Use instead - * of addEventListener('webglcontextlostevent', listener); - * - * ctx.registerOnContextRestoredListener(listener): - * lets you register a listener for context restored. Use - * instead of addEventListener('webglcontextrestored', - * listener); - * - * @param {!WebGLRenderingContext} ctx The webgl context to wrap. - */ - 'makeLostContextSimulatingContext': makeLostContextSimulatingContext, - - /** - * Resets a context to the initial state. - * @param {!WebGLRenderingContext} ctx The webgl context to - * reset. - */ - 'resetToInitialState': resetToInitialState -}; - -}(); - diff --git a/lab3Bis/lib/webgl-utils.js b/lab3Bis/lib/webgl-utils.js deleted file mode 100644 index 26ed37e..0000000 --- a/lab3Bis/lib/webgl-utils.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2010, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/** - * @fileoverview This file contains functions every webgl program will need - * a version of one way or another. - * - * Instead of setting up a context manually it is recommended to - * use. This will check for success or failure. On failure it - * will attempt to present an approriate message to the user. - * - * gl = WebGLUtils.setupWebGL(canvas); - * - * For animated WebglInstance apps use of setTimeout or setInterval are - * discouraged. It is recommended you structure your rendering - * loop like this. - * - * function render() { - * window.requestAnimationFrame(render, canvas); - * - * // do rendering - * ... - * } - * render(); - * - * This will call your rendering function up to the refresh rate - * of your display but will stop rendering if your app is not - * visible. - */ - -WebGLUtils = function() { - -/** - * Creates the HTLM for a failure message - * @param {string} canvasContainerId id of container of th - * canvas. - * @return {string} The html. - */ -var makeFailHTML = function(msg) { - return '' + - '<div style="margin: auto; width:500px;z-index:10000;margin-top:20em;text-align:center;">' + msg + '</div>'; - return '' + - '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' + - '<td align="center">' + - '<div style="display: table-cell; vertical-align: middle;">' + - '<div style="">' + msg + '</div>' + - '</div>' + - '</td></tr></table>'; -}; - -/** - * Mesasge for getting a webgl browser - * @type {string} - */ -var GET_A_WEBGL_BROWSER = '' + - 'This page requires a browser that supports WebglInstance.<br/>' + - '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>'; - -/** - * Mesasge for need better hardware - * @type {string} - */ -var OTHER_PROBLEM = '' + - "It doesn't appear your computer can support WebglInstance.<br/>" + - '<a href="http://get.webgl.org">Click here for more information.</a>'; - -/** - * Creates a webgl context. If creation fails it will - * change the contents of the container of the <canvas> - * tag to an error message with the correct links for WebglInstance. - * @param {Element} canvas. The canvas element to create a - * context from. - * @param {WebGLContextCreationAttirbutes} opt_attribs Any - * creation attributes you want to pass in. - * @param {function:(msg)} opt_onError An function to call - * if there is an error during creation. - * @return {WebGLRenderingContext} The created context. - */ -var setupWebGL = function(canvas, opt_attribs, opt_onError) { - function handleCreationError(msg) { - var container = document.getElementsByTagName("body")[0]; - //var container = canvas.parentNode; - if (container) { - var str = window.WebGLRenderingContext ? - OTHER_PROBLEM : - GET_A_WEBGL_BROWSER; - if (msg) { - str += "<br/><br/>Status: " + msg; - } - container.innerHTML = makeFailHTML(str); - } - }; - - opt_onError = opt_onError || handleCreationError; - - if (canvas.addEventListener) { - canvas.addEventListener("webglcontextcreationerror", function(event) { - opt_onError(event.statusMessage); - }, false); - } - var context = create3DContext(canvas, opt_attribs); - if (!context) { - if (!window.WebGLRenderingContext) { - opt_onError(""); - } else { - opt_onError(""); - } - } - - return context; -}; - -/** - * Creates a webgl context. - * @param {!Canvas} canvas The canvas tag to get context - * from. If one is not passed in one will be created. - * @return {!WebGLContext} The created context. - */ -var create3DContext = function(canvas, opt_attribs) { - var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; - var context = null; - for (var ii = 0; ii < names.length; ++ii) { - try { - context = canvas.getContext(names[ii], opt_attribs); - } catch(e) {} - if (context) { - break; - } - } - return context; -} - -return { - create3DContext: create3DContext, - setupWebGL: setupWebGL -}; -}(); - -/** - * Provides requestAnimationFrame in a cross browser - * way. - */ -if (!window.requestAnimationFrame) { - window.requestAnimationFrame = (function() { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { - window.setTimeout(callback, 1000/60); - }; - })(); -} - -/** * ERRATA: 'cancelRequestAnimationFrame' renamed to 'cancelAnimationFrame' to reflect an update to the W3C Animation-Timing Spec. - * - * Cancels an animation frame request. - * Checks for cross-browser support, falls back to clearTimeout. - * @param {number} Animation frame request. */ -if (!window.cancelAnimationFrame) { - window.cancelAnimationFrame = (window.cancelRequestAnimationFrame || - window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame || - window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame || - window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame || - window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame || - window.clearTimeout); -} \ No newline at end of file diff --git a/lab3Bis/src/lab3.html b/lab3Bis/src/lab3.html deleted file mode 100644 index 6acac41..0000000 --- a/lab3Bis/src/lab3.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <title>point light</title> -</head> - -<body onload="main()"> - <canvas width="500" height="500" id="my-canvas"> -Please use a browser that supports "canvas" -</canvas> - <script src="../lib/webgl-utils.js"></script> - <script src="../lib/webgl-debug.js"></script> - <script src="../lib/cuon-utils.js"></script> - <script src="../lib/cuon-matrix.js"></script> - <script src="lab3.js"></script> -</body> - -</html> \ No newline at end of file diff --git a/lab3Bis/src/lab3.js b/lab3Bis/src/lab3.js deleted file mode 100644 index 5b2bf83..0000000 --- a/lab3Bis/src/lab3.js +++ /dev/null @@ -1,458 +0,0 @@ -//author : QUentin Berthet -const VSHADER_SOURCE = - 'attribute vec4 a_position;\n' + - 'attribute vec4 a_Color;\n' + - 'attribute vec3 a_normal;\n' + - - - 'uniform vec3 u_lightWorldPosition;\n' + - 'uniform vec3 u_viewWorldPosition;\n' + - - - 'uniform mat4 u_world;\n' + - 'uniform mat4 u_worldViewProjection;\n' + - 'uniform mat4 u_worldInverseTranspose;\n' + - - 'varying vec3 v_normal;\n' + - - 'varying vec3 v_surfaceToLight;\n' + - 'varying vec3 v_surfaceToView;\n' + - - 'void main() {\n' + - ' gl_Position = u_worldViewProjection * a_position ;\n' + - ' v_normal = mat3(u_worldInverseTranspose) * a_normal;\n' + - ' vec3 surfaceWorldPosition = (u_world * a_position).xyz;\n' + - ' v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;\n' + - ' v_surfaceToView = u_viewWorldPosition - surfaceWorldPosition;\n' + - '}\n'; - - -const FSHADER_SOURCE = - 'precision mediump float;\n' + - 'varying vec3 v_normal;\n' + - 'varying vec3 v_surfaceToLight;\n' + - 'varying vec3 v_surfaceToView;\n' + - 'uniform vec4 u_color;\n' + - 'uniform float u_shininess;\n' + - - 'void main() {\n' + - ' vec3 normal = normalize(v_normal);\n' + - ' vec3 surfaceToLightDirection = normalize(v_surfaceToLight);\n' + - ' vec3 surfaceToViewDirection = normalize(v_surfaceToView);\n' + - ' vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);\n' + - ' float light = dot(normal, surfaceToLightDirection);\n' + - ' float specular = 0.0;\n' + - ' if (light > 0.0) {specular = pow(dot(normal, halfVector), u_shininess);}\n' + - ' gl_FragColor = u_color;\n' + - ' gl_FragColor.rgb *= light;\n' + - ' gl_FragColor.rgb += specular;\n' + - '}\n'; - - - -function main() { - - const canvas = document.getElementById('my-canvas'); - - - const gl = getWebGLContext(canvas); - if (!gl) { - console.log('Failed to get the displaying context for WebGL'); - return; - } - - - if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { - console.log('Failed to intialize shaders.'); - return; - } - - // look up where the vertex data needs to go. - var positionLocation = gl.getAttribLocation(gl.program, "a_position"); - var normalLocation = gl.getAttribLocation(gl.program, "a_normal"); - - // lookup uniforms - var worldViewProjectionLocation = gl.getUniformLocation(gl.program, "u_worldViewProjection"); - var worldInverseTransposeLocation = gl.getUniformLocation(gl.program, "u_worldInverseTranspose"); - var colorLocation = gl.getUniformLocation(gl.program, "u_color"); - var shininessLocation = gl.getUniformLocation(gl.program, "u_shininess"); - var lightWorldPositionLocation = - gl.getUniformLocation(gl.program, "u_lightWorldPosition"); - var viewWorldPositionLocation = - gl.getUniformLocation(gl.program, "u_viewWorldPosition"); - var worldLocation = - gl.getUniformLocation(gl.program, "u_world"); - - - - // Create a buffer to put positions in - var positionBuffer = gl.createBuffer(); - // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - // Put geometry data into buffer - - const len = initVertexBuffers(gl); - - if (len < 0) { - console.log('Failed to set the positions of the vertices'); - return; - } - - // Create a buffer to put normals in - var normalBuffer = gl.createBuffer(); - // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = normalBuffer) - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - // Put normals data into buffer - - - CreateNormals(gl); - var shininess = 150; - - function updateShininess(event, ui) { - shininess = ui.value; - drawScene(); - } - - - - - function drawScene() { - - gl.clearColor(0.75, 0.85, 0.8, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.enable(gl.DEPTH_TEST); - gl.frontFace(gl.CCW); - gl.cullFace(gl.BACK); - // Turn on the position attribute - - const projMatrix = new Matrix4(); - projMatrix.setPerspective(45, gl.canvas.clientWidth / gl.canvas.clientHeight, 1, 100); - - const cameraMatrix = new Matrix4(); - let angle = 1; - let X = 5 * Math.cos(angle); - let Y = 0; - let Z = 5 * Math.sin(angle); - - cameraMatrix.setLookAt(X, Y, Z, 0, 0, 0, 0, 1, 0); - const viewMatrix = new Matrix4(cameraMatrix); - - const viewProjectionMatrix = new Matrix4(projMatrix).multiply(new Matrix4(viewMatrix)); - - const worldMatrix = new Matrix4(); - - - const worldViewProjectionMatrix = new Matrix4(viewProjectionMatrix).multiply(worldMatrix); - const worldInverseMatrix = new Matrix4(worldMatrix).invert(); - const worldInverseTransposeMatrix = new Matrix4(worldInverseMatrix).transpose(); - - - - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - gl.enableVertexAttribArray(positionLocation); - var size = 3; // 3 components per iteration - var type = gl.FLOAT; // the data is 32bit floats - var normalize = false; // don't normalize the data - var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position - var offset = 0; // start at the beginning of the buffer - gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset); - - - - - - // Turn on the normal attribute - gl.enableVertexAttribArray(normalLocation); - // Bind the normal buffer. - gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); - // Tell the attribute how to get data out of normalBuffer (ARRAY_BUFFER) - var size = 3; // 3 components per iteration - var type = gl.FLOAT; // the data is 32bit floating point values - var normalize = false; // normalize the data (convert from 0-255 to 0-1) - var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position - var offset = 0; // start at the beginning of the buffer - gl.vertexAttribPointer( - normalLocation, size, type, normalize, stride, offset); - - - //Set the matrices - gl.uniformMatrix4fv(worldViewProjectionLocation, false, worldViewProjectionMatrix); - gl.uniformMatrix4fv(worldInverseTransposeLocation, false, worldInverseTransposeMatrix); - gl.uniformMatrix4fv(worldLocation, false, worldMatrix); - // Set the color to use - gl.uniform4fv(colorLocation, [0.2, 1, 0.2, 1]); // green - // set the light position - gl.uniform3fv(lightWorldPositionLocation, [20, 30, 60]); - // set the camera/view position - gl.uniform3fv(viewWorldPositionLocation, camera); - // set the shininess - gl.uniform1f(shininessLocation, shininess); - - - - - - - var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); - if (a_Color < 0) { - console.log('Failed to get the storage location of a_Color'); - return -1; - } - - gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12); - gl.enableVertexAttribArray(a_Color); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - - - - var viewProjMatrix = new Matrix4(); - viewProjMatrix.setPerspective(100.0, 1.0, 1.0, 1000.0); - viewProjMatrix.lookAt(1.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - - var vals = [0.0, 0.0]; - ObjectManager(vals); - - var display = function() { - let count = 42; - // Don't render the upper surface because we duplicate frustum + surface - if (i === 1) { - count -= 6; - } - cameraMatrix.set(viewProjMatrix); - cameraMatrix.rotate(vals[0], 1.0, 0.0, 0.0); - cameraMatrix.rotate(vals[1], 0.0, 1.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); - - - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0); - - cameraMatrix.translate(0, 3.0, -4) - cameraMatrix.rotate(180, 1.0, 0.0, 0.0); - gl.uniformMatrix4fv(u_worldViewProjection, false, cameraMatrix.elements); - - gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, 0); - - - requestAnimationFrame(display); - }; - display(); - } - -} - -function ObjectManager(values) { - document.onkeydown = (ev) => { - v = 10; - switch (ev.key) { - case 'ArrowDown': - values[0] += v; - break; - case 'ArrowUp': - values[0] -= v; - break; - case 'ArrowRight': - values[1] += v; - break; - case 'ArrowLeft': - values[1] -= v; - break; - } - }; -} - - - -function initVertexBuffers(gl) { - - let vertices = new Float32Array([ - - // Front - -2, -1.5, 0, -1, 1.5, -1, - 0, -1.5, 0, - - -1, 1.5, -1, - 0, -1.5, 0, - 1, 1.5, -1, - - 0, -1.5, 0, - 1, 1.5, -1, - 2, -1.5, 0, - - // Back - -2, -1.5, -4, -1, 1.5, -3, - 0, -1.5, -4, - - -1, 1.5, -3, - 0, -1.5, -4, - 1, 1.5, -3, - - 0, -1.5, -4, - 1, 1.5, -3, - 2, -1.5, -4, - - // Left - -2, -1.5, -4, -1, 1.5, -3, -2, -1.5, -2, - - -1, 1.5, -3, -2, -1.5, -2, -1, 1.5, -1, - - -2, -1.5, -2, -1, 1.5, -1, -2, -1.5, 0, - - // Right - 2, -1.5, -4, - 1, 1.5, -3, - 2, -1.5, -2, - - 1, 1.5, -3, - 2, -1.5, -2, - 1, 1.5, -1, - - 2, -1.5, -2, - 1, 1.5, -1, - 2, -1.5, -0, - - // top - -1, 1.5, -1, -1, 1.5, -3, - 0, 1.5, -1, - - -1, 1.5, -3, - 0, 1.5, -1, - 1, 1.5, -3, - - 0, 1.5, -1, - 1, 1.5, -3, - 1, 1.5, -1, - - // ground - -2, -1.5, 0, -2, -1.5, -4, - 0, -1.5, 0, - - -2, -1.5, -4, - 0, -1.5, 0, - 2, -1.5, -4, - - 0, -1.5, 0, - 2, -1.5, -4, - 2, -1.5, 0, - - - ]); - - const len = vertices.length / 6; - const vertexBuffer = gl.createBuffer(); - if (!vertexBuffer) { - console.log('Failed to create the buffer object'); - return -1; - } - - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - - return len; -} - -function normalizedCrossWith3Points(a0, a1, a2, b0, b1, b2, c0, c1, c2) { - const u = [b0 - a0, b1 - a1, b2 - a2]; - const v = [c0 - a0, c1 - a1, c2 - a2]; - const rawNormal = [ - u[1] * v[2] - u[2] * v[1], - u[2] * v[0] - u[0] * v[2], - u[0] * v[1] - u[1] * v[0] - ]; - const norm = Math.hypot(...rawNormal); - return rawNormal.map((n) => n / norm); -} - -const Normal_f = normalizedCrossWith3Points(-1, 1.5, -1, - 0, -1.5, 0, - 1, 1.5, -1 - -); -const Normal_b = normalizedCrossWith3Points(-1, 1.5, -3, - 0, -1.5, -4, - 1, 1.5, -3 -); -const Normal_t = normalizedCrossWith3Points(-1, 1.5, -3, - 0, 1.5, -1, - 1, 1.5, -3 -); -const Normal_g = normalizedCrossWith3Points(-2, -1.5, -4, - 0, -1.5, 0, - 2, -1.5, -4 -); -const Normal_r = normalizedCrossWith3Points( - 1, 1.5, -3, - 2, -1.5, -2, - 1, 1.5, -1 -); - -const leftNormal = normalizedCrossWith3Points(-1, 1.5, -3, -2, -1.5, -2, -1, 1.5, -1); - - - -function CreateNormals(gl, bottomNormal) { - var vertexNormals = new Float32Array( - [ //front - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - - // back - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - 0, 0, -1, - - - // left - -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, - - // right - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - 1, 0, 0, - - // top - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - 0, 1, 0, - - // ground - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - 0, -1, 0, - - ]); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals), gl.STATIC_DRAW); -} \ No newline at end of file diff --git a/lab4/README.md b/lab4/README.md new file mode 100644 index 0000000..ec24bbc --- /dev/null +++ b/lab4/README.md @@ -0,0 +1,6 @@ +# Lab4 IHM + +* **docs**: contains the lab's statement +* **libs**: contains WebGL libraries and utilities +* **src**: contains the source code of the lab4 that you should complete (`main()` function in **lab4.js** file) +* **DO NOT CHANGE** the name of the file `lab4.html`, however, you are free to change its content. diff --git a/lab4/docs/Cours 3D Labo 4.pdf b/lab4/docs/Cours 3D Labo 4.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e639f4bfba3ee962e43ab8c26c7d1e2e56830580 GIT binary patch literal 74144 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%0AE}EcVvUiLV7WaCcYzzPP`!*zxE^i$DBF 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 MajB}h`nz!f0G18cbN~PV literal 0 HcmV?d00001 diff --git a/lab3.0/lib/cuon-utils.js b/lab4/lib/cuon-utils.js similarity index 100% rename from lab3.0/lib/cuon-utils.js rename to lab4/lib/cuon-utils.js diff --git a/lab3.0/lib/webgl-debug.js b/lab4/lib/webgl-debug.js similarity index 100% rename from lab3.0/lib/webgl-debug.js rename to lab4/lib/webgl-debug.js diff --git a/lab3.0/lib/webgl-utils.js b/lab4/lib/webgl-utils.js similarity index 100% rename from lab3.0/lib/webgl-utils.js rename to lab4/lib/webgl-utils.js diff --git a/lab4/src/lab4.html b/lab4/src/lab4.html new file mode 100644 index 0000000..2bb37bc --- /dev/null +++ b/lab4/src/lab4.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Lab 4</title> +</head> +<body onload="main()"> +<canvas width="400" height="600" id="my-canvas"> + Please use a browser that supports "canvas" +</canvas> +<script src="../lib/webgl-utils.js"></script> +<script src="../lib/webgl-debug.js"></script> +<script src="../lib/cuon-utils.js"></script> +<script src="lab4.js"></script> +</body> +</html> \ No newline at end of file diff --git a/lab4/src/lab4.js b/lab4/src/lab4.js new file mode 100644 index 0000000..105a227 --- /dev/null +++ b/lab4/src/lab4.js @@ -0,0 +1,18 @@ +// Vertex shader program +const VSHADER_SOURCE = + '\n' + + // TODO: Implement your vertex shader code here + '\n'; + +// Fragment shader program +const FSHADER_SOURCE = + '\n' + + // TODO: Implement your fragment shader code here + '\n'; + +function main() { + // Retrieve <canvas> element + const canvas = document.getElementById('my-canvas'); + + // TODO: Complete with your code here +} \ No newline at end of file -- GitLab