aboutsummaryrefslogtreecommitdiff
path: root/lib/flower.js
diff options
context:
space:
mode:
authorBen Beltran <ben@nsovocal.com>2018-07-31 21:30:16 -0500
committerBen Beltran <ben@nsovocal.com>2018-07-31 21:30:16 -0500
commitb006b62b6d8de603bde0fa416a818608e3ed5574 (patch)
tree9cc1617b50700180cc548bb92222e6442ded7f86 /lib/flower.js
parent440966c18cc6546ef7975049967c57bbb118fd2a (diff)
Dump codepen to a static site
Diffstat (limited to 'lib/flower.js')
-rw-r--r--lib/flower.js337
1 files changed, 337 insertions, 0 deletions
diff --git a/lib/flower.js b/lib/flower.js
new file mode 100644
index 0000000..78b657a
--- /dev/null
+++ b/lib/flower.js
@@ -0,0 +1,337 @@
+const internals = {
+
+ // Constants
+
+ kEntrypointElementId: 'entrypoint', // The id of the canvas element where we will render
+ kWidthRatio: 2.76,
+ kHeightRatio: 1,
+ kTargetVerticalResolution: 32,
+ kFieldOfView: 45,
+ kNearLimit: 0.1,
+ kFarLimit: 100,
+ kBackgroundColor: [0.811, 0.73, 0.48, 1.0],
+ kRotationValues: [Math.random(), Math.random(), Math.random()],
+ kFPS: 30,
+
+ // Constants: Shaders
+
+ kVertexShader: `
+
+ attribute vec4 aVertexPosition;
+ attribute vec4 aColor;
+
+ varying vec4 vColor;
+
+ uniform mat4 uModelViewMatrix;
+ uniform mat4 uProjectionMatrix;
+
+ void main() {
+
+ gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
+ vColor = aColor;
+ }
+ `,
+
+ kFragmentShader: `
+
+ precision mediump float;
+ varying vec4 vColor;
+
+ void main() {
+
+ gl_FragColor = vColor;
+ }
+ `,
+
+ // Properties: Animation
+
+ currentTime: 0,
+
+ // Runs on load, Initializes WebGL and starts the animation loop.
+
+ onLoad() {
+
+
+ const canvas = internals.initializeCanvas();
+ const {gl, programInfo, buffers} = internals.initializeWebGL(canvas);
+
+ window.requestAnimationFrame(internals.animate.bind(this, gl, programInfo, buffers));
+ },
+
+ // Gets a canvas element and sets up resizing events.
+
+ initializeCanvas() {
+
+ const canvas = document.getElementById(internals.kEntrypointElementId);
+ internals.resizeCanvas(canvas);
+ window.addEventListener('resize', () => internals.resizeCanvas(canvas));
+
+ return canvas;
+ },
+
+ // Given a canvas, it will initialize the webgl context and set up the shaders.
+
+ initializeWebGL(canvas) {
+
+ const gl = canvas.getContext('webgl', {
+ preserveDrawingBuffer: true
+ });
+ const shaderProgram = internals.initializeShaderProgram(gl, internals.kVertexShader, internals.kFragmentShader);
+
+ const programInfo = {
+ program: shaderProgram,
+ attribLocations: {
+ vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
+ vertexColor: gl.getAttribLocation(shaderProgram, 'aColor')
+ },
+ uniformLocations: {
+ projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
+ modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix')
+ }
+ };
+
+ const buffers = internals.initializeBuffers(gl);
+
+ return { gl, programInfo, buffers};
+ },
+
+ // Methods: Canvas
+
+ resizeCanvas(canvas) {
+
+ let width = window.innerWidth;
+ let height = Math.round(width * internals.kHeightRatio / internals.kWidthRatio);
+
+ if (window.innerHeight < height) {
+ height = window.innerHeight;
+ width = Math.round(height * internals.kWidthRatio / internals.kHeightRatio);
+ console.log(width, height);
+ }
+
+ canvas.style.width = `${width}px`;
+ canvas.style.height = `${height}px`;
+
+ canvas.width = internals.kTargetVerticalResolution * internals.kWidthRatio;
+ canvas.height = internals.kTargetVerticalResolution;
+
+ canvas.width = width;
+ canvas.height = height;
+ },
+
+ // Methods: Shader / GL Related
+
+ initializeShaderProgram(gl, vertexShaderSource, fragmentShaderSource) {
+
+ const vertexShader = internals.loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
+ const fragmentShader = internals.loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
+
+ const shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+
+ gl.linkProgram(shaderProgram);
+
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ alert(`Unable to initialize shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
+ return null;
+ }
+
+ return shaderProgram;
+ },
+
+ loadShader(gl, type, source) {
+
+ const shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ alert(`Unable to compile shader: ${gl.getShaderInfoLog(shader)}`);
+ gl.deleteShader(shader);
+ return null;
+ }
+
+ return shader;
+ },
+
+ initializeBuffers(gl) {
+
+ const positionBuffer = gl.createBuffer();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ const positions = [
+ -1.0, 1.0, 1.0, // Front-top-left
+ 1.0, 1.0, 1.0, // Front-top-right
+ -1.0, -1.0, 1.0, // Front-bottom-left
+ 1.0, -1.0, 1.0, // Front-bottom-right
+ 1.0, -1.0, -1.0, // Back-bottom-right
+ 1.0, 1.0, 1.0, // Front-top-right
+ 1.0, 1.0, -1.0, // Back-top-right
+ -1.0, 1.0, 1.0, // Front-top-left
+ -1.0, 1.0, -1.0, // Back-top-left
+ -1.0, -1.0, 1.0, // Front-bottom-left
+ -1.0, -1.0, -1.0, // Back-bottom-left
+ 1.0, -1.0, -1.0, // Back-bottom-right
+ -1.0, 1.0, -1.0, // Back-top-left
+ 1.0, 1.0, -1.0 // Back-top-right
+ ];
+
+ gl.bufferData(gl.ARRAY_BUFFER,
+ new Float32Array(positions),
+ gl.STATIC_DRAW);
+
+ return {
+ position: positionBuffer
+ }
+ },
+
+ // Methods: Utility
+
+ createMatrix() {
+
+ const matrix = mat4.create();
+
+ mat4.translate(
+ matrix,
+ matrix,
+ [-0.0, 0.0, -6.0]
+ );
+
+ return matrix;
+ },
+
+ // Methods: Animation
+
+ rotate(matrix) {
+
+ mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[0], [1, 0, 0]);
+ mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[1], [0, 1, 0]);
+ mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[2], [0, 0, 1]);
+ },
+
+ drawScene(gl, programInfo, buffers) {
+
+ gl.clearColor(...internals.kBackgroundColor);
+ gl.clearDepth(1.0);
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthFunc(gl.LEQUAL);
+
+ const fieldOfView = internals.kFieldOfView * Math.PI / 180;
+ const aspectRatio = internals.kWidthRatio / internals.kHeightRatio;
+ const projectionMatrix = mat4.create();
+
+ mat4.perspective(
+ projectionMatrix,
+ fieldOfView,
+ aspectRatio,
+ internals.kNearLimit,
+ internals.kFarLimit
+ );
+
+ internals.modelViewMatrix = internals.modelViewMatrix || internals.createMatrix();
+
+ internals.rotate(internals.modelViewMatrix);
+
+ {
+ const numberOfComponents = 3;
+ const type = gl.FLOAT;
+ const normalize = false;
+ const stride = 0;
+ const offset = 0;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
+ gl.vertexAttribPointer(
+ programInfo.attribLocations.vertexPosition,
+ numberOfComponents,
+ type,
+ normalize,
+ stride,
+ offset
+ );
+ gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
+ }
+
+ {
+ // ATTEMPT TO SEND COLOR DATA
+
+ const colorBuffer = gl.createBuffer();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+
+ const colors = [
+ 1.0, 0.0, 0.5, 1.0, // Front-top-left
+ 1.0, 0.3, 0.8, 1.0, // Front-top-right
+ 1.0, 1.0, 0.7, 1.0, // Front-bottom-left
+ 0.0, 0.3, 0.5, 1.0, // Front-bottom-right
+ 0.0, 0.3, 0.5, 1.0, // Back-bottom-right
+ 1.0, 0.3, 0.8, 1.0, // Front-top-right
+ 1.0, 0.3, 0.8, 1.0, // Back-top-right
+ 1.0, 0.0, 0.5, 1.0, // Front-top-left
+ 1.0, 0.0, 0.5, 1.0, // Back-top-left
+ 1.0, 1.0, 0.7, 1.0, // Front-bottom-left
+ 1.0, 1.0, 0.7, 1.0, // Back-bottom-left
+ 0.0, 0.3, 0.5, 1.0, // Back-bottom-right
+ 1.0, 0.0, 0.5, 1.0, // Back-top-left
+ 1.0, 0.3, 0.8, 1.0 // Back-top-right
+ ];
+
+ gl.bufferData(gl.ARRAY_BUFFER,
+ new Float32Array(colors),
+ gl.STATIC_DRAW);
+
+ const numberOfComponents = 4;
+ const type = gl.FLOAT;
+ const normalize = false;
+ const stride = 0;
+ const offset = 0;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.vertexAttribPointer(
+ programInfo.attribLocations.vertexColor,
+ numberOfComponents,
+ type,
+ normalize,
+ stride,
+ offset
+ );
+ gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
+
+ // END ATTEMPT
+ }
+
+ gl.useProgram(programInfo.program);
+
+ gl.uniformMatrix4fv(
+ programInfo.uniformLocations.projectionMatrix,
+ false,
+ projectionMatrix
+ );
+ gl.uniformMatrix4fv(
+ programInfo.uniformLocations.modelViewMatrix,
+ false,
+ internals.modelViewMatrix
+ );
+
+ {
+ const offset = 0;
+ const vertexCount = 14;
+ gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
+ }
+ },
+
+ animate(gl, programInfo, buffers, time) {
+
+ const delta = time - internals.currentTime;
+ const interval = 1000 / internals.kFPS;
+
+ if (delta >= interval) {
+ internals.drawScene(gl, programInfo, buffers, delta);
+ internals.currentTime = time;
+ }
+
+ window.requestAnimationFrame(internals.animate.bind(this, gl, programInfo, buffers));
+ }
+};
+
+window.addEventListener('load', internals.onLoad);