diff --git a/frontend/src/scripts/commands/types/cursor-move-command.ts b/frontend/src/scripts/commands/types/cursor-move-command.ts new file mode 100644 index 0000000..d086192 --- /dev/null +++ b/frontend/src/scripts/commands/types/cursor-move-command.ts @@ -0,0 +1,8 @@ +import { Command } from '../command'; +import { vec2 } from 'gl-matrix'; + +export class CursorMoveCommand extends Command { + public constructor(public readonly position?: vec2) { + super(); + } +} diff --git a/frontend/src/scripts/drawing/webgl2-renderer.ts b/frontend/src/scripts/drawing/webgl2-renderer.ts index f8cfb47..024db43 100644 --- a/frontend/src/scripts/drawing/webgl2-renderer.ts +++ b/frontend/src/scripts/drawing/webgl2-renderer.ts @@ -6,15 +6,17 @@ import { Rectangle } from '../math/rectangle'; import { IntermediateFrameBuffer } from './graphics-library/intermediate-frame-buffer'; import { FrameBuffer } from './graphics-library/frame-buffer'; import { DefaultFrameBuffer } from './graphics-library/default-frame-buffer'; +import { translate } from 'gl-matrix/src/gl-matrix/mat2d'; export class WebGl2Renderer implements Drawer { private gl: WebGL2RenderingContext; private stopwatch: WebGlStopwatch; private viewBox: Rectangle = new Rectangle(); - private nextFrameUniforms: any; + private uniforms: any; private cursorPosition = vec2.create(); - private frameBuffers: Array = []; + private distanceFieldFrameBuffer: IntermediateFrameBuffer; + private lightingFrameBuffer: DefaultFrameBuffer; constructor( private canvas: HTMLCanvasElement, @@ -26,20 +28,16 @@ export class WebGl2Renderer implements Drawer { throw new Error('WebGl2 is not supported'); } - this.frameBuffers.push( - new IntermediateFrameBuffer(this.gl, [ - new FragmentShaderOnlyProgram(this.gl, shaderSources[0]), - ]) - ); + this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl, [ + new FragmentShaderOnlyProgram(this.gl, shaderSources[0]), + ]); - this.frameBuffers.push( - new DefaultFrameBuffer(this.gl, [ - new FragmentShaderOnlyProgram(this.gl, shaderSources[1]), - ]) - ); + this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl, [ + new FragmentShaderOnlyProgram(this.gl, shaderSources[1]), + ]); - this.frameBuffers[0].renderScale = 1; - this.frameBuffers[1].renderScale = 1; + this.distanceFieldFrameBuffer.renderScale = 0.2; + this.lightingFrameBuffer.renderScale = 1; try { this.stopwatch = new WebGlStopwatch(this.gl); @@ -48,13 +46,54 @@ export class WebGl2Renderer implements Drawer { startFrame(): void { this.stopwatch?.start(); - this.nextFrameUniforms = {}; - this.frameBuffers.forEach((f) => f.setSize()); + this.uniforms = {}; + this.distanceFieldFrameBuffer.setSize(); + this.lightingFrameBuffer.setSize(); } public finishFrame() { const resolution = vec2.fromValues(this.canvas.width, this.canvas.height); + const distanceScreenToWorld = this.getScreenToWorldTransform( + this.distanceFieldFrameBuffer.getSize() + ); + + const lightingScreenToWorld = this.getScreenToWorldTransform( + this.lightingFrameBuffer.getSize() + ); + + const screenToWorld = this.getScreenToWorldTransform(resolution); + + const worldToDistanceUV = mat2d.scale( + mat2d.create(), + distanceScreenToWorld, + this.distanceFieldFrameBuffer.getSize() + ); + mat2d.invert(worldToDistanceUV, worldToDistanceUV); + + const cursorPosition = vec2.transformMat2d( + vec2.create(), + vec2.multiply(vec2.create(), this.cursorPosition, resolution), + screenToWorld + ); + + this.giveUniforms({ + distanceScreenToWorld, + lightingScreenToWorld, + worldToDistanceUV, + cursorPosition, + }); + + this.distanceFieldFrameBuffer.render(this.uniforms); + this.lightingFrameBuffer.render( + this.uniforms, + this.distanceFieldFrameBuffer.texture + ); + + this.stopwatch?.stop(); + } + + private getScreenToWorldTransform(screenSize: vec2) { const transform = mat2d.fromTranslation( mat2d.create(), this.viewBox.topLeft @@ -62,29 +101,11 @@ export class WebGl2Renderer implements Drawer { mat2d.scale( transform, transform, - vec2.divide( - vec2.create(), - this.viewBox.size, - this.frameBuffers[0].getSize() - ) + vec2.divide(vec2.create(), this.viewBox.size, screenSize) ); mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5)); - this.nextFrameUniforms.transform = transform; - const transformUV = mat2d.fromScaling( - mat2d.create(), - vec2.divide(vec2.create(), vec2.fromValues(1, 1), resolution) - ); - mat2d.translate(transformUV, transformUV, vec2.fromValues(0.5, 0.5)); - this.nextFrameUniforms.transformUV = transformUV; - - this.frameBuffers[0].render(this.nextFrameUniforms); - this.frameBuffers[1].render( - this.nextFrameUniforms, - (this.frameBuffers[0] as IntermediateFrameBuffer).texture - ); - - this.stopwatch?.stop(); + return transform; } public setCameraPosition(position: vec2) { @@ -96,7 +117,7 @@ export class WebGl2Renderer implements Drawer { } public giveUniforms(uniforms: any): void { - this.nextFrameUniforms = { ...this.nextFrameUniforms, ...uniforms }; + this.uniforms = { ...this.uniforms, ...uniforms }; } public setInViewArea(size: number): vec2 { diff --git a/frontend/src/scripts/game.ts b/frontend/src/scripts/game.ts index f96beee..6c68efa 100644 --- a/frontend/src/scripts/game.ts +++ b/frontend/src/scripts/game.ts @@ -12,8 +12,8 @@ import { InfoText } from './objects/types/info-text'; import { timeIt } from './helper/timing'; import caveFragmentShader from '../shaders/cave-distance-fs.glsl'; -import lightsShader from '../shaders/rainbow-shading-fs.glsl'; -//import lightsShader from '../shaders/lights-shading-fs.glsl'; +// import lightsShader from '../shaders/rainbow-shading-fs.glsl'; +import lightsShader from '../shaders/lights-shading-fs.glsl'; import { Dungeon } from './objects/types/dungeon'; import { BeforeDrawCommand } from './commands/types/before-draw'; diff --git a/frontend/src/scripts/input/mouse-listener.ts b/frontend/src/scripts/input/mouse-listener.ts index 9b2e05e..7db8a1a 100644 --- a/frontend/src/scripts/input/mouse-listener.ts +++ b/frontend/src/scripts/input/mouse-listener.ts @@ -5,6 +5,7 @@ import { SwipeCommand } from '../commands/types/swipe'; import { ZoomCommand } from '../commands/types/zoom'; import { vec2 } from 'gl-matrix'; import { clamp01 } from '../helper/clamp'; +import { CursorMoveCommand } from '../commands/types/cursor-move-command'; export class MouseListener extends CommandGenerator { private previousPosition = vec2.create(); @@ -25,8 +26,9 @@ export class MouseListener extends CommandGenerator { }); target.addEventListener('mousemove', (event: MouseEvent) => { + const position = this.positionFromEvent(event); + if (this.isMouseDown) { - const position = this.positionFromEvent(event); this.sendCommand( new SwipeCommand( vec2.subtract(vec2.create(), this.previousPosition, position) @@ -34,6 +36,8 @@ export class MouseListener extends CommandGenerator { ); this.previousPosition = position; } + + this.sendCommand(new CursorMoveCommand(position)); }); target.addEventListener('mouseup', (event: MouseEvent) => { diff --git a/frontend/src/scripts/objects/types/camera.ts b/frontend/src/scripts/objects/types/camera.ts index 87b0724..4695603 100644 --- a/frontend/src/scripts/objects/types/camera.ts +++ b/frontend/src/scripts/objects/types/camera.ts @@ -4,6 +4,7 @@ import { ZoomCommand } from '../../commands/types/zoom'; import { BeforeDrawCommand } from '../../commands/types/before-draw'; import { PrimaryActionCommand } from '../../commands/types/primary-action'; import { vec2 } from 'gl-matrix'; +import { CursorMoveCommand } from '../../commands/types/cursor-move-command'; export class Camera extends GameObject { private inViewArea = 1920 * 1080; @@ -14,11 +15,11 @@ export class Camera extends GameObject { this.addCommandExecutor(BeforeDrawCommand, this.draw.bind(this)); this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this)); - this.addCommandExecutor(ZoomCommand, this.zoom.bind(this)); this.addCommandExecutor( - PrimaryActionCommand, + CursorMoveCommand, this.setCursorPosition.bind(this) ); + this.addCommandExecutor(ZoomCommand, this.zoom.bind(this)); } private draw(c: BeforeDrawCommand) { @@ -35,7 +36,7 @@ export class Camera extends GameObject { this.inViewArea *= c.factor; } - private setCursorPosition(c: PrimaryActionCommand) { + private setCursorPosition(c: CursorMoveCommand) { this.cursorPosition = c.position; } } diff --git a/frontend/src/scripts/objects/types/dungeon.ts b/frontend/src/scripts/objects/types/dungeon.ts index e2dbbc5..fcf8784 100644 --- a/frontend/src/scripts/objects/types/dungeon.ts +++ b/frontend/src/scripts/objects/types/dungeon.ts @@ -20,10 +20,10 @@ export class Dungeon extends GameObject { let previousRadius = 0; let previousEnd = vec2.create(); - for (let i = 0; i < 5000; i += 50) { - const height = previousEnd.y + (Math.random() - 0.5) * 200; + for (let i = 0; i < 500000; i += 500) { + const height = previousEnd.y + (Math.random() - 0.5) * 2000; const currentEnd = vec2.fromValues(i, height); - const currentToRadius = Math.random() * 10 + 30; + const currentToRadius = Math.random() * 10 + 300; this.lines.push({ start: previousEnd, diff --git a/frontend/src/shaders/cave-distance-fs.glsl b/frontend/src/shaders/cave-distance-fs.glsl index 685bb26..0fc4db9 100644 --- a/frontend/src/shaders/cave-distance-fs.glsl +++ b/frontend/src/shaders/cave-distance-fs.glsl @@ -36,11 +36,11 @@ float getDistance(in vec2 target) { return -minDistance; } -uniform mat3 transform; +uniform mat3 distanceScreenToWorld; out vec4 fragmentColor; void main() { - vec2 position = (vec3(gl_FragCoord.xy, 1.0) * transform).xy; + vec2 position = (vec3(gl_FragCoord.xy, 1.0) * distanceScreenToWorld).xy; float distance = getDistance(position); fragmentColor = vec4(vec3(0.0), distance / 256.0 + 0.5); } diff --git a/frontend/src/shaders/cave-fs copy.glsl b/frontend/src/shaders/cave-fs copy.glsl deleted file mode 100644 index 891985c..0000000 --- a/frontend/src/shaders/cave-fs copy.glsl +++ /dev/null @@ -1,75 +0,0 @@ -#version 300 es - -precision mediump float; - -#define SMOOTHING 10.0 -#define INFINITY 10000.0; -#define LINE_COUNT 100 - - -float interpolate(float from, float to, float quotient) { - return from + (to - from) * smoothstep(0.0, 1.0, quotient); -} - -vec2 rotate90deg(in vec2 vector) { - return vec2(-vector.y, vector.x); -} - -uniform struct Line { - vec2 from; - vec2 to; - vec2 normal; - bool isLineEnd; -}[LINE_COUNT] 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; -} - -float getDistance(in vec2 target) { - float positiveMinDistance = INFINITY; - float negativeMaxDistance = INFINITY; - - float leftJoinAcuteness = 0.0; - vec2 splitterLineNormalStart = vec2(-1.0, 0.0); - for (int i = 0; i < LINE_COUNT - 1; i++) { - vec2 splitterLineNormalEnd = rotate90deg(normalize(lines[i].normal + lines[i + 1].normal)); - - float h; - float distanceToCurrent = lineDistance(target, lines[i], h); - float rightJoinAcuteness = dot(lines[i + 1].to - lines[i].from, lines[i + 1].normal - lines[i].normal); - distanceToCurrent -= interpolate( - sign(leftJoinAcuteness) * SMOOTHING, - sign(rightJoinAcuteness) * SMOOTHING, h - ); - leftJoinAcuteness = rightJoinAcuteness; - - if ( - !( - dot(target - lines[i].from, splitterLineNormalStart * -sign(dot(lines[i].to - lines[i].from, splitterLineNormalStart))) > 0.0 - || dot(target - lines[i].to, splitterLineNormalEnd * sign(dot(lines[i].from - lines[i].to, splitterLineNormalEnd))) <= 0.0 - ) - ) { - float distanceToCurrentSign = sign(distanceToCurrent) / 2.0; - positiveMinDistance = min(positiveMinDistance, 1.0 / (0.5 + distanceToCurrentSign) * abs(distanceToCurrent)); - negativeMaxDistance = min(negativeMaxDistance, 1.0 / (0.5 - distanceToCurrentSign) * abs(distanceToCurrent)); - } - splitterLineNormalStart = splitterLineNormalEnd; - } - - return positiveMinDistance < negativeMaxDistance ? positiveMinDistance : -negativeMaxDistance; -} - -uniform mat3 transform; -out vec4 fragmentColor; - -void main() { - vec2 position = (vec3(gl_FragCoord.xy, 1.0) * transform).xy; - fragmentColor = vec4(vec3(1.0) * clamp(0.0, 1.0, getDistance(position)), 1.0); - -} diff --git a/frontend/src/shaders/lights-shading-fs.glsl b/frontend/src/shaders/lights-shading-fs.glsl index 3ca4754..31f68ed 100644 --- a/frontend/src/shaders/lights-shading-fs.glsl +++ b/frontend/src/shaders/lights-shading-fs.glsl @@ -2,21 +2,13 @@ precision mediump float; -#define INFINITY 1.0 / 0.0 +#define INFINITY 10000.0 -#define WORLD_SIZE 4 -#define LIGHTS_SIZE 2 +#define LIGHTS_SIZE 3 #define LIGHT_PENETRATION 0.95 #define ANTIALIASING_RADIUS 1.0 -uniform vec2 resolution; -uniform vec2 mouse; -uniform sampler2D distanceTexture; -uniform mat3 transformUV; - -out vec4 fragmentColor; - struct Light { vec2 center; float radius; @@ -24,62 +16,38 @@ struct Light { float intensity; }; -struct Circle { - vec2 center; - float radius; - vec3 color; -}; +uniform sampler2D distanceTexture; +uniform mat3 worldToDistanceUV; +uniform mat3 lightingScreenToWorld; +uniform vec2 cursorPosition; + Light lights[LIGHTS_SIZE]; -Circle world[WORLD_SIZE]; - -vec3 red = vec3(5.0, 0.0, 2.0); -vec3 blue = vec3(0.0, 0.0, 3.0); - -float circleDistance(in vec2 position, in Circle circle) -{ - return length(position - circle.center) - circle.radius; -} float circleDistance(in vec2 position, in Light circle) { return length(position - circle.center) - circle.radius; } -float getDistance(in vec2 target) { - float distance = INFINITY; - for (int i = 0; i < WORLD_SIZE; i++) { - distance = min(distance, circleDistance(target, world[i])); - } - return distance; -} - -float getDistance(in vec2 target, out Circle nearest) { - float distance = INFINITY; - for (int i = 0; i < WORLD_SIZE; i++) { - float distanceToCurrent = circleDistance(target, world[i]); - if (distanceToCurrent < distance) { - distance = distanceToCurrent; - nearest = world[i]; - } - } - return distance; +float getDistance(in vec2 target, out vec3 color) { + vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy; + vec4 values = texture(distanceTexture, targetUV); + color = values.rgb; + return (values.a - 0.5) * 256.0; } void createWorld() { - lights[0] = Light(mouse, 40.5, vec3(1.0), 25.0); + lights[0] = Light(vec2(600, 700), 40.5, vec3(1.0), 25.0); lights[1] = Light(vec2(100.0, 350.0), 52.5,vec3(2.0, 1.0, 0.25), 20.5); - - world[0] = Circle(vec2(250.0, 100.0), 12.5, blue); - world[1] = Circle(vec2(150.0, 50.0), 32.5, red); - world[2] = Circle(vec2(300.0, 350.0), 52.5, blue); + lights[2] = Light(cursorPosition, 52.5,vec3(0.63, 0.07, 0.19), 200.5); } float escapeFromObject(inout vec2 position, in vec2 direction) { float fractionOfLightPenetrating = 1.0; float rayLength = 0.0; for (int i = 0; i < 64; i++) { - float minDistance = getDistance(position); + vec3 color; + float minDistance = getDistance(position, color); if (minDistance >= 0.0) { return fractionOfLightPenetrating; } @@ -94,10 +62,11 @@ float escapeFromObject(inout vec2 position, in vec2 direction) { float getFractionOfLightArriving(in vec2 position, in vec2 direction, in float lightDistance, in float lightRadius) { float fractionOfLightArriving = 1.0; + vec3 color; float rayLength = 0.0; for (int j = 0; j < 64; j++) { - float minDistance = getDistance(position + direction * rayLength); + float minDistance = getDistance(position + direction * rayLength, color); fractionOfLightArriving = min(fractionOfLightArriving, minDistance / rayLength); rayLength += max(1.0, abs(minDistance)); @@ -110,25 +79,27 @@ float getFractionOfLightArriving(in vec2 position, in vec2 direction, in float l return 0.0; } -vec3 getPixelColor(in vec2 position, in bool startsInside, in vec3 colorBias) { +vec3 getPixelColor(in vec2 targetLighting, in bool startsInside, in vec3 colorBias) { vec3 result = vec3(0.0); for (int i = 0; i < LIGHTS_SIZE; i++) { Light light = lights[i]; - float lightDistance = circleDistance(position, light); - vec3 lightColor = normalize(light.color) * light.intensity / mix(1.0, lightDistance, clamp(lightDistance, 0.0, 1.0)); + float lightDistance = circleDistance(targetLighting, light); + vec3 lightColor = normalize(light.color) * light.intensity + / mix(1.0, lightDistance, clamp(lightDistance, 0.0, 1.0)); + if (lightDistance < 0.0) { return lightColor; } - vec2 lightDirection = normalize(light.center - position); - vec2 rayStart = position; + vec2 lightDirection = normalize(light.center - targetLighting); + vec2 rayStart = targetLighting; float fractionOfLightPenetrating = 1.0; if (startsInside) { - fractionOfLightPenetrating = escapeFromObject(rayStart, lightDirection); + fractionOfLightPenetrating = escapeFromObject(rayStart, lightDirection); lightColor *= colorBias; } @@ -139,7 +110,8 @@ vec3 getPixelColor(in vec2 position, in bool startsInside, in vec3 colorBias) { return clamp(result, 0.0, 1.0); } -vec3 getPixelColorAntialiased(in vec2 position) { + +/*vec3 getPixelColorAntialiased(in vec2 position) { Circle nearest; float minDistance = getDistance(position, nearest); if (0.0 < minDistance && minDistance < 1.0) { @@ -148,13 +120,23 @@ vec3 getPixelColorAntialiased(in vec2 position) { } return getPixelColor(position, minDistance < 0.0, minDistance < 0.0 ? nearest.color : vec3(1.0)); -} +}*/ + +out vec4 fragmentColor; + void main() { createWorld(); - - vec2 position = gl_FragCoord.xy + vec2(0.5); - vec3 color = getPixelColorAntialiased(position); + + vec2 pixelWorldCoordinates = (vec3(gl_FragCoord.xy, 1.0) * lightingScreenToWorld).xy; + + vec3 color; + float minDistance = getDistance(pixelWorldCoordinates, color); + color = getPixelColor(pixelWorldCoordinates, minDistance < 0.0, minDistance < 0.0 ? color : vec3(1.0)); fragmentColor = vec4(color, 1.0); + + if (distance(cursorPosition, pixelWorldCoordinates) < 50.0) { + fragmentColor = vec4(vec3(1.0, 1.0, 0.0), 1.0); + } } diff --git a/frontend/src/shaders/rainbow-shading-fs.glsl b/frontend/src/shaders/rainbow-shading-fs.glsl index aade889..91fd598 100644 --- a/frontend/src/shaders/rainbow-shading-fs.glsl +++ b/frontend/src/shaders/rainbow-shading-fs.glsl @@ -22,12 +22,28 @@ vec4 smoothRainbow(float x) { uniform sampler2D distanceTexture; -uniform mat3 transformUV; +uniform mat3 worldToDistanceUV; +uniform mat3 lightingScreenToWorld; out vec4 fragmentColor; +uniform vec2 cursorPosition; + + +float getDistance(in vec2 targetUV, out vec3 color) { + vec4 values = texture(distanceTexture, targetUV); + color = values.rgb; + return values.a; +} void main() { - vec2 position = (vec3(gl_FragCoord.xy, 1.0) * transformUV).xy; - vec4 previous = texture(distanceTexture, position); + vec2 targetUV = (vec3(gl_FragCoord.xy, 1.0) * worldToDistanceUV).xy; + vec2 targetLighting = (vec3(gl_FragCoord.xy, 1.0) * lightingScreenToWorld).xy; + + vec4 previous = texture(distanceTexture, targetUV); + //fragmentColor = smoothRainbow(previous.a); fragmentColor = previous.a > 0.5 ? vec4(1.0, 1.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 1.0); + + if (distance(targetLighting, cursorPosition) < 0.01) { + fragmentColor = vec4(1.0, 1.0, 0.0, 1.0); + } } diff --git a/frontend/src/shaders/random.frag b/frontend/src/shaders/random.frag index 3b3c5aa..d8f0df9 100644 --- a/frontend/src/shaders/random.frag +++ b/frontend/src/shaders/random.frag @@ -2,7 +2,6 @@ precision mediump float; -const float smoothing = 10.0; const float inf = 1000000.0; const float pi = atan(1.0) * 4.0; @@ -11,16 +10,6 @@ float interpolate(float from, float to, float quotient) { return from + (to - from) * clamp(steppedQ, 0.0, 1.0); } -vec2 rotate90deg(in vec2 vector) { - return vec2(-vector.y, vector.x); -} - -struct Line { - vec2 a; - vec2 b; - vec2 normal; - bool isLineEnd; -}[16] lines; float noise(float x){ return fract(sin(x) * 43758.5453123); @@ -57,101 +46,4 @@ float noise(vec2 st) { dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); -} - -float lineDistance(in vec2 position, in Line line, out float h) { - vec2 pa = position - line.a, ba = line.b - line.a; - 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; //+ terrain(length(ba * h)); -} - - -Line endDummyLineFromLine(Line line) { - return Line(line.b, line.b + 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.b - current.a, next.normal - current.normal); - distanceToCurrent -= interpolate( - sign(leftJoinAcuteness) * smoothing, - sign(rightJoinAcuteness) * smoothing, h - ); - leftJoinAcuteness = rightJoinAcuteness; - - 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 - ) && 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].b - lines[i].a; - 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; - -out vec4 fragmentColor; - -void main() { - createWorld(); - - vec2 pixelPosition = gl_FragCoord.xy + vec2(0.5); - vec2 position = pixelPosition / resolution * viewBoxSize + cameraPosition; - - fragmentColor = vec4(vec3(1.0) * clamp(0.0, 1.0, getDistance(position)), 1.0); -} +} \ No newline at end of file