diff --git a/src/main.mjs b/src/main.mjs index 50ed004..541e21f 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -1,9 +1,11 @@ import { Thread, supportThreads } from "./utils/workerUtils.mjs"; import Renderer from "./modules/renderer/renderer.mjs"; +import Noise from '../libs/alea.mjs' +import Delaunator from 'https://cdn.skypack.dev/delaunator@5.0.0'; (async function() { - globalThis.DEBUG = localStorage.getItem("debug"); + globalThis.DEBUG = !!localStorage.getItem("debug"); globalThis.VERBOSE = DEBUG && localStorage.getItem("verbose"); globalThis.TIMINGS = DEBUG && localStorage.getItem("timings"); globalThis.RELEASE = !DEBUG; @@ -11,15 +13,17 @@ import Renderer from "./modules/renderer/renderer.mjs"; const thread = new Thread("./workers/base.mjs", "model", true); await thread.setup(); - const settings = { x: 200, y: 200, seed: 0, jitter: 0.5, width: window.innerWidth, height: window.innerHeight }; - await thread.model.generatePoints(settings); - await thread.model.generateTriangles(settings); + //await new Promise(r => setTimeout(r, 3000)); - const delaunay = await thread.debug.getDelaunay(); - console.log(delaunay); + const settings = { model: { x: 50, y: 25, seed: 0, jitter: 0.2, }, view: { width: window.innerWidth, height: window.innerHeight, }, }; + await thread.global.updateSettings(settings); - const view = new Float32Array(await thread.view.lerpToViewport(settings)); + await thread.model.generateTriangles(); + + const view = await thread.view.lerpToViewport(); + + const debug = await thread.debug.getAll(); Renderer.init(); - Renderer.initGrid(view, settings); + Renderer.initGrid(view.position, view.vertices); })(); \ No newline at end of file diff --git a/src/modules/renderer/renderer.mjs b/src/modules/renderer/renderer.mjs index 183ce95..f00b334 100644 --- a/src/modules/renderer/renderer.mjs +++ b/src/modules/renderer/renderer.mjs @@ -23,8 +23,11 @@ class Renderer this._width = window.innerWidth; this._height = window.innerHeight; + this._clock = new Three.Clock(); this._scene = new Three.Scene(); - this._camera = new Three.OrthographicCamera(this._width / - 2, this._width / 2, this._height / 2, this._height / - 2, 0.1, 1000); + this._camera = new Three.OrthographicCamera(0, this._width, 0, this._height, 0.1, 1000); + this._camera.zoom = 0.98; + this._camera.updateProjectionMatrix(); Renderer.render(); } @@ -36,22 +39,30 @@ class Renderer this._rAF = requestAnimationFrame(Renderer.render.bind(Renderer)); + /*this._camera.zoom = 1 + (0.5 + Math.sin(this._clock.getElapsedTime()) / 2) * 5; + this._camera.updateProjectionMatrix();*/ + this._renderer.render(this._scene, this._camera); } - static async initGrid(grid, settings) //Share the list of cell and the resolution in the model with the view + static async initGrid(position, vertices) //Share the list of cell and the resolution in the model with the view { if(this._threaded) { //We can share the cells with the rendering thread because it will only be used as read-only to create the point data - await this._renderer_thread.view.lerpToView(grid, settings); + await this._renderer_thread.view.lerpToView(position, settings); } else { const geometry = new Three.BufferGeometry(); - geometry.setAttribute('position', new Three.Float32BufferAttribute(grid, 3)); + geometry.setIndex( new Three.Uint32BufferAttribute( vertices, 1 ) ); + geometry.setAttribute('position', new Three.Float32BufferAttribute( position, 3)); - const points = new Three.Points(geometry); - this._scene.add(points); + const material = new Three.MeshBasicMaterial( { color: 0xff0000, wireframe: true, } ); + const mesh = new Three.Mesh( geometry, material ); + this._scene.add( mesh ); + + /*const points = new Three.Points( geometry, new Three.PointsMaterial( { size: 3.0 } ) ); + this._scene.add( points );*/ } } } diff --git a/src/utils/workerUtils.mjs b/src/utils/workerUtils.mjs index e9c4611..51fa4c9 100644 --- a/src/utils/workerUtils.mjs +++ b/src/utils/workerUtils.mjs @@ -9,12 +9,13 @@ const Constants = { WAITING: 1, OK: 2, ERROR: 3, + LOG: 4, }, REQUEST: { WAKEUP: 1, SETUP: 2, CALL: 3, - TERMINATE: 4, + TERMINATE: 4 }, TRANSFERABLE: [ ArrayBuffer, @@ -101,6 +102,17 @@ function wrapper(thread, mod, fn) function onmessage(thread) { return function(e) { + if(e.data[0] === Constants.STATE.LOG) + { + globalThis.VERBOSE && console.debug(ret); + return; + } + if(e.data[0] === Constants.STATE.ERROR) + { + console.error(e.data[1]); + return; + } + const ret = parseReturns(e.data); globalThis.VERBOSE && console.debug(`Received message from ${thread._name} containing `, ret); globalThis.TIMINGS && thread._calledFn !== "" && console.timeEnd("Measuring " + thread._calledMod + "." + thread._calledFn); @@ -178,6 +190,16 @@ function send(ret) postMessage([Constants.STATE.OK, ret], getTransferables(ret)); } +function error(err) +{ + postMessage([Constants.STATE.ERROR, err]); +} + +function log(msg) +{ + postMessage([Constants.STATE.LOG, msg]); +} + class Process { static _isSetup = false; @@ -187,10 +209,11 @@ class Process Process._isSetup = true; Process._customFn = {}; globalThis.onmessage = Process.onmessage; + globalThis.onerror = Process.onerror; } static onmessage(e) { - globalThis.VERBOSE && console.debug(`Received `, e.data); + globalThis.VERBOSE && log(`Received `, e.data); if(e && e.data) { switch(e.data[0]) @@ -210,7 +233,14 @@ class Process case Constants.REQUEST.CALL: const args = e.data[3]; - send(Process._customFn[e.data[1]][e.data[2]](...args)); + try + { + send(Process._customFn[e.data[1]][e.data[2]](...args)); + } + catch(e) + { + error(e); + } break; case Constants.REQUEST.TERMINATE: diff --git a/src/workers/base.mjs b/src/workers/base.mjs index 2743af1..fd8f61b 100644 --- a/src/workers/base.mjs +++ b/src/workers/base.mjs @@ -4,33 +4,37 @@ import Delaunator from 'https://cdn.skypack.dev/delaunator@5.0.0'; let settings = {}; const model = {}; +const view = {}; -//Settings contains x, y, seed, jitter -function generatePoints(settings) +function lerp(a, b, x) { - const noise = Noise(settings.seed); - const grid = new Float32Array(settings.x * settings.y * 2); + return a + (b - a) * x; +} +function inverse_lerp(a, b, x) +{ + return (x - a) / (b - a); +} + +//Settings model contains x, y, seed, jitter +function generateTriangles() +{ + const rand = Noise(settings.model.seed); + const grid = new Float32Array(settings.model.x * settings.model.y * 2); for(let i = grid.length * 2 - 2; i > 0; i -= 2) { - const _x = i / 2 % settings.x; - const _y = (i / 2 - _x) / settings.x; + const _x = i / 2 % settings.model.x; + const _y = (i / 2 - _x) / settings.model.x; - grid[i] = _x + (noise() - 0.5) * settings.jitter; - grid[i + 1] = _y + (noise() - 0.5) * settings.jitter; + const angle = lerp(0, Math.PI * 2, rand()); + const magnitude = lerp(0, settings.model.jitter, rand()); + + grid[i ] = _x + Math.sin(angle) * magnitude; + grid[i + 1] = _y + Math.cos(angle) * magnitude; } - model.grid = grid; + model.delaunay = new Delaunator(grid); } -function generateTriangles(settings) -{ - if(!model.hasOwnProperty("grid")) - generatePoints(settings); - - const delaunay = new Delaunator(model.grid); - - model.delaunay = delaunay; -} -function generateVoronoi(settings) +function generateVoronoi() { function circumcenter(a, b, c) { @@ -44,30 +48,52 @@ function generateVoronoi(settings) ]; } - + const coords = model.delaunay.coords; + const tri = model.delaunay.triangles; + + for(let i = model.delaunay.trianglesLen - 1; i >= 0; --i) + { + tri[] + } } function getDelaunay() { return model.delaunay; } - -function lerpToViewport(settings) +function getAll() { - const size = settings.x * settings.y; - const grid = model.grid; - const view = new Float32Array(size * 3); + return { model: model, view: view }; +} + +//Settings view contains width & height +function lerpToViewport() +{ + const size = settings.model.x * settings.model.y; + const grid = model.delaunay.coords; + view.grid = new Float32Array(size * 3); for(let i = size - 1; i >= 0; --i) { - view[i * 3] = settings.width * grid[i * 2] / settings.x - settings.width / 2; - view[i * 3 + 1] = settings.height * grid[i * 2 + 1] / settings.y - settings.height / 2; - view[i * 3 + 2] = -3; + view.grid[i * 3 ] = lerp(0, settings.view.width , inverse_lerp(0, settings.model.x - 1, grid[i * 2 ])); + view.grid[i * 3 + 1] = lerp(0, settings.view.height, inverse_lerp(0, settings.model.y - 1, grid[i * 2 + 1])); + view.grid[i * 3 + 2] = -3; } - return view.buffer; + + return { position: view.grid, vertices: model.delaunay.triangles }; } //Process.register is the equivalent of export -Process.register("model", [generatePoints, generateTriangles]); +Process.register("model", [generateTriangles]); Process.register("view", [lerpToViewport]); -Process.register("debug", [getDelaunay]); +function updateSettings(s) +{ + const old_settings = settings; + settings = s; + + //Check which property has change and regenerate the appropriate objects. + +} + +Process.register("global", [updateSettings]); +Process.register("debug", [getDelaunay, getAll]);