From fd1173d0a8821e90f91bcf5e7d4e98999915ca48 Mon Sep 17 00:00:00 2001 From: ivan perez <ivan.perez@etu.hesge.ch> Date: Fri, 6 Nov 2020 12:53:17 +0100 Subject: [PATCH] Lab 2 --- lab2/README.md | 6 + lab2/docs/Cours 3D Labo 2.pdf | Bin 0 -> 73912 bytes lab2/lib/cuon-matrix.js | 741 ++++++++++++++++++++++++++++++++++ lab2/lib/cuon-utils.js | 113 ++++++ lab2/lib/webgl-debug.js | 677 +++++++++++++++++++++++++++++++ lab2/lib/webgl-utils.js | 197 +++++++++ lab2/src/lab2.html | 17 + lab2/src/lab2.js | 193 +++++++++ 8 files changed, 1944 insertions(+) create mode 100644 lab2/README.md create mode 100644 lab2/docs/Cours 3D Labo 2.pdf create mode 100644 lab2/lib/cuon-matrix.js create mode 100644 lab2/lib/cuon-utils.js create mode 100644 lab2/lib/webgl-debug.js create mode 100644 lab2/lib/webgl-utils.js create mode 100644 lab2/src/lab2.html create mode 100644 lab2/src/lab2.js diff --git a/lab2/README.md b/lab2/README.md new file mode 100644 index 0000000..073809a --- /dev/null +++ b/lab2/README.md @@ -0,0 +1,6 @@ +# 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/lab2/docs/Cours 3D Labo 2.pdf b/lab2/docs/Cours 3D Labo 2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..66071f225ca9c1724c1340fe0600b3df3b6e0d12 GIT binary patch literal 73912 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	btwq7<g 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 literal 0 HcmV?d00001 diff --git a/lab2/lib/cuon-matrix.js b/lab2/lib/cuon-matrix.js new file mode 100644 index 0000000..b67a5dd --- /dev/null +++ b/lab2/lib/cuon-matrix.js @@ -0,0 +1,741 @@ +// 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/lab2/lib/cuon-utils.js b/lab2/lib/cuon-utils.js new file mode 100644 index 0000000..dc08b2e --- /dev/null +++ b/lab2/lib/cuon-utils.js @@ -0,0 +1,113 @@ +// 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/lab2/lib/webgl-debug.js b/lab2/lib/webgl-debug.js new file mode 100644 index 0000000..685868d --- /dev/null +++ b/lab2/lib/webgl-debug.js @@ -0,0 +1,677 @@ +//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/lab2/lib/webgl-utils.js b/lab2/lib/webgl-utils.js new file mode 100644 index 0000000..26ed37e --- /dev/null +++ b/lab2/lib/webgl-utils.js @@ -0,0 +1,197 @@ +/* + * 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/lab2/src/lab2.html b/lab2/src/lab2.html new file mode 100644 index 0000000..3959087 --- /dev/null +++ b/lab2/src/lab2.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Simple model</title> +</head> +<body onload="main()"> +<canvas width="400" height="600" id="my-canvas"> + Please use a browser that supports "canvas" +</canvas> +<script src="../lib/cuon-matrix.js"></script> +<script src="../lib/webgl-utils.js"></script> +<script src="../lib/webgl-debug.js"></script> +<script src="../lib/cuon-utils.js"></script> +<script src="lab2.js"></script> +</body> +</html> \ No newline at end of file diff --git a/lab2/src/lab2.js b/lab2/src/lab2.js new file mode 100644 index 0000000..136373d --- /dev/null +++ b/lab2/src/lab2.js @@ -0,0 +1,193 @@ +// Vertex shader program +const VSHADER_SOURCE = + 'attribute vec4 a_Position;\n' + + 'attribute vec4 a_Color;\n' + // Attribute variable color to bind the effective vertex color from the model data + 'uniform mat4 u_ModelViewMatrix;\n' + + 'uniform mat4 u_ModelMatrixRotate;\n' + + + 'varying vec4 v_Color;\n' + // Varying variable color to pass the vertex color to the fragment shader + + 'void main() {\n' + + ' gl_Position = u_ModelViewMatrix * u_ModelMatrixRotate * a_Position;\n' + + + ' v_Color = a_Color;\n' + // Set the varying color value with the attribute color value + '}\n'; + +// Fragment shader program +const FSHADER_SOURCE = + 'precision mediump float;\n' + // This determines how much precision the GPU uses when calculating floats + 'varying vec4 v_Color;\n' + // Varying variable color to get the vertex color from + // The vertex shader (!!same name as in the vertex shafer) + 'void main() {\n' + + ' gl_FragColor = v_Color;\n' + // Set the fragment color with the vertex shader + '}\n'; + +var ANGLE_STEP = 45.0; +var currentAngle = 0.0; + +function main() { + // Retrieve <canvas> element + const canvas = document.getElementById('my-canvas'); + + // Get the rendering context for WebGL + const gl = getWebGLContext(canvas); + if (!gl) { + console.log('Failed to get the rendering context for WebGL'); + return; + } + + // Initialize shaders + if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { + console.log('Failed to intialize shaders.'); + return; + } + + // Write the positions of vertices to a vertex shader + const n = initVertexBuffers(gl); + if (n < 0) { + console.log('Failed to set the positions of the vertices'); + return; + } + + // Specify the color for clearing <canvas> + gl.clearColor(0, 0, 0, 1); + + + // Get the storage location of u_ModelViewMatrix + var u_ModelViewMatrix = gl.getUniformLocation(gl.program, 'u_ModelViewMatrix'); + if(!u_ModelViewMatrix) { + console.log('Failed to get the storage locations of u_ModelViewMatrix'); + return; + } + + // Get the storage location of u_ModelMatrixRotate + var u_ModelMatrixRotate = gl.getUniformLocation(gl.program, 'u_ModelMatrixRotate'); + if(!u_ModelMatrixRotate) { + console.log('Failed to get the storage locations of u_ModelMatrixRotate'); + return; + } + + // Set the matrix to be used for to set the camera view + var viewMatrix = new Matrix4(); + viewMatrix.setLookAt(0.0, 0.0, 1, 0, 0, 0, 0, 1, 0); + + // Model matrix + var modelMatrixRotate = new Matrix4(); + + // Start drawing + var tick = function() { + currentAngle = animate(currentAngle); // Update the rotation angle + draw(gl, n, currentAngle, modelMatrixRotate, u_ModelMatrixRotate, viewMatrix, u_ModelViewMatrix); // Draw the triangle + requestAnimationFrame(tick, canvas); // Request that the browser calls tick + }; + tick(); + + + + +} + +function initVertexBuffers(gl) { + // This is the model + const vertices = new Float32Array([ + // x y z + + -3/5, 3/7, 0.5, 1.0, 0.0, 0.0, + 3/5, 3/7, 0.5, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, + + 3/5, 3/7, 0.5, 0.0, 1.0, 0.0, + 3/5, 3/7, -0.5, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, + + -3/5, 3/7, 0.5, 1.0, 0.0, 1.0, + -3/5, 3/7, -0.5, 1.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, + + -3/5, 3/7, -0.5, 0.0, 0.0, 1.0, + 3/5, 3/7, -0.5, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 + + ]); + const n = vertices.length / 6; // The number of vertices + // Create a buffer object + const vertexBuffer = gl.createBuffer(); + if (!vertexBuffer) { + console.log('Failed to create the buffer object'); + return -1; + } + + // Bind the buffer object to target + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + // Write date into the buffer object + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + + // Get the storage location of a_Position, assign buffer and enable + 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; + } + // Assign the buffer object to a_Position variable + // Read 2 elements of type gl.FLOAT, starting at the offset 0. + // Next offset will be 20: after 5 elements (x, y, r, g, and b) of 4 bytes (32 bits) each + gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 24, 0); + // Enable the assignment to a_Position variable + gl.enableVertexAttribArray(a_Position); + + // Get the storage location of a_Color, assign buffer and enable + 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; + } + // Assign the buffer object to a_Color variable + // Read 3 elements of type gl.FLOAT, starting at the offset 8 (after 2 elements (x and z) of 4 bytes each). + // Next offset will be 20: after 5 elements (x, y, r, g, and b) of 4 bytes (32 bits) each + gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12); + // Enable the assignment to a_Color variable + gl.enableVertexAttribArray(a_Color); + + // Unbind the buffer object + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + return n; +} + +function draw(gl, n, currentAngle, modelMatrixRotate, u_ModelMatrixRotate, viewMatrix, u_ModelViewMatrix) { + viewMatrix.rotate(0.5, 0, 1, 0); + //console.log(currentAngle); + // Multiply model matrix to view matrix + + // Set the view matrix + gl.uniformMatrix4fv(u_ModelViewMatrix, false, viewMatrix.elements); + // Set the rotation matrix + modelMatrixRotate.setRotate(0, 1, 0, 1); // Rotation angle, rotation axis (0, 0, 1) + var modelViewMatrix = viewMatrix.multiply(modelMatrixRotate); + gl.uniformMatrix4fv(u_ModelViewMatrix, false, modelViewMatrix.elements); + // Pass the rotation matrix to the vertex shader + gl.uniformMatrix4fv(u_ModelMatrixRotate, false, modelMatrixRotate.elements); + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.drawArrays(gl.TRIANGLES, 0, n); + + // Set the rotation matrix + modelMatrixRotate.setRotate(180, 1, 0, 1); // Rotation angle, rotation axis (0, 0, 1) + //modelViewMatrix = viewMatrix.multiply(modelMatrixRotate); + gl.uniformMatrix4fv(u_ModelMatrixRotate, false, modelMatrixRotate.elements); + //gl.uniformMatrix4fv(u_ModelViewMatrix, false, modelViewMatrix.elements); + + gl.drawArrays(gl.TRIANGLES, 0, n); +} + +// Last time that this function was called +var g_last = Date.now(); +function animate(angle) { + // Calculate the elapsed time + var now = Date.now(); + var elapsed = now - g_last; + g_last = now; + // Update the current rotation angle (adjusted by the elapsed time) + var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0; + return newAngle %= 360; +} -- GitLab