diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c0905f5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+
+
+# SDF-2D library
+
+Documentation will be provided by the end of september 2020.
diff --git a/package.json b/package.json
index db7a524..f1f671f 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,10 @@
"url": "https://github.com/schmelczerandras/sdf-2d/issues",
"email": "andras@schmelczer.dev"
},
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/schmelczerandras/sdf-2d.git"
+ },
"license": "ISC",
"scripts": {
"start": "shx rm -rf lib/* && webpack --mode development -w",
@@ -30,10 +34,11 @@
"lib"
],
"sideEffects": false,
- "optimization": {
- "usedExports": true
+ "dependencies": {
+ "gl-matrix": "^3.3.0"
},
"devDependencies": {
+ "@types/gl-matrix": "^2.4.5",
"@typescript-eslint/eslint-plugin": "^3.10.1",
"@typescript-eslint/parser": "^3.10.1",
"eslint": "^7.9.0",
@@ -41,7 +46,6 @@
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-unused-imports": "^0.1.3",
- "gl-matrix": "^3.3.0",
"prettier": "^2.1.2",
"raw-loader": "^4.0.1",
"shx": "^0.3.2",
diff --git a/src/drawables/drawable.ts b/src/drawables/drawable.ts
index 300fc27..f7265fb 100644
--- a/src/drawables/drawable.ts
+++ b/src/drawables/drawable.ts
@@ -5,7 +5,7 @@ export abstract class Drawable {
// This should be overriden by inherited classes
public static readonly descriptor: DrawableDescriptor;
- public abstract distance(target: vec2): number;
+ public abstract minDistance(target: vec2): number;
protected abstract getObjectToSerialize(transform2d: mat2d, transform1d: number): any;
diff --git a/src/drawables/lights/circle-light.ts b/src/drawables/lights/circle-light.ts
index d2edff7..f468895 100644
--- a/src/drawables/lights/circle-light.ts
+++ b/src/drawables/lights/circle-light.ts
@@ -1,8 +1,8 @@
-import { mat2d, vec2, vec3 } from 'gl-matrix';
-import { Drawable } from '../drawable';
+import { vec2, vec3 } from 'gl-matrix';
import { DrawableDescriptor } from '../drawable-descriptor';
+import { LightDrawable } from './light-drawable';
-export class CircleLight extends Drawable {
+export class CircleLight extends LightDrawable {
public static readonly descriptor: DrawableDescriptor = {
uniformName: 'circleLights',
uniformCountMacroName: 'CIRCLE_LIGHT_COUNT',
@@ -10,19 +10,7 @@ export class CircleLight extends Drawable {
empty: new CircleLight(vec2.fromValues(0, 0), vec3.fromValues(0, 0, 0), 0),
};
- constructor(public center: vec2, public color: vec3, public intensity: number) {
- super();
- }
-
- public distance(target: vec2): number {
- return vec2.dist(this.center, target);
- }
-
- protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
- return {
- center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
- color: this.color,
- intensity: this.intensity,
- };
+ constructor(center: vec2, color: vec3, intensity: number) {
+ super(center, color, intensity);
}
}
diff --git a/src/drawables/lights/flashlight.ts b/src/drawables/lights/flashlight.ts
index 7ddb1ef..9d60c36 100644
--- a/src/drawables/lights/flashlight.ts
+++ b/src/drawables/lights/flashlight.ts
@@ -1,39 +1,33 @@
import { mat2d, vec2, vec3 } from 'gl-matrix';
-import { Drawable } from '../drawable';
import { DrawableDescriptor } from '../drawable-descriptor';
+import { LightDrawable } from './light-drawable';
-export class Flashlight extends Drawable {
+export class Flashlight extends LightDrawable {
public static readonly descriptor: DrawableDescriptor = {
uniformName: 'flashlights',
uniformCountMacroName: 'FLASHLIGHT_COUNT',
shaderCombinationSteps: [0, 1, 2, 4],
empty: new Flashlight(
- vec2.fromValues(0, 0),
vec2.fromValues(0, 0),
vec3.fromValues(0, 0, 0),
- 0
+ 0,
+ vec2.fromValues(0, 0)
),
};
public constructor(
- public center: vec2,
- public direction: vec2,
- public color: vec3,
- public intensity: number
+ center: vec2,
+ color: vec3,
+ intensity: number,
+ public direction: vec2
) {
- super();
- }
-
- public distance(_: vec2): number {
- return 0;
+ super(center, color, intensity);
}
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
return {
- center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
+ ...super.getObjectToSerialize(transform2d, transform1d),
direction: this.direction,
- intensity: this.intensity,
- color: this.color,
};
}
}
diff --git a/src/drawables/lights/light-drawable.ts b/src/drawables/lights/light-drawable.ts
new file mode 100644
index 0000000..49e0aee
--- /dev/null
+++ b/src/drawables/lights/light-drawable.ts
@@ -0,0 +1,26 @@
+import { mat2d, vec2, vec3 } from 'gl-matrix';
+import { Drawable } from '../../main';
+
+export class LightDrawable extends Drawable {
+ protected lightnessRatio = 1;
+
+ constructor(public center: vec2, public color: vec3, public intensity: number) {
+ super();
+ }
+
+ public setLightnessRatio(ratio: number) {
+ this.lightnessRatio = ratio;
+ }
+
+ public minDistance(target: vec2): number {
+ return vec2.dist(this.center, target);
+ }
+
+ protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
+ return {
+ center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
+ color: this.color,
+ intensity: this.intensity * this.lightnessRatio,
+ };
+ }
+}
diff --git a/src/drawables/shapes/circle.ts b/src/drawables/shapes/circle.ts
index 76c9bd5..051db2d 100644
--- a/src/drawables/shapes/circle.ts
+++ b/src/drawables/shapes/circle.ts
@@ -36,7 +36,7 @@ export class Circle extends Drawable {
super();
}
- public distance(target: vec2): number {
+ public minDistance(target: vec2): number {
return vec2.dist(this.center, target) - this.radius;
}
diff --git a/src/drawables/shapes/inverted-tunnel.ts b/src/drawables/shapes/inverted-tunnel.ts
index 0c278f1..3a02434 100644
--- a/src/drawables/shapes/inverted-tunnel.ts
+++ b/src/drawables/shapes/inverted-tunnel.ts
@@ -60,7 +60,7 @@ export class InvertedTunnel extends Drawable {
super();
}
- public distance(target: vec2): number {
+ public minDistance(target: vec2): number {
const toFromDelta = vec2.subtract(vec2.create(), this.to, this.from);
const targetFromDelta = vec2.subtract(vec2.create(), target, this.from);
diff --git a/src/drawables/shapes/tunnel.ts b/src/drawables/shapes/tunnel.ts
index f01b013..3fe837a 100644
--- a/src/drawables/shapes/tunnel.ts
+++ b/src/drawables/shapes/tunnel.ts
@@ -65,7 +65,7 @@ export class Tunnel extends Drawable {
super();
}
- public distance(target: vec2): number {
+ public minDistance(target: vec2): number {
const toFromDelta = vec2.subtract(vec2.create(), this.to, this.from);
const targetFromDelta = vec2.subtract(vec2.create(), target, this.from);
diff --git a/src/graphics/rendering/rendering-pass.ts b/src/graphics/rendering/render-pass/distance-render-pass.ts
similarity index 58%
rename from src/graphics/rendering/rendering-pass.ts
rename to src/graphics/rendering/render-pass/distance-render-pass.ts
index 8866825..b48cf03 100644
--- a/src/graphics/rendering/rendering-pass.ts
+++ b/src/graphics/rendering/render-pass/distance-render-pass.ts
@@ -1,33 +1,13 @@
import { vec2 } from 'gl-matrix';
-import { Drawable } from '../../drawables/drawable';
-import { DrawableDescriptor } from '../../drawables/drawable-descriptor';
-import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer';
-import { UniformArrayAutoScalingProgram } from '../graphics-library/program/uniform-array-autoscaling-program';
-import { Insights } from './insights';
-import { RenderingPassName } from './rendering-pass-name';
+import { Drawable } from '../../../drawables/drawable';
+import { Insights } from '../insights';
+import { RenderPass } from './render-pass';
-export class RenderingPass {
+export class DistanceRenderPass extends RenderPass {
public tileMultiplier = 8;
public isWorldInverted = false;
private drawables: Array = [];
- private program: UniformArrayAutoScalingProgram;
-
- constructor(
- gl: WebGL2RenderingContext,
- private frame: FrameBuffer,
- private name: RenderingPassName
- ) {
- this.program = new UniformArrayAutoScalingProgram(gl);
- }
-
- public async initialize(
- shaderSources: [string, string],
- descriptors: Array,
- substitutions: { [name: string]: any } = {}
- ): Promise {
- await this.program.initialize(shaderSources, descriptors, substitutions);
- }
public addDrawable(drawable: Drawable) {
this.drawables.push(drawable);
@@ -72,7 +52,7 @@ export class RenderingPass {
);
const drawablesNearTile = this.drawables.filter(
- (d) => d.distance(tileCenterWorldCoordinates) < 2 * worldR
+ (d) => d.minDistance(tileCenterWorldCoordinates) < 2 * worldR
);
drawnDrawablesCount += drawablesNearTile.length;
@@ -89,18 +69,19 @@ export class RenderingPass {
}
}
- Insights.setValue(['render pass', this.name, 'all drawables'], this.drawables.length);
- Insights.setValue(['render pass', this.name, 'tile count'], this.tileMultiplier ** 2);
Insights.setValue(
- ['render pass', this.name, 'rendered drawables'],
+ ['render pass', 'distance', 'all drawables'],
+ this.drawables.length
+ );
+ Insights.setValue(
+ ['render pass', 'distance', 'tile count'],
+ this.tileMultiplier ** 2
+ );
+ Insights.setValue(
+ ['render pass', 'distance', 'rendered drawables'],
drawnDrawablesCount / this.tileMultiplier ** 2
);
this.drawables = [];
}
-
- public destroy(): void {
- this.frame.destroy();
- this.program.destroy();
- }
}
diff --git a/src/graphics/rendering/render-pass/lights-render-pass.ts b/src/graphics/rendering/render-pass/lights-render-pass.ts
new file mode 100644
index 0000000..1dd560f
--- /dev/null
+++ b/src/graphics/rendering/render-pass/lights-render-pass.ts
@@ -0,0 +1,58 @@
+import { vec2 } from 'gl-matrix';
+import { LightDrawable } from '../../../drawables/lights/light-drawable';
+import { clamp01 } from '../../../helper/clamp';
+import { Insights } from '../insights';
+import { RenderPass } from './render-pass';
+
+export class LightsRenderPass extends RenderPass {
+ public lightPhaseOutLength = 400;
+ private drawables: Array = [];
+
+ public addDrawable(drawable: LightDrawable) {
+ this.drawables.push(drawable);
+ }
+
+ public render(commonUniforms: any, inputTexture?: WebGLTexture) {
+ this.frame.bindAndClear(inputTexture);
+
+ const tileCenterWorldCoordinates = vec2.transformMat2d(
+ vec2.create(),
+ vec2.fromValues(0.5, 0.5),
+ commonUniforms.uvToWorld
+ );
+
+ const drawablesNearTile = this.drawables.filter((l) => {
+ const d = vec2.subtract(
+ vec2.create(),
+ [
+ Math.abs(l.center.x - tileCenterWorldCoordinates.x),
+ Math.abs(l.center.y - tileCenterWorldCoordinates.y),
+ ],
+ vec2.scale(vec2.create(), commonUniforms.worldAreaInView, 0.5)
+ );
+ const distance =
+ vec2.length([Math.max(d.x, 0), Math.max(d.y, 0)]) +
+ Math.min(Math.max(d.x, d.y), 0.0);
+ l.setLightnessRatio(clamp01(1 - distance / this.lightPhaseOutLength));
+
+ return distance < this.lightPhaseOutLength;
+ });
+
+ drawablesNearTile.forEach((p) =>
+ p.serializeToUniforms(
+ commonUniforms,
+ commonUniforms.transformWorldToNDC,
+ commonUniforms.scaleWorldLengthToNDC
+ )
+ );
+
+ this.program.draw(commonUniforms);
+
+ Insights.setValue(
+ ['render pass', 'lights', 'rendered drawables'],
+ drawablesNearTile.length
+ );
+
+ this.drawables = [];
+ }
+}
diff --git a/src/graphics/rendering/render-pass/render-pass.ts b/src/graphics/rendering/render-pass/render-pass.ts
new file mode 100644
index 0000000..c252e9b
--- /dev/null
+++ b/src/graphics/rendering/render-pass/render-pass.ts
@@ -0,0 +1,26 @@
+import { DrawableDescriptor } from '../../../drawables/drawable-descriptor';
+import { FrameBuffer } from '../../graphics-library/frame-buffer/frame-buffer';
+import { UniformArrayAutoScalingProgram } from '../../graphics-library/program/uniform-array-autoscaling-program';
+
+export abstract class RenderPass {
+ protected program: UniformArrayAutoScalingProgram;
+
+ constructor(gl: WebGL2RenderingContext, protected frame: FrameBuffer) {
+ this.program = new UniformArrayAutoScalingProgram(gl);
+ }
+
+ public async initialize(
+ shaderSources: [string, string],
+ descriptors: Array,
+ substitutions: { [name: string]: any } = {}
+ ): Promise {
+ await this.program.initialize(shaderSources, descriptors, substitutions);
+ }
+
+ public abstract render(commonUniforms: any, inputTexture?: WebGLTexture): void;
+
+ public destroy(): void {
+ this.frame.destroy();
+ this.program.destroy();
+ }
+}
diff --git a/src/graphics/rendering/rendering-pass-name.ts b/src/graphics/rendering/rendering-pass-name.ts
deleted file mode 100644
index 5d593c6..0000000
--- a/src/graphics/rendering/rendering-pass-name.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export enum RenderingPassName {
- distance = 'distance',
- pixel = 'pixel',
-}
diff --git a/src/graphics/rendering/webgl2-renderer.ts b/src/graphics/rendering/webgl2-renderer.ts
index 5f04b1a..91c37cd 100644
--- a/src/graphics/rendering/webgl2-renderer.ts
+++ b/src/graphics/rendering/webgl2-renderer.ts
@@ -1,6 +1,7 @@
import { vec2, vec3 } from 'gl-matrix';
import { Drawable } from '../../drawables/drawable';
import { DrawableDescriptor } from '../../drawables/drawable-descriptor';
+import { LightDrawable } from '../../drawables/lights/light-drawable';
import { msToString } from '../../helper/ms-to-string';
import { DefaultFrameBuffer } from '../graphics-library/frame-buffer/default-frame-buffer';
import { IntermediateFrameBuffer } from '../graphics-library/frame-buffer/intermediate-frame-buffer';
@@ -9,9 +10,9 @@ import { WebGlStopwatch } from '../graphics-library/helper/stopwatch';
import { ParallelCompiler } from '../graphics-library/parallel-compiler';
import { FpsAutoscaler } from './fps-autoscaler';
import { Insights } from './insights';
+import { DistanceRenderPass } from './render-pass/distance-render-pass';
+import { LightsRenderPass } from './render-pass/lights-render-pass';
import { Renderer } from './renderer';
-import { RenderingPass } from './rendering-pass';
-import { RenderingPassName } from './rendering-pass-name';
import { RuntimeSettings } from './settings/runtime-settings';
import { StartupSettings } from './settings/startup-settings';
import distanceFragmentShader from './shaders/distance-fs.glsl';
@@ -20,15 +21,14 @@ import lightsFragmentShader from './shaders/shading-fs.glsl';
import lightsVertexShader from './shaders/shading-vs.glsl';
import { UniformsProvider } from './uniforms-provider';
-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 distancePass: DistanceRenderPass;
+ private lightsPass: LightsRenderPass;
private lightingFrameBuffer: DefaultFrameBuffer;
- private passes: Passes;
private autoscaler: FpsAutoscaler;
private applyRuntimeSettings: {
@@ -39,12 +39,10 @@ export class WebGl2Renderer implements Renderer {
this.lightingFrameBuffer.enableHighDpiRendering = v;
},
tileMultiplier: (v) => {
- this.passes[RenderingPassName.distance].tileMultiplier = v;
- this.passes[RenderingPassName.pixel].tileMultiplier = 1;
+ this.distancePass.tileMultiplier = v;
},
isWorldInverted: (v) => {
- this.passes[RenderingPassName.distance].isWorldInverted = v;
- this.passes[RenderingPassName.pixel].isWorldInverted = v;
+ this.distancePass.isWorldInverted = v;
},
shadowLength: (v) => {
this.uniformsProvider.shadowLength = v;
@@ -75,9 +73,8 @@ export class WebGl2Renderer implements Renderer {
this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl);
this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl);
- this.passes = this.createPasses();
-
- this.passes.pixel.tileMultiplier = 1;
+ this.distancePass = new DistanceRenderPass(this.gl, this.distanceFieldFrameBuffer);
+ this.lightsPass = new LightsRenderPass(this.gl, this.lightingFrameBuffer);
this.uniformsProvider = new UniformsProvider(this.gl);
@@ -88,21 +85,6 @@ export class WebGl2Renderer implements Renderer {
});
}
- private createPasses(): Passes {
- return {
- [RenderingPassName.distance]: new RenderingPass(
- this.gl,
- this.distanceFieldFrameBuffer,
- RenderingPassName.distance
- ),
- [RenderingPassName.pixel]: new RenderingPass(
- this.gl,
- this.lightingFrameBuffer,
- RenderingPassName.pixel
- ),
- };
- }
-
public async initialize(
palette: Array,
settingsOverrides: Partial
@@ -112,14 +94,14 @@ export class WebGl2Renderer implements Renderer {
const promises: Array> = [];
promises.push(
- this.passes[RenderingPassName.distance].initialize(
+ this.distancePass.initialize(
[distanceVertexShader, distanceFragmentShader],
this.descriptors.filter(WebGl2Renderer.hasSdf)
)
);
promises.push(
- this.passes[RenderingPassName.pixel].initialize(
+ this.lightsPass.initialize(
[lightsVertexShader, lightsFragmentShader],
this.descriptors.filter((d) => !WebGl2Renderer.hasSdf(d)),
{
@@ -150,9 +132,9 @@ export class WebGl2Renderer implements Renderer {
public addDrawable(drawable: Drawable): void {
if (WebGl2Renderer.hasSdf((drawable.constructor as typeof Drawable).descriptor)) {
- this.passes[RenderingPassName.distance].addDrawable(drawable);
+ this.distancePass.addDrawable(drawable);
} else {
- this.passes[RenderingPassName.pixel].addDrawable(drawable);
+ this.lightsPass.addDrawable(drawable as LightDrawable);
}
}
@@ -193,10 +175,8 @@ export class WebGl2Renderer implements Renderer {
shadingNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()),
};
- this.passes[RenderingPassName.distance].render(
- this.uniformsProvider.getUniforms(common)
- );
- this.passes[RenderingPassName.pixel].render(
+ this.distancePass.render(this.uniformsProvider.getUniforms(common));
+ this.lightsPass.render(
this.uniformsProvider.getUniforms(common),
this.distanceFieldFrameBuffer.colorTexture
);
@@ -219,7 +199,7 @@ export class WebGl2Renderer implements Renderer {
}
public destroy(): void {
- this.passes.distance.destroy();
- this.passes.pixel.destroy();
+ this.distancePass.destroy();
+ this.lightsPass.destroy();
}
}
diff --git a/src/main.ts b/src/main.ts
index fb53bea..0154567 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -5,6 +5,7 @@ import { Renderer } from './graphics/rendering/renderer';
import { StartupSettings } from './graphics/rendering/settings/startup-settings';
import { WebGl2Renderer } from './graphics/rendering/webgl2-renderer';
import { applyArrayPlugins } from './helper/array';
+
export { Drawable } from './drawables/drawable';
export { DrawableDescriptor } from './drawables/drawable-descriptor';
export { CircleLight } from './drawables/lights/circle-light';
@@ -13,7 +14,6 @@ export { Circle } from './drawables/shapes/circle';
export { InvertedTunnel } from './drawables/shapes/inverted-tunnel';
export { Tunnel } from './drawables/shapes/tunnel';
export { Renderer } from './graphics/rendering/renderer';
-export { RenderingPassName } from './graphics/rendering/rendering-pass-name';
declare global {
interface Array {
diff --git a/tsconfig.json b/tsconfig.json
index 48b6aef..0323388 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,7 @@
"sourceMap": true,
"declaration": true,
"declarationMap": true,
- "target": "es6",
+ "target": "ES2017",
"esModuleInterop": true,
"strict": true,
"experimentalDecorators": true,
diff --git a/webpack.config.js b/webpack.config.js
index 217c655..749d6de 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -14,7 +14,7 @@ module.exports = {
output: {
path: PATHS.bundles,
filename: '[name].js',
- library: 'SDF2D',
+ library: 'sdf-2d',
libraryTarget: 'umd',
umdNamedDefine: true,
},
@@ -23,8 +23,12 @@ module.exports = {
aggregateTimeout: 600,
ignored: /node_modules/,
},
+ externals: {
+ 'gl-matrix': 'gl-matrix',
+ },
optimization: {
minimize: true,
+ usedExports: true,
minimizer: [
new TerserJSPlugin({
sourceMap: true,