#if !PROXY_TO_WORKER
#error "proxyClient.js should only be included in PROXY_TO_WORKER mode"
#endif
#if ENVIRONMENT_MAY_BE_NODE
if (!ENVIRONMENT_IS_NODE) {
#endif
function FPSTracker(text) {
var last = 0;
var mean = 0;
var counter = 0;
this.tick = () => {
var now = Date.now();
if (last > 0) {
var diff = now - last;
mean = 0.99*mean + 0.01*diff;
if (counter++ === 60) {
counter = 0;
dump(text + ' fps: ' + (1000/mean).toFixed(2) + '\n');
}
}
last = now;
}
}
function Element() { throw 'TODO: Element' }
function HTMLCanvasElement() { throw 'TODO: HTMLCanvasElement' }
function HTMLVideoElement() { throw 'TODO: HTMLVideoElement' }
var KeyboardEvent = {
'DOM_KEY_LOCATION_RIGHT': 2,
};
function PropertyBag() {
this.addProperty = () => {};
this.removeProperty = () => {};
this.setProperty = () => {};
};
var IndexedObjects = {
nextId: 1,
cache: {},
add(object) {
object.id = this.nextId++;
this.cache[object.id] = object;
}
};
function EventListener() {
this.listeners = {};
this.addEventListener = function addEventListener(event, func) {
this.listeners[event] ||= [];
this.listeners[event].push(func);
};
this.removeEventListener = function(event, func) {
var list = this.listeners[event];
if (!list) return;
var me = list.indexOf(func);
if (me < 0) return;
list.splice(me, 1);
};
this.fireEvent = function(event) {
event.preventDefault = () => {};
if (event.type in this.listeners) {
this.listeners[event.type].forEach((listener) => listener(event));
}
}
}
function Image() {
IndexedObjects.add(this);
EventListener.call(this);
var src = '';
Object.defineProperty(this, 'src', {
set: (value) => {
src = value;
assert(this.id);
postMessage({ target: 'Image', method: 'src', src, id: this.id });
},
get: () => src
});
}
Image.prototype.onload = () => {};
Image.prototype.onerror = () => {};
var HTMLImageElement = Image;
var window = this;
var windowExtra = new EventListener();
for (var x in windowExtra) window[x] = windowExtra[x];
window.close = () => {
postMessage({ target: 'window', method: 'close' });
};
window.alert = (text) => {
err(`alert forever: ${text}`);
while (1) {};
};
window.scrollX = window.scrollY = 0;
window.WebGLRenderingContext = WebGLWorker;
window.requestAnimationFrame = (() => {
var nextRAF = 0;
return (func) => {
var now = Date.now();
if (nextRAF === 0) {
nextRAF = now + 1000/60;
} else {
while (now + 2 >= nextRAF) {
nextRAF += 1000/60;
}
}
var delay = Math.max(nextRAF - now, 0);
setTimeout(func, delay);
};
})();
var webGLWorker = new WebGLWorker();
var document = new EventListener();
document.createElement = (what) => {
switch (what) {
case 'canvas': {
var canvas = new EventListener();
canvas.ensureData = () => {
if (!canvas.data || canvas.data.width !== canvas.width || canvas.data.height !== canvas.height) {
canvas.data = {
width: canvas.width,
height: canvas.height,
data: new Uint8Array(canvas.width*canvas.height*4)
};
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'resize', width: canvas.width, height: canvas.height });
}
}
};
canvas.getContext = (type, attributes) => {
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'getContext', type, attributes });
}
if (type === '2d') {
return {
getImageData: (x, y, w, h) => {
assert(x == 0 && y == 0 && w == canvas.width && h == canvas.height);
canvas.ensureData();
return {
width: canvas.data.width,
height: canvas.data.height,
data: new Uint8Array(canvas.data.data)
};
},
putImageData: (image, x, y) => {
canvas.ensureData();
assert(x == 0 && y == 0 && image.width == canvas.width && image.height == canvas.height);
canvas.data.data.set(image.data);
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'render', image: canvas.data });
}
},
drawImage: (image, x, y, w, h, ox, oy, ow, oh) => {
assert (!x && !y && !ox && !oy);
assert(w === ow && h === oh);
assert(canvas.width === w || w === undefined);
assert(canvas.height === h || h === undefined);
assert(image.width === canvas.width && image.height === canvas.height);
canvas.ensureData();
canvas.data.data.set(image.data.data);
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'render', image: canvas.data });
}
}
};
} else {
return webGLWorker;
}
};
canvas.boundingClientRect = {};
canvas.getBoundingClientRect = () => ({
width: canvas.boundingClientRect.width,
height: canvas.boundingClientRect.height,
top: canvas.boundingClientRect.top,
left: canvas.boundingClientRect.left,
bottom: canvas.boundingClientRect.bottom,
right: canvas.boundingClientRect.right
});
canvas.style = new PropertyBag();
canvas.width_ ||= 0;
canvas.height_ ||= 0;
Object.defineProperty(canvas, 'width', {
set: (value) => {
canvas.width_ = value;
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'resize', width: canvas.width_, height: canvas.height_ });
}
},
get: () => canvas.width_
});
Object.defineProperty(canvas, 'height', {
set: (value) => {
canvas.height_ = value;
if (canvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'resize', width: canvas.width_, height: canvas.height_ });
}
},
get: () => canvas.height_
});
var style = {
parentCanvas: canvas,
removeProperty: () => {},
setProperty: () => {},
};
Object.defineProperty(style, 'cursor', {
set: (value) => {
if (!style.cursor_ || style.cursor_ !== value) {
style.cursor_ = value;
if (style.parentCanvas === Module['canvas']) {
postMessage({ target: 'canvas', op: 'setObjectProperty', object: 'style', property: 'cursor', value: style.cursor_ });
}
}
},
get: () => style.cursor,
});
canvas.style = style;
return canvas;
}
default: {
throw 'document.createElement ' + what;
}
}
};
document.getElementById = (id) => {
if (id === 'canvas' || id === 'application-canvas') {
return Module['canvas'];
}
throw 'document.getElementById failed on ' + id;
};
document.querySelector = (id) => {
if (id === '#canvas' || id === '#application-canvas' || id === 'canvas' || id === 'application-canvas') {
return Module['canvas'];
}
throw 'document.querySelector failed on ' + id;
};
document.documentElement = {};
document.styleSheets = [{
cssRules: [],
insertRule(rule, i) {
this.cssRules.splice(i, 0, rule);
}
}];
document.URL = 'http://worker.not.yet.ready.wait.for.window.onload?fake';
document.exitPointerLock = () => {};
function Audio() {
warnOnce('faking Audio elements, no actual sound will play');
}
Audio.prototype = new EventListener();
Object.defineProperty(Audio.prototype, 'src', {
set(value) {
if (value[0] === 'd') return;
this.onerror();
},
});
Audio.prototype.play = () => {};
Audio.prototype.pause = () => {};
Audio.prototype.cloneNode = () => new Audio;
function AudioContext() {
warnOnce('faking WebAudio elements, no actual sound will play');
var makeNode = () => {
return {
connect: () => {},
disconnect: () => {},
}
};
this.listener = {
setPosition: () => {},
setOrientation: () => {},
};
this.decodeAudioData = () => {};
this.createBuffer = makeNode;
this.createBufferSource = makeNode;
this.createGain = makeNode;
this.createPanner = makeNode;
}
var screen = {
width: 0,
height: 0
};
Module['canvas'] = document.createElement('canvas');
Module.setStatus = () => {};
out = (x) => {
postMessage({ target: 'stdout', content: x });
};
err = (x) => {
postMessage({ target: 'stderr', content: x });
};
var frameId = 0;
var clientFrameId = 0;
var postMainLoop = Module['postMainLoop'];
Module['postMainLoop'] = () => {
postMainLoop?.();
postMessage({ target: 'tick', id: frameId++ });
commandBuffer = [];
};
#if PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) {
#endif
addRunDependency('gl-prefetch');
addRunDependency('worker-init');
#if PTHREADS
}
#endif
#if ENVIRONMENT_MAY_BE_NODE
}
#endif
var messageBuffer = null;
var messageResenderTimeout = null;
var calledMain = false;
Module['postRun'] ||= [];
if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
Module['postRun'].push(() => { calledMain = true; });
function messageResender() {
if (calledMain) {
assert(messageBuffer && messageBuffer.length > 0);
messageResenderTimeout = null;
messageBuffer.forEach(onmessage);
messageBuffer = null;
} else {
messageResenderTimeout = setTimeout(messageResender, 100);
}
}
function onMessageFromMainEmscriptenThread(message) {
if (!calledMain && !message.data.preMain) {
if (!messageBuffer) {
messageBuffer = [];
messageResenderTimeout = setTimeout(messageResender, 100);
}
messageBuffer.push(message);
return;
}
if (calledMain && messageResenderTimeout) {
clearTimeout(messageResenderTimeout);
messageResender();
}
switch (message.data.target) {
case 'document': {
document.fireEvent(message.data.event);
break;
}
case 'window': {
window.fireEvent(message.data.event);
break;
}
case 'canvas': {
if (message.data.event) {
Module['canvas'].fireEvent(message.data.event);
} else if (message.data.boundingClientRect) {
Module['canvas'].boundingClientRect = message.data.boundingClientRect;
} else throw 'ey?';
break;
}
case 'gl': {
webGLWorker.onmessage(message.data);
break;
}
case 'tock': {
clientFrameId = message.data.id;
break;
}
case 'Image': {
var img = IndexedObjects.cache[message.data.id];
switch (message.data.method) {
case 'onload': {
img.width = message.data.width;
img.height = message.data.height;
img.data = { width: img.width, height: img.height, data: message.data.data };
img.complete = true;
img.onload();
break;
}
case 'onerror': {
img.onerror({ srcElement: img });
break;
}
}
break;
}
case 'IDBStore': {
assert(message.data.method === 'response');
assert(IDBStore.pending);
IDBStore.pending(message.data);
break;
}
case 'worker-init': {
Module['canvas'] = document.createElement('canvas');
screen.width = Module['canvas'].width_ = message.data.width;
screen.height = Module['canvas'].height_ = message.data.height;
Module['canvas'].boundingClientRect = message.data.boundingClientRect;
#if ENVIRONMENT_MAY_BE_NODE
if (ENVIRONMENT_IS_NODE)
#endif
document.URL = message.data.URL;
#if PTHREADS
currentScriptUrl = message.data.currentScriptUrl;
#endif
window.fireEvent({ type: 'load' });
removeRunDependency('worker-init');
break;
}
case 'custom': {
if (Module['onCustomMessage']) {
Module['onCustomMessage'](message);
} else {
throw 'Custom message received but worker Module.onCustomMessage not implemented.';
}
break;
}
case 'setimmediate': {
Module['setImmediates']?.shift()();
break;
}
default: throw 'wha? ' + message.data.target;
}
};
#if PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) {
#endif
onmessage = onMessageFromMainEmscriptenThread;
#if PTHREADS
}
#endif
if (typeof specialHTMLTargets != 'undefined') {
specialHTMLTargets = [0, document, window];
}
function postCustomMessage(data) {
postMessage({ target: 'custom', userData: data });
}