Add glsl loader
This commit is contained in:
parent
ac66c91000
commit
ef315b7089
8 changed files with 150 additions and 150 deletions
|
|
@ -4,6 +4,6 @@ export interface Drawer {
|
|||
startFrame();
|
||||
finishFrame();
|
||||
setCameraPosition(position: Vec2);
|
||||
setInViewWidth(size: number): Vec2;
|
||||
setInViewArea(size: number): Vec2;
|
||||
drawInfoText(text: string);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
78
frontend/src/scripts/math/mat3.ts
Normal file
78
frontend/src/scripts/math/mat3.ts
Normal file
|
|
@ -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<Array<number>>) {}
|
||||
|
||||
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<number> {
|
||||
const transposed = this.transposed;
|
||||
return [
|
||||
...transposed.values[0],
|
||||
...transposed.values[1],
|
||||
...transposed.values[2],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
115
frontend/src/shaders/cave-fs.glsl
Normal file
115
frontend/src/shaders/cave-fs.glsl
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
const float smoothing = 10.0;
|
||||
const float inf = 1000000.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;
|
||||
return from + (to - from) * clamp(steppedQ, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec2 rotate90deg(in vec2 vector) {
|
||||
return vec2(-vector.y, vector.x);
|
||||
}
|
||||
|
||||
struct Line {
|
||||
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.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
|
||||
float side = sign(sign(dot(delta, line.normal)) - 0.5);
|
||||
return length(delta) * side;
|
||||
}
|
||||
|
||||
Line endDummyLineFromLine(Line line) {
|
||||
return Line(line.to, line.to + rotate90deg(line.normal), line.normal, false);
|
||||
}
|
||||
|
||||
float getDistance(in vec2 target) {
|
||||
float minDistance = inf;
|
||||
|
||||
float leftJoinAcuteness = 0.0;
|
||||
vec2 splitterLineNormalStart = vec2(-1.0, 0.0);
|
||||
bool skipDistanceToPrevious = true;
|
||||
for (int i = 0; i < lines.length(); i++) {
|
||||
Line current = lines[i];
|
||||
|
||||
Line next;
|
||||
if (current.isLineEnd || i + 1 == lines.length()) {
|
||||
next = endDummyLineFromLine(current);
|
||||
} else {
|
||||
next = lines[i + 1];
|
||||
}
|
||||
|
||||
vec2 splitterLineNormalEnd = rotate90deg(normalize(current.normal + next.normal));
|
||||
|
||||
float h;
|
||||
float distanceToCurrent = lineDistance(target, current, h);
|
||||
float rightJoinAcuteness = dot(next.to - current.from, next.normal - current.normal);
|
||||
distanceToCurrent -= interpolate(
|
||||
sign(leftJoinAcuteness) * smoothing,
|
||||
sign(rightJoinAcuteness) * smoothing, h
|
||||
);
|
||||
leftJoinAcuteness = rightJoinAcuteness;
|
||||
|
||||
if (
|
||||
!(
|
||||
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;
|
||||
}
|
||||
splitterLineNormalStart = splitterLineNormalEnd;
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
void createWorld() {
|
||||
lines[0] = Line(vec2(0.0, 300.0), vec2(550.0, 140.0), vec2(1.0), false);
|
||||
lines[1] = Line(vec2(550.0, 140.0), vec2(750.0, 130.0), vec2(1.0), false);
|
||||
lines[2] = Line(vec2(750.0, 130.0), vec2(650.0, 230.0), vec2(1.0), false);
|
||||
lines[3] = Line(vec2(650.0, 230.0), vec2(850.0, 230.0), vec2(1.0), false);
|
||||
lines[4] = Line(vec2(850.0, 230.0), vec2(800.0, 150.0), vec2(1.0), false);
|
||||
lines[5] = Line(vec2(800.0, 150.0), vec2(1000.0, 120.0), vec2(1.0), false);
|
||||
lines[6] = Line(vec2(1000.0, 120.0), vec2(1150, 120.0), vec2(1.0), false);
|
||||
lines[7] = Line(vec2(1150, 120.0), vec2(10200, 350.0), vec2(1.0), true);
|
||||
lines[8] = Line(vec2(0.0, 600.0), vec2(550.0, 440.0), vec2(-1.0), false);
|
||||
lines[9] = Line(vec2(550.0, 440.0), vec2(750.0, 430.0), vec2(-1.0), false);
|
||||
lines[10] = Line(vec2(750.0, 430.0), vec2(650.0, 530.0), vec2(-1.0), false);
|
||||
lines[11] = Line(vec2(650.0, 530.0), vec2(850.0, 530.0), vec2(-1.0), false);
|
||||
lines[12] = Line(vec2(850.0, 530.0), vec2(820.0, 450.0), vec2(-1.0), false);
|
||||
lines[13] = Line(vec2(820.0, 450.0), vec2(1000.0, 420.0), vec2(-1.0), false);
|
||||
lines[14] = Line(vec2(1000.0, 420.0), vec2(1150, 420.0), vec2(-1.0), false);
|
||||
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].to - lines[i].from;
|
||||
lines[i].normal = normalize(
|
||||
vec2(-lines[i].normal.x * tangent.y, lines[i].normal.x * tangent.x)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uniform mat3 transform;
|
||||
out vec4 fragmentColor;
|
||||
|
||||
void main() {
|
||||
createWorld();
|
||||
|
||||
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);
|
||||
}
|
||||
7
frontend/src/shaders/passthrough-vs.glsl
Normal file
7
frontend/src/shaders/passthrough-vs.glsl
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#version 300 es
|
||||
|
||||
in vec4 a_position;
|
||||
|
||||
void main() {
|
||||
gl_Position = a_position;
|
||||
}
|
||||
Loading…
Reference in a new issue