First test features
This commit is contained in:
commit
8be7991b1d
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Map Generator</title>
|
||||
<link rel="stylesheet" type="text/css" href="resources/style.css">
|
||||
<script type="module" src="main.mjs"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Copyright (C) 2010 by Johannes Baagøe baagoe@baagoe.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
function masher() {
|
||||
let n = 0xefc8249d;
|
||||
return function(data) {
|
||||
data = data.toString();
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
n += data.charCodeAt(i);
|
||||
let h = 0.02519603282416938 * n;
|
||||
n = h >>> 0;
|
||||
h -= n;
|
||||
h *= n;
|
||||
n = h >>> 0;
|
||||
h -= n;
|
||||
n += h * 0x100000000; // 2^32
|
||||
}
|
||||
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
|
||||
};
|
||||
}
|
||||
|
||||
export default function alea(seed)
|
||||
{
|
||||
let s0 = 0;
|
||||
let s1 = 0;
|
||||
let s2 = 0;
|
||||
let c = 1;
|
||||
|
||||
const mash = masher();
|
||||
s0 = mash(' ');
|
||||
s1 = mash(' ');
|
||||
s2 = mash(' ');
|
||||
|
||||
s0 -= mash(seed);
|
||||
if (s0 < 0) {
|
||||
s0 += 1;
|
||||
}
|
||||
s1 -= mash(seed);
|
||||
if (s1 < 0) {
|
||||
s1 += 1;
|
||||
}
|
||||
s2 -= mash(seed);
|
||||
if (s2 < 0) {
|
||||
s2 += 1;
|
||||
}
|
||||
|
||||
return function() {
|
||||
const t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
|
||||
s0 = s1;
|
||||
s1 = s2;
|
||||
return s2 = t - (c = t | 0);
|
||||
};
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,17 @@
|
|||
import { Thread, supportThreads } from "./utils/workerUtils.mjs";
|
||||
import Renderer from "./modules/renderer/renderer.mjs";
|
||||
|
||||
(async function()
|
||||
{
|
||||
globalThis.DEBUG = localStorage.getItem("debug");
|
||||
globalThis.VERBOSE = DEBUG && localStorage.getItem("verbose");
|
||||
globalThis.TIMINGS = DEBUG && localStorage.getItem("timings");
|
||||
globalThis.RELEASE = !DEBUG;
|
||||
|
||||
const renderer = new Renderer();
|
||||
renderer.render();
|
||||
|
||||
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 });
|
||||
})();
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import * as Three from "../../libs/three.mjs";
|
||||
import Thread from "../../utils/workerUtils.mjs";
|
||||
|
||||
class Renderer
|
||||
{
|
||||
static async init()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
export default Renderer;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
html, body, div
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -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 };
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
"use strict";
|
||||
|
||||
// MAIN THREAD SIDE //
|
||||
|
||||
const supportThreads = !!globalThis.Process;
|
||||
|
||||
const Constants = {
|
||||
STATE: {
|
||||
WAITING: 1,
|
||||
OK: 2,
|
||||
ERROR: 3,
|
||||
},
|
||||
REQUEST: {
|
||||
WAKEUP: 1,
|
||||
SETUP: 2,
|
||||
CALL: 3,
|
||||
TERMINATE: 4
|
||||
},
|
||||
};
|
||||
|
||||
function cleanUp(thread)
|
||||
{
|
||||
thread._waiting = false;
|
||||
thread._resolver = undefined;
|
||||
thread._rejecter = undefined;
|
||||
thread._calledFn = "";
|
||||
}
|
||||
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);
|
||||
});
|
||||
|
||||
return thread._promise;
|
||||
}
|
||||
|
||||
function parseReturns(data)
|
||||
{
|
||||
if(data.length != 2)
|
||||
{
|
||||
throw new Error("Invalid message");
|
||||
}
|
||||
if(data[0] !== Constants.STATE.OK)
|
||||
{
|
||||
throw new Error("Invalid message");
|
||||
}
|
||||
return data[1];
|
||||
}
|
||||
function wrapper(thread, fn)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
globalThis.TIMINGS && console.time("Measuring " + fn);
|
||||
return request(thread, [Constants.REQUEST.CALL, fn, [...arguments]]);
|
||||
}
|
||||
}
|
||||
|
||||
function onmessage(thread)
|
||||
{
|
||||
return function(e) {
|
||||
const ret = parseReturns(e.data);
|
||||
globalThis.VERBOSE && console.debug(`Received message from ${thread._name} containing ${ret}`);
|
||||
|
||||
if(thread._waiting && ret)
|
||||
{
|
||||
globalThis.DEBUG && console.log(`Resolving ${thread._name}`);
|
||||
thread._ret = ret;
|
||||
thread._resolver(ret);
|
||||
cleanUp(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
function onerror(thread)
|
||||
{
|
||||
return function(e) {
|
||||
console.error(`Received error from ${thread._name} containing ${e}`);
|
||||
|
||||
if(thread._waiting)
|
||||
{
|
||||
thread._rejecter(e);
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
this._worker = new Worker(url, {type: "module"});
|
||||
this._name = name || url;
|
||||
|
||||
this._worker.onmessage = onmessage(this);
|
||||
this._worker.onmerror = onerror(this);
|
||||
cleanUp(this);
|
||||
}
|
||||
/**
|
||||
* Will ask every custom function registered in the worker and add them in the prototype of this instance.
|
||||
*/
|
||||
async setup()
|
||||
{
|
||||
const result = await request(this, [Constants.REQUEST.SETUP]);
|
||||
|
||||
if(result && result.length)
|
||||
{
|
||||
for(let i = 0; i < result.length; i++)
|
||||
{
|
||||
const custom = result[i];
|
||||
this[custom] = wrapper(this, custom);
|
||||
}
|
||||
}
|
||||
}
|
||||
complete()
|
||||
{
|
||||
if(this._waiting)
|
||||
{
|
||||
return this._promise;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Promise.resolve(this._ret);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// WORKER SIDE //
|
||||
|
||||
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 = {};
|
||||
globalThis.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(mod, arr)
|
||||
{
|
||||
if(!Process._isSetup)
|
||||
Process.setup();
|
||||
|
||||
if(!Array.isArray(arr))
|
||||
arr = [arr];
|
||||
for(let i = 0; i < arr.length; ++i)
|
||||
{
|
||||
if(typeof arr[i] != 'function')
|
||||
throw new Error("You can only register functions");
|
||||
|
||||
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
|
||||
Process._customFn[name] = arr[i];
|
||||
}
|
||||
}
|
||||
static cleanUp()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export { Thread, Process, supportThreads };
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { Process } from "../utils/workerUtils.mjs";
|
||||
import Noise from '../libs/alea.mjs'
|
||||
|
||||
//Settings contains x, y depth, seed, jitter
|
||||
function fillArr(settings)
|
||||
{
|
||||
const noise = Noise(settings.seed);
|
||||
const arr = new Float32Array(settings.x * settings.y * settings.depth);
|
||||
for(let i = arr.length - 1; i >= 0; --i)
|
||||
{
|
||||
const _x = i % settings.x;
|
||||
const _y = (i - _x) / settings.x;
|
||||
arr[i] =
|
||||
}
|
||||
}
|
||||
|
||||
//Process.register is the equivalent of export
|
||||
Process.register("test", [fillArr]);
|
||||
Loading…
Reference in New Issue