Compare commits
No commits in common. "37d1051838621c72cbd38928e9f2f3e0b93dc477" and "8be7991b1dcc0c503fc0362997818e9b11a2a23e" have entirely different histories.
37d1051838
...
8be7991b1d
15
src/main.mjs
15
src/main.mjs
|
|
@ -8,15 +8,10 @@ import Renderer from "./modules/renderer/renderer.mjs";
|
|||
globalThis.TIMINGS = DEBUG && localStorage.getItem("timings");
|
||||
globalThis.RELEASE = !DEBUG;
|
||||
|
||||
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 };
|
||||
const grid = new Float32Array(await thread.model.fillArr(settings));
|
||||
console.log(grid);
|
||||
const renderer = new Renderer();
|
||||
renderer.render();
|
||||
|
||||
const view = new Float32Array(await thread.view.lerpToViewport(grid.buffer, settings));
|
||||
console.log(view);
|
||||
|
||||
Renderer.init();
|
||||
Renderer.initGrid(view, settings);
|
||||
const thread = new Thread("./workers/base.mjs", "backend");
|
||||
await thread.setup().complete();
|
||||
const grid = await thread.test_fillArr({x: 20, y: 20, depth: 2, seed: 0, jitter: 3 });
|
||||
})();
|
||||
|
|
@ -1,58 +1,13 @@
|
|||
import * as Three from "../../libs/three.mjs";
|
||||
import { Thread } from "../../utils/workerUtils.mjs";
|
||||
import Thread from "../../utils/workerUtils.mjs";
|
||||
|
||||
class Renderer
|
||||
{
|
||||
static async init(threaded)
|
||||
static async init()
|
||||
{
|
||||
this._threaded = threaded === undefined ? false : threaded;
|
||||
if(threaded)
|
||||
{
|
||||
this._renderer_thread = new Thread("../../workers/renderer.mjs", "view", true);
|
||||
await this._renderer_thread.setup();
|
||||
this._canvas = document.createElement("canvas");
|
||||
const offcanvas = this._canvas.transferControlToOffscreen();
|
||||
await this._renderer_thread.render.init(offcanvas, window.innerWidth, window.innerHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._renderer = new Three.WebGLRenderer();
|
||||
this._renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(this._renderer.domElement);
|
||||
|
||||
this._width = window.innerWidth;
|
||||
this._height = window.innerHeight;
|
||||
|
||||
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);
|
||||
|
||||
Renderer.render();
|
||||
}
|
||||
}
|
||||
static render()
|
||||
{
|
||||
if(this._threaded)
|
||||
return;
|
||||
|
||||
this._rAF = requestAnimationFrame(Renderer.render.bind(Renderer));
|
||||
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
const geometry = new Three.BufferGeometry();
|
||||
geometry.setAttribute('position', new Three.Float32BufferAttribute(grid, 3));
|
||||
|
||||
const points = new Three.Points(geometry);
|
||||
this._scene.add(points);
|
||||
}
|
||||
const renderer_thread = new Thread("../../workers/renderer.mjs", "renderer");
|
||||
await renderer_thread.setup().complete();
|
||||
renderer_thread.init(document.createElement("canvas").transferControlToOffscreen(), window.innerWidth, window.innerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
// WORKER SIDE //
|
||||
|
||||
const Constants = {
|
||||
STATE: {
|
||||
WAITING: 1,
|
||||
OK: 2,
|
||||
ERROR: 3,
|
||||
},
|
||||
REQUEST: {
|
||||
SETUP: 1,
|
||||
CALL: 2,
|
||||
TERMINATE: 3
|
||||
},
|
||||
};
|
||||
|
||||
function send(ret)
|
||||
{
|
||||
globalThis.VERBOSE && console.debug(`Sending ${ret} to the main thread`);
|
||||
postMessage([Constants.STATE.OK, ret]);
|
||||
}
|
||||
|
||||
class Process
|
||||
{
|
||||
static _isSetup = false;
|
||||
static setup()
|
||||
{
|
||||
globalThis.DEBUG && console.log(`Setting up process`);
|
||||
Process._isSetup = true;
|
||||
Process._customFn = {};
|
||||
onmessage = Process.onmessage;
|
||||
}
|
||||
static onmessage(e)
|
||||
{
|
||||
globalThis.VERBOSE && console.debug(`Received ${e.data}`);
|
||||
if(e && e.data)
|
||||
{
|
||||
switch(e.data[0])
|
||||
{
|
||||
case Constants.REQUEST.SETUP:
|
||||
send(Object.keys(Process._customFn));
|
||||
break;
|
||||
|
||||
case Constants.REQUEST.CALL:
|
||||
send(Process._customFn[e.data[1]](...e.data[2]));
|
||||
break;
|
||||
|
||||
case Constants.REQUEST.TERMINATE:
|
||||
Process.cleanUp();
|
||||
send();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Invalid message received in the Process");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Error("Can't find any data");
|
||||
}
|
||||
}
|
||||
static register(name, fn)
|
||||
{
|
||||
if(!Process._isSetup)
|
||||
Process.setup();
|
||||
|
||||
if(name in Process._customFn)
|
||||
throw new Error("This function name is already registered in the process. Please use a different one.");
|
||||
else
|
||||
Process._customFn[name] = fn;
|
||||
}
|
||||
static cleanUp()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export { Process, Constants };
|
||||
|
|
@ -14,19 +14,8 @@ const Constants = {
|
|||
WAKEUP: 1,
|
||||
SETUP: 2,
|
||||
CALL: 3,
|
||||
TERMINATE: 4,
|
||||
TERMINATE: 4
|
||||
},
|
||||
TRANSFERABLE: [
|
||||
ArrayBuffer,
|
||||
MessagePort,
|
||||
ReadableStream,
|
||||
WritableStream,
|
||||
TransformStream,
|
||||
AudioData,
|
||||
ImageBitmap,
|
||||
VideoFrame,
|
||||
OffscreenCanvas,
|
||||
]
|
||||
};
|
||||
|
||||
function cleanUp(thread)
|
||||
|
|
@ -34,44 +23,21 @@ function cleanUp(thread)
|
|||
thread._waiting = false;
|
||||
thread._resolver = undefined;
|
||||
thread._rejecter = undefined;
|
||||
thread._calledMod = "";
|
||||
thread._calledFn = "";
|
||||
}
|
||||
function request(thread, req, shared)
|
||||
function request(thread, req)
|
||||
{
|
||||
thread._promise = new Promise(function(res, rej) {
|
||||
thread._waiting = true;
|
||||
thread._resolver = res;
|
||||
thread._rejecter = rej;
|
||||
|
||||
thread._worker && thread._worker.postMessage(req, shared);
|
||||
thread._worker && thread._worker.postMessage(req);
|
||||
});
|
||||
|
||||
return thread._promise;
|
||||
}
|
||||
|
||||
function getTransferables(args)
|
||||
{
|
||||
const arr = [];
|
||||
|
||||
if(!Array.isArray(args))
|
||||
args = [args];
|
||||
|
||||
for(let i = 0; i < args.length; ++i)
|
||||
{
|
||||
for(let j = 0; j < Constants.TRANSFERABLE.length; ++j)
|
||||
{
|
||||
if(args[i] instanceof Constants.TRANSFERABLE[j])
|
||||
{
|
||||
arr.push(args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arr.length === 0 ? undefined : arr;
|
||||
}
|
||||
|
||||
function parseReturns(data)
|
||||
{
|
||||
if(data.length != 2)
|
||||
|
|
@ -84,17 +50,12 @@ function parseReturns(data)
|
|||
}
|
||||
return data[1];
|
||||
}
|
||||
function wrapper(thread, mod, fn)
|
||||
function wrapper(thread, fn)
|
||||
{
|
||||
return function(...args)
|
||||
return function()
|
||||
{
|
||||
if(globalThis.TIMINGS)
|
||||
{
|
||||
console.time("Measuring " + mod + "." + fn);
|
||||
thread._calledMod = mod;
|
||||
thread._calledFn = fn;
|
||||
}
|
||||
return request(thread, [Constants.REQUEST.CALL, mod, fn, [...args]], getTransferables([...args]));
|
||||
globalThis.TIMINGS && console.time("Measuring " + fn);
|
||||
return request(thread, [Constants.REQUEST.CALL, fn, [...arguments]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +63,7 @@ function onmessage(thread)
|
|||
{
|
||||
return function(e) {
|
||||
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);
|
||||
globalThis.VERBOSE && console.debug(`Received message from ${thread._name} containing ${ret}`);
|
||||
|
||||
if(thread._waiting && ret)
|
||||
{
|
||||
|
|
@ -117,8 +77,7 @@ function onmessage(thread)
|
|||
function onerror(thread)
|
||||
{
|
||||
return function(e) {
|
||||
globalThis.DEBUG && console.error(`Received error from ${thread._name} containing `, e);
|
||||
globalThis.TIMINGS && thread._calledFn !== "" && console.timeEnd("Measuring " + thread._calledMod + "." + thread._calledFn);
|
||||
console.error(`Received error from ${thread._name} containing ${e}`);
|
||||
|
||||
if(thread._waiting)
|
||||
{
|
||||
|
|
@ -134,9 +93,9 @@ const Thread = Object.freeze(class
|
|||
* Creates a new Thread loading the linked file. The linked file must follow the Thread expectations.
|
||||
* You can give it a optionnal name to make the debug easier.
|
||||
*/
|
||||
constructor(url, name, mod)
|
||||
constructor(url, name)
|
||||
{
|
||||
this._worker = new Worker(url, mod ? {type: "module"} : undefined);
|
||||
this._worker = new Worker(url, {type: "module"});
|
||||
this._name = name || url;
|
||||
|
||||
this._worker.onmessage = onmessage(this);
|
||||
|
|
@ -148,25 +107,27 @@ const Thread = Object.freeze(class
|
|||
*/
|
||||
async setup()
|
||||
{
|
||||
const result = await request(this, [Constants.REQUEST.SETUP], undefined);
|
||||
const result = await request(this, [Constants.REQUEST.SETUP]);
|
||||
|
||||
if(result)
|
||||
if(result && result.length)
|
||||
{
|
||||
for(let mod of Object.getOwnPropertyNames(result))
|
||||
for(let i = 0; i < result.length; i++)
|
||||
{
|
||||
this[mod] = {};
|
||||
for(let i = 0; i < result[mod].length; ++i)
|
||||
{
|
||||
const fn = result[mod][i];
|
||||
this[mod][fn] = wrapper(this, mod, fn);
|
||||
}
|
||||
const custom = result[i];
|
||||
this[custom] = wrapper(this, custom);
|
||||
}
|
||||
}
|
||||
}
|
||||
async terminate()
|
||||
complete()
|
||||
{
|
||||
await request(this, [Constants.REQUEST.TERMINATE]);
|
||||
this._worker.terminate();
|
||||
if(this._waiting)
|
||||
{
|
||||
return this._promise;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Promise.resolve(this._ret);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -174,8 +135,8 @@ const Thread = Object.freeze(class
|
|||
|
||||
function send(ret)
|
||||
{
|
||||
globalThis.VERBOSE && console.debug(`Sending `, ret, ` back to the main thread`);
|
||||
postMessage([Constants.STATE.OK, ret], getTransferables(ret));
|
||||
globalThis.VERBOSE && console.debug(`Sending ${ret} to the main thread`);
|
||||
postMessage([Constants.STATE.OK, ret]);
|
||||
}
|
||||
|
||||
class Process
|
||||
|
|
@ -190,27 +151,17 @@ class Process
|
|||
}
|
||||
static onmessage(e)
|
||||
{
|
||||
globalThis.VERBOSE && console.debug(`Received `, e.data);
|
||||
globalThis.VERBOSE && console.debug(`Received ${e.data}`);
|
||||
if(e && e.data)
|
||||
{
|
||||
switch(e.data[0])
|
||||
{
|
||||
case Constants.REQUEST.SETUP:
|
||||
const obj = {};
|
||||
for(let mod of Object.getOwnPropertyNames(Process._customFn))
|
||||
{
|
||||
obj[mod] = [];
|
||||
for(let fn of Object.getOwnPropertyNames(Process._customFn[mod]))
|
||||
{
|
||||
obj[mod].push(fn);
|
||||
}
|
||||
}
|
||||
send(obj);
|
||||
send(Object.keys(Process._customFn));
|
||||
break;
|
||||
|
||||
case Constants.REQUEST.CALL:
|
||||
const args = e.data[3];
|
||||
send(Process._customFn[e.data[1]][e.data[2]](...args));
|
||||
send(Process._customFn[e.data[1]](...e.data[2]));
|
||||
break;
|
||||
|
||||
case Constants.REQUEST.TERMINATE:
|
||||
|
|
@ -235,28 +186,21 @@ class Process
|
|||
|
||||
if(!Array.isArray(arr))
|
||||
arr = [arr];
|
||||
|
||||
if(mod in Process._customFn)
|
||||
throw new Error("This module has already been registered in the process.");
|
||||
|
||||
const modObj = {};
|
||||
for(let i = 0; i < arr.length; ++i)
|
||||
{
|
||||
if(typeof arr[i] != 'function')
|
||||
throw new Error("You can only register functions");
|
||||
|
||||
const name = arr[i].name;
|
||||
if(name in modObj)
|
||||
const name = mod + "_" arr[i].name;
|
||||
if(name in Process._customFn)
|
||||
throw new Error("This function name is already registered in the process. Please use a different one.");
|
||||
else
|
||||
modObj[name] = arr[i];
|
||||
Process._customFn[name] = arr[i];
|
||||
}
|
||||
|
||||
Process._customFn[mod] = modObj;
|
||||
}
|
||||
static cleanUp()
|
||||
{
|
||||
Process._customFn = {};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +1,18 @@
|
|||
import { Process } from "../utils/workerUtils.mjs";
|
||||
import Noise from '../libs/alea.mjs'
|
||||
import Delaunator from '../libs/delaunator.mjs'
|
||||
|
||||
//Settings contains x, y depth, seed, jitter
|
||||
function fillArr(settings)
|
||||
{
|
||||
const noise = Noise(settings.seed);
|
||||
const grid = new Float32Array(settings.x * settings.y * 2);
|
||||
for(let i = grid.length * 2 - 2; i > 0; i -= 2)
|
||||
const arr = new Float32Array(settings.x * settings.y * settings.depth);
|
||||
for(let i = arr.length - 1; i >= 0; --i)
|
||||
{
|
||||
const _x = i / 2 % settings.x;
|
||||
const _y = (i / 2 - _x) / settings.x;
|
||||
|
||||
grid[i] = _x + (noise() - 0.5) * settings.jitter;
|
||||
grid[i + 1] = _y + (noise() - 0.5) * settings.jitter;
|
||||
const _x = i % settings.x;
|
||||
const _y = (i - _x) / settings.x;
|
||||
arr[i] =
|
||||
}
|
||||
|
||||
return grid.buffer;
|
||||
}
|
||||
|
||||
function lerpToViewport(buffer, settings)
|
||||
{
|
||||
const size = settings.x * settings.y;
|
||||
const grid = new Float32Array(buffer);
|
||||
const view = 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;
|
||||
}
|
||||
return view.buffer;
|
||||
}
|
||||
|
||||
//Process.register is the equivalent of export
|
||||
Process.register("model", [fillArr]);
|
||||
Process.register("view", [lerpToViewport]);
|
||||
Process.register("test", [fillArr]);
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
import { Process } from "../utils/workerUtils.mjs";
|
||||
import * as Three from '../libs/three.mjs'
|
||||
|
||||
class Renderer
|
||||
{
|
||||
static init(canvas, width, height)
|
||||
}
|
||||
|
||||
//Process.register is the equivalent of export
|
||||
Process.register("render", [Renderer.init]);
|
||||
Loading…
Reference in New Issue