From 9703298f40cf59aea249d9dcf77b3628d98fdd95 Mon Sep 17 00:00:00 2001 From: gbrochar Date: Sun, 22 Nov 2020 15:09:28 +0100 Subject: [PATCH] Colored square --- config/webpack.client.common.js | 2 +- package-lock.json | 5 + package.json | 1 + public/css/style.css | 18 +++ src/client/components/Root.tsx | 12 -- src/client/main.ts | 261 ++++++++++++++++++++++++++++++++ src/client/main.tsx | 13 -- views/index.ejs | 11 +- 8 files changed, 293 insertions(+), 30 deletions(-) create mode 100644 public/css/style.css delete mode 100644 src/client/components/Root.tsx create mode 100644 src/client/main.ts delete mode 100644 src/client/main.tsx diff --git a/config/webpack.client.common.js b/config/webpack.client.common.js index 6b33b86..72eca2e 100644 --- a/config/webpack.client.common.js +++ b/config/webpack.client.common.js @@ -3,7 +3,7 @@ const nodeExternals = require('webpack-node-externals'); const EsLint = require('eslint-webpack-plugin'); module.exports = { - entry: path.resolve(__dirname, '../src/client/main.tsx'), + entry: path.resolve(__dirname, '../src/client/main.ts'), output: { filename: 'bundle.js', path: path.resolve(__dirname, '../dist/client'), diff --git a/package-lock.json b/package-lock.json index 1111e8c..9fa8a16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3194,6 +3194,11 @@ "pump": "^3.0.0" } }, + "gl-mat4": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz", + "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==" + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", diff --git a/package.json b/package.json index b480e02..0379d11 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "dependencies": { "ejs": "^3.1.5", "express": "^4.17.1", + "gl-mat4": "^1.2.0", "react": "^17.0.1", "react-dom": "^17.0.1" } diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..21329a9 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,18 @@ +html { + padding: 0; + margin: 0; + height: 100%; + width: 100%; +} + +body { + padding: 0; + margin: 0; + height: 100%; + width: 100%; + overflow: hidden; +} + +#glCanvas { + display: inline-block; +} \ No newline at end of file diff --git a/src/client/components/Root.tsx b/src/client/components/Root.tsx deleted file mode 100644 index c8a3e23..0000000 --- a/src/client/components/Root.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -/** - * @return {jsx} The root component - */ -export default function Root() { - return ( -
- Hello World from React ! -
- ); -} diff --git a/src/client/main.ts b/src/client/main.ts new file mode 100644 index 0000000..1bd0fae --- /dev/null +++ b/src/client/main.ts @@ -0,0 +1,261 @@ +// @ts-ignore +import mat4 from 'gl-mat4'; + +main(); + +/** + * The program purpose is encapsulated in a main function + */ +function main() { + const canvas: any = document.querySelector('#glCanvas')!; + const gl = canvas.getContext('webgl'); + + if (gl == null) { + canvas.parentNode.removeChild(canvas); + document.getElementById('root')!.insertAdjacentHTML('beforeend', + `

Unable to initialize WebGL. Your browser or machine may not + support it.

`); + } + + const vsSource = ` + attribute vec4 aVertexPosition; + attribute vec4 aVertexColor; + + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + varying lowp vec4 vColor; + + void main() { + gl_Position = uProjectionMatrix * + uModelViewMatrix * + aVertexPosition; + vColor = aVertexColor; + } + `; + const fsSource = ` + varying lowp vec4 vColor; + + void main() { + gl_FragColor = vColor; + } + `; + + + const shaderProgram = initShaderProgram(gl, vsSource, fsSource); + + const programInfo: any = { + program: shaderProgram, + attribLocations: { + vertexPosition: gl.getAttribLocation(shaderProgram, + 'aVertexPosition'), + vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'), + }, + uniformLocations: { + projectionMatrix: gl.getUniformLocation( + shaderProgram, 'uProjectionMatrix'), + modelViewMatrix: gl.getUniformLocation( + shaderProgram, 'uModelViewMatrix'), + }, + }; + + const buffers = initBuffers(gl); + drawScene(gl, programInfo, buffers); +} + +/** + * Initialize a shader program, so WebGL knows how to draw our data + * @param {any} gl the WebGL context + * @param {string} vsSource the vertex shader source + * @param {string} fsSource the fragment shader source + * @return {any} the shader program + */ +function initShaderProgram(gl: any, vsSource: string, fsSource: string) { + const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); + const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); + + // Create the shader program + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + // If creating the shader program failed, alert + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + alert('Unable to initialize the shader program: ' + + gl.getProgramInfoLog(shaderProgram)); + return null; + } + return shaderProgram; +} + +/** + * load a GL shader + * @param {any} gl the WebGL context + * @param {any} type type of shader to load + * @param {string} source source code of shader + * @return {any} the loaded shader + */ +function loadShader(gl: any, type: any, source: string) { + const shader = gl.createShader(type); + // Send the source to the shader object + gl.shaderSource(shader, source); + // Compile the shader program + gl.compileShader(shader); + // See if it compiled successfully + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert('An error occurred compiling the shaders: ' + + gl.getShaderInfoLog(shader)); + gl.deleteShader(shader); + return null; + } + return shader; +} + +/** + * init buffers to create a square + * @param {any} gl the web gl context + * @return {any} the buffer + */ +function initBuffers(gl: any) { + // Create a buffer for the square's positions. + const positionBuffer = gl.createBuffer(); + // Select the positionBuffer as the one to apply buffer + // operations to from here out. + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + // Now create an array of positions for the square. + const positions = [ + -1.0, 1.0, + 1.0, 1.0, + -1.0, -1.0, + 1.0, -1.0, + ]; + // Now pass the list of positions into WebGL to build the + // shape. We do this by creating a Float32Array from the + // JavaScript array, then use it to fill the current buffer. + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array(positions), + gl.STATIC_DRAW); + + const colors = [ + 1.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0, + ]; + + const colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); + + return { + position: positionBuffer, + color: colorBuffer, + }; +} + +/** + * Draw a webgl scene + * @param {any} gl the WebGL context + * @param {any} programInfo WebGL program information + * @param {any} buffers the buffers to draw + */ +function drawScene(gl: any, programInfo: any, buffers: any) { + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.clearDepth(1.0); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + // Clear the canvas before we start drawing on it. + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Create a perspective matrix, a special matrix that is + // used to simulate the distortion of perspective in a camera. + // Our field of view is 45 degrees, with a width/height + // ratio that matches the display size of the canvas + // and we only want to see objects between 0.1 units + // and 100 units away from the camera. + const fieldOfView = 45 * Math.PI / 180; + const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; + const zNear = 0.1; + const zFar = 100.0; + const projectionMatrix = mat4.create(); + + // note: glmatrix.js always has the first argument + // as the destination to receive the result. + mat4.perspective( + projectionMatrix, + fieldOfView, + aspect, + zNear, + zFar); + + // Set the drawing position to the "identity" point, which is + // the center of the scene. + const modelViewMatrix = mat4.create(); + + // Now move the drawing position a bit to where we want to + // start drawing the square. + mat4.translate( + modelViewMatrix, + modelViewMatrix, + [-0.0, 0.0, -6.0]); + + // Tell WebGL how to pull out the positions from the position + // buffer into the vertexPosition attribute. + { + const numComponents = 2; + 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, + numComponents, + type, + normalize, + stride, + offset); + gl.enableVertexAttribArray( + programInfo.attribLocations.vertexPosition); + } + + // Tell WebGL how to pull out the positions from the position + // buffer into the vertexPosition attribute. + { + const numComponents = 4; + const type = gl.FLOAT; + const normalize = false; + const stride = 0; + const offset = 0; + gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexColor, + numComponents, + type, + normalize, + stride, + offset); + gl.enableVertexAttribArray( + programInfo.attribLocations.vertexColor); + } + + // Tell WebGL to use our program when drawing + gl.useProgram(programInfo.program); + // Set the shader uniforms + gl.uniformMatrix4fv( + programInfo.uniformLocations.projectionMatrix, + false, + projectionMatrix); + gl.uniformMatrix4fv( + programInfo.uniformLocations.modelViewMatrix, + false, + modelViewMatrix); + + { + const offset = 0; + const vertexCount = 4; + gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount); + } +} diff --git a/src/client/main.tsx b/src/client/main.tsx deleted file mode 100644 index e30f6b8..0000000 --- a/src/client/main.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import {hydrate, render} from 'react-dom'; -import Root from './components/Root'; - -const root = document.getElementById('root'); -let renderMethod; -if (root && root.innerHTML !== '') { - renderMethod = hydrate; -} else { - renderMethod = render; -} - -renderMethod(, document.getElementById('root')); diff --git a/views/index.ejs b/views/index.ejs index ab7644a..500fe09 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -3,14 +3,17 @@ - - Web-Expo + + WebGL - -
+
+ +