A Pen by Cedric Warny on CodePen.
Created
July 11, 2015 23:55
-
-
Save cwarny/2446f231b7014d414d50 to your computer and use it in GitHub Desktop.
xGjMOw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | |
<title>Twist</title> | |
<script id="vertex-shader" type="x-shader/x-vertex"> | |
attribute vec4 vPosition; | |
void main() { | |
gl_Position = vPosition; | |
} | |
</script> | |
<script id="fragment-shader" type="x-shader/x-fragment"> | |
precision mediump float; | |
void main() { | |
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); | |
} | |
</script> | |
<script type="text/javascript" src="../Common/webgl-utils.js"></script> | |
<script type="text/javascript" src="../Common/initShaders.js"></script> | |
<script type="text/javascript" src="../Common/MV.js"></script> | |
<script type="text/javascript" src="handlers.js"></script> | |
<script type="text/javascript" src="index.js"></script> | |
</head> | |
<body> | |
<canvas id="gl-canvas" width="512" height="512"> | |
Oops ... your browser doesn't support the HTML5 canvas element | |
</canvas> | |
<div> | |
Angle | |
<input type="number" id="angle-input" min="0" max="5" step="0.25"> | |
</div> | |
<div> | |
Subdivision steps | |
<input type="number" id="subdivision-input" min="1" max="8"> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 WebGL apps use of setTimeout or setInterval are | |
* discouraged. It is recommended you structure your rendering | |
* loop like this. | |
* | |
* function render() { | |
* window.requestAnimFrame(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 '' + | |
'<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 WebGL.<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 WebGL.<br/>" + | |
'<a href="http://get.webgl.org/troubleshooting/">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 WebGL. | |
* @param {Element} canvas. The canvas element to create a | |
* context from. | |
* @param {WebGLContextCreationAttirbutes} opt_attribs Any | |
* creation attributes you want to pass in. | |
* @return {WebGLRenderingContext} The created context. | |
*/ | |
var setupWebGL = function(canvas, opt_attribs) { | |
function showLink(str) { | |
var container = canvas.parentNode; | |
if (container) { | |
container.innerHTML = makeFailHTML(str); | |
} | |
}; | |
if (!window.WebGLRenderingContext) { | |
showLink(GET_A_WEBGL_BROWSER); | |
return null; | |
} | |
var context = create3DContext(canvas, opt_attribs); | |
if (!context) { | |
showLink(OTHER_PROBLEM); | |
} | |
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. | |
*/ | |
window.requestAnimFrame = (function() { | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { | |
window.setTimeout(callback, 1000/60); | |
}; | |
})(); | |
// | |
// initShaders.js | |
// | |
function initShaders( gl, vertexShaderId, fragmentShaderId ) | |
{ | |
var vertShdr; | |
var fragShdr; | |
var vertElem = document.getElementById( vertexShaderId ); | |
if ( !vertElem ) { | |
alert( "Unable to load vertex shader " + vertexShaderId ); | |
return -1; | |
} | |
else { | |
vertShdr = gl.createShader( gl.VERTEX_SHADER ); | |
gl.shaderSource( vertShdr, vertElem.text ); | |
gl.compileShader( vertShdr ); | |
if ( !gl.getShaderParameter(vertShdr, gl.COMPILE_STATUS) ) { | |
var msg = "Vertex shader failed to compile. The error log is:" | |
+ "<pre>" + gl.getShaderInfoLog( vertShdr ) + "</pre>"; | |
alert( msg ); | |
return -1; | |
} | |
} | |
var fragElem = document.getElementById( fragmentShaderId ); | |
if ( !fragElem ) { | |
alert( "Unable to load vertex shader " + fragmentShaderId ); | |
return -1; | |
} | |
else { | |
fragShdr = gl.createShader( gl.FRAGMENT_SHADER ); | |
gl.shaderSource( fragShdr, fragElem.text ); | |
gl.compileShader( fragShdr ); | |
if ( !gl.getShaderParameter(fragShdr, gl.COMPILE_STATUS) ) { | |
var msg = "Fragment shader failed to compile. The error log is:" | |
+ "<pre>" + gl.getShaderInfoLog( fragShdr ) + "</pre>"; | |
alert( msg ); | |
return -1; | |
} | |
} | |
var program = gl.createProgram(); | |
gl.attachShader( program, vertShdr ); | |
gl.attachShader( program, fragShdr ); | |
gl.linkProgram( program ); | |
if ( !gl.getProgramParameter(program, gl.LINK_STATUS) ) { | |
var msg = "Shader program failed to link. The error log is:" | |
+ "<pre>" + gl.getProgramInfoLog( program ) + "</pre>"; | |
alert( msg ); | |
return -1; | |
} | |
return program; | |
} | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
// Angel.js | |
// | |
////////////////////////////////////////////////////////////////////////////// | |
//---------------------------------------------------------------------------- | |
// | |
// Helper functions | |
// | |
function _argumentsToArray( args ) | |
{ | |
return [].concat.apply( [], Array.prototype.slice.apply(args) ); | |
} | |
//---------------------------------------------------------------------------- | |
function radians( degrees ) { | |
return degrees * Math.PI / 180.0; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Vector Constructors | |
// | |
function vec2() | |
{ | |
var result = _argumentsToArray( arguments ); | |
switch ( result.length ) { | |
case 0: result.push( 0.0 ); | |
case 1: result.push( 0.0 ); | |
} | |
return result.splice( 0, 2 ); | |
} | |
function vec3() | |
{ | |
var result = _argumentsToArray( arguments ); | |
switch ( result.length ) { | |
case 0: result.push( 0.0 ); | |
case 1: result.push( 0.0 ); | |
case 2: result.push( 0.0 ); | |
} | |
return result.splice( 0, 3 ); | |
} | |
function vec4() | |
{ | |
var result = _argumentsToArray( arguments ); | |
switch ( result.length ) { | |
case 0: result.push( 0.0 ); | |
case 1: result.push( 0.0 ); | |
case 2: result.push( 0.0 ); | |
case 3: result.push( 1.0 ); | |
} | |
return result.splice( 0, 4 ); | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Matrix Constructors | |
// | |
function mat2() | |
{ | |
var v = _argumentsToArray( arguments ); | |
var m = []; | |
switch ( v.length ) { | |
case 0: | |
v[0] = 1; | |
case 1: | |
m = [ | |
vec2( v[0], 0.0 ), | |
vec2( 0.0, v[0] ) | |
]; | |
break; | |
default: | |
m.push( vec2(v) ); v.splice( 0, 2 ); | |
m.push( vec2(v) ); | |
break; | |
} | |
m.matrix = true; | |
return m; | |
} | |
//---------------------------------------------------------------------------- | |
function mat3() | |
{ | |
var v = _argumentsToArray( arguments ); | |
var m = []; | |
switch ( v.length ) { | |
case 0: | |
v[0] = 1; | |
case 1: | |
m = [ | |
vec3( v[0], 0.0, 0.0 ), | |
vec3( 0.0, v[0], 0.0 ), | |
vec3( 0.0, 0.0, v[0] ) | |
]; | |
break; | |
default: | |
m.push( vec3(v) ); v.splice( 0, 3 ); | |
m.push( vec3(v) ); v.splice( 0, 3 ); | |
m.push( vec3(v) ); | |
break; | |
} | |
m.matrix = true; | |
return m; | |
} | |
//---------------------------------------------------------------------------- | |
function mat4() | |
{ | |
var v = _argumentsToArray( arguments ); | |
var m = []; | |
switch ( v.length ) { | |
case 0: | |
v[0] = 1; | |
case 1: | |
m = [ | |
vec4( v[0], 0.0, 0.0, 0.0 ), | |
vec4( 0.0, v[0], 0.0, 0.0 ), | |
vec4( 0.0, 0.0, v[0], 0.0 ), | |
vec4( 0.0, 0.0, 0.0, v[0] ) | |
]; | |
break; | |
default: | |
m.push( vec4(v) ); v.splice( 0, 4 ); | |
m.push( vec4(v) ); v.splice( 0, 4 ); | |
m.push( vec4(v) ); v.splice( 0, 4 ); | |
m.push( vec4(v) ); | |
break; | |
} | |
m.matrix = true; | |
return m; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Generic Mathematical Operations for Vectors and Matrices | |
// | |
function equal( u, v ) | |
{ | |
if ( u.length != v.length ) { return false; } | |
if ( u.matrix && v.matrix ) { | |
for ( var i = 0; i < u.length; ++i ) { | |
if ( u[i].length != v[i].length ) { return false; } | |
for ( var j = 0; j < u[i].length; ++j ) { | |
if ( u[i][j] !== v[i][j] ) { return false; } | |
} | |
} | |
} | |
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) { | |
return false; | |
} | |
else { | |
for ( var i = 0; i < u.length; ++i ) { | |
if ( u[i] !== v[i] ) { return false; } | |
} | |
} | |
return true; | |
} | |
//---------------------------------------------------------------------------- | |
function add( u, v ) | |
{ | |
var result = []; | |
if ( u.matrix && v.matrix ) { | |
if ( u.length != v.length ) { | |
throw "add(): trying to add matrices of different dimensions"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
if ( u[i].length != v[i].length ) { | |
throw "add(): trying to add matrices of different dimensions"; | |
} | |
result.push( [] ); | |
for ( var j = 0; j < u[i].length; ++j ) { | |
result[i].push( u[i][j] + v[i][j] ); | |
} | |
} | |
result.matrix = true; | |
return result; | |
} | |
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) { | |
throw "add(): trying to add matrix and non-matrix variables"; | |
} | |
else { | |
if ( u.length != v.length ) { | |
throw "add(): vectors are not the same dimension"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( u[i] + v[i] ); | |
} | |
return result; | |
} | |
} | |
//---------------------------------------------------------------------------- | |
function subtract( u, v ) | |
{ | |
var result = []; | |
if ( u.matrix && v.matrix ) { | |
if ( u.length != v.length ) { | |
throw "subtract(): trying to subtract matrices" + | |
" of different dimensions"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
if ( u[i].length != v[i].length ) { | |
throw "subtract(): trying to subtact matrices" + | |
" of different dimensions"; | |
} | |
result.push( [] ); | |
for ( var j = 0; j < u[i].length; ++j ) { | |
result[i].push( u[i][j] - v[i][j] ); | |
} | |
} | |
result.matrix = true; | |
return result; | |
} | |
else if ( u.matrix && !v.matrix || !u.matrix && v.matrix ) { | |
throw "subtact(): trying to subtact matrix and non-matrix variables"; | |
} | |
else { | |
if ( u.length != v.length ) { | |
throw "subtract(): vectors are not the same length"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( u[i] - v[i] ); | |
} | |
return result; | |
} | |
} | |
//---------------------------------------------------------------------------- | |
function mult( u, v ) | |
{ | |
var result = []; | |
if ( u.matrix && v.matrix ) { | |
if ( u.length != v.length ) { | |
throw "mult(): trying to add matrices of different dimensions"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
if ( u[i].length != v[i].length ) { | |
throw "mult(): trying to add matrices of different dimensions"; | |
} | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( [] ); | |
for ( var j = 0; j < v.length; ++j ) { | |
var sum = 0.0; | |
for ( var k = 0; k < u.length; ++k ) { | |
sum += u[i][k] * v[k][j]; | |
} | |
result[i].push( sum ); | |
} | |
} | |
result.matrix = true; | |
return result; | |
} | |
else { | |
if ( u.length != v.length ) { | |
throw "mult(): vectors are not the same dimension"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( u[i] * v[i] ); | |
} | |
return result; | |
} | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Basic Transformation Matrix Generators | |
// | |
function translate( x, y, z ) | |
{ | |
if ( Array.isArray(x) && x.length == 3 ) { | |
z = x[2]; | |
y = x[1]; | |
x = x[0]; | |
} | |
var result = mat4(); | |
result[0][3] = x; | |
result[1][3] = y; | |
result[2][3] = z; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
function rotate( angle, axis ) | |
{ | |
if ( !Array.isArray(axis) ) { | |
axis = [ arguments[1], arguments[2], arguments[3] ]; | |
} | |
var v = normalize( axis ); | |
var x = v[0]; | |
var y = v[1]; | |
var z = v[2]; | |
var c = Math.cos( radians(angle) ); | |
var omc = 1.0 - c; | |
var s = Math.sin( radians(angle) ); | |
var result = mat4( | |
vec4( x*x*omc + c, x*y*omc - z*s, x*z*omc + y*s, 0.0 ), | |
vec4( x*y*omc + z*s, y*y*omc + c, y*z*omc - x*s, 0.0 ), | |
vec4( x*z*omc - y*s, y*z*omc + x*s, z*z*omc + c, 0.0 ), | |
vec4() | |
); | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
function scalem( x, y, z ) | |
{ | |
if ( Array.isArray(x) && x.length == 3 ) { | |
z = x[2]; | |
y = x[1]; | |
x = x[0]; | |
} | |
var result = mat4(); | |
result[0][0] = x; | |
result[1][1] = y; | |
result[2][2] = z; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// ModelView Matrix Generators | |
// | |
function lookAt( eye, at, up ) | |
{ | |
if ( !Array.isArray(eye) || eye.length != 3) { | |
throw "lookAt(): first parameter [eye] must be an a vec3"; | |
} | |
if ( !Array.isArray(at) || at.length != 3) { | |
throw "lookAt(): first parameter [at] must be an a vec3"; | |
} | |
if ( !Array.isArray(up) || up.length != 3) { | |
throw "lookAt(): first parameter [up] must be an a vec3"; | |
} | |
if ( equal(eye, at) ) { | |
return mat4(); | |
} | |
var v = normalize( subtract(at, eye) ); // view direction vector | |
var n = normalize( cross(v, up) ); // perpendicular vector | |
var u = normalize( cross(n, v) ); // "new" up vector | |
v = negate( v ); | |
var result = mat4( | |
vec4( n, -dot(n, eye) ), | |
vec4( u, -dot(u, eye) ), | |
vec4( v, -dot(v, eye) ), | |
vec4() | |
); | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Projection Matrix Generators | |
// | |
function ortho( left, right, bottom, top, near, far ) | |
{ | |
if ( left == right ) { throw "ortho(): left and right are equal"; } | |
if ( bottom == top ) { throw "ortho(): bottom and top are equal"; } | |
if ( near == far ) { throw "ortho(): near and far are equal"; } | |
var w = right - left; | |
var h = top - bottom; | |
var d = far - near; | |
var result = mat4(); | |
result[0][0] = 2.0 / w; | |
result[1][1] = 2.0 / h; | |
result[2][2] = -2.0 / d; | |
result[0][3] = (left + right) / w; | |
result[1][3] = (top + bottom) / h; | |
result[2][3] = (near + far) / d; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
function perspective( fovy, aspect, near, far ) | |
{ | |
var f = 1.0 / Math.tan( radians(fovy) / 2 ); | |
var d = far - near; | |
var result = mat4(); | |
result[0][0] = f / aspect; | |
result[1][1] = f; | |
result[2][2] = -(near + far) / d; | |
result[2][3] = -2 * near * far / d; | |
result[3][2] = -1; | |
result[3][3] = 0.0; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Matrix Functions | |
// | |
function transpose( m ) | |
{ | |
if ( !m.matrix ) { | |
return "transpose(): trying to transpose a non-matrix"; | |
} | |
var result = []; | |
for ( var i = 0; i < m.length; ++i ) { | |
result.push( [] ); | |
for ( var j = 0; j < m[i].length; ++j ) { | |
result[i].push( m[j][i] ); | |
} | |
} | |
result.matrix = true; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Vector Functions | |
// | |
function dot( u, v ) | |
{ | |
if ( u.length != v.length ) { | |
throw "dot(): vectors are not the same dimension"; | |
} | |
var sum = 0.0; | |
for ( var i = 0; i < u.length; ++i ) { | |
sum += u[i] * v[i]; | |
} | |
return sum; | |
} | |
//---------------------------------------------------------------------------- | |
function negate( u ) | |
{ | |
result = []; | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( -u[i] ); | |
} | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
function cross( u, v ) | |
{ | |
if ( !Array.isArray(u) || u.length < 3 ) { | |
throw "cross(): first argument is not a vector of at least 3"; | |
} | |
if ( !Array.isArray(v) || v.length < 3 ) { | |
throw "cross(): second argument is not a vector of at least 3"; | |
} | |
var result = [ | |
u[1]*v[2] - u[2]*v[1], | |
u[2]*v[0] - u[0]*v[2], | |
u[0]*v[1] - u[1]*v[0] | |
]; | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
function length( u ) | |
{ | |
return Math.sqrt( dot(u, u) ); | |
} | |
//---------------------------------------------------------------------------- | |
function normalize( u, excludeLastComponent ) | |
{ | |
if ( excludeLastComponent ) { | |
var last = u.pop(); | |
} | |
var len = length( u ); | |
if ( !isFinite(len) ) { | |
throw "normalize: vector " + u + " has zero length"; | |
} | |
for ( var i = 0; i < u.length; ++i ) { | |
u[i] /= len; | |
} | |
if ( excludeLastComponent ) { | |
u.push( last ); | |
} | |
return u; | |
} | |
//---------------------------------------------------------------------------- | |
function mix( u, v, s ) | |
{ | |
if ( typeof s !== "number" ) { | |
throw "mix: the last paramter " + s + " must be a number"; | |
} | |
if ( u.length != v.length ) { | |
throw "vector dimension mismatch"; | |
} | |
var result = []; | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( s * u[i] + (1.0 - s) * v[i] ); | |
} | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// Vector and Matrix functions | |
// | |
function scale( s, u ) | |
{ | |
if ( !Array.isArray(u) ) { | |
throw "scale: second parameter " + u + " is not a vector"; | |
} | |
result = []; | |
for ( var i = 0; i < u.length; ++i ) { | |
result.push( s * u[i] ); | |
} | |
return result; | |
} | |
//---------------------------------------------------------------------------- | |
// | |
// | |
// | |
function flatten( v ) | |
{ | |
if ( v.matrix === true ) { | |
v = transpose( v ); | |
} | |
var n = v.length; | |
var elemsAreArrays = false; | |
if ( Array.isArray(v[0]) ) { | |
elemsAreArrays = true; | |
n *= v[0].length; | |
} | |
var floats = new Float32Array( n ); | |
if ( elemsAreArrays ) { | |
var idx = 0; | |
for ( var i = 0; i < v.length; ++i ) { | |
for ( var j = 0; j < v[i].length; ++j ) { | |
floats[idx++] = v[i][j]; | |
} | |
} | |
} | |
else { | |
for ( var i = 0; i < v.length; ++i ) { | |
floats[i] = v[i]; | |
} | |
} | |
return floats; | |
} | |
//---------------------------------------------------------------------------- | |
var sizeof = { | |
'vec2' : new Float32Array( flatten(vec2()) ).byteLength, | |
'vec3' : new Float32Array( flatten(vec3()) ).byteLength, | |
'vec4' : new Float32Array( flatten(vec4()) ).byteLength, | |
'mat2' : new Float32Array( flatten(mat2()) ).byteLength, | |
'mat3' : new Float32Array( flatten(mat3()) ).byteLength, | |
'mat4' : new Float32Array( flatten(mat4()) ).byteLength | |
}; | |
function setupHandlers() { | |
var angleInput = document.getElementById("angle-input"), | |
subdivisionInput = document.getElementById("subdivision-input"); | |
angleInput.value = theta; | |
subdivisionInput.value = numTimesToSubdivide; | |
angleInput.onchange = function changeAngle(evt) { | |
theta = angleInput.value; | |
init(); | |
} | |
subdivisionInput.onchange = function changeSubdivision(evt) { | |
numTimesToSubdivide = subdivisionInput.value; | |
init(); | |
} | |
} | |
var canvas; | |
var gl; | |
var points = []; | |
var numTimesToSubdivide = 5; | |
var theta = 2.5; | |
window.onload = init; | |
function init() { | |
setupHandlers(); | |
points = []; | |
canvas = document.getElementById("gl-canvas"); | |
gl = WebGLUtils.setupWebGL(canvas); | |
if (!gl) { alert("WebGL isn't available"); } | |
// | |
// Initialize our data for the Sierpinski Gasket | |
// | |
// First, initialize the corners of our gasket with three points. | |
var vertices = [ | |
vec2(-0.5, -0.5), | |
vec2(0, 0.5), | |
vec2(0.5, -0.5) | |
]; | |
divideTriangle(vertices[0], vertices[1], vertices[2], numTimesToSubdivide); | |
// | |
// Configure WebGL | |
// | |
gl.viewport(0, 0, canvas.width, canvas.height); | |
gl.clearColor(1.0, 1.0, 1.0, 1.0); | |
// Load shaders and initialize attribute buffers | |
var program = initShaders(gl, "vertex-shader", "fragment-shader"); | |
gl.useProgram(program); | |
// Load the data into the GPU | |
var bufferId = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); | |
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW); | |
// Associate out shader variables with our data buffer | |
var vPosition = gl.getAttribLocation(program, "vPosition"); | |
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(vPosition); | |
render(); | |
}; | |
function triangle(a, b, c) { | |
points.push(a, b, c); | |
} | |
function rotateTriangle(a, b, c) { | |
// var G = vec2((a[0] + b[0] + c[0]) / 3, (a[1] + b[1] + c[1]) / 3); | |
// var d = Math.sqrt(Math.pow(G[0], 2) + Math.pow(G[1], 2)); | |
// return [a, b, c].map(function(p) { | |
// return vec2( | |
// p[0] * Math.cos(d * theta) - p[1] * Math.sin(d * theta), | |
// p[0] * Math.sin(d * theta) + p[1] * Math.cos(d * theta) | |
// ); | |
// }); | |
return [a,b,c].map(function(p) { | |
var x = p[0], y = p[1]; | |
var d = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); | |
var xp = x * Math.cos(d * theta) - y * Math.sin(d * theta); | |
var yp = x * Math.sin(d * theta) + y * Math.cos(d * theta); | |
// rotatedPoints.push([xp, yp]); | |
return [xp, yp]; | |
}) | |
} | |
function divideTriangle(a, b, c, count) { | |
// check for end of recursion | |
if (count === 0) { | |
triangle.apply(this, rotateTriangle(a, b, c)); | |
} | |
else { | |
//bisect the sides | |
var ab = mix(a, b, 0.5); | |
var ac = mix(a, c, 0.5); | |
var bc = mix(b, c, 0.5); | |
--count; | |
// three new triangles | |
divideTriangle(a, ab, ac, count); | |
divideTriangle(c, ac, bc, count); | |
divideTriangle(b, bc, ab, count); | |
divideTriangle(ac, bc, ab, count); // Fourth triangle necessary for the twist | |
} | |
} | |
function render() { | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
gl.drawArrays(gl.TRIANGLES, 0, points.length); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment