@oliversalzburg/js-utils 0.0.28-dev.3 → 0.0.28-dev.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/graphics/canvas-sandbox-mp.d.ts +269 -0
- package/graphics/canvas-sandbox-mp.js +282 -0
- package/graphics/canvas-sandbox-mp.js.map +1 -0
- package/graphics/canvas-sandbox.d.ts +29 -2
- package/graphics/canvas-sandbox.js +9 -27
- package/graphics/canvas-sandbox.js.map +1 -1
- package/graphics/canvas.d.ts +4 -4
- package/graphics/canvas.js +6 -6
- package/graphics/canvas.js.map +1 -1
- package/graphics/canvas2d-headless.d.ts +87 -0
- package/graphics/canvas2d-headless.js +194 -0
- package/graphics/canvas2d-headless.js.map +1 -0
- package/graphics/canvas2d.d.ts +13 -12
- package/graphics/canvas2d.js +22 -13
- package/graphics/canvas2d.js.map +1 -1
- package/graphics/canvas3d.js +4 -2
- package/graphics/canvas3d.js.map +1 -1
- package/graphics/core.d.ts +0 -18
- package/graphics/core.js +0 -346
- package/graphics/core.js.map +1 -1
- package/graphics/index.d.ts +4 -0
- package/graphics/index.js +4 -0
- package/graphics/index.js.map +1 -1
- package/graphics/palette-sampler.d.ts +9 -0
- package/graphics/palette-sampler.js +24 -0
- package/graphics/palette-sampler.js.map +1 -0
- package/graphics/palette.d.ts +126 -0
- package/graphics/palette.js +475 -0
- package/graphics/palette.js.map +1 -0
- package/graphics/render-loop.js +9 -14
- package/graphics/render-loop.js.map +1 -1
- package/log/report.js +1 -1
- package/log/report.js.map +1 -1
- package/math/easing.d.ts +0 -68
- package/math/easing.js +0 -68
- package/math/easing.js.map +1 -1
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/// <reference types="@types/web" />
|
|
2
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
4
|
+
import { ConstructorOf } from "../core.js";
|
|
5
|
+
import { Random } from "../random.js";
|
|
6
|
+
import { CanvasSandboxApplication, CanvasSandboxExpectedOptions } from "./canvas-sandbox.js";
|
|
7
|
+
import { Canvas } from "./canvas.js";
|
|
8
|
+
import { Canvas2DHeadless } from "./canvas2d-headless.js";
|
|
9
|
+
import { RenderLoop } from "./render-loop.js";
|
|
10
|
+
/**
|
|
11
|
+
* Sent from the host when a worker should reconfigure itself.
|
|
12
|
+
* @group Graphics
|
|
13
|
+
*/
|
|
14
|
+
export interface CanvasWorkerMessageReconfigure<TApplicationOptions extends CanvasSandboxExpectedOptions> {
|
|
15
|
+
/**
|
|
16
|
+
* Type identifier of this message.
|
|
17
|
+
*/
|
|
18
|
+
type: "reconfigure";
|
|
19
|
+
/**
|
|
20
|
+
* New ID for the worker.
|
|
21
|
+
*/
|
|
22
|
+
id: string;
|
|
23
|
+
/**
|
|
24
|
+
* New canvas for the worker to use.
|
|
25
|
+
*/
|
|
26
|
+
canvas: OffscreenCanvas;
|
|
27
|
+
/**
|
|
28
|
+
* New application options to use.
|
|
29
|
+
*/
|
|
30
|
+
options: TApplicationOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sent from the host when a worker should start its rendering kernel.
|
|
34
|
+
* @group Graphics
|
|
35
|
+
*/
|
|
36
|
+
export interface CanvasWorkerMessageStart<TApplicationOptions extends CanvasSandboxExpectedOptions> {
|
|
37
|
+
/**
|
|
38
|
+
* Type identifier of this message.
|
|
39
|
+
*/
|
|
40
|
+
type: "start";
|
|
41
|
+
/**
|
|
42
|
+
* New application options to use before starting.
|
|
43
|
+
*/
|
|
44
|
+
options: TApplicationOptions;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sent from the host when a worker should un/pause rendering.
|
|
48
|
+
* @group Graphics
|
|
49
|
+
*/
|
|
50
|
+
export interface CanvasWorkerMessagePause {
|
|
51
|
+
/**
|
|
52
|
+
* Type identifier of this message.
|
|
53
|
+
*/
|
|
54
|
+
type: "pause";
|
|
55
|
+
/**
|
|
56
|
+
* Should the worker pause (`true`) or unpause (`false`)?
|
|
57
|
+
*/
|
|
58
|
+
pause: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Sent from a worker when it finished rendering the current scene.
|
|
62
|
+
* @group Graphics
|
|
63
|
+
*/
|
|
64
|
+
export interface CanvasWorkerSceneFinishMessage {
|
|
65
|
+
/**
|
|
66
|
+
* Type identifier of this message.
|
|
67
|
+
*/
|
|
68
|
+
type: "sceneFinish";
|
|
69
|
+
/**
|
|
70
|
+
* Point in time when the scene finished rendering.
|
|
71
|
+
*/
|
|
72
|
+
timestamp: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The messages that are passed between the canvas sandbox host and its workers.
|
|
76
|
+
* @group Graphics
|
|
77
|
+
*/
|
|
78
|
+
export type CanvasWorkerMessage<TApplicationOptions extends CanvasSandboxExpectedOptions> = CanvasWorkerMessageReconfigure<TApplicationOptions> | CanvasWorkerMessageStart<TApplicationOptions> | CanvasWorkerSceneFinishMessage | CanvasWorkerMessagePause | {
|
|
79
|
+
type: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The canvas worker handles a web worker instance in the canvas sandbox host.
|
|
83
|
+
*
|
|
84
|
+
* It provides a thin abstraction over the web worker IPC messaging.
|
|
85
|
+
* @group Graphics
|
|
86
|
+
*/
|
|
87
|
+
export declare class CanvasWorker<TApplicationOptions extends CanvasSandboxExpectedOptions> extends EventTarget {
|
|
88
|
+
/**
|
|
89
|
+
* The ID of this worker.
|
|
90
|
+
*/
|
|
91
|
+
id: string;
|
|
92
|
+
/**
|
|
93
|
+
* The canvas element that this worker should handle.
|
|
94
|
+
* This is purely for informational purposes on the host side.
|
|
95
|
+
*/
|
|
96
|
+
canvas: HTMLCanvasElement | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* The offscreen canvas that we created for this worker.
|
|
99
|
+
*/
|
|
100
|
+
canvasOffscreen: OffscreenCanvas | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* The application options for the worker.
|
|
103
|
+
*
|
|
104
|
+
* These are usually very similar, if not identical, to the host application options.
|
|
105
|
+
* Workers just usually get a different viewport assigned to them, correlating with the
|
|
106
|
+
* canvas element in the DOM that they draw to.
|
|
107
|
+
*/
|
|
108
|
+
readonly options: TApplicationOptions;
|
|
109
|
+
/**
|
|
110
|
+
* The web worker instance itself.
|
|
111
|
+
*/
|
|
112
|
+
readonly workerInstance: Worker;
|
|
113
|
+
/**
|
|
114
|
+
* Constructs a new canvas worker.
|
|
115
|
+
* @param id - The ID of the worker.
|
|
116
|
+
* @param source - The code that the worker should run. It's common to use a hybrid code module
|
|
117
|
+
* for as the sandbox application. This means the code of the host and the workers is identical,
|
|
118
|
+
* they just construct different code path on load/init. In such case, the source can simply be
|
|
119
|
+
* `new URL(import.meta.url)`.
|
|
120
|
+
* @param canvas - The canvas element to draw to.
|
|
121
|
+
* @param options - The application options.
|
|
122
|
+
*/
|
|
123
|
+
constructor(id: string, source: URL, canvas: HTMLCanvasElement, options: TApplicationOptions);
|
|
124
|
+
/**
|
|
125
|
+
* Posts a message to the worker.
|
|
126
|
+
*
|
|
127
|
+
* As messages to workers are _posted_ instead of _sent_, there is no delivery feedback.
|
|
128
|
+
* @param message - The message to post.
|
|
129
|
+
* @param transfer - The transferables to transfer to the worker with this message.
|
|
130
|
+
*/
|
|
131
|
+
postMessage(message: CanvasWorkerMessage<TApplicationOptions>, transfer?: Array<Transferable>): void;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The canvas worker instance handles a web worker instance in worker instance itself, and
|
|
135
|
+
* handles a feedback channel to the host application.
|
|
136
|
+
*
|
|
137
|
+
* It provides a thin abstraction over the web worker IPC messaging.
|
|
138
|
+
*
|
|
139
|
+
* ```ts
|
|
140
|
+
* // Construct inside of worker from global scope and rendering kernel class.
|
|
141
|
+
* const worker = new CanvasWorkerInstance(self, RenderKernel);
|
|
142
|
+
* // Listen to custom events (messages) you send from the host.
|
|
143
|
+
* worker.addEventListener("fade", () => worker.renderKernel?.fadeOut());
|
|
144
|
+
* ```
|
|
145
|
+
* @group Graphics
|
|
146
|
+
*/
|
|
147
|
+
export declare class CanvasWorkerInstance<TCanvas extends Canvas2DHeadless, TApplicationOptions extends CanvasSandboxExpectedOptions, TKernel extends CanvasSandboxApplication<TCanvas, TApplicationOptions>> extends EventTarget {
|
|
148
|
+
#private;
|
|
149
|
+
/**
|
|
150
|
+
* The global scope of the worker.
|
|
151
|
+
*/
|
|
152
|
+
readonly self: typeof globalThis;
|
|
153
|
+
/**
|
|
154
|
+
* The ID of the worker.
|
|
155
|
+
*/
|
|
156
|
+
id: string;
|
|
157
|
+
/**
|
|
158
|
+
* The rendering kernel, which produces frames, and renders them to our
|
|
159
|
+
* offscreen canvas.
|
|
160
|
+
*/
|
|
161
|
+
renderKernel: TKernel | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* The canvas element we're presenting to.
|
|
164
|
+
*/
|
|
165
|
+
canvas: TCanvas | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* The offscreen canvas we're rendering to.
|
|
168
|
+
*/
|
|
169
|
+
offscreenCanvas: OffscreenCanvas | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Our rendering context to draw to.
|
|
172
|
+
*/
|
|
173
|
+
offscreenContext: OffscreenCanvasRenderingContext2D | undefined;
|
|
174
|
+
/**
|
|
175
|
+
* Manages frame rendering timing.
|
|
176
|
+
*/
|
|
177
|
+
renderLoop: RenderLoop | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* Constructs a new canvas worker instance.
|
|
180
|
+
*
|
|
181
|
+
* Note that many properties are only initialized after the host sent an
|
|
182
|
+
* initialization message.
|
|
183
|
+
* @param self - Our global worker scope.
|
|
184
|
+
* @param Kernel - The rendering kernel class to construct.
|
|
185
|
+
*/
|
|
186
|
+
constructor(self: typeof globalThis, Kernel: ConstructorOf<TKernel>);
|
|
187
|
+
/**
|
|
188
|
+
* Render a frame.
|
|
189
|
+
* @param delta - How many milliseconds have passed since the last invocation?
|
|
190
|
+
*/
|
|
191
|
+
render: (delta: number) => void;
|
|
192
|
+
/**
|
|
193
|
+
* Reconfigure the worker.
|
|
194
|
+
* @param id - New ID for this worker.
|
|
195
|
+
* @param offscreenCanvas - New canvas to render to.
|
|
196
|
+
* @param options - New application options.
|
|
197
|
+
*/
|
|
198
|
+
reconfigure(id: string, offscreenCanvas: OffscreenCanvas, options: TApplicationOptions): void;
|
|
199
|
+
/**
|
|
200
|
+
* Start rendering.
|
|
201
|
+
* @param options - New application options.
|
|
202
|
+
*/
|
|
203
|
+
start(options: TApplicationOptions): void;
|
|
204
|
+
/**
|
|
205
|
+
* Posts a message to the host.
|
|
206
|
+
* @param message - The message to post.
|
|
207
|
+
*/
|
|
208
|
+
postMessage(message: CanvasWorkerMessage<TApplicationOptions>): void;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Base class for multi-process canvas sandbox applications.
|
|
212
|
+
*
|
|
213
|
+
* Helps in orchestrating the workers.
|
|
214
|
+
* @group Graphics
|
|
215
|
+
*/
|
|
216
|
+
export declare abstract class CanvasSandboxHostApplication<TCanvas extends Canvas, TApplicationOptions extends CanvasSandboxExpectedOptions> implements CanvasSandboxApplication<TCanvas, TApplicationOptions> {
|
|
217
|
+
/**
|
|
218
|
+
* Usually a hidden canvas that serves as a proxy for canvas sandbox events.
|
|
219
|
+
*/
|
|
220
|
+
canvas: TCanvas;
|
|
221
|
+
/**
|
|
222
|
+
* Application options.
|
|
223
|
+
*/
|
|
224
|
+
options: TApplicationOptions;
|
|
225
|
+
/**
|
|
226
|
+
* PRNG instance for the application.
|
|
227
|
+
*/
|
|
228
|
+
random: Random;
|
|
229
|
+
/**
|
|
230
|
+
* Is the application running right now?
|
|
231
|
+
*/
|
|
232
|
+
paused: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Web worker instances.
|
|
235
|
+
*/
|
|
236
|
+
readonly workers: CanvasWorker<TApplicationOptions>[];
|
|
237
|
+
/**
|
|
238
|
+
* Construct a new host application.
|
|
239
|
+
* @param canvas - Usually a hidden canvas in the DOM to serve as an event proxy.
|
|
240
|
+
* @param options - Application options.
|
|
241
|
+
*/
|
|
242
|
+
constructor(canvas: TCanvas, options: TApplicationOptions);
|
|
243
|
+
/**
|
|
244
|
+
* Reconfigure the application with the given options and restart it.
|
|
245
|
+
* @param canvas - The canvas to use.
|
|
246
|
+
* @param options - The new options to use.
|
|
247
|
+
*/
|
|
248
|
+
abstract reconfigure(canvas: TCanvas, options?: Partial<TApplicationOptions>): void;
|
|
249
|
+
/**
|
|
250
|
+
* Request the application to draw a new frame.
|
|
251
|
+
* This call has no effect in a host application, as all rendering happens in the workers.
|
|
252
|
+
* @param _delta - How many milliseconds passed since the last frame draw.
|
|
253
|
+
* @param _timestamp - The current timestamp.
|
|
254
|
+
*/
|
|
255
|
+
onDraw(_delta: number, _timestamp: number): void;
|
|
256
|
+
/**
|
|
257
|
+
* Pauses all workers.
|
|
258
|
+
*/
|
|
259
|
+
pause(): void;
|
|
260
|
+
/**
|
|
261
|
+
* Start the application.
|
|
262
|
+
*/
|
|
263
|
+
start(): void;
|
|
264
|
+
/**
|
|
265
|
+
* Posts a message to all workers.
|
|
266
|
+
* @param message - Message to post to all workers.
|
|
267
|
+
*/
|
|
268
|
+
postMessageAll(message: CanvasWorkerMessage<TApplicationOptions>): void;
|
|
269
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { isNil, mustExist } from "../nil.js";
|
|
2
|
+
import { Random } from "../random.js";
|
|
3
|
+
import { Canvas2DHeadless } from "./canvas2d-headless.js";
|
|
4
|
+
import { RenderLoop } from "./render-loop.js";
|
|
5
|
+
/**
|
|
6
|
+
* The canvas worker handles a web worker instance in the canvas sandbox host.
|
|
7
|
+
*
|
|
8
|
+
* It provides a thin abstraction over the web worker IPC messaging.
|
|
9
|
+
* @group Graphics
|
|
10
|
+
*/
|
|
11
|
+
export class CanvasWorker extends EventTarget {
|
|
12
|
+
/**
|
|
13
|
+
* The ID of this worker.
|
|
14
|
+
*/
|
|
15
|
+
id;
|
|
16
|
+
/**
|
|
17
|
+
* The canvas element that this worker should handle.
|
|
18
|
+
* This is purely for informational purposes on the host side.
|
|
19
|
+
*/
|
|
20
|
+
canvas;
|
|
21
|
+
/**
|
|
22
|
+
* The offscreen canvas that we created for this worker.
|
|
23
|
+
*/
|
|
24
|
+
canvasOffscreen;
|
|
25
|
+
/**
|
|
26
|
+
* The application options for the worker.
|
|
27
|
+
*
|
|
28
|
+
* These are usually very similar, if not identical, to the host application options.
|
|
29
|
+
* Workers just usually get a different viewport assigned to them, correlating with the
|
|
30
|
+
* canvas element in the DOM that they draw to.
|
|
31
|
+
*/
|
|
32
|
+
options;
|
|
33
|
+
/**
|
|
34
|
+
* The web worker instance itself.
|
|
35
|
+
*/
|
|
36
|
+
workerInstance;
|
|
37
|
+
/**
|
|
38
|
+
* Constructs a new canvas worker.
|
|
39
|
+
* @param id - The ID of the worker.
|
|
40
|
+
* @param source - The code that the worker should run. It's common to use a hybrid code module
|
|
41
|
+
* for as the sandbox application. This means the code of the host and the workers is identical,
|
|
42
|
+
* they just construct different code path on load/init. In such case, the source can simply be
|
|
43
|
+
* `new URL(import.meta.url)`.
|
|
44
|
+
* @param canvas - The canvas element to draw to.
|
|
45
|
+
* @param options - The application options.
|
|
46
|
+
*/
|
|
47
|
+
constructor(id, source, canvas, options) {
|
|
48
|
+
super();
|
|
49
|
+
this.id = id;
|
|
50
|
+
this.canvas = canvas;
|
|
51
|
+
this.options = options;
|
|
52
|
+
this.workerInstance = new Worker(source, {
|
|
53
|
+
type: "module",
|
|
54
|
+
});
|
|
55
|
+
// Translate messages to events.
|
|
56
|
+
this.workerInstance.onmessage = (message) => this.dispatchEvent(new CustomEvent(message.data.type));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Posts a message to the worker.
|
|
60
|
+
*
|
|
61
|
+
* As messages to workers are _posted_ instead of _sent_, there is no delivery feedback.
|
|
62
|
+
* @param message - The message to post.
|
|
63
|
+
* @param transfer - The transferables to transfer to the worker with this message.
|
|
64
|
+
*/
|
|
65
|
+
postMessage(message, transfer) {
|
|
66
|
+
this.workerInstance.postMessage(message, transfer ?? []);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The canvas worker instance handles a web worker instance in worker instance itself, and
|
|
71
|
+
* handles a feedback channel to the host application.
|
|
72
|
+
*
|
|
73
|
+
* It provides a thin abstraction over the web worker IPC messaging.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Construct inside of worker from global scope and rendering kernel class.
|
|
77
|
+
* const worker = new CanvasWorkerInstance(self, RenderKernel);
|
|
78
|
+
* // Listen to custom events (messages) you send from the host.
|
|
79
|
+
* worker.addEventListener("fade", () => worker.renderKernel?.fadeOut());
|
|
80
|
+
* ```
|
|
81
|
+
* @group Graphics
|
|
82
|
+
*/
|
|
83
|
+
export class CanvasWorkerInstance extends EventTarget {
|
|
84
|
+
/**
|
|
85
|
+
* The global scope of the worker.
|
|
86
|
+
*/
|
|
87
|
+
self;
|
|
88
|
+
/**
|
|
89
|
+
* The ID of the worker.
|
|
90
|
+
*/
|
|
91
|
+
id;
|
|
92
|
+
/**
|
|
93
|
+
* The rendering kernel, which produces frames, and renders them to our
|
|
94
|
+
* offscreen canvas.
|
|
95
|
+
*/
|
|
96
|
+
renderKernel;
|
|
97
|
+
/**
|
|
98
|
+
* The canvas element we're presenting to.
|
|
99
|
+
*/
|
|
100
|
+
canvas;
|
|
101
|
+
/**
|
|
102
|
+
* The offscreen canvas we're rendering to.
|
|
103
|
+
*/
|
|
104
|
+
offscreenCanvas;
|
|
105
|
+
/**
|
|
106
|
+
* Our rendering context to draw to.
|
|
107
|
+
*/
|
|
108
|
+
offscreenContext;
|
|
109
|
+
/**
|
|
110
|
+
* Manages frame rendering timing.
|
|
111
|
+
*/
|
|
112
|
+
renderLoop;
|
|
113
|
+
/**
|
|
114
|
+
* Constructor of our rendering kernel.
|
|
115
|
+
*/
|
|
116
|
+
#Kernel;
|
|
117
|
+
/**
|
|
118
|
+
* Constructs a new canvas worker instance.
|
|
119
|
+
*
|
|
120
|
+
* Note that many properties are only initialized after the host sent an
|
|
121
|
+
* initialization message.
|
|
122
|
+
* @param self - Our global worker scope.
|
|
123
|
+
* @param Kernel - The rendering kernel class to construct.
|
|
124
|
+
*/
|
|
125
|
+
constructor(self, Kernel) {
|
|
126
|
+
super();
|
|
127
|
+
this.self = self;
|
|
128
|
+
this.id = "<unassigned>";
|
|
129
|
+
this.#Kernel = Kernel;
|
|
130
|
+
self.onmessage = (message) => {
|
|
131
|
+
const event = new CustomEvent(message.data.type);
|
|
132
|
+
this.dispatchEvent(event);
|
|
133
|
+
if (event.defaultPrevented) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (message.data.type === "start") {
|
|
137
|
+
const startMessage = message.data;
|
|
138
|
+
this.start(startMessage.options);
|
|
139
|
+
}
|
|
140
|
+
else if (message.data.type === "pause") {
|
|
141
|
+
const pauseMessage = message.data;
|
|
142
|
+
this.renderKernel?.pause(pauseMessage.pause);
|
|
143
|
+
}
|
|
144
|
+
else if (message.data.type === "reconfigure") {
|
|
145
|
+
const reconfigureMessage = message.data;
|
|
146
|
+
this.reconfigure(reconfigureMessage.id, reconfigureMessage.canvas, reconfigureMessage.options);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Render a frame.
|
|
152
|
+
* @param delta - How many milliseconds have passed since the last invocation?
|
|
153
|
+
*/
|
|
154
|
+
render = (delta) => {
|
|
155
|
+
this.renderKernel?.onDraw(delta, new Date().valueOf());
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Reconfigure the worker.
|
|
159
|
+
* @param id - New ID for this worker.
|
|
160
|
+
* @param offscreenCanvas - New canvas to render to.
|
|
161
|
+
* @param options - New application options.
|
|
162
|
+
*/
|
|
163
|
+
reconfigure(id, offscreenCanvas, options) {
|
|
164
|
+
this.renderLoop?.block();
|
|
165
|
+
this.id = id;
|
|
166
|
+
this.offscreenCanvas = offscreenCanvas;
|
|
167
|
+
this.offscreenContext = mustExist(this.offscreenCanvas.getContext("2d"));
|
|
168
|
+
this.canvas = new Canvas2DHeadless(this.offscreenCanvas, this.offscreenContext);
|
|
169
|
+
this.renderLoop = new RenderLoop(this.render, this.canvas);
|
|
170
|
+
if (isNil(this.renderKernel)) {
|
|
171
|
+
this.renderKernel = new this.#Kernel(this, this.canvas, options);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.renderKernel.reconfigure(this.canvas, options);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Start rendering.
|
|
179
|
+
* @param options - New application options.
|
|
180
|
+
*/
|
|
181
|
+
start(options) {
|
|
182
|
+
if (!this.renderKernel) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.renderKernel.random = new Random(options.seed);
|
|
186
|
+
this.renderKernel.start(options);
|
|
187
|
+
this.renderLoop?.unblock();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Posts a message to the host.
|
|
191
|
+
* @param message - The message to post.
|
|
192
|
+
*/
|
|
193
|
+
postMessage(message) {
|
|
194
|
+
this.self.postMessage(message);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Base class for multi-process canvas sandbox applications.
|
|
199
|
+
*
|
|
200
|
+
* Helps in orchestrating the workers.
|
|
201
|
+
* @group Graphics
|
|
202
|
+
*/
|
|
203
|
+
export class CanvasSandboxHostApplication {
|
|
204
|
+
/**
|
|
205
|
+
* Usually a hidden canvas that serves as a proxy for canvas sandbox events.
|
|
206
|
+
*/
|
|
207
|
+
canvas;
|
|
208
|
+
/**
|
|
209
|
+
* Application options.
|
|
210
|
+
*/
|
|
211
|
+
options;
|
|
212
|
+
/**
|
|
213
|
+
* PRNG instance for the application.
|
|
214
|
+
*/
|
|
215
|
+
random;
|
|
216
|
+
/**
|
|
217
|
+
* Is the application running right now?
|
|
218
|
+
*/
|
|
219
|
+
paused = false;
|
|
220
|
+
/**
|
|
221
|
+
* Web worker instances.
|
|
222
|
+
*/
|
|
223
|
+
workers = new Array();
|
|
224
|
+
/**
|
|
225
|
+
* Construct a new host application.
|
|
226
|
+
* @param canvas - Usually a hidden canvas in the DOM to serve as an event proxy.
|
|
227
|
+
* @param options - Application options.
|
|
228
|
+
*/
|
|
229
|
+
constructor(canvas, options) {
|
|
230
|
+
this.options = options;
|
|
231
|
+
this.canvas = canvas;
|
|
232
|
+
this.random = new Random(options.seed);
|
|
233
|
+
this.reconfigure(canvas, options);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Request the application to draw a new frame.
|
|
237
|
+
* This call has no effect in a host application, as all rendering happens in the workers.
|
|
238
|
+
* @param _delta - How many milliseconds passed since the last frame draw.
|
|
239
|
+
* @param _timestamp - The current timestamp.
|
|
240
|
+
*/
|
|
241
|
+
onDraw(_delta, _timestamp) {
|
|
242
|
+
// Draws happen in workers.
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Pauses all workers.
|
|
246
|
+
*/
|
|
247
|
+
pause() {
|
|
248
|
+
this.paused = !this.paused;
|
|
249
|
+
for (const worker of this.workers) {
|
|
250
|
+
worker.postMessage({
|
|
251
|
+
type: "pause",
|
|
252
|
+
pause: this.paused,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Start the application.
|
|
258
|
+
*/
|
|
259
|
+
start() {
|
|
260
|
+
this.paused = false;
|
|
261
|
+
for (const worker of this.workers) {
|
|
262
|
+
worker.postMessage({
|
|
263
|
+
type: "start",
|
|
264
|
+
options: {
|
|
265
|
+
...this.options,
|
|
266
|
+
seed: this.random.seed,
|
|
267
|
+
viewport: worker.options.viewport,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Posts a message to all workers.
|
|
274
|
+
* @param message - Message to post to all workers.
|
|
275
|
+
*/
|
|
276
|
+
postMessageAll(message) {
|
|
277
|
+
for (const worker of this.workers) {
|
|
278
|
+
worker.postMessage(message);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=canvas-sandbox-mp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-sandbox-mp.js","sourceRoot":"","sources":["../../source/graphics/canvas-sandbox-mp.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,7 +37,29 @@ export interface CanvasSandboxExpectedOptions {
|
|
|
37
37
|
/**
|
|
38
38
|
* The seed for the PRNG.
|
|
39
39
|
*/
|
|
40
|
-
seed:
|
|
40
|
+
seed: number;
|
|
41
|
+
/**
|
|
42
|
+
* The part of the canvas that the targetted render kernel will handle.
|
|
43
|
+
* This is ignored, unless you use multi-process rendering.
|
|
44
|
+
*/
|
|
45
|
+
viewport: {
|
|
46
|
+
/**
|
|
47
|
+
* Start of the viewport in fractional world-space.
|
|
48
|
+
*/
|
|
49
|
+
x: number;
|
|
50
|
+
/**
|
|
51
|
+
* Start of the viewport in fractional world-space.
|
|
52
|
+
*/
|
|
53
|
+
y: number;
|
|
54
|
+
/**
|
|
55
|
+
* Width of the viewport in fractional world-space.
|
|
56
|
+
*/
|
|
57
|
+
w: number;
|
|
58
|
+
/**
|
|
59
|
+
* Height of the viewport in fractional world-space.
|
|
60
|
+
*/
|
|
61
|
+
h: number;
|
|
62
|
+
};
|
|
41
63
|
}
|
|
42
64
|
/**
|
|
43
65
|
* Describes an application running inside the {@linkcode CanvasSandbox}.
|
|
@@ -74,7 +96,12 @@ export interface CanvasSandboxApplication<TCanvas extends Canvas, TApplicationOp
|
|
|
74
96
|
/**
|
|
75
97
|
* Start the application.
|
|
76
98
|
*/
|
|
77
|
-
start(): void;
|
|
99
|
+
start(options?: Partial<TApplicationOptions>): void;
|
|
100
|
+
/**
|
|
101
|
+
* Pause rendering.
|
|
102
|
+
* @param paused - Should rendering be paused (`true`) or unpaused (`false`)?
|
|
103
|
+
*/
|
|
104
|
+
pause(paused: boolean): void;
|
|
78
105
|
}
|
|
79
106
|
/**
|
|
80
107
|
* Options for a {@linkcode CanvasSandbox}.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { Shake } from "../device/shake.js";
|
|
3
3
|
import { getDocumentElementTypeById } from "../dom/core.js";
|
|
4
|
-
import { nextPalette } from "./core.js";
|
|
5
4
|
import { RenderLoop } from "./render-loop.js";
|
|
6
5
|
/**
|
|
7
6
|
* Provides the input as-is.
|
|
@@ -51,13 +50,16 @@ export const CANVAS_SANDBOX_DEFAULT_CSS = /* PURE */ css `
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
#main {
|
|
54
|
-
display:
|
|
53
|
+
display: flex;
|
|
55
54
|
position: absolute;
|
|
56
55
|
margin: auto;
|
|
57
56
|
top: 0;
|
|
58
57
|
left: 0;
|
|
59
58
|
right: 0;
|
|
60
59
|
bottom: 0;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
align-items: center;
|
|
62
|
+
z-index: 1;
|
|
61
63
|
|
|
62
64
|
filter: drop-shadow(10px 10px 4px rgba(0, 0, 0, 0.5));
|
|
63
65
|
transition: all 1s;
|
|
@@ -269,18 +271,11 @@ export class CanvasSandbox {
|
|
|
269
271
|
switch (event.keyCode) {
|
|
270
272
|
case 13:
|
|
271
273
|
// Enter
|
|
272
|
-
|
|
273
|
-
this.#reconfigureApplication({
|
|
274
|
-
seed: this.application.random.next().toString(),
|
|
275
|
-
});
|
|
276
|
-
this.application.reconfigure(this.canvas, {
|
|
277
|
-
seed: this.application.random.next().toString(),
|
|
278
|
-
});
|
|
279
|
-
this.application.start();
|
|
274
|
+
this.#reconfigureApplication();
|
|
280
275
|
break;
|
|
281
276
|
case 32:
|
|
282
277
|
// Space
|
|
283
|
-
this.application.
|
|
278
|
+
this.application.pause(!this.application.paused);
|
|
284
279
|
break;
|
|
285
280
|
}
|
|
286
281
|
});
|
|
@@ -299,20 +294,8 @@ export class CanvasSandbox {
|
|
|
299
294
|
* Create event listeners on the canvas node in the document.
|
|
300
295
|
*/
|
|
301
296
|
#hookCanvas() {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (this.document.fullscreenElement) {
|
|
305
|
-
if (this.sandboxOptions.devMode) {
|
|
306
|
-
console.info("CanvasSandbox: Exiting fullscreen mode...");
|
|
307
|
-
}
|
|
308
|
-
await document.exitFullscreen();
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
// Run the next variation of the application.
|
|
312
|
-
nextPalette();
|
|
313
|
-
this.#reconfigureApplication({
|
|
314
|
-
seed: this.application.random.next().toString(),
|
|
315
|
-
});
|
|
297
|
+
this.canvasNode.addEventListener("click", (event) => {
|
|
298
|
+
this.application.pause(!this.application.paused);
|
|
316
299
|
event.preventDefault();
|
|
317
300
|
});
|
|
318
301
|
}
|
|
@@ -325,8 +308,7 @@ export class CanvasSandbox {
|
|
|
325
308
|
.then(() => {
|
|
326
309
|
this.shakeHandler.addEventListener("shake", () => {
|
|
327
310
|
console.info("CanvasSandbox: Shake detected. Reconfiguring application...");
|
|
328
|
-
this
|
|
329
|
-
this.application.start();
|
|
311
|
+
this.#reconfigureApplication();
|
|
330
312
|
});
|
|
331
313
|
})
|
|
332
314
|
.catch(console.error);
|