From 9062ae04a36847719fa537eebbab5355f9f685f3 Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Mon, 19 Oct 2020 12:22:08 +0200 Subject: [PATCH] Update to use new SDF2D version --- package.json | 2 +- src/helper/pretty-print.ts | 2 +- src/index.html | 2 +- src/index.ts | 41 +------------ src/scenes/blob/blob-scene.ts | 75 +++++++++++------------ src/scenes/metaball/metaball-scene.ts | 73 ++++++++++------------- src/scenes/metaball/metaball.ts | 4 +- src/scenes/rain/droplet.ts | 4 +- src/scenes/rain/rain-scene.ts | 65 ++++++++++---------- src/scenes/scene.ts | 4 +- src/scenes/tunnel-scene.ts | 86 +++++++++++++-------------- src/settings.ts | 3 + src/styles/index.scss | 7 ++- src/styles/mixins.scss | 1 + 14 files changed, 160 insertions(+), 209 deletions(-) create mode 100644 src/settings.ts diff --git a/package.json b/package.json index c3daa84..e48c9b1 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "resolve-url-loader": "^3.1.1", "sass": "^1.26.3", "sass-loader": "^9.0.3", - "sdf-2d": "^0.5.0", + "sdf-2d": "^0.6.0", "source-map-loader": "^1.1.0", "svg-url-loader": "^6.0.0", "terser-webpack-plugin": "^2.3.8", diff --git a/src/helper/pretty-print.ts b/src/helper/pretty-print.ts index 704a6fc..48fd593 100644 --- a/src/helper/pretty-print.ts +++ b/src/helper/pretty-print.ts @@ -1,4 +1,4 @@ export const prettyPrint = (o: any): string => - JSON.stringify(o, (_, v) => (v.toFixed ? Number(v.toFixed(3)) : v), ' ') + JSON.stringify(o, (_, v) => (v?.toFixed ? Number(v.toFixed(3)) : v), ' ') .replace(/("|,|{|^\n)/g, '') .replace(/(\W*}\n?)+/g, '\n\n'); diff --git a/src/index.html b/src/index.html index cf390e1..2b8ae3e 100644 --- a/src/index.html +++ b/src/index.html @@ -25,7 +25,7 @@

SDF-2D

- logo + logo
diff --git a/src/index.ts b/src/index.ts index 50108da..c2ff4ce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,22 +7,18 @@ import '../static/logo-white.svg'; import '../static/no-change/404.html'; import '../static/no-change/robots.txt'; import '../static/og-image.png'; -import { DeltaTimeCalculator } from './helper/delta-time-calculator'; import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines'; import { BlobScene } from './scenes/blob/blob-scene'; import { MetaballScene } from './scenes/metaball/metaball-scene'; import { RainScene } from './scenes/rain/rain-scene'; -import { Scene } from './scenes/scene'; import { TunnelScene } from './scenes/tunnel-scene'; import './styles/index.scss'; const scenes = [TunnelScene, MetaballScene, RainScene, BlobScene]; -const sceneIntervalInSeconds = 8; glMatrix.setMatrixArrayType(Array); removeUnnecessaryOutlines(); -const deltaTimeCalculator = new DeltaTimeCalculator(); const canvas = document.querySelector('canvas') as HTMLCanvasElement; const errorText = document.querySelector('#error-text') as HTMLParamElement; const errorsContainer = document.querySelector('#errors-container') as HTMLDivElement; @@ -43,44 +39,13 @@ const handleTextToggle = () => { toggleButton.addEventListener('click', handleTextToggle); handleTextToggle(); -const handleScene = async ( - currentScene: Scene, - NextSceneConstructor: new () => Scene -): Promise => { - let triggerIsOver: () => void; - const isOver = new Promise((resolve) => (triggerIsOver = resolve)); - let timeSinceStart = 0; - - const handleFrame = (currentTime: DOMHighResTimeStamp) => { - const deltaTime = deltaTimeCalculator.getNextDeltaTime(currentTime); - - currentScene.drawNextFrame(currentTime, deltaTime); - - if ((timeSinceStart += deltaTime) > sceneIntervalInSeconds * 1000) { - triggerIsOver(); - } else { - requestAnimationFrame(handleFrame); - } - }; - - requestAnimationFrame(handleFrame); - - await isOver; - currentScene.destroy(); - - const nextScene = new NextSceneConstructor(); - await nextScene.initialize(canvas, overlay); - - return nextScene; -}; - const main = async () => { try { let i = 0; - let currentScene: Scene = new scenes[i++](); - await currentScene.initialize(canvas, overlay); for (;;) { - currentScene = await handleScene(currentScene, scenes[i++ % scenes.length]); + const currentScene = new scenes[i++ % scenes.length](); + + await currentScene.run(canvas, overlay); } } catch (e) { console.error(e); diff --git a/src/scenes/blob/blob-scene.ts b/src/scenes/blob/blob-scene.ts index f668a62..453cde1 100644 --- a/src/scenes/blob/blob-scene.ts +++ b/src/scenes/blob/blob-scene.ts @@ -1,65 +1,66 @@ import { vec2 } from 'gl-matrix'; -import { CircleFactory, CircleLight, compile, Renderer, rgb, rgb255 } from 'sdf-2d'; +import { CircleFactory, CircleLight, Renderer, rgb, rgb255, runAnimation } from 'sdf-2d'; import { prettyPrint } from '../../helper/pretty-print'; +import { settings } from '../../settings'; import { Scene } from '../scene'; import { Blob } from './blob'; const Circle = CircleFactory(rgb255(119, 143, 120)); export class BlobScene implements Scene { - private renderer: Renderer; private canvas: HTMLCanvasElement; private overlay: HTMLDivElement; - public async initialize( - canvas: HTMLCanvasElement, - overlay: HTMLDivElement - ): Promise { + public async run(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise { this.canvas = canvas; this.overlay = overlay; - this.renderer = await compile(canvas, [ - Circle.descriptor, - { - ...CircleLight.descriptor, - shaderCombinationSteps: [0, 1, 2], - }, - Blob.descriptor, - ]); - - this.renderer.setRuntimeSettings({ - ambientLight: rgb255(89, 25, 115), - colorPalette: [ - rgb255(0, 0, 0), - rgb255(119, 143, 120), - rgb255(119, 143, 120), - rgb255(224, 96, 126), - ], - }); const { width, height } = this.canvas.getBoundingClientRect(); const length = vec2.length([width, height]); this.blob = new Blob([width / 2, -length / 4 + length / 2]); + + await runAnimation( + canvas, + [ + Circle.descriptor, + { + ...CircleLight.descriptor, + shaderCombinationSteps: [0, 1, 2], + }, + Blob.descriptor, + ], + this.drawNextFrame.bind(this), + {}, + { + ambientLight: rgb255(89, 25, 115), + enableHighDpiRendering: true, + colorPalette: [ + rgb255(0, 0, 0), + rgb255(119, 143, 120), + rgb255(119, 143, 120), + rgb255(224, 96, 126), + ], + } + ); } private blob: Blob; - private deltaSinceStart = 0; - public drawNextFrame( + private drawNextFrame( + renderer: Renderer, currentTime: DOMHighResTimeStamp, deltaTime: DOMHighResTimeStamp - ): void { + ): boolean { const { width, height } = this.canvas.getBoundingClientRect(); - this.deltaSinceStart += deltaTime; - this.renderer.setViewArea([0, height], [width, height]); + renderer.setViewArea([0, height], [width, height]); - this.renderer.autoscaleQuality(deltaTime); - this.overlay.innerText = prettyPrint(this.renderer.insights); + this.overlay.innerText = prettyPrint(renderer.insights); const length = vec2.length([width, height]); - const q = (this.deltaSinceStart % 8000) / 4300; - this.blob.animate(this.deltaSinceStart); + const q = (currentTime % 8000) / 4300; + this.blob.animate(currentTime); [ new Circle([width / 2, -length / 4], length / 2), this.blob, @@ -79,12 +80,8 @@ export class BlobScene implements Scene { rgb(0, 0.8, 1), 1 ), - ].forEach((d) => this.renderer.addDrawable(d)); + ].forEach((d) => renderer.addDrawable(d)); - this.renderer.renderDrawables(); - } - - public destroy(): void { - this.renderer.destroy(); + return currentTime < settings.sceneTimeInMilliseconds; } } diff --git a/src/scenes/metaball/metaball-scene.ts b/src/scenes/metaball/metaball-scene.ts index f1f0926..9892663 100644 --- a/src/scenes/metaball/metaball-scene.ts +++ b/src/scenes/metaball/metaball-scene.ts @@ -1,45 +1,20 @@ import { vec2 } from 'gl-matrix'; -import { compile, Flashlight, Renderer, rgb, rgb255 } from 'sdf-2d'; +import { Flashlight, Renderer, rgb, rgb255, runAnimation } from 'sdf-2d'; import { prettyPrint } from '../../helper/pretty-print'; import { Random } from '../../helper/random'; +import { settings } from '../../settings'; import { Scene } from '../scene'; import { Metaball, MetaCircle } from './metaball'; export class MetaballScene implements Scene { private circles: Array = []; - private renderer: Renderer; private canvas: HTMLCanvasElement; private overlay: HTMLDivElement; - public async initialize( - canvas: HTMLCanvasElement, - overlay: HTMLDivElement - ): Promise { + public async run(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise { this.canvas = canvas; this.overlay = overlay; - this.renderer = await compile(canvas, [ - { - ...Flashlight.descriptor, - shaderCombinationSteps: [0, 2], - }, - { - ...MetaCircle.descriptor, - shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16], - }, - ]); - - this.renderer.setRuntimeSettings({ - ambientLight: rgb(0.1, 0.1, 0.3), - colorPalette: [ - rgb(1, 1, 1), - rgb(1, 1, 1), - rgb(1, 1, 1), - rgb(1, 1, 1), - rgb(1, 1, 0), - rgb255(186, 59, 70), - ], - }); for (let i = 0; i < 16; i++) { this.circles.push( @@ -55,26 +30,46 @@ export class MetaballScene implements Scene { ) ); } + + await runAnimation( + canvas, + [ + { + ...Flashlight.descriptor, + shaderCombinationSteps: [0, 2], + }, + { + ...MetaCircle.descriptor, + shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16], + }, + ], + this.drawNextFrame.bind(this), + {}, + { + ambientLight: rgb(0.1, 0.1, 0.3), + enableHighDpiRendering: true, + } + ); } - public drawNextFrame( + private drawNextFrame( + renderer: Renderer, currentTime: DOMHighResTimeStamp, deltaTime: DOMHighResTimeStamp - ): void { + ): boolean { const { width, height } = this.canvas.getBoundingClientRect(); const viewAreaWidth = width / Math.max(width, height); const viewAreaHeight = height / Math.max(width, height); - this.renderer.setViewArea( + renderer.setViewArea( vec2.fromValues(0, viewAreaHeight), vec2.fromValues(viewAreaWidth, viewAreaHeight) ); - this.renderer.autoscaleQuality(deltaTime); - this.overlay.innerText = prettyPrint(this.renderer.insights); + this.overlay.innerText = prettyPrint(renderer.insights); this.circles.forEach((c) => { c.animate(currentTime / 2000, viewAreaWidth, viewAreaHeight); - this.renderer.addDrawable(c.shape); + renderer.addDrawable(c.shape); }); const light1 = new Flashlight( @@ -90,13 +85,9 @@ export class MetaballScene implements Scene { vec2.fromValues(-1, 1) ); - this.renderer.addDrawable(light1); - this.renderer.addDrawable(light2); + renderer.addDrawable(light1); + renderer.addDrawable(light2); - this.renderer.renderDrawables(); - } - - public destroy(): void { - this.renderer.destroy(); + return currentTime < settings.sceneTimeInMilliseconds; } } diff --git a/src/scenes/metaball/metaball.ts b/src/scenes/metaball/metaball.ts index e007a14..592dc2f 100644 --- a/src/scenes/metaball/metaball.ts +++ b/src/scenes/metaball/metaball.ts @@ -1,8 +1,8 @@ import { vec2 } from 'gl-matrix'; -import { MetaCircleFactory } from 'sdf-2d'; +import { MetaCircleFactory, rgb255 } from 'sdf-2d'; import { Random } from '../../helper/random'; -export const MetaCircle = MetaCircleFactory(5); +export const MetaCircle = MetaCircleFactory(rgb255(186, 59, 70)); export class Metaball { public shape = new MetaCircle(vec2.create(), Random.getRandomInRange(0.025, 0.075)); diff --git a/src/scenes/rain/droplet.ts b/src/scenes/rain/droplet.ts index c23c4ff..7f3c99f 100644 --- a/src/scenes/rain/droplet.ts +++ b/src/scenes/rain/droplet.ts @@ -1,8 +1,8 @@ import { vec2 } from 'gl-matrix'; -import { DropletFactory } from 'sdf-2d'; +import { DropletFactory, rgb } from 'sdf-2d'; import { Random } from '../../helper/random'; -export const Droplet = DropletFactory(1); +export const Droplet = DropletFactory(rgb(0.3, 1, 1)); export class DropletWrapper { public readonly drawable: InstanceType; diff --git a/src/scenes/rain/rain-scene.ts b/src/scenes/rain/rain-scene.ts index 84703c0..bf6bcc9 100644 --- a/src/scenes/rain/rain-scene.ts +++ b/src/scenes/rain/rain-scene.ts @@ -1,6 +1,7 @@ import { vec2 } from 'gl-matrix'; -import { CircleLight, compile, Renderer, rgb, rgb255 } from 'sdf-2d'; +import { CircleLight, Renderer, rgb, rgb255, runAnimation } from 'sdf-2d'; import { prettyPrint } from '../../helper/pretty-print'; +import { settings } from '../../settings'; import { Scene } from '../scene'; import { Droplet, DropletWrapper } from './droplet'; @@ -9,47 +10,47 @@ export class RainScene implements Scene { private light1: CircleLight = new CircleLight(vec2.create(), rgb255(184, 41, 255), 2); private light2: CircleLight = new CircleLight(vec2.create(), rgb255(255, 31, 109), 2); - private renderer: Renderer; private canvas: HTMLCanvasElement; private overlay: HTMLDivElement; - public async initialize( - canvas: HTMLCanvasElement, - overlay: HTMLDivElement - ): Promise { + public async run(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise { this.canvas = canvas; this.overlay = overlay; - this.renderer = await compile(canvas, [ - { - ...Droplet.descriptor, - shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16, 24], - }, - { - ...CircleLight.descriptor, - shaderCombinationSteps: [0, 2], - }, - ]); - - this.renderer.setRuntimeSettings({ - ambientLight: rgb(0.2, 0.2, 0.2), - colorPalette: [rgb(1, 1, 1), rgb(0.3, 1, 1), rgb(1, 1, 0), rgb(0.3, 1, 1)], - }); - for (let i = 0; i < (canvas.getBoundingClientRect().width / 800) * 20; i++) { this.droplets.push(new DropletWrapper()); } + + await runAnimation( + canvas, + [ + { + ...Droplet.descriptor, + shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16, 24], + }, + { + ...CircleLight.descriptor, + shaderCombinationSteps: [0, 2], + }, + ], + this.drawNextFrame.bind(this), + {}, + { + ambientLight: rgb(0.2, 0.2, 0.2), + enableHighDpiRendering: true, + } + ); } - public drawNextFrame( + private drawNextFrame( + renderer: Renderer, currentTime: DOMHighResTimeStamp, deltaTime: DOMHighResTimeStamp - ): void { + ): boolean { const { width, height } = this.canvas.getBoundingClientRect(); - this.renderer.setViewArea(vec2.fromValues(0, height), vec2.fromValues(width, height)); - this.renderer.autoscaleQuality(deltaTime); - this.overlay.innerText = prettyPrint(this.renderer.insights); + renderer.setViewArea(vec2.fromValues(0, height), vec2.fromValues(width, height)); + this.overlay.innerText = prettyPrint(renderer.insights); - const viewAreaSize = this.renderer.viewAreaSize; + const viewAreaSize = renderer.viewAreaSize; vec2.set(this.light1.center, 0, viewAreaSize.y / 2); vec2.set(this.light2.center, viewAreaSize.x, viewAreaSize.y / 2); @@ -57,13 +58,9 @@ export class RainScene implements Scene { this.droplets.forEach((d) => d.animate(currentTime, viewAreaSize)); [...this.droplets.map((d) => d.drawable), this.light1, this.light2].forEach((d) => - this.renderer.addDrawable(d) + renderer.addDrawable(d) ); - this.renderer.renderDrawables(); - } - - public destroy(): void { - this.renderer.destroy(); + return currentTime < settings.sceneTimeInMilliseconds; } } diff --git a/src/scenes/scene.ts b/src/scenes/scene.ts index d99e786..43093d5 100644 --- a/src/scenes/scene.ts +++ b/src/scenes/scene.ts @@ -1,5 +1,3 @@ export interface Scene { - initialize(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise; - drawNextFrame(currentTime: DOMHighResTimeStamp, deltaTime: DOMHighResTimeStamp): void; - destroy(): void; + run(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise; } diff --git a/src/scenes/tunnel-scene.ts b/src/scenes/tunnel-scene.ts index c83d9e5..c18c595 100644 --- a/src/scenes/tunnel-scene.ts +++ b/src/scenes/tunnel-scene.ts @@ -1,24 +1,24 @@ import { vec2, vec3 } from 'gl-matrix'; import { CircleLight, - compile, FilteringOptions, InvertedTunnelFactory, Renderer, renderNoise, rgb, + runAnimation, WrapOptions, } from 'sdf-2d'; import { clamp } from '../helper/clamp'; import { last } from '../helper/last'; import { prettyPrint } from '../helper/pretty-print'; import { Random } from '../helper/random'; +import { settings } from '../settings'; import { Scene } from './scene'; const InvertedTunnel = InvertedTunnelFactory(3); export class TunnelScene implements Scene { - private renderer: Renderer; private canvas: HTMLCanvasElement; private overlay: HTMLDivElement; @@ -68,73 +68,69 @@ export class TunnelScene implements Scene { } } - public async initialize( - canvas: HTMLCanvasElement, - overlay: HTMLDivElement - ): Promise { + public async run(canvas: HTMLCanvasElement, overlay: HTMLDivElement): Promise { const noiseTexture = await renderNoise([1024, 1], 15, 1); this.canvas = canvas; this.overlay = overlay; - this.renderer = await compile(canvas, [ - { - ...InvertedTunnel.descriptor, - shaderCombinationSteps: [0, 1, 2, 4, 8, 12], - }, - { - ...CircleLight.descriptor, - shaderCombinationSteps: [0, 1, 2, 3, 4, 5, 6, 7], - }, - ]); - - this.renderer.setRuntimeSettings({ - isWorldInverted: true, - ambientLight: rgb(0.35, 0.1, 0.45), - colorPalette: [rgb(0.4, 0.5, 0.6), rgb(0, 0, 0), rgb(0, 0, 0), rgb(0, 0, 0)], - textures: { - noiseTexture: { - source: noiseTexture, - overrides: { - maxFilter: FilteringOptions.LINEAR, - wrapS: WrapOptions.MIRRORED_REPEAT, - }, - }, - }, - }); for (let i = 0; i < 200; i++) { this.generateTunnel(); } + + await runAnimation( + canvas, + [ + { + ...InvertedTunnel.descriptor, + shaderCombinationSteps: [0, 1, 2, 4, 8, 12], + }, + { + ...CircleLight.descriptor, + shaderCombinationSteps: [0, 1, 2, 3, 4, 5, 6, 7], + }, + ], + this.drawNextFrame.bind(this), + { lightPenetrationRatio: 0.5 }, + { + isWorldInverted: true, + enableHighDpiRendering: true, + ambientLight: rgb(0.35, 0.1, 0.45), + colorPalette: [rgb(0.4, 0.5, 0.6), rgb(0, 0, 0), rgb(0, 0, 0), rgb(0, 0, 0)], + textures: { + noiseTexture: { + source: noiseTexture, + overrides: { + maxFilter: FilteringOptions.LINEAR, + wrapS: WrapOptions.MIRRORED_REPEAT, + }, + }, + }, + } + ); } private deltaSinceStart = 0; - public drawNextFrame( + private drawNextFrame( + renderer: Renderer, currentTime: DOMHighResTimeStamp, deltaTime: DOMHighResTimeStamp - ): void { + ): boolean { const { width, height } = this.canvas.getBoundingClientRect(); this.deltaSinceStart += deltaTime; const startX = this.deltaSinceStart / 3; const endX = startX + width; - this.renderer.setViewArea( - vec2.fromValues(startX, height), - vec2.fromValues(width, height) - ); + renderer.setViewArea(vec2.fromValues(startX, height), vec2.fromValues(width, height)); - this.renderer.autoscaleQuality(deltaTime); - this.overlay.innerText = prettyPrint(this.renderer.insights); + this.overlay.innerText = prettyPrint(renderer.insights); [ ...this.tunnels.filter( (t) => startX < t.to.x + t.toRadius && t.from.x - t.fromRadius <= endX ), ...this.lights, - ].forEach((d) => this.renderer.addDrawable(d)); + ].forEach((d) => renderer.addDrawable(d)); - this.renderer.renderDrawables(); - } - - public destroy(): void { - this.renderer.destroy(); + return currentTime < settings.sceneTimeInMilliseconds; } } diff --git a/src/settings.ts b/src/settings.ts new file mode 100644 index 0000000..3234bb3 --- /dev/null +++ b/src/settings.ts @@ -0,0 +1,3 @@ +export const settings = { + sceneTimeInMilliseconds: 7000, +}; diff --git a/src/styles/index.scss b/src/styles/index.scss index 3c435b8..133c215 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -66,12 +66,15 @@ body { #overlay { right: 0; - font-size: 0.75rem; - white-space: pre; + white-space: pre-wrap; + overflow-wrap: break-word; font-family: 'Lucida Console', Monaco, monospace; + font-size: 0.75rem; + max-width: 400px; @media (max-width: $breakpoint) { font-size: 0.6rem; + max-width: 200px; } } diff --git a/src/styles/mixins.scss b/src/styles/mixins.scss index e119c57..93fefb4 100644 --- a/src/styles/mixins.scss +++ b/src/styles/mixins.scss @@ -1,5 +1,6 @@ @mixin card { backdrop-filter: blur(16px); + background-color: rgba(0, 0, 0, 0.15); border: 2px solid white; border-radius: 12px;