From ef315b70890c02d73a0b43c5e365cc0060d31586 Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Mon, 20 Jul 2020 15:52:18 +0200 Subject: [PATCH] Add glsl loader --- frontend/Dockerfile | 7 +- frontend/error-pages/build.py | 43 ---------- frontend/error-pages/template.html | 36 --------- frontend/nginx-config/nginx.conf | 2 +- frontend/package.json | 3 +- frontend/src/scripts/drawing/drawer.ts | 2 +- frontend/src/scripts/drawing/renderer.ts | 39 ++++------ frontend/src/scripts/game.ts | 14 +++- frontend/src/scripts/math/mat3.ts | 78 +++++++++++++++++++ frontend/src/scripts/math/vec2.ts | 12 ++- frontend/src/scripts/objects/types/camera.ts | 5 +- .../src/shaders/{dist.frag => cave-fs.glsl} | 27 +++---- .../{passthrough.vert => passthrough-vs.glsl} | 0 frontend/tsconfig.json | 3 +- frontend/webpack.config.js | 29 ++++--- 15 files changed, 150 insertions(+), 150 deletions(-) delete mode 100644 frontend/error-pages/build.py delete mode 100644 frontend/error-pages/template.html create mode 100644 frontend/src/scripts/math/mat3.ts rename frontend/src/shaders/{dist.frag => cave-fs.glsl} (81%) rename frontend/src/shaders/{passthrough.vert => passthrough-vs.glsl} (100%) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 2daa5de..bbddad7 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,12 +1,9 @@ -FROM python:3.8-alpine as build-error-pages +FROM error-pages as build-error-pages -WORKDIR /home/python -COPY error-pages . -RUN python build.py +RUN python build.py 403 404 50x FROM node:latest as build-webpage - WORKDIR /home/node COPY src src diff --git a/frontend/error-pages/build.py b/frontend/error-pages/build.py deleted file mode 100644 index f9900c9..0000000 --- a/frontend/error-pages/build.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import NamedTuple, Dict, List, Type -from os import makedirs, path - - -template_path = 'template.html' -result_path = 'built' - -class Substitutions(NamedTuple): - title: str - description: str - -error_messages: Dict[str, Substitutions] = { - '403': Substitutions( - title='403 - Forbidden', - description='You are not allowed to view this resource.' - ), - '404': Substitutions( - title='404 - Not found', - description='The requested resource cannot be found.' - ), - '50x': Substitutions( - title='50x - Server error', - description='It\'s my fault.' - ), -} - - -def substitute(source: str, substitutions: Substitutions) -> str: - for i, property_name in enumerate(Substitutions._fields): - source = source.replace(f'{{{property_name}}}', str(substitutions[i])) - return source - - -if __name__ == '__main__': - with open(template_path) as f: - template = f.read() - - makedirs(result_path, mode=0o440, exist_ok=True) - - for name, substitutions in error_messages.items(): - with open(path.join(result_path, f'{name}.html'), 'w') as f: - html = substitute(template, substitutions) - f.write(html) diff --git a/frontend/error-pages/template.html b/frontend/error-pages/template.html deleted file mode 100644 index 82a55c3..0000000 --- a/frontend/error-pages/template.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - {title} - - - - - - -

{description}

- - diff --git a/frontend/nginx-config/nginx.conf b/frontend/nginx-config/nginx.conf index beb8e6d..901dada 100644 --- a/frontend/nginx-config/nginx.conf +++ b/frontend/nginx-config/nginx.conf @@ -38,7 +38,7 @@ http { root /usr/share/nginx/html; index index.html; - location ~* \.(jpg|jpeg|png|ico)$ { + location ~* \.(jpg|jpeg|png|ico)$ { expires 30d; } diff --git a/frontend/package.json b/frontend/package.json index f5e3552..3e3af8c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -52,6 +52,7 @@ "uuid": "^8.2.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11", - "webpack-dev-server": "^3.10.3" + "webpack-dev-server": "^3.10.3", + "webpack-glsl-minify": "^1.4.0" } } diff --git a/frontend/src/scripts/drawing/drawer.ts b/frontend/src/scripts/drawing/drawer.ts index d03b3df..6fcbae0 100644 --- a/frontend/src/scripts/drawing/drawer.ts +++ b/frontend/src/scripts/drawing/drawer.ts @@ -4,6 +4,6 @@ export interface Drawer { startFrame(); finishFrame(); setCameraPosition(position: Vec2); - setInViewWidth(size: number): Vec2; + setInViewArea(size: number): Vec2; drawInfoText(text: string); } diff --git a/frontend/src/scripts/drawing/renderer.ts b/frontend/src/scripts/drawing/renderer.ts index dc42ef4..d2e7f2a 100644 --- a/frontend/src/scripts/drawing/renderer.ts +++ b/frontend/src/scripts/drawing/renderer.ts @@ -2,6 +2,7 @@ import { Drawer } from './drawer'; import { Vec2 } from '../math/vec2'; import { createProgram } from './graphics-library/create-program'; import { prepareScreenQuad } from './graphics-library/prepare-screen-quad'; +import { Mat3 } from '../math/mat3'; export class WebGl2Renderer implements Drawer { private gl: WebGL2RenderingContext; @@ -56,29 +57,20 @@ export class WebGl2Renderer implements Drawer { } finishFrame() { - const resolutionUniformLocation = this.gl.getUniformLocation( - this.program, - 'resolution' - ); - this.gl.uniform2f( - resolutionUniformLocation, - this.canvas.width, - this.canvas.height - ); + const resolution = new Vec2(this.canvas.width, this.canvas.height); + + const transform = Mat3.translateMatrix(new Vec2(0.5, 0.5)) + .times(Mat3.scaleMatrix(this.viewBoxSize.divide(resolution))) + .times(Mat3.translateMatrix(this.cameraPosition)); const viewBoxSizeUniformLocation = this.gl.getUniformLocation( this.program, - 'viewBoxSize' + 'transform' ); - this.gl.uniform2f(viewBoxSizeUniformLocation, ...this.viewBoxSize.list); - - const cameraPositionUniformLocation = this.gl.getUniformLocation( - this.program, - 'cameraPosition' - ); - this.gl.uniform2f( - cameraPositionUniformLocation, - ...this.cameraPosition.list + this.gl.uniformMatrix3fv( + viewBoxSizeUniformLocation, + false, + new Float32Array(transform.transposedFlat) ); this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); @@ -88,11 +80,14 @@ export class WebGl2Renderer implements Drawer { this.cameraPosition = position; } - setInViewWidth(size: number): Vec2 { + setInViewArea(size: number): Vec2 { const canvasAspectRatio = - this.canvas.clientHeight / this.canvas.clientWidth; + this.canvas.clientWidth / this.canvas.clientHeight; - this.viewBoxSize = new Vec2(size, size * canvasAspectRatio); + this.viewBoxSize = new Vec2( + Math.sqrt(size * canvasAspectRatio), + Math.sqrt(size / canvasAspectRatio) + ); return this.viewBoxSize; } diff --git a/frontend/src/scripts/game.ts b/frontend/src/scripts/game.ts index 13cf469..05ae664 100644 --- a/frontend/src/scripts/game.ts +++ b/frontend/src/scripts/game.ts @@ -5,13 +5,17 @@ import { TouchListener } from './input/touch-listener'; import { CommandBroadcaster } from './commands/command-broadcaster'; import { ObjectContainer } from './objects/object-container'; import { DrawCommand } from './commands/types/draw'; -import passthroughVertexShader from '../shaders/passthrough.vert'; -import distanceFragmentShader from '../shaders/dist.frag'; + import { StepCommand } from './commands/types/step'; import { Character } from './objects/types/character'; import { InfoText } from './objects/types/info-text'; import { timeIt } from './helper/timing'; +import { GlslShader, GlslVariable, GlslVariableMap } from 'webpack-glsl-minify'; + +let passthroughVertexShader = require('../shaders/passthrough-vs.glsl') as GlslShader; +let distanceFragmentShader = require('../shaders/cave-fs.glsl') as GlslShader; + export class Game { private previousTime: DOMHighResTimeStamp = 0; private objects: ObjectContainer = new ObjectContainer(); @@ -31,9 +35,11 @@ export class Game { [this.objects] ); + console.log(distanceFragmentShader); + this.renderer = new WebGl2Renderer(canvas, overlay, [ - passthroughVertexShader, - distanceFragmentShader, + passthroughVertexShader.sourceCode, + distanceFragmentShader.sourceCode, ]); this.initializeScene(); diff --git a/frontend/src/scripts/math/mat3.ts b/frontend/src/scripts/math/mat3.ts new file mode 100644 index 0000000..87af25c --- /dev/null +++ b/frontend/src/scripts/math/mat3.ts @@ -0,0 +1,78 @@ +// https://github.com/Azleur/mat3/blob/master/src/index.ts + +import { Vec2 } from './vec2'; + +export class Mat3 { + constructor(private readonly values: Array>) {} + + public static get Zero() { + return new Mat3([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ]); + } + + public static get Id() { + return new Mat3([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + ]); + } + + public static get Ones() { + return new Mat3([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + ]); + } + + public static translateMatrix(by: Vec2): Mat3 { + return new Mat3([ + [1, 0, 0], + [0, 1, 0], + [by.x, by.y, 1], + ]); + } + + public static scaleMatrix(by: Vec2): Mat3 { + return new Mat3([ + [by.x, 0, 0], + [0, by.y, 0], + [0, 0, 1], + ]); + } + + public get transposed(): Mat3 { + const values: number[][] = [[], [], []]; + for (let i = 0; i < 3; i++) { + for (let j = 0; j < 3; j++) { + values[i][j] = this.values[j][i]; + } + } + return new Mat3(values); + } + + public times(other: Mat3): Mat3 { + const values: number[][] = Mat3.Zero.values; + for (let i = 0; i < 3; i++) { + for (let j = 0; j < 3; j++) { + for (let k = 0; k < 3; k++) { + values[i][j] += this.values[i][k] * other.values[k][j]; + } + } + } + return new Mat3(values); + } + + public get transposedFlat(): Array { + const transposed = this.transposed; + return [ + ...transposed.values[0], + ...transposed.values[1], + ...transposed.values[2], + ]; + } +} diff --git a/frontend/src/scripts/math/vec2.ts b/frontend/src/scripts/math/vec2.ts index a71b2a0..595a26d 100644 --- a/frontend/src/scripts/math/vec2.ts +++ b/frontend/src/scripts/math/vec2.ts @@ -13,10 +13,6 @@ export class Vec2 extends Typed { return new Vec2(this.x * scalar, this.y * scalar); } - public times(other: Vec2): Vec2 { - return new Vec2(this.x * other.x, this.y * other.y); - } - public add(other: Vec2): Vec2 { return new Vec2(this.x + other.x, this.y + other.y); } @@ -25,6 +21,14 @@ export class Vec2 extends Typed { return new Vec2(this.x - other.x, this.y - other.y); } + public times(other: Vec2): Vec2 { + return new Vec2(this.x * other.x, this.y * other.y); + } + + public divide(other: Vec2): Vec2 { + return new Vec2(this.x / other.x, this.y / other.y); + } + public get length(): number { return Math.sqrt(this.x * this.x + this.y * this.y); } diff --git a/frontend/src/scripts/objects/types/camera.ts b/frontend/src/scripts/objects/types/camera.ts index d5442a5..9908ccc 100644 --- a/frontend/src/scripts/objects/types/camera.ts +++ b/frontend/src/scripts/objects/types/camera.ts @@ -3,7 +3,8 @@ import { DrawCommand } from '../../commands/types/draw'; import { MoveToCommand } from '../../commands/types/move-to'; export class Camera extends GameObject { - private inViewWidth = 1500; + private inViewArea = 1920 * 1080; + constructor() { super(); @@ -13,7 +14,7 @@ export class Camera extends GameObject { private draw(c: DrawCommand) { c.drawer.setCameraPosition(this.position); - this._boundingBoxSize = c.drawer.setInViewWidth(this.inViewWidth); + this._boundingBoxSize = c.drawer.setInViewArea(this.inViewArea); } private moveTo(c: MoveToCommand) { diff --git a/frontend/src/shaders/dist.frag b/frontend/src/shaders/cave-fs.glsl similarity index 81% rename from frontend/src/shaders/dist.frag rename to frontend/src/shaders/cave-fs.glsl index 30d8842..187833c 100644 --- a/frontend/src/shaders/dist.frag +++ b/frontend/src/shaders/cave-fs.glsl @@ -4,7 +4,7 @@ precision mediump float; const float smoothing = 10.0; const float inf = 1000000.0; -const float pi = atan(1.0) * 4.0; +const float pi = 3.141592654; float interpolate(float from, float to, float quotient) { float steppedQ = sin(quotient * pi - pi * 0.5) * 0.5 + 0.5; @@ -16,14 +16,14 @@ vec2 rotate90deg(in vec2 vector) { } struct Line { - vec2 a; - vec2 b; + vec2 from; + vec2 to; vec2 normal; bool isLineEnd; }[16] lines; float lineDistance(in vec2 position, in Line line, out float h) { - vec2 pa = position - line.a, ba = line.b - line.a; + vec2 pa = position - line.from, ba = line.to - line.from; h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); vec2 delta = pa - ba*h; // sign can return 0, double sign prevents this @@ -32,7 +32,7 @@ float lineDistance(in vec2 position, in Line line, out float h) { } Line endDummyLineFromLine(Line line) { - return Line(line.b, line.b + rotate90deg(line.normal), line.normal, false); + return Line(line.to, line.to + rotate90deg(line.normal), line.normal, false); } float getDistance(in vec2 target) { @@ -55,7 +55,7 @@ float getDistance(in vec2 target) { float h; float distanceToCurrent = lineDistance(target, current, h); - float rightJoinAcuteness = dot(next.b - current.a, next.normal - current.normal); + float rightJoinAcuteness = dot(next.to - current.from, next.normal - current.normal); distanceToCurrent -= interpolate( sign(leftJoinAcuteness) * smoothing, sign(rightJoinAcuteness) * smoothing, h @@ -64,8 +64,8 @@ float getDistance(in vec2 target) { if ( !( - dot(target - current.a, splitterLineNormalStart * -sign(dot(current.b - current.a, splitterLineNormalStart))) > 0.0 - || dot(target - current.b, splitterLineNormalEnd * sign(dot(current.a - current.b, splitterLineNormalEnd))) <= 0.0 + dot(target - current.from, splitterLineNormalStart * -sign(dot(current.to - current.from, splitterLineNormalStart))) > 0.0 + || dot(target - current.to, splitterLineNormalEnd * sign(dot(current.from - current.to, splitterLineNormalEnd))) <= 0.0 ) && abs(distanceToCurrent) < abs(minDistance) ) { minDistance = distanceToCurrent; @@ -95,24 +95,21 @@ void createWorld() { lines[15] = Line(vec2(1150, 420.0), vec2(10200, 650.0), vec2(-1.0), true); for (int i = 0; i < lines.length(); i++) { - vec2 tangent = lines[i].b - lines[i].a; + vec2 tangent = lines[i].to - lines[i].from; lines[i].normal = normalize( vec2(-lines[i].normal.x * tangent.y, lines[i].normal.x * tangent.x) ); } } -uniform vec2 cameraPosition; -uniform vec2 viewBoxSize; -uniform vec2 resolution; - +uniform mat3 transform; out vec4 fragmentColor; void main() { createWorld(); - vec2 pixelPosition = gl_FragCoord.xy + vec2(0.5); - vec2 position = pixelPosition / resolution * viewBoxSize + cameraPosition; + vec3 projectiveXY = vec3(gl_FragCoord.xy, 1.0); + vec2 position = (projectiveXY * transform).xy; //fragmentColor = getDistance(position) > 0.0 ? vec4(0.0, 0.0, 0.0, 0.0) : vec4(0.0, 0.0, 0.0, 1.0); fragmentColor = vec4(vec3(1.0) * clamp(0.0, 1.0, getDistance(position)), 1.0); } diff --git a/frontend/src/shaders/passthrough.vert b/frontend/src/shaders/passthrough-vs.glsl similarity index 100% rename from frontend/src/shaders/passthrough.vert rename to frontend/src/shaders/passthrough-vs.glsl diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3c93363..dd8863d 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -7,6 +7,7 @@ "target": "es5", "downlevelIteration": true, "allowJs": true, - "experimentalDecorators": true + "experimentalDecorators": true, + "moduleResolution": "Node" } } diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 171c4b6..097a724 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -5,10 +5,10 @@ const TerserJSPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); -const Sharp = require('responsive-loader/sharp'); const Sass = require('sass'); const isProduction = process.env.NODE_ENV === 'production'; +const isDevelopment = !isProduction; module.exports = { watchOptions: { @@ -70,13 +70,18 @@ module.exports = { module: { rules: [ { - test: /\.(jpe?g|png)$/i, - loader: 'responsive-loader', - options: { - adapter: Sharp, - outputPath: 'static/', - sizes: [200, 400, 800, 1200, 2000], - placeholder: false, + test: /\.(glsl)$/, + use: { + loader: 'webpack-glsl-minify', + options: { + output: 'object', + esModule: false, + stripVersion: false, + preserveDefines: false, + preserveUniforms: true, + preserveVariables: true, + disableMangle: false, + }, }, }, { @@ -87,12 +92,6 @@ module.exports = { noquotes: true, }, }, - { - test: /\.(frag|vert)$/i, - use: { - loader: 'raw-loader', - }, - }, { test: /\.ico$/i, use: { @@ -145,7 +144,7 @@ module.exports = { ], }, resolve: { - extensions: ['.ts', '.js'], + extensions: ['.ts', '.js', '.glsl'], }, output: { filename: '[name].[contenthash].js',