Skip to content

Commit

Permalink
WIP: Intergrate EventProxy for OffscreenCanvas
Browse files Browse the repository at this point in the history
  • Loading branch information
kaisalmen committed Nov 13, 2023
1 parent cea9c8c commit 70b272f
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 37 deletions.
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"dependencies": {
"lil-gui": "~0.19.0",
"three": "~0.158.0",
"wtd-core": "~3.0.0-next.0",
"wtd-three-ext": "~3.0.0-next.0",
"wtd-core": "~3.0.0-next.1",
"wtd-three-ext": "~3.0.0-next.1",
"wwobjloader2": "6.2.0-next.4"
},
"devDependencies": {
Expand Down
31 changes: 21 additions & 10 deletions packages/examples/src/com/WorkerCom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
WorkerTaskMessageConfig
} from 'wtd-core';
import { recalcAspectRatio, updateText } from '../worker/ComWorkerCommon.js';
import { OffscreenPayload } from 'wtd-three-ext';

/**
* Hello World example using a classic worker
Expand Down Expand Up @@ -53,27 +54,37 @@ class HelloWorldStandardWorkerExample {

try {
const offscreenCom1 = this.canvasCom1.transferControlToOffscreen();
const offscreenPayload1 = new OffscreenPayload({
event: {
type: 'init',
drawingSurface: offscreenCom1,
width: this.canvasCom1.clientWidth,
height: this.canvasCom1.clientHeight
}
});
const payload1 = new RawPayload({
port: channel.port1,
drawingSurface: offscreenCom1,
width: this.canvasCom1.clientWidth,
height: this.canvasCom1.clientHeight
port: channel.port1
});

const offscreenCom2 = this.canvasCom2.transferControlToOffscreen();
const offscreenPayload2 = new OffscreenPayload({
event: {
type: 'init',
drawingSurface: offscreenCom2,
width: this.canvasCom2.clientWidth,
height: this.canvasCom2.clientHeight
}
});
const payload2 = new RawPayload({
port: channel.port2,
drawingSurface: offscreenCom2,
width: this.canvasCom2.clientWidth,
height: this.canvasCom2.clientHeight
port: channel.port2
});
const promisesinit = [];
promisesinit.push(this.workerTaskCom1.initWorker({
message: WorkerTaskMessage.fromPayload(payload1),
message: WorkerTaskMessage.fromPayload([offscreenPayload1, payload1]),
transferables: [channel.port1, offscreenCom1]
}));
promisesinit.push(this.workerTaskCom2.initWorker({
message: WorkerTaskMessage.fromPayload(payload2),
message: WorkerTaskMessage.fromPayload([offscreenPayload2, payload2]),
transferables: [channel.port2, offscreenCom2],
}));
await Promise.all(promisesinit);
Expand Down
11 changes: 7 additions & 4 deletions packages/examples/src/worker/Com1Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ import {
WorkerTaskWorker
} from 'wtd-core';
import { getOffScreenCanvas, updateText } from './ComWorkerCommon.js';
import { OffscreenPayload } from 'wtd-three-ext';

export class Com1Worker implements WorkerTaskWorker, InterComWorker {

private icph = new InterComPortHandler();
private offScreenCanvas?: HTMLCanvasElement;

init(message: WorkerTaskMessageConfig): void {
// register the default com-routing function for inter-worker communication
const payload = message.payloads?.[0];
this.icph.registerPort('com2', payload, message => comRouting(this, message));
this.offScreenCanvas = getOffScreenCanvas(payload);
const payloadOffscreen = message.payloads?.[0] as OffscreenPayload;
this.offScreenCanvas = getOffScreenCanvas(payloadOffscreen);
updateText({
text: 'Worker 1: init',
width: this.offScreenCanvas?.width ?? 0,
Expand All @@ -29,6 +28,10 @@ export class Com1Worker implements WorkerTaskWorker, InterComWorker {
log: true
});

// register the default com-routing function for inter-worker communication
const payloadPort = message.payloads?.[1];
this.icph.registerPort('com2', payloadPort, message => comRouting(this, message));

// send initComplete to main
const initComplete = WorkerTaskMessage.createFromExisting({} as WorkerTaskMessageConfig, WorkerTaskCommandResponse.INIT_COMPLETE);
const payloadResponse = new RawPayload({ hello: 'Worker 1 initComplete!' });
Expand Down
11 changes: 7 additions & 4 deletions packages/examples/src/worker/Com2Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ import {
WorkerTaskWorker
} from 'wtd-core';
import { getOffScreenCanvas, updateText } from './ComWorkerCommon.js';
import { OffscreenPayload } from 'wtd-three-ext';

export class Com2Worker implements WorkerTaskWorker, InterComWorker {

private icph = new InterComPortHandler();
private offScreenCanvas?: HTMLCanvasElement;

init(message: WorkerTaskMessageConfig): void {
// register the default com-routing function for inter-worker communication
const payload = message.payloads?.[0];
this.icph.registerPort('com1', payload, message => comRouting(this, message));
this.offScreenCanvas = getOffScreenCanvas(payload);
const payloadOffscreen = message.payloads?.[0] as OffscreenPayload;
this.offScreenCanvas = getOffScreenCanvas(payloadOffscreen);
updateText({
text: 'Worker 2: init',
width: this.offScreenCanvas?.width ?? 0,
Expand All @@ -29,6 +28,10 @@ export class Com2Worker implements WorkerTaskWorker, InterComWorker {
log: true
});

// register the default com-routing function for inter-worker communication
const payloadPort = message.payloads?.[1];
this.icph.registerPort('com1', payloadPort, message => comRouting(this, message));

// send initComplete to main
const initComplete = WorkerTaskMessage.createFromExisting({} as WorkerTaskMessageConfig, WorkerTaskCommandResponse.INIT_COMPLETE);
const payloadResponse = new RawPayload({ hello: 'Worker 2 initComplete!' });
Expand Down
6 changes: 3 additions & 3 deletions packages/examples/src/worker/ComWorkerCommon.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Payload, RawPayload } from 'wtd-core';
import { OffscreenPayload } from 'wtd-three-ext';

export const getOffScreenCanvas = (payload?: Payload) => {
return payload ? (payload as RawPayload).message.raw.drawingSurface as HTMLCanvasElement : undefined;
export const getOffScreenCanvas = (offScreenPayload?: OffscreenPayload) => {
return offScreenPayload ? offScreenPayload.message.drawingSurface as HTMLCanvasElement : undefined;
};

export const updateText = (params: {
Expand Down
2 changes: 1 addition & 1 deletion packages/wtd-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wtd-core",
"version": "3.0.0-next.0",
"version": "3.0.0-next.1",
"license": "MIT",
"type": "module",
"main": "./dist/index.js",
Expand Down
5 changes: 3 additions & 2 deletions packages/wtd-core/src/WorkerTask.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
WorkerTaskCommands,
WorkerTaskMessageConfig
} from './WorkerTaskMessage.js';
import {
Expand Down Expand Up @@ -197,9 +198,9 @@ export class WorkerTask {
* @param message
* @param transferables
*/
sentMessage(message: WorkerTaskMessage, transferables?: Transferable[]) {
sentMessage(message: WorkerTaskMessage, cmd: WorkerTaskCommands, transferables?: Transferable[]) {
if (this.isWorkerExecuting() && this.worker) {
message.cmd = WorkerTaskCommandRequest.INTERMEDIATE;
message.cmd = cmd;
message.workerId = this.workerId;
this.worker.postMessage(message, transferables!);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/wtd-core/src/WorkerTaskMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ export class WorkerTaskMessage {
return instance;
}

static fromPayload(payload: Payload) {
static fromPayload(payloads: Payload | Payload[]) {
const wtm = new WorkerTaskMessage({});
wtm.addPayload(payload);
wtm.addPayload(payloads);
return wtm;
}
}
4 changes: 2 additions & 2 deletions packages/wtd-three-ext/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wtd-three-ext",
"version": "3.0.0-next.0",
"version": "3.0.0-next.1",
"license": "MIT",
"type": "module",
"main": "./dist/index.js",
Expand Down Expand Up @@ -45,7 +45,7 @@
"npm": "9.8.1"
},
"dependencies": {
"wtd-core": "~3.0.0-next.0",
"wtd-core": "~3.0.0-next.1",
"three": "~0.158.0"
},
"devDependencies": {
Expand Down
15 changes: 13 additions & 2 deletions packages/wtd-three-ext/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,15 @@ import {
packGeometryBuffers,
reconstructBuffer
} from './MeshPayload.js';

import type {
OffscreenPayloadAdditions,
OffscreenPayloadMessage
} from './offscreen/OffscreenPayload.js';
import {
OffscreenPayload
} from './offscreen/OffscreenPayload.js';
export * from './offscreen/EventProxy.js';
export * from './offscreen/ProxyManager.js';
export {
MaterialUtils,
MaterialCloneInstructionsType,
Expand All @@ -47,5 +55,8 @@ export {
addAttributeToBuffers,
assignAttributeFromTransfered,
packGeometryBuffers,
reconstructBuffer
reconstructBuffer,
OffscreenPayloadAdditions,
OffscreenPayloadMessage,
OffscreenPayload,
};
138 changes: 138 additions & 0 deletions packages/wtd-three-ext/src/offscreen/EventProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { AssociatedArrayType, WorkerTask, WorkerTaskMessage } from 'wtd-core';
import { OffscreenPayload } from './OffscreenPayload.js';

export const wheelEventHandler = (event: Event, sendFn: (data: OffscreenPayload) => void) => {
event.preventDefault();
wheelEventHandlerImpl(event, sendFn);
};

export const preventDefaultHandler = (event: Event) => {
event.preventDefault();
};

export const copyProperties = (src: Event, properties: string[], dst: AssociatedArrayType<unknown>) => {
for (const name of properties) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
dst[name] = (src as any)[name];
}
};

export const makeSendPropertiesHandler = (properties: string[]) => {
return function sendProperties(event: Event, sendFn: (data: OffscreenPayload) => void) {
const eventTarget = {
type: event.type,
};
copyProperties(event, properties, eventTarget);
const payload = new OffscreenPayload({
event: eventTarget
});

sendFn(payload);
};
};

export const touchEventHandler = (event: TouchEvent, sendFn: (data: OffscreenPayload) => void) => {
const touches = [];

// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < event.touches.length; ++i) {
const touch = event.touches[i];
touches.push({
pageX: touch.pageX,
pageY: touch.pageY,
});
}
const payload = new OffscreenPayload({
event: {
type: event.type,
touches
}
});
sendFn(payload);
};

// The four arrow keys
export const orbitKeys: AssociatedArrayType<boolean> = {
'37': true, // left
'38': true, // up
'39': true, // right
'40': true, // down
};

export const filteredKeydownEventHandler = (event: KeyboardEvent, sendFn: (data: OffscreenPayload) => void) => {
const { code } = event;
if (orbitKeys[code]) {
event.preventDefault();
keydownEventHandler(event, sendFn);
}
};

export const mouseEventHandler = makeSendPropertiesHandler([
'ctrlKey',
'metaKey',
'shiftKey',
'button',
'clientX',
'clientY',
'pageX',
'pageY',
]);

export const wheelEventHandlerImpl = makeSendPropertiesHandler([
'deltaX',
'deltaY',
]);

export const keydownEventHandler = makeSendPropertiesHandler([
'ctrlKey',
'metaKey',
'shiftKey',
'keyCode',
]);

// function sendSize() {
// const rect = element.getBoundingClientRect();
// sendEvent({
// type: 'size',
// left: rect.left,
// top: rect.top,
// width: element.clientWidth,
// height: element.clientHeight,
// });
// }

// // really need to use ResizeObserver
// window.addEventListener('resize', sendSize);
// }

export const registerCanvas = (canvas: HTMLCanvasElement, workerTask: WorkerTask) => {
canvas.focus();

const offscreenPayload = new OffscreenPayload({
event: {
type: 'init'
}
});
workerTask.sentMessage(WorkerTaskMessage.fromPayload(offscreenPayload), 'proxyStart');

const eventHandlers = {
contextmenu: preventDefaultHandler,
mousedown: mouseEventHandler,
mousemove: mouseEventHandler,
mouseup: mouseEventHandler,
touchstart: touchEventHandler,
touchmove: touchEventHandler,
touchend: touchEventHandler,
wheel: wheelEventHandler,
keydown: filteredKeydownEventHandler,
};

for (const [eventName, handler] of Object.entries(eventHandlers)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
canvas.addEventListener(eventName, function(event: any) {
handler(event, (offscreenPayload: OffscreenPayload) => {
workerTask.sentMessage(WorkerTaskMessage.fromPayload(offscreenPayload), 'proxyEvent');
});
});
}
};
Loading

0 comments on commit 70b272f

Please sign in to comment.