diff --git a/src/drawables/shapes/circle.ts b/src/drawables/shapes/circle.ts index 82c7f75..1debece 100644 --- a/src/drawables/shapes/circle.ts +++ b/src/drawables/shapes/circle.ts @@ -13,15 +13,15 @@ export class Circle extends Drawable { }[CIRCLE_COUNT] circles; void circleMinDistance(inout float minDistance, inout float color) { - float circleMinDistance = minDistance; + float myMinDistance = maxMinDistance; for (int i = 0; i < CIRCLE_COUNT; i++) { float dist = distance(circles[i].center, position) - circles[i].radius; - circleMinDistance = min(circleMinDistance, dist); + myMinDistance = min(myMinDistance, dist); } - minDistance = min(minDistance, circleMinDistance); + minDistance = min(minDistance, myMinDistance); color = mix(2.0, color, step( distanceNdcPixelSize + SURFACE_OFFSET, - circleMinDistance + myMinDistance )); } `, diff --git a/src/drawables/shapes/tunnel.ts b/src/drawables/shapes/tunnel.ts index eb1edcb..7beef1b 100644 --- a/src/drawables/shapes/tunnel.ts +++ b/src/drawables/shapes/tunnel.ts @@ -5,8 +5,6 @@ import { Drawable } from '../drawable'; import { DrawableDescriptor } from '../drawable-descriptor'; export class Tunnel extends Drawable { - public readonly isInverted = false; - public static get descriptor(): DrawableDescriptor { return { sdf: { @@ -16,11 +14,10 @@ export class Tunnel extends Drawable { vec2 toFromDelta; float fromRadius; float toRadius; - float inverted; }[TUNNEL_COUNT] tunnels; void tunnelMinDistance(inout float minDistance, inout float color) { - float myMinDistance = minDistance; + float myMinDistance = maxMinDistance; for (int i = 0; i < TUNNEL_COUNT; i++) { Tunnel tunnel = tunnels[i]; vec2 targetFromDelta = position - tunnel.from; @@ -31,20 +28,20 @@ export class Tunnel extends Drawable { 0.0, 1.0 ); - float lineDistance = -mix( + float currentDistance = -mix( tunnel.fromRadius, tunnel.toRadius, h ) + distance( - targetFromDelta, tunnel.toFromDelta * h + targetFromDelta, tunnel.toFromDelta * h ); - myMinDistance = min(myMinDistance, lineDistance); + myMinDistance = min(myMinDistance, currentDistance); } color = mix(2.0, color, step( distanceNdcPixelSize + SURFACE_OFFSET, - -myMinDistance + myMinDistance )); - minDistance = -myMinDistance; + minDistance = min(minDistance, myMinDistance); } `, distanceFunctionName: 'tunnelMinDistance', @@ -52,7 +49,12 @@ export class Tunnel extends Drawable { uniformName: 'tunnels', uniformCountMacroName: 'TUNNEL_COUNT', shaderCombinationSteps: [0, 1, 4, 16, 32], - empty: new Tunnel(vec2.fromValues(0, 0), vec2.fromValues(0, 0), 0, 0), + empty: new Tunnel( + vec2.fromValues(-100000, -100000), + vec2.fromValues(-100000, -100000), + 0, + 0 + ), }; } @@ -87,7 +89,6 @@ export class Tunnel extends Drawable { toFromDelta: vec2.scale(vec2.create(), toFromDelta, transform1d), fromRadius: this.fromRadius * transform1d, toRadius: this.toRadius * transform1d, - inverted: this.isInverted ? -1 : 1, }; } } diff --git a/src/graphics/graphics-library/helper/enable-extension.ts b/src/graphics/graphics-library/helper/enable-extension.ts index fd23466..96a622f 100644 --- a/src/graphics/graphics-library/helper/enable-extension.ts +++ b/src/graphics/graphics-library/helper/enable-extension.ts @@ -3,7 +3,7 @@ import { Insights } from '../../rendering/insights'; const extensions: Map = new Map(); const logExtensions = () => { - const values = {}; + const values: any = {}; for (const [k, v] of extensions.entries()) { values[k] = v !== null; } diff --git a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts index b302958..1b44690 100644 --- a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts +++ b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts @@ -97,7 +97,13 @@ export class UniformArrayAutoScalingProgram implements IProgram { descriptors: Array ): string { return combination - .map((v, i) => `#define ${descriptors[i].uniformCountMacroName} ${v}`) + .map( + (v, i) => ` + #ifndef ${descriptors[i].uniformCountMacroName} + #define ${descriptors[i].uniformCountMacroName} ${v} + #endif + ` + ) .join('\n'); } diff --git a/src/graphics/rendering/insights.ts b/src/graphics/rendering/insights.ts index ff139a4..fef0814 100644 --- a/src/graphics/rendering/insights.ts +++ b/src/graphics/rendering/insights.ts @@ -3,9 +3,9 @@ export class Insights { public static setValue(key: string | Array, value: any): void { if (Array.isArray(key)) { - key.reduce((previousValue, currentKey) => { + key.reduce((previousValue, currentKey, i, a) => { if (!Object.prototype.hasOwnProperty.call(previousValue, currentKey)) { - previousValue[currentKey] = {}; + previousValue[currentKey] = i == a.length - 1 ? value : {}; } return previousValue[currentKey]; @@ -15,6 +15,25 @@ export class Insights { } } + public static measure(name: string) { + return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + const targetFunction = descriptor.value; + + descriptor.value = function (...values: Array) { + const start = performance.now(); + + const result = targetFunction.bind(this)(...values); + + const end = performance.now(); + Insights.setValue(['measurements', name], `${(end - start).toFixed(3)} ms`); + + return result; + }; + + return descriptor; + }; + } + public static get values(): any { return Insights.insights; } diff --git a/src/graphics/rendering/webgl2-renderer-settings.ts b/src/graphics/rendering/webgl2-renderer-settings.ts index 5578edf..7d9272e 100644 --- a/src/graphics/rendering/webgl2-renderer-settings.ts +++ b/src/graphics/rendering/webgl2-renderer-settings.ts @@ -5,5 +5,7 @@ export interface WebGl2RendererSettings { shaderMacros: { softShadowTraceCount: string; hardShadowTraceCount: string; + // ambientColor: vec3; + // defaultIsInside: boolean; }; } diff --git a/src/graphics/rendering/webgl2-renderer.ts b/src/graphics/rendering/webgl2-renderer.ts index 8759724..f7fdb70 100644 --- a/src/graphics/rendering/webgl2-renderer.ts +++ b/src/graphics/rendering/webgl2-renderer.ts @@ -1,6 +1,8 @@ import { vec2, vec3 } from 'gl-matrix'; import { Drawable } from '../../drawables/drawable'; import { DrawableDescriptor } from '../../drawables/drawable-descriptor'; +import { CircleLight } from '../../drawables/lights/circle-light'; +import { Flashlight } from '../../drawables/lights/flashlight'; import { DefaultFrameBuffer } from '../graphics-library/frame-buffer/default-frame-buffer'; import { IntermediateFrameBuffer } from '../graphics-library/frame-buffer/intermediate-frame-buffer'; import { getWebGl2Context } from '../graphics-library/helper/get-webgl2-context'; @@ -17,13 +19,15 @@ import lightsVertexShader from './shaders/shading-vs.glsl'; import { UniformsProvider } from './uniforms-provider'; import { WebGl2RendererSettings } from './webgl2-renderer-settings'; +type Passes = { [key in keyof typeof RenderingPassName]: RenderingPass }; + export class WebGl2Renderer implements Renderer { private gl: WebGL2RenderingContext; private stopwatch?: WebGlStopwatch; private uniformsProvider: UniformsProvider; private distanceFieldFrameBuffer: IntermediateFrameBuffer; private lightingFrameBuffer: DefaultFrameBuffer; - private passes: { [key in keyof typeof RenderingPassName]: RenderingPass }; + private passes: Passes; private autoscaler: FpsAutoscaler; private static defaultSettings: WebGl2RendererSettings = { @@ -55,27 +59,7 @@ export class WebGl2Renderer implements Renderer { settings.enableHighDpiRendering ); - this.passes = { - [RenderingPassName.distance]: new RenderingPass( - this.gl, - [distanceVertexShader, distanceFragmentShader], - descriptors.filter(WebGl2Renderer.hasSdf), - this.distanceFieldFrameBuffer, - settings.shaderMacros, - settings.tileMultiplier - ), - [RenderingPassName.pixel]: new RenderingPass( - this.gl, - [lightsVertexShader, lightsFragmentShader], - descriptors.filter((d) => !WebGl2Renderer.hasSdf(d)), - this.lightingFrameBuffer, - { - palette: this.generatePaletteCode(palette), - ...settings.shaderMacros, - }, - settings.tileMultiplier - ), - }; + this.passes = this.createPasses(descriptors, palette, settings); this.uniformsProvider = new UniformsProvider(this.gl); @@ -96,6 +80,41 @@ export class WebGl2Renderer implements Renderer { } } + @Insights.measure('create render passes') + private createPasses( + descriptors: Array, + palette: Array, + settings: WebGl2RendererSettings + ): Passes { + const allDescriptors = [ + ...descriptors, + CircleLight.descriptor, + Flashlight.descriptor, + ]; + + return { + [RenderingPassName.distance]: new RenderingPass( + this.gl, + [distanceVertexShader, distanceFragmentShader], + allDescriptors.filter(WebGl2Renderer.hasSdf), + this.distanceFieldFrameBuffer, + settings.shaderMacros, + settings.tileMultiplier + ), + [RenderingPassName.pixel]: new RenderingPass( + this.gl, + [lightsVertexShader, lightsFragmentShader], + allDescriptors.filter((d) => !WebGl2Renderer.hasSdf(d)), + this.lightingFrameBuffer, + { + palette: this.generatePaletteCode(palette), + ...settings.shaderMacros, + }, + settings.tileMultiplier + ), + }; + } + public get insights(): any { return Insights.values; } @@ -124,7 +143,7 @@ export class WebGl2Renderer implements Renderer { } private generatePaletteCode(palette: Array) { - const numberToGlslFloat = (n) => (Number.isInteger(n) ? `${n}.0` : `${n}`); + const numberToGlslFloat = (n: number) => (Number.isInteger(n) ? `${n}.0` : `${n}`); return palette .map( (c) => diff --git a/src/helper/autoscaler.ts b/src/helper/autoscaler.ts index c7b7143..85a613a 100644 --- a/src/helper/autoscaler.ts +++ b/src/helper/autoscaler.ts @@ -39,7 +39,7 @@ export class Autoscaler { const nextTarget = floor + 1 == this.targets.length ? previousTarget : this.targets[floor + 1]; - const result = {}; + const result: any = {}; for (const key in this.setters) { const previous = previousTarget[key]; const next = nextTarget[key]; diff --git a/src/helper/get-combinations.ts b/src/helper/get-combinations.ts index 42c36d6..ba086aa 100644 --- a/src/helper/get-combinations.ts +++ b/src/helper/get-combinations.ts @@ -6,7 +6,7 @@ export const getCombinations = (values: Array>): Array> = []; const counters = values.map((_) => 0); - const increaseCounter = (i: number) => { + const increaseCounter = (i: number): boolean => { if (i >= counters.length) { return false; } diff --git a/src/helper/timing.ts b/src/helper/timing.ts deleted file mode 100644 index 529c715..0000000 --- a/src/helper/timing.ts +++ /dev/null @@ -1,32 +0,0 @@ -export function timeIt(interval = 60) { - return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { - let i = 0; - let previousTimes: Array = []; - - const targetFunction = descriptor.value; - - descriptor.value = function (...values) { - const start = performance.now(); - targetFunction.bind(this)(...values); - const end = performance.now(); - - previousTimes.push(end - start); - - if (i++ % interval == 0) { - previousTimes = previousTimes.sort(); - - /*const text = `Max: ${last(previousTimes).toFixed( - 2 - )} ms\n\tMedian: ${previousTimes[Math.floor(previousTimes.length / 2)].toFixed( - 2 - )} ms`;*/ - - //InfoText.modifyRecord(propertyKey, text); - - previousTimes = []; - } - }; - - return descriptor; - }; -} diff --git a/src/main.ts b/src/main.ts index 2749dd4..54785a2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,10 +6,12 @@ import { WebGl2RendererSettings } from './graphics/rendering/webgl2-renderer-set import { applyArrayPlugins } from './helper/array'; export { Drawable } from './drawables/drawable'; +export { DrawableDescriptor } from './drawables/drawable-descriptor'; export { CircleLight } from './drawables/lights/circle-light'; export { Flashlight } from './drawables/lights/flashlight'; export { Circle } from './drawables/shapes/circle'; export { Tunnel } from './drawables/shapes/tunnel'; +export { Renderer } from './graphics/rendering/renderer'; export { RenderingPassName } from './graphics/rendering/rendering-pass-name'; export const compile = (