From b1b3ca685aa5bdb910899e6702e9ee556b35b3bf Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Fri, 11 Sep 2020 21:06:40 +0200 Subject: [PATCH] Some improvements --- .../compiling/create-program.ts | 2 +- .../frame-buffer/default-frame-buffer.ts | 10 +- .../frame-buffer/frame-buffer.ts | 16 ++- .../frame-buffer/intermediate-frame-buffer.ts | 39 ++++--- .../helper/enable-extension.ts | 12 ++ .../graphics-library/helper/stopwatch.ts | 3 - .../graphics-library/program/i-program.ts | 2 +- .../graphics-library/program/program.ts | 9 +- .../uniform-array-autoscaling-program.ts | 10 +- .../drawing/rendering/fps-autoscaler.ts | 21 +--- .../drawing/rendering/rendering-pass.ts | 56 ++++----- .../drawing/rendering/webgl2-renderer.ts | 106 +++++++++--------- frontend/src/scripts/drawing/settings.ts | 53 +++++++-- .../drawing/shaders/cave-distance-fs.glsl | 15 ++- .../drawing/shaders/lights-shading-fs.glsl | 65 +++++------ .../shaders/passthrough-distance-vs.glsl | 6 +- .../shaders/passthrough-shading-vs.glsl | 6 +- frontend/src/scripts/helper/autoscaler.ts | 27 ++++- .../{wait-for.ts => wait-while-false.ts} | 0 .../src/scripts/objects/types/info-text.ts | 18 ++- 20 files changed, 259 insertions(+), 217 deletions(-) rename frontend/src/scripts/helper/{wait-for.ts => wait-while-false.ts} (100%) diff --git a/frontend/src/scripts/drawing/graphics-library/compiling/create-program.ts b/frontend/src/scripts/drawing/graphics-library/compiling/create-program.ts index 790178c..174dbaa 100644 --- a/frontend/src/scripts/drawing/graphics-library/compiling/create-program.ts +++ b/frontend/src/scripts/drawing/graphics-library/compiling/create-program.ts @@ -1,4 +1,4 @@ -import { waitWhileFalse } from '../../../helper/wait-for'; +import { waitWhileFalse } from '../../../helper/wait-while-false'; import { tryEnableExtension } from '../helper/enable-extension'; import { checkProgram } from './check-program'; import { createShader } from './create-shader'; diff --git a/frontend/src/scripts/drawing/graphics-library/frame-buffer/default-frame-buffer.ts b/frontend/src/scripts/drawing/graphics-library/frame-buffer/default-frame-buffer.ts index 1e697b7..be495ad 100644 --- a/frontend/src/scripts/drawing/graphics-library/frame-buffer/default-frame-buffer.ts +++ b/frontend/src/scripts/drawing/graphics-library/frame-buffer/default-frame-buffer.ts @@ -4,16 +4,16 @@ export class DefaultFrameBuffer extends FrameBuffer { constructor(gl: WebGL2RenderingContext) { super(gl); this.frameBuffer = null; - this.setSize(); } - public setSize() { - super.setSize(); - - if (this.gl.canvas.width !== this.size.x || this.gl.canvas.height !== this.size.y) { + public setSize(): boolean { + const hasChanged = super.setSize(); + if (hasChanged) { this.gl.canvas.width = this.size.x; this.gl.canvas.height = this.size.y; } + + return hasChanged; } } diff --git a/frontend/src/scripts/drawing/graphics-library/frame-buffer/frame-buffer.ts b/frontend/src/scripts/drawing/graphics-library/frame-buffer/frame-buffer.ts index 8259ba5..14a2db8 100644 --- a/frontend/src/scripts/drawing/graphics-library/frame-buffer/frame-buffer.ts +++ b/frontend/src/scripts/drawing/graphics-library/frame-buffer/frame-buffer.ts @@ -1,12 +1,11 @@ import { vec2 } from 'gl-matrix'; +import { settings } from '../../settings'; export abstract class FrameBuffer { public renderScale = 1; + public enableHighDpiRendering = settings.enableHighDpiRendering; - public enableHighDpiRendering = false; - - protected size: vec2; - + protected size = vec2.create(); protected frameBuffer: WebGLFramebuffer; constructor(protected gl: WebGL2RenderingContext) {} @@ -23,15 +22,20 @@ export abstract class FrameBuffer { this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); } - public setSize() { - const realToCssPixels = window.devicePixelRatio * this.renderScale; + public setSize(): boolean { + const realToCssPixels = + (this.enableHighDpiRendering ? window.devicePixelRatio : 1) * this.renderScale; + const canvasWidth = (this.gl.canvas as HTMLCanvasElement).clientWidth; const canvasHeight = (this.gl.canvas as HTMLCanvasElement).clientHeight; const displayWidth = Math.floor(canvasWidth * realToCssPixels); const displayHeight = Math.floor(canvasHeight * realToCssPixels); + const oldSize = vec2.clone(this.getSize()); this.size = vec2.fromValues(displayWidth, displayHeight); + + return this.size.x != oldSize.x || this.size.y != oldSize.y; } public getSize(): vec2 { diff --git a/frontend/src/scripts/drawing/graphics-library/frame-buffer/intermediate-frame-buffer.ts b/frontend/src/scripts/drawing/graphics-library/frame-buffer/intermediate-frame-buffer.ts index f8d10bc..f7fb178 100644 --- a/frontend/src/scripts/drawing/graphics-library/frame-buffer/intermediate-frame-buffer.ts +++ b/frontend/src/scripts/drawing/graphics-library/frame-buffer/intermediate-frame-buffer.ts @@ -1,10 +1,9 @@ -import { FrameBuffer } from './frame-buffer'; import { enableExtension } from '../helper/enable-extension'; +import { FrameBuffer } from './frame-buffer'; export class IntermediateFrameBuffer extends FrameBuffer { private frameTexture: WebGLTexture; - - private floatLinearEnabled = true; + private floatLinearEnabled = false; constructor(gl: WebGL2RenderingContext) { super(gl); @@ -13,8 +12,9 @@ export class IntermediateFrameBuffer extends FrameBuffer { try { enableExtension(gl, 'OES_texture_float_linear'); + this.floatLinearEnabled = true; } catch { - this.floatLinearEnabled = false; + // it's okay } this.frameTexture = this.gl.createTexture(); @@ -30,22 +30,25 @@ export class IntermediateFrameBuffer extends FrameBuffer { return this.frameTexture; } - public setSize() { - super.setSize(); + public setSize(): boolean { + const hasChanged = super.setSize(); + if (hasChanged) { + this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); - this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RG16F, + this.size.x, + this.size.y, + 0, + this.gl.RG, + this.gl.FLOAT, + null + ); + } - this.gl.texImage2D( - this.gl.TEXTURE_2D, - 0, - this.gl.RG16F, - this.size.x, - this.size.y, - 0, - this.gl.RG, - this.gl.FLOAT, - null - ); + return hasChanged; } private configureTexture() { diff --git a/frontend/src/scripts/drawing/graphics-library/helper/enable-extension.ts b/frontend/src/scripts/drawing/graphics-library/helper/enable-extension.ts index 23e51c9..388a649 100644 --- a/frontend/src/scripts/drawing/graphics-library/helper/enable-extension.ts +++ b/frontend/src/scripts/drawing/graphics-library/helper/enable-extension.ts @@ -1,5 +1,15 @@ +import { InfoText } from '../../../objects/types/info-text'; + const extensions: Map = new Map(); +const printExtensions = () => { + const values = {}; + for (const [k, v] of extensions.entries()) { + values[k] = v !== null; + } + InfoText.modifyRecord('extensions', values); +}; + export const tryEnableExtension = ( gl: WebGL2RenderingContext, name: string @@ -15,6 +25,8 @@ export const tryEnableExtension = ( extensions.set(name, extension); + printExtensions(); + return extension; }; diff --git a/frontend/src/scripts/drawing/graphics-library/helper/stopwatch.ts b/frontend/src/scripts/drawing/graphics-library/helper/stopwatch.ts index 3937fae..595f0b9 100644 --- a/frontend/src/scripts/drawing/graphics-library/helper/stopwatch.ts +++ b/frontend/src/scripts/drawing/graphics-library/helper/stopwatch.ts @@ -5,11 +5,8 @@ import { enableExtension } from './enable-extension'; export class WebGlStopwatch { private timerExtension: any; - private timerQuery: WebGLQuery; - private isReady = true; - private resultsInNanoSeconds: number; constructor(private gl: WebGL2RenderingContext) { diff --git a/frontend/src/scripts/drawing/graphics-library/program/i-program.ts b/frontend/src/scripts/drawing/graphics-library/program/i-program.ts index 2eec3b7..901c327 100644 --- a/frontend/src/scripts/drawing/graphics-library/program/i-program.ts +++ b/frontend/src/scripts/drawing/graphics-library/program/i-program.ts @@ -2,7 +2,7 @@ import { vec2 } from 'gl-matrix'; export interface IProgram { initialize(): Promise; - setDrawingRectangle(bottomLeft: vec2, size: vec2): void; + setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void; bindAndSetUniforms(values: { [name: string]: any }): void; draw(): void; delete(): void; diff --git a/frontend/src/scripts/drawing/graphics-library/program/program.ts b/frontend/src/scripts/drawing/graphics-library/program/program.ts index ca5bd9d..fef88b0 100644 --- a/frontend/src/scripts/drawing/graphics-library/program/program.ts +++ b/frontend/src/scripts/drawing/graphics-library/program/program.ts @@ -8,7 +8,7 @@ export default abstract class Program implements IProgram { protected program: WebGLProgram; private programPromise: Promise; private modelTransform = mat2d.identity(mat2d.create()); - private readonly ndcToUv: mat2d; + private readonly ndcToUv = mat2d.fromValues(0.5, 0, 0, 0.5, 0.5, 0.5); private uniforms: Array<{ name: Array; location: WebGLUniformLocation; @@ -28,9 +28,6 @@ export default abstract class Program implements IProgram { fragmentShaderSource, substitutions ); - - this.ndcToUv = mat2d.fromScaling(mat2d.create(), vec2.fromValues(0.5, 0.5)); - mat2d.translate(this.ndcToUv, this.ndcToUv, vec2.fromValues(1, 1)); } public async initialize(): Promise { @@ -43,7 +40,7 @@ export default abstract class Program implements IProgram { this.setUniforms({ modelTransform: this.modelTransform, ...values }); } - public setDrawingRectangle(bottomLeft: vec2, size: vec2) { + public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) { mat2d.invert(this.modelTransform, this.ndcToUv); mat2d.translate(this.modelTransform, this.modelTransform, bottomLeft); mat2d.scale(this.modelTransform, this.modelTransform, size); @@ -93,9 +90,11 @@ export default abstract class Program implements IProgram { this.uniforms.map((u1) => { const isSingle = this.uniforms.filter((u2) => u2.name.includes(u1.name[0])).length == 1; + if (u1.name.includes('0') && isSingle) { u1.name = u1.name.slice(0, -1); } + return u1; }); } diff --git a/frontend/src/scripts/drawing/graphics-library/program/uniform-array-autoscaling-program.ts b/frontend/src/scripts/drawing/graphics-library/program/uniform-array-autoscaling-program.ts index 0e26a4c..8e1df24 100644 --- a/frontend/src/scripts/drawing/graphics-library/program/uniform-array-autoscaling-program.ts +++ b/frontend/src/scripts/drawing/graphics-library/program/uniform-array-autoscaling-program.ts @@ -12,7 +12,7 @@ export class UniformArrayAutoScalingProgram implements IProgram { }> = []; private current: FragmentShaderOnlyProgram; - private drawingRectangleTopLeft = vec2.fromValues(0, 0); + private drawingRectangleBottomLeft = vec2.fromValues(0, 0); private drawingRectangleSize = vec2.fromValues(1, 1); constructor( @@ -50,15 +50,15 @@ export class UniformArrayAutoScalingProgram implements IProgram { }); } - this.current.setDrawingRectangle( - this.drawingRectangleTopLeft, + this.current.setDrawingRectangleUV( + this.drawingRectangleBottomLeft, this.drawingRectangleSize ); this.current.bindAndSetUniforms(uniforms); } - public setDrawingRectangle(topLeft: vec2, size: vec2) { - this.drawingRectangleTopLeft = topLeft; + public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) { + this.drawingRectangleBottomLeft = bottomLeft; this.drawingRectangleSize = size; } diff --git a/frontend/src/scripts/drawing/rendering/fps-autoscaler.ts b/frontend/src/scripts/drawing/rendering/fps-autoscaler.ts index fdb6067..528cadf 100644 --- a/frontend/src/scripts/drawing/rendering/fps-autoscaler.ts +++ b/frontend/src/scripts/drawing/rendering/fps-autoscaler.ts @@ -1,19 +1,15 @@ -import { Autoscaler } from '../../helper/autoscaler'; -import { settings } from '../settings'; +import { Autoscaler as AutoScaler } from '../../helper/autoscaler'; import { exponentialDecay } from '../../helper/exponential-decay'; -import { InfoText } from '../../objects/types/info-text'; -import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer'; -import { toPercent } from '../../helper/to-percent'; +import { settings } from '../settings'; -export class FpsAutoscaler extends Autoscaler { +export class FpsAutoscaler extends AutoScaler { private timeSinceLastAdjusment = 0; - private exponentialDecayedDeltaTime = 0.0; - constructor(private frameBuffers: Array) { + constructor(setters: { [key: string]: (value: number | boolean) => void }) { super( - frameBuffers.map((f) => (v) => (f.renderScale = v)), - settings.qualityScaling.scaleTargets, + setters, + settings.qualityScaling.qualityTargets, settings.qualityScaling.startingTargetIndex, settings.qualityScaling.scalingOptions ); @@ -45,10 +41,5 @@ export class FpsAutoscaler extends Autoscaler { this.decrease(); } } - - InfoText.modifyRecord( - 'quality', - this.frameBuffers.map((f) => toPercent(f.renderScale)).join(', ') - ); } } diff --git a/frontend/src/scripts/drawing/rendering/rendering-pass.ts b/frontend/src/scripts/drawing/rendering/rendering-pass.ts index de03fa2..cfe809e 100644 --- a/frontend/src/scripts/drawing/rendering/rendering-pass.ts +++ b/frontend/src/scripts/drawing/rendering/rendering-pass.ts @@ -1,5 +1,4 @@ import { mat2d, vec2 } from 'gl-matrix'; -import { InfoText } from '../../objects/types/info-text'; import { IDrawable } from '../drawables/i-drawable'; import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor'; import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer'; @@ -8,13 +7,12 @@ import { settings } from '../settings'; export class RenderingPass { private drawables: Array = []; - private program: UniformArrayAutoScalingProgram; constructor( gl: WebGL2RenderingContext, shaderSources: [string, string], - private drawableDescriptors: Array, + drawableDescriptors: Array, private frame: FrameBuffer ) { this.program = new UniformArrayAutoScalingProgram( @@ -39,38 +37,34 @@ export class RenderingPass { inputTexture?: WebGLTexture ) { this.frame.bindAndClear(inputTexture); - const q = 1 / settings.tileMultiplier; - const tileUvSize = vec2.fromValues(q, q); - const origin = vec2.transformMat2d( - vec2.create(), - vec2.fromValues(0, 0), - commonUniforms.uvToWorld - ); + const stepsInUV = 1 / settings.tileMultiplier; - const firstCenter = vec2.transformMat2d( - vec2.create(), - vec2.fromValues(q, q), - commonUniforms.uvToWorld - ); + const worldR = + 0.5 * + vec2.length(vec2.scale(vec2.create(), commonUniforms.worldAreaInView, stepsInUV)); - vec2.subtract(firstCenter, firstCenter, origin); + const stepsInNDC = 2 * stepsInUV; - const worldR = vec2.length(firstCenter); - - let sumLineCount = 0; - - for (let x = 0; x < 1; x += q) { - for (let y = 0; y < 1; y += q) { + for (let x = -1; x < 1; x += stepsInNDC) { + for (let y = -1; y < 1; y += stepsInNDC) { const uniforms = { ...commonUniforms }; uniforms.maxMinDistance = 2 * worldR * scale; - const uvBottomLeft = vec2.fromValues(x, y); - this.program.setDrawingRectangle(uvBottomLeft, tileUvSize); + const ndcBottomLeft = vec2.fromValues(x, y); + + this.program.setDrawingRectangleUV( + [(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2], + vec2.fromValues(stepsInUV, stepsInUV) + ); const tileCenterWorldCoordinates = vec2.transformMat2d( vec2.create(), - vec2.add(vec2.create(), uvBottomLeft, vec2.fromValues(q, q)), + vec2.add( + vec2.create(), + [(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2], + vec2.fromValues(stepsInUV / 2, stepsInUV / 2) + ), uniforms.uvToWorld ); @@ -78,8 +72,6 @@ export class RenderingPass { (d) => d.distance(tileCenterWorldCoordinates) < 2 * worldR ); - sumLineCount += primitivesNearTile.length; - primitivesNearTile.forEach((p) => p.serializeToUniforms(uniforms, scale, transform) ); @@ -89,16 +81,6 @@ export class RenderingPass { } } - InfoText.modifyRecord( - `nearby ${this.drawableDescriptors[0].countMacroName}`, - this.drawables.length.toFixed(2) - ); - - InfoText.modifyRecord( - `drawn ${this.drawableDescriptors[0].countMacroName}`, - (sumLineCount / settings.tileMultiplier / settings.tileMultiplier).toFixed(2) - ); - this.drawables = []; } } diff --git a/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts b/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts index feb75a9..7ee0d2e 100644 --- a/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts +++ b/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts @@ -22,12 +22,13 @@ export class WebGl2Renderer implements IRenderer { private gl: WebGL2RenderingContext; private stopwatch?: WebGlStopwatch; - private upscaleTransform = mat2d.create(); - private linearUpscale = 1; + private scaleWorldToNDC = mat2d.create(); + private scaleWorldAreaInViewToNDC = 1; - private viewBoxBottomLeft = vec2.create(); - private viewBoxSize = vec2.create(); - private viewAreaScale: vec2; + private viewAreaBottomLeft = vec2.create(); + private worldAreaInView = vec2.create(); + private squareToAspectRatio: vec2; + private uvToWorld: mat2d; private cursorPosition = vec2.create(); private distanceFieldFrameBuffer: IntermediateFrameBuffer; @@ -38,12 +39,7 @@ export class WebGl2Renderer implements IRenderer { private initializePromise: Promise<[void, void]> = null; - private matrices: { - distanceScreenToWorld?: mat2d; - worldToDistanceUV?: mat2d; - cursorPosition?: mat2d; - uvToWorld?: mat2d; - } = {}; + private softShadowsEnabled: boolean; constructor(private canvas: HTMLCanvasElement, private overlay: HTMLElement) { this.gl = getWebGl2Context(canvas); @@ -70,10 +66,12 @@ export class WebGl2Renderer implements IRenderer { this.lightingPass.initialize(), ]); - this.autoscaler = new FpsAutoscaler([ - this.lightingFrameBuffer, - this.distanceFieldFrameBuffer, - ]); + this.autoscaler = new FpsAutoscaler({ + distanceRenderScale: (v) => + (this.distanceFieldFrameBuffer.renderScale = v as number), + finalRenderScale: (v) => (this.lightingFrameBuffer.renderScale = v as number), + softShadowsEnabled: (v) => (this.softShadowsEnabled = v as boolean), + }); try { this.stopwatch = new WebGlStopwatch(this.gl); @@ -106,11 +104,15 @@ export class WebGl2Renderer implements IRenderer { public finishFrame() { this.calculateMatrices(); - this.distancePass.render(this.uniforms, this.linearUpscale, this.upscaleTransform); + this.distancePass.render( + this.uniforms, + this.scaleWorldAreaInViewToNDC, + this.scaleWorldToNDC + ); this.lightingPass.render( this.uniforms, - this.linearUpscale, - this.upscaleTransform, + this.scaleWorldAreaInViewToNDC, + this.scaleWorldToNDC, this.distanceFieldFrameBuffer.colorTexture ); @@ -118,46 +120,37 @@ export class WebGl2Renderer implements IRenderer { } private get uniforms(): any { - const cursorPosition = this.screenUvToWorldCoordinate(this.cursorPosition); + const cursorPosition = this.uvToWorldCoordinate(this.cursorPosition); return { - ...this.matrices, cursorPosition, - viewAreaScale: this.viewAreaScale, + pixelSize: + (4.5 * this.scaleWorldAreaInViewToNDC) / + this.distanceFieldFrameBuffer.renderScale, + uvToWorld: this.uvToWorld, + worldAreaInView: this.worldAreaInView, + squareToAspectRatio: this.squareToAspectRatio, + softShadowsEnabled: this.softShadowsEnabled, }; } private calculateMatrices() { - this.matrices.uvToWorld = mat2d.fromTranslation( - mat2d.create(), - this.viewBoxBottomLeft - ); - mat2d.scale(this.matrices.uvToWorld, this.matrices.uvToWorld, this.viewBoxSize); - - this.matrices.distanceScreenToWorld = this.getScreenToWorldTransform( - this.distanceFieldFrameBuffer.getSize() - ); - - this.matrices.worldToDistanceUV = mat2d.scale( - mat2d.create(), - this.matrices.distanceScreenToWorld, - this.distanceFieldFrameBuffer.getSize() - ); - mat2d.invert(this.matrices.worldToDistanceUV, this.matrices.worldToDistanceUV); + this.uvToWorld = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); + mat2d.scale(this.uvToWorld, this.uvToWorld, this.worldAreaInView); } private getScreenToWorldTransform(screenSize: vec2) { - const transform = mat2d.fromTranslation(mat2d.create(), this.viewBoxBottomLeft); + const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); mat2d.scale( transform, transform, - vec2.divide(vec2.create(), this.viewBoxSize, screenSize) + vec2.divide(vec2.create(), this.worldAreaInView, screenSize) ); mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5)); return transform; } - public screenUvToWorldCoordinate(screenUvPosition: vec2): vec2 { + public uvToWorldCoordinate(screenUvPosition: vec2): vec2 { const resolution = vec2.fromValues(this.canvas.width, this.canvas.height); return vec2.transformMat2d( @@ -172,31 +165,36 @@ export class WebGl2Renderer implements IRenderer { } public setViewArea(viewArea: BoundingBoxBase) { - const targetRange = 2; + this.worldAreaInView = viewArea.size; - this.viewBoxSize = viewArea.size; - this.viewBoxBottomLeft = vec2.add( + // world coordinates + this.viewAreaBottomLeft = vec2.add( vec2.create(), viewArea.topLeft, vec2.fromValues(0, -viewArea.size.y) ); - this.linearUpscale = targetRange / Math.max(this.viewBoxSize.x, this.viewBoxSize.y); + const scaleLongerEdgeTo1 = + 1 / Math.max(this.worldAreaInView.x, this.worldAreaInView.y); - this.viewAreaScale = vec2.fromValues( - (this.viewBoxSize.x * this.linearUpscale) / 2, - (this.viewBoxSize.y * this.linearUpscale) / 2 + this.squareToAspectRatio = vec2.fromValues( + this.worldAreaInView.x * scaleLongerEdgeTo1, + this.worldAreaInView.y * scaleLongerEdgeTo1 ); + this.scaleWorldAreaInViewToNDC = scaleLongerEdgeTo1 * 2; + mat2d.fromScaling( - this.upscaleTransform, - vec2.fromValues(this.linearUpscale, this.linearUpscale) + this.scaleWorldToNDC, + vec2.fromValues(this.scaleWorldAreaInViewToNDC, this.scaleWorldAreaInViewToNDC) ); - - const translate = vec2.scale(vec2.create(), this.viewBoxBottomLeft, -1); - vec2.subtract(translate, translate, vec2.scale(vec2.create(), this.viewBoxSize, 0.5)); - - mat2d.translate(this.upscaleTransform, this.upscaleTransform, translate); + const translate = vec2.scale(vec2.create(), this.viewAreaBottomLeft, -1); + vec2.subtract( + translate, + translate, + vec2.scale(vec2.create(), this.worldAreaInView, 0.5) + ); + mat2d.translate(this.scaleWorldToNDC, this.scaleWorldToNDC, translate); } public setCursorPosition(position: vec2): void { diff --git a/frontend/src/scripts/drawing/settings.ts b/frontend/src/scripts/drawing/settings.ts index f5db8a7..64b9f28 100644 --- a/frontend/src/scripts/drawing/settings.ts +++ b/frontend/src/scripts/drawing/settings.ts @@ -1,18 +1,51 @@ export const settings = { + enableHighDpiRendering: true, qualityScaling: { - targetDeltaTimeInMilliseconds: 30, + targetDeltaTimeInMilliseconds: 20, deltaTimeError: 2, deltaTimeResponsiveness: 1 / 16, adjusmentRateInMilliseconds: 300, - scaleTargets: [ - [0.2, 0.1], - [0.6, 0.1], - [1, 1], - /*[1.25, 0.75], - [1.5, 1], - [1.75, 1.25], - //[1.75, 1.75], - //[2, 2],*/ + qualityTargets: [ + { + distanceRenderScale: 0.1, + finalRenderScale: 0.2, + softShadowsEnabled: false, + }, + { + distanceRenderScale: 0.1, + finalRenderScale: 0.6, + softShadowsEnabled: false, + }, + { + distanceRenderScale: 0.2, + finalRenderScale: 1.0, + softShadowsEnabled: false, + }, + /* { + distanceRenderScale: 0.3, + finalRenderScale: 1.0, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 1.0, + finalRenderScale: 1.25, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 1.0, + finalRenderScale: 1.5, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 1.25, + finalRenderScale: 1.75, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 2, + finalRenderScale: 2, + softShadowsEnabled: true, + },*/ ], startingTargetIndex: 2, scalingOptions: { diff --git a/frontend/src/scripts/drawing/shaders/cave-distance-fs.glsl b/frontend/src/scripts/drawing/shaders/cave-distance-fs.glsl index eeef5f3..89ffdfd 100644 --- a/frontend/src/scripts/drawing/shaders/cave-distance-fs.glsl +++ b/frontend/src/scripts/drawing/shaders/cave-distance-fs.glsl @@ -1,15 +1,15 @@ #version 300 es -precision mediump float; +precision lowp float; #define LINE_COUNT {lineCount} #define BLOB_COUNT {blobCount} uniform float maxMinDistance; +uniform float pixelSize; in vec2 position; - #if LINE_COUNT > 0 uniform struct { vec2 from; @@ -19,7 +19,7 @@ in vec2 position; }[LINE_COUNT] lines; void lineMinDistance(inout float minDistance, inout float color) { - float myMinDistance = 10.0; + float myMinDistance = maxMinDistance; for (int i = 0; i < LINE_COUNT; i++) { vec2 targetFromDelta = position - lines[i].from; vec2 toFromDelta = lines[i].toFromDelta; @@ -35,10 +35,11 @@ in vec2 position; targetFromDelta, toFromDelta * h ); - color = mix(1.0, color, step(0.0, lineDistance)); myMinDistance = min(myMinDistance, lineDistance); } + color = mix(0.0, color, step(pixelSize, -myMinDistance)); + minDistance = -myMinDistance; } #endif @@ -67,7 +68,7 @@ in vec2 position; res += exp2(-blobs[i].k * circleMinDistance(blobs[i].rightFootCenter, blobs[i].footRadius)); res = -log2(res) / blobs[i].k; - color = mix(2.0, color, step(0.0, res)); + color = mix(1.0, color, step(pixelSize, res)); minDistance = min(minDistance, res); } @@ -77,7 +78,7 @@ in vec2 position; out vec2 fragmentColor; void main() { - float minDistance = -10.0; + float minDistance = -maxMinDistance; float color = 0.0; #if LINE_COUNT > 0 @@ -86,6 +87,8 @@ void main() { #if BLOB_COUNT > 0 blobMinDistance(minDistance, color); + //fragmentColor = vec2(-1.0, 2.0); + //return; #endif fragmentColor = vec2(minDistance, color); diff --git a/frontend/src/scripts/drawing/shaders/lights-shading-fs.glsl b/frontend/src/scripts/drawing/shaders/lights-shading-fs.glsl index 0c9c218..160f5da 100644 --- a/frontend/src/scripts/drawing/shaders/lights-shading-fs.glsl +++ b/frontend/src/scripts/drawing/shaders/lights-shading-fs.glsl @@ -1,28 +1,28 @@ #version 300 es -precision mediump float; +precision lowp float; #define INFINITY 1000.0 #define LIGHT_DROP 0.25 -#define AMBIENT_LIGHT vec3(0.3) +#define SOFT_SHADOWS_QUALITY 2.0 +#define AMBIENT_LIGHT vec3(0.75) #define CIRCLE_LIGHT_COUNT {circleLightCount} #define POINT_LIGHT_COUNT {pointLightCount} -#define SOFT_SHADOWS_ENABLED 1 -#define HARD_SHADOWS_QUALITY 1.5 -#define SOFT_SHADOWS_QUALITY 2.0 +uniform bool softShadowsEnabled; + +#define AIR_COLOR vec3(0.4) uniform sampler2D distanceTexture; -vec3[4] colors = vec3[4]( - vec3(0.2), - vec3(1.0, 1.0, 1.0), +vec3[3] colors = vec3[]( + vec3(0.1, 0.05, 0.15), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0) ); -float getDistance(in vec2 target, out vec3 color) { +float getDistance(in vec2 target, out vec3 color, out float nearness) { vec4 values = texture(distanceTexture, target); color = colors[int(values[1])]; @@ -56,13 +56,21 @@ float getDistance(in vec2 target) { in vec2 position; in vec2 uvCoordinates; -uniform vec2 viewAreaScale; +uniform vec2 squareToAspectRatio; out vec4 fragmentColor; void main() { vec3 colorAtPosition; - float startingDistance = getDistance(uvCoordinates, colorAtPosition); + float nearness; + float startingDistance = getDistance(uvCoordinates, colorAtPosition, nearness); + if (startingDistance < 0.0) { + fragmentColor = vec4(colorAtPosition, 1.0); + return; + } + + colorAtPosition = AIR_COLOR; + vec3 lighting = AMBIENT_LIGHT; #if CIRCLE_LIGHT_COUNT > 0 @@ -71,18 +79,14 @@ void main() { float lightDistance = lightCenterDistance - circleLights[i].radius; float traceDistance = lightCenterDistance - circleLights[i].traceRadius; - if (traceDistance < 0.0) { - lighting = vec3(1.0, 1.0, 0.0); - } - vec3 lightColorAtPosition = circleLights[i].value / pow( lightDistance / LIGHT_DROP + 1.0, 2.0 ); - #if SOFT_SHADOWS_ENABLED + if (softShadowsEnabled) { float q = INFINITY; float rayLength = startingDistance / SOFT_SHADOWS_QUALITY; - vec2 direction = normalize(circleLightDirections[i]) / viewAreaScale / 2.0; + vec2 direction = normalize(circleLightDirections[i]) / squareToAspectRatio / 2.05; for (int j = 0; j < 48 * int(ceil(SOFT_SHADOWS_QUALITY)); j++) { if (rayLength >= traceDistance) { lighting += lightColorAtPosition * clamp( @@ -96,20 +100,17 @@ void main() { q = min(q, minDistance / rayLength); rayLength += minDistance / SOFT_SHADOWS_QUALITY; } - #else - float rayLength = startingDistance / 2.0; - vec2 direction = normalize(circleLightDirections[i]) / viewAreaScale / 2.0; - for (int j = 0; j < 24 * int(ceil(HARD_SHADOWS_QUALITY)); j++) { - float minDistance = getDistance(uvCoordinates + direction * rayLength); - if (minDistance < 0.0) { - break; - } - rayLength += minDistance / HARD_SHADOWS_QUALITY; + } else { + float rayLength = startingDistance; + vec2 direction = normalize(circleLightDirections[i]) / squareToAspectRatio / 2.05; + for (int j = 0; j < 24; j++) { + float currentDistance = getDistance(uvCoordinates + direction * rayLength); + rayLength += currentDistance; } if (rayLength >= traceDistance) { lighting += lightColorAtPosition * step(0.0, startingDistance); } - #endif + } } #endif @@ -143,15 +144,5 @@ void main() { }*/ #endif - - float d = startingDistance; - vec3 col = (d<0.0) ? vec3(0.6,0.8,1.0) : vec3(0.9,0.6,0.3); - col *= 1.0 - exp(-9.0*abs(d)); - col *= 1.0 + 0.2*cos(128.0*abs(d)); - col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) ); - fragmentColor = vec4(col, 1.0); fragmentColor = vec4(colorAtPosition * lighting, 1.0); - fragmentColor = vec4(mix(colorAtPosition * lighting, col, 0.2), 1.0); - - //fragmentColor = vec4(vec3(startingDistance), 1.0); } diff --git a/frontend/src/scripts/drawing/shaders/passthrough-distance-vs.glsl b/frontend/src/scripts/drawing/shaders/passthrough-distance-vs.glsl index c5bbeb5..0e54025 100644 --- a/frontend/src/scripts/drawing/shaders/passthrough-distance-vs.glsl +++ b/frontend/src/scripts/drawing/shaders/passthrough-distance-vs.glsl @@ -1,9 +1,9 @@ #version 300 es -precision mediump float; +precision lowp float; uniform mat3 modelTransform; -uniform vec2 viewAreaScale; +uniform vec2 squareToAspectRatio; in vec4 vertexPosition; out vec2 position; @@ -11,5 +11,5 @@ out vec2 position; void main() { vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform; gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0); - position = vertexPosition2D.xy * viewAreaScale; + position = vertexPosition2D.xy * squareToAspectRatio; } diff --git a/frontend/src/scripts/drawing/shaders/passthrough-shading-vs.glsl b/frontend/src/scripts/drawing/shaders/passthrough-shading-vs.glsl index 78ebdad..fd0ebd4 100644 --- a/frontend/src/scripts/drawing/shaders/passthrough-shading-vs.glsl +++ b/frontend/src/scripts/drawing/shaders/passthrough-shading-vs.glsl @@ -1,6 +1,6 @@ #version 300 es -precision mediump float; +precision lowp float; #define CIRCLE_LIGHT_COUNT {circleLightCount} #define POINT_LIGHT_COUNT {pointLightCount} @@ -11,7 +11,7 @@ in vec4 vertexPosition; out vec2 position; out vec2 uvCoordinates; -uniform vec2 viewAreaScale; +uniform vec2 squareToAspectRatio; #if CIRCLE_LIGHT_COUNT > 0 uniform struct { @@ -37,7 +37,7 @@ uniform vec2 viewAreaScale; void main() { vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform; gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0); - position = vertexPosition2D.xy * viewAreaScale; + position = vertexPosition2D.xy * squareToAspectRatio; uvCoordinates = (vertexPosition2D * mat3( 0.5, 0.0, 0.5, diff --git a/frontend/src/scripts/helper/autoscaler.ts b/frontend/src/scripts/helper/autoscaler.ts index f427105..b3e1ddb 100644 --- a/frontend/src/scripts/helper/autoscaler.ts +++ b/frontend/src/scripts/helper/autoscaler.ts @@ -1,13 +1,14 @@ -import { mix } from './mix'; +import { InfoText } from '../objects/types/info-text'; import { clamp } from './clamp'; +import { mix } from './mix'; export class Autoscaler { // can have fractions private index: number; constructor( - private setters: Array<(value: number) => void>, - private targets: Array>, + private setters: { [key: string]: (value: number | boolean) => void }, + private targets: Array<{ [key: string]: number | boolean }>, startingIndex: number, private scalingOptions: { additiveIncrease: number; @@ -38,8 +39,22 @@ export class Autoscaler { const nextTarget = floor + 1 == this.targets.length ? previousTarget : this.targets[floor + 1]; - this.setters.forEach((setter, i) => - setter(mix(previousTarget[i], nextTarget[i], fract)) - ); + const result = {}; + for (const key in this.setters) { + const previous = previousTarget[key]; + const next = nextTarget[key]; + let current: number | boolean; + if (typeof previous == 'number') { + current = mix(previous, next as number, fract); + } else { + current = next; + } + + result[key] = current; + + this.setters[key](current); + } + + InfoText.modifyRecord('quality', result); } } diff --git a/frontend/src/scripts/helper/wait-for.ts b/frontend/src/scripts/helper/wait-while-false.ts similarity index 100% rename from frontend/src/scripts/helper/wait-for.ts rename to frontend/src/scripts/helper/wait-while-false.ts diff --git a/frontend/src/scripts/objects/types/info-text.ts b/frontend/src/scripts/objects/types/info-text.ts index 1ab4e2a..bd369a8 100644 --- a/frontend/src/scripts/objects/types/info-text.ts +++ b/frontend/src/scripts/objects/types/info-text.ts @@ -2,6 +2,8 @@ import { RenderCommand } from '../../drawing/commands/render'; import { GameObject } from '../game-object'; export class InfoText extends GameObject { + private static MinRowLength = 60; + constructor() { super(); @@ -10,13 +12,25 @@ export class InfoText extends GameObject { private static records: Map = new Map(); - public static modifyRecord(key: string, value: string) { + public static modifyRecord(key: string, value: string | any) { + if (typeof value == 'string') { + value = ' ' + value; + } else { + value = JSON.stringify( + value, + (_, v) => (v.toFixed ? Number(v.toFixed(2)) : v), + ' ' + ); + } + InfoText.records.set(key, value); } private draw(e: RenderCommand) { let text = ''; - InfoText.records.forEach((v, k) => (text += `${k}\n\t${v}\n`)); + InfoText.records.forEach( + (v, k) => (text += `${k}\n${v.padEnd(InfoText.MinRowLength)}\n`) + ); e.renderer.drawInfoText(text); } }