simulationjsv2 0.10.6 → 0.11.1

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.
Files changed (46) hide show
  1. package/TODO.md +4 -20
  2. package/dist/backend.d.ts +38 -0
  3. package/dist/backend.js +127 -0
  4. package/dist/backends/backend.d.ts +22 -0
  5. package/dist/backends/backend.js +21 -0
  6. package/dist/backends/webgl.d.ts +19 -0
  7. package/dist/backends/webgl.js +112 -0
  8. package/dist/backends/webgpu.d.ts +25 -0
  9. package/dist/backends/webgpu.js +134 -0
  10. package/dist/buffers/buffer.d.ts +15 -0
  11. package/dist/buffers/buffer.js +42 -0
  12. package/dist/buffers/webgl.d.ts +13 -0
  13. package/dist/buffers/webgl.js +46 -0
  14. package/dist/buffers/webgpu.d.ts +12 -0
  15. package/dist/buffers/webgpu.js +40 -0
  16. package/dist/buffers.d.ts +20 -6
  17. package/dist/buffers.js +54 -20
  18. package/dist/constants.d.ts +1 -0
  19. package/dist/constants.js +1 -0
  20. package/dist/geometry.d.ts +3 -2
  21. package/dist/geometry.js +8 -4
  22. package/dist/globals.d.ts +6 -6
  23. package/dist/globals.js +7 -12
  24. package/dist/graphics.d.ts +19 -19
  25. package/dist/graphics.js +57 -59
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.js +3 -1
  28. package/dist/internalUtils.d.ts +2 -2
  29. package/dist/internalUtils.js +3 -1
  30. package/dist/shaders/shader.d.ts +18 -0
  31. package/dist/shaders/shader.js +63 -0
  32. package/dist/shaders/utils.d.ts +33 -0
  33. package/dist/shaders/utils.js +25 -0
  34. package/dist/shaders/webgl.d.ts +74 -0
  35. package/dist/shaders/webgl.js +242 -0
  36. package/dist/shaders/webgpu.d.ts +40 -0
  37. package/dist/{shaders.js → shaders/webgpu.js} +73 -114
  38. package/dist/simulation.d.ts +11 -5
  39. package/dist/simulation.js +49 -86
  40. package/dist/types.d.ts +54 -35
  41. package/dist/utils.d.ts +3 -3
  42. package/dist/utils.js +6 -9
  43. package/package.json +26 -26
  44. package/dist/pipelineUtil.d.ts +0 -5
  45. package/dist/pipelineUtil.js +0 -22
  46. package/dist/shaders.d.ts +0 -36
@@ -1,32 +1,44 @@
1
- import { MemoBuffer } from './buffers.js';
2
- import { mat4ByteLength } from './constants.js';
3
- import { globalInfo } from './globals.js';
4
- import { createBindGroup, writeUniformWorldMatrix } from './utils.js';
5
- export const uniformBufferSize = mat4ByteLength * 2 + 4 * 2 + 8; // 4x4 matrix * 2 + vec2<f32> + 8 bc 144 is cool
1
+ import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
2
+ import { mat4ByteLength, modelProjMatOffset } from '../constants.js';
3
+ import { globalInfo, logger } from '../globals.js';
4
+ import { createBindGroup } from '../utils.js';
5
+ import { orthogonalMatrix, worldProjectionMatrix } from '../simulation.js';
6
+ import { worldProjMatOffset } from '../constants.js';
7
+ import { defaultVertexColorBufferWriter, SimJSShader } from './shader.js';
8
+ export const WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE = mat4ByteLength * 2 + 4 * 2 + 8; // 4x4 matrix * 2 + vec2<f32> + 8 bc 144 is cool
6
9
  const defaultInfos = [
7
10
  {
8
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
9
- owned: false
10
- },
11
- {
12
- usage: GPUBufferUsage.STORAGE,
11
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
13
12
  defaultSize: 10 * 4 * 16 // not sure where this came from, made it up a while ago
14
13
  }
15
14
  ];
16
- const defaultBufferWriter = (el) => {
17
- writeUniformWorldMatrix(el);
18
- // not writing to buffer[0] because the buffer exists
19
- // on the element
15
+ const defaultWebGPUUniformBufferWriter = (device, el, buffers) => {
16
+ const projBuf = el.is3d ? worldProjectionMatrix : orthogonalMatrix;
17
+ let buffer = el.getUniformBuffer();
18
+ if (!buffer) {
19
+ buffer = new WebGPUMemoBuffer(device, GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE);
20
+ el.setUniformBuffer(buffer);
21
+ }
22
+ device.queue.writeBuffer(buffer.getBuffer(), worldProjMatOffset, projBuf.buffer, projBuf.byteOffset, projBuf.byteLength);
23
+ const modelMatrix = el.getModelMatrix();
24
+ device.queue.writeBuffer(buffer.getBuffer(), modelProjMatOffset, modelMatrix.buffer, modelMatrix.byteOffset, modelMatrix.byteLength);
25
+ if (el.isInstance) {
26
+ buffers[0].write(el.getInstanceBuffer());
27
+ }
20
28
  };
21
- const defaultBindGroupGenerator = (el, buffers) => {
29
+ const defaultBindGroupGenerator = (_device, el, buffers) => {
30
+ // TODO - why is this here?
22
31
  const shader = el.getShader();
32
+ if (!shader.compatableWith('webgpu'))
33
+ throw logger.error('Wrong shader type for backend or something idk');
23
34
  const gpuBuffers = [
24
- el.getUniformBuffer(),
25
- el.isInstance ? el.getInstanceBuffer() : buffers[0].getBuffer()
35
+ el.getUniformBuffer().getBuffer(),
36
+ buffers[0].getBuffer()
26
37
  ];
27
38
  return [createBindGroup(shader, 0, gpuBuffers)];
28
39
  };
29
- export class Shader {
40
+ export class SimJSWebGPUShader extends SimJSShader {
41
+ buffers;
30
42
  bindGroupLayoutDescriptors;
31
43
  bindGroupLayouts;
32
44
  module;
@@ -34,29 +46,23 @@ export class Shader {
34
46
  fragmentMain;
35
47
  vertexMain;
36
48
  vertexBuffers;
37
- bufferLength;
38
- bufferWriter;
39
- vertexBufferWriter;
49
+ uniformBufferWriter;
40
50
  bindGroupGenerator;
41
- buffers;
42
- bufferInfos;
43
- constructor(code, descriptors, vertexParams, bufferInfos, bufferWriter, bindGroupGenerator, vertexBufferWriter, vertexMain = 'vertex_main', fragmentMain = 'fragment_main') {
51
+ bufferDeclerations;
52
+ device;
53
+ constructor(code, descriptors, vertexParams, bufferDeclerations, uniformBufferWriter, bindGroupGenerator, vertexBufferWriter, vertexMain = 'vertex_main', fragmentMain = 'fragment_main') {
54
+ super('webgpu', vertexBufferWriter);
55
+ this.buffers = [];
56
+ this.device = null;
44
57
  this.code = code;
45
58
  this.bindGroupLayoutDescriptors = descriptors;
46
59
  this.bindGroupLayouts = null;
47
60
  this.module = null;
48
- this.bufferWriter = bufferWriter;
49
- this.vertexBufferWriter = vertexBufferWriter;
61
+ this.uniformBufferWriter = uniformBufferWriter;
50
62
  this.bindGroupGenerator = bindGroupGenerator;
51
63
  this.vertexMain = vertexMain;
52
64
  this.fragmentMain = fragmentMain;
53
- this.bufferInfos = bufferInfos;
54
- this.buffers = [];
55
- for (let i = 0; i < bufferInfos.length; i++) {
56
- if (bufferInfos[i].owned === false)
57
- continue;
58
- this.buffers.push(new MemoBuffer(bufferInfos[i].usage, bufferInfos[i].defaultSize ?? 0));
59
- }
65
+ this.bufferDeclerations = bufferDeclerations;
60
66
  let stride = 0;
61
67
  const attributes = [];
62
68
  for (let i = 0; i < vertexParams.length; i++) {
@@ -72,18 +78,30 @@ export class Shader {
72
78
  arrayStride: stride,
73
79
  attributes
74
80
  };
81
+ const canvas = globalInfo.getCanvas();
82
+ if (!canvas) {
83
+ globalInfo.addToInitShader(this);
84
+ return;
85
+ }
86
+ const backend = canvas.getBackend().as('webgpu');
87
+ this.init(backend.getDeviceOrError());
88
+ }
89
+ init(device) {
90
+ this.device = device;
91
+ for (let i = 0; i < this.bufferDeclerations.length; i++) {
92
+ this.buffers.push(new WebGPUMemoBuffer(device, this.bufferDeclerations[i].usage, this.bufferDeclerations[i].defaultSize ?? 0));
93
+ }
75
94
  }
76
95
  getCode() {
77
96
  return this.code;
78
97
  }
79
- getBufferLength() {
80
- return this.bufferLength;
81
- }
82
98
  getVertexBuffers() {
83
99
  return this.vertexBuffers;
84
100
  }
85
101
  getBindGroupLayouts() {
86
- const device = globalInfo.errorGetDevice();
102
+ // TODO - probably change
103
+ const backend = globalInfo.errorGetCanvas().getBackend();
104
+ const device = backend.getDeviceOrError();
87
105
  if (!this.bindGroupLayouts) {
88
106
  this.bindGroupLayouts = this.bindGroupLayoutDescriptors.map((descriptor) => device.createBindGroupLayout(descriptor));
89
107
  }
@@ -93,10 +111,10 @@ export class Shader {
93
111
  return this.bindGroupLayoutDescriptors;
94
112
  }
95
113
  getBufferInfo() {
96
- return this.bufferInfos;
114
+ return this.bufferDeclerations;
97
115
  }
98
- getBufferWriter() {
99
- return this.bufferWriter;
116
+ getUniformBufferWriter() {
117
+ return this.uniformBufferWriter;
100
118
  }
101
119
  getVertexBufferWriter() {
102
120
  return this.vertexBufferWriter;
@@ -105,7 +123,9 @@ export class Shader {
105
123
  return this.bindGroupGenerator;
106
124
  }
107
125
  getModule() {
108
- const device = globalInfo.errorGetDevice();
126
+ // TODO - probably change
127
+ const backend = globalInfo.errorGetCanvas().getBackend();
128
+ const device = backend.getDeviceOrError();
109
129
  if (!this.module) {
110
130
  this.module = device.createShaderModule({ code: this.code });
111
131
  }
@@ -120,19 +140,20 @@ export class Shader {
120
140
  setVertexInfo(element, buffer, vertex, vertexIndex, offset) {
121
141
  this.vertexBufferWriter(element, buffer, vertex, vertexIndex, offset);
122
142
  }
123
- writeBuffers(el) {
124
- const device = globalInfo.errorGetDevice();
125
- this.bufferWriter(el, this.buffers, device);
143
+ writeUniformBuffers(el) {
144
+ if (!this.device)
145
+ throw logger.error('Shader not initialized');
146
+ this.uniformBufferWriter(this.device, el, this.buffers);
126
147
  }
127
- getBindGroups(el) {
128
- return this.bindGroupGenerator(el, this.buffers);
148
+ getBindGroups(device, el) {
149
+ return this.bindGroupGenerator(device, el, this.buffers);
129
150
  }
130
151
  }
131
152
  const positionSize = 4 * 3;
132
153
  const colorSize = 4 * 4;
133
154
  const uvSize = 4 * 2;
134
155
  const drawingInstancesSize = 4;
135
- export const defaultShader = new Shader(`struct Uniforms {
156
+ const defaultWebGPUShaderSource = `struct Uniforms {
136
157
  worldProjectionMatrix: mat4x4<f32>,
137
158
  modelProjectionMatrix: mat4x4<f32>,
138
159
  }
@@ -178,7 +199,8 @@ fn fragment_main(
178
199
  ) -> @location(0) vec4<f32> {
179
200
  return fragColor;
180
201
  }
181
- `, [
202
+ `;
203
+ export const defaultWebGPUShader = new SimJSWebGPUShader(defaultWebGPUShaderSource, [
182
204
  {
183
205
  entries: [
184
206
  {
@@ -214,7 +236,7 @@ fn fragment_main(
214
236
  size: drawingInstancesSize,
215
237
  format: 'float32'
216
238
  }
217
- ], defaultInfos, defaultBufferWriter, defaultBindGroupGenerator, (el, buffer, vertex, _, offset) => {
239
+ ], defaultInfos, defaultWebGPUUniformBufferWriter, defaultBindGroupGenerator, (el, buffer, vertex, _, offset) => {
218
240
  const material = el.getMaterial();
219
241
  const vertexColor = material.getColor();
220
242
  buffer[offset] = vertex[0];
@@ -229,54 +251,7 @@ fn fragment_main(
229
251
  buffer[offset + 8] = 0;
230
252
  buffer[offset + 9] = el.isInstanced ? 1 : 0;
231
253
  });
232
- export const vertexColorShader = new Shader(`
233
- struct Uniforms {
234
- worldProjectionMatrix: mat4x4<f32>,
235
- modelProjectionMatrix: mat4x4<f32>,
236
- }
237
-
238
- @group(0) @binding(0) var<uniform> uniforms: Uniforms;
239
-
240
- @group(0) @binding(1) var<storage> instanceMatrices: array<mat4x4f>;
241
-
242
- struct VertexOutput {
243
- @builtin(position) Position: vec4<f32>,
244
- @location(0) fragUV: vec2<f32>,
245
- @location(1) fragColor: vec4<f32>,
246
- @location(2) fragPosition: vec4<f32>,
247
- }
248
-
249
- @vertex
250
- fn vertex_main(
251
- @builtin(instance_index) instanceIdx: u32,
252
- @location(0) position: vec3<f32>,
253
- @location(1) color: vec4<f32>,
254
- @location(2) uv: vec2<f32>,
255
- @location(3) drawingInstance: f32
256
- ) -> VertexOutput {
257
- var output: VertexOutput;
258
-
259
- if (drawingInstance == 1) {
260
- output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * instanceMatrices[instanceIdx] * vec4(position, 1.0);
261
- } else {
262
- output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * vec4(position, 1.0);
263
- }
264
-
265
- output.fragUV = uv;
266
- output.fragPosition = output.Position;
267
- output.fragColor = color;
268
- return output;
269
- }
270
-
271
- @fragment
272
- fn fragment_main(
273
- @location(0) fragUV: vec2<f32>,
274
- @location(1) fragColor: vec4<f32>,
275
- @location(2) fragPosition: vec4<f32>
276
- ) -> @location(0) vec4<f32> {
277
- return fragColor;
278
- }
279
- `, [
254
+ export const defaultWebGPUVertexColorShader = new SimJSWebGPUShader(defaultWebGPUShaderSource, [
280
255
  {
281
256
  entries: [
282
257
  {
@@ -312,20 +287,4 @@ fn fragment_main(
312
287
  size: drawingInstancesSize,
313
288
  format: 'float32'
314
289
  }
315
- ], defaultInfos, defaultBufferWriter, defaultBindGroupGenerator, (el, buffer, vertex, vertexIndex, offset) => {
316
- const material = el.getMaterial();
317
- const colors = material.getVertexColors();
318
- const vertexColor = colors[vertexIndex] ?? el.getColor();
319
- // const vertexColor = color(0, 255, 255);
320
- buffer[offset] = vertex[0];
321
- buffer[offset + 1] = vertex[1];
322
- buffer[offset + 2] = vertex[2];
323
- buffer[offset + 3] = vertexColor.r / 255;
324
- buffer[offset + 4] = vertexColor.g / 255;
325
- buffer[offset + 5] = vertexColor.b / 255;
326
- buffer[offset + 6] = vertexColor.a;
327
- // TODO possibly change uv for textures
328
- buffer[offset + 7] = 0;
329
- buffer[offset + 8] = 0;
330
- buffer[offset + 9] = el.isInstanced ? 1 : 0;
331
- });
290
+ ], defaultInfos, defaultWebGPUUniformBufferWriter, defaultBindGroupGenerator, defaultVertexColorBufferWriter);
@@ -1,7 +1,8 @@
1
1
  import { SimulationElement3d } from './graphics.js';
2
- import type { Vector2, Vector3, LerpFunc } from './types.js';
2
+ import type { Vector2, Vector3, LerpFunc, BackendType } from './types.js';
3
3
  import { Color } from './utils.js';
4
4
  import { Settings } from './settings.js';
5
+ import { SimJsBackend } from './backends/backend.js';
5
6
  export declare const worldProjectionMatrix: import("./types.js").Mat4;
6
7
  export declare const orthogonalMatrix: import("./types.js").Mat4;
7
8
  export declare class Camera {
@@ -24,9 +25,13 @@ export declare class Camera {
24
25
  getAspectRatio(): number;
25
26
  }
26
27
  export declare let camera: Camera;
28
+ type SimulationOptions = {
29
+ sceneCamera?: Camera | null;
30
+ showFrameRate?: boolean;
31
+ backendMode?: BackendType;
32
+ };
27
33
  export declare class Simulation extends Settings {
28
34
  canvasRef: HTMLCanvasElement | null;
29
- private bgColor;
30
35
  private scene;
31
36
  private fittingElement;
32
37
  private running;
@@ -34,12 +39,12 @@ export declare class Simulation extends Settings {
34
39
  private resizeEvents;
35
40
  private frameRateView;
36
41
  private transparentElements;
37
- private vertexBuffer;
38
- private indexBuffer;
39
- constructor(idOrCanvasRef: string | HTMLCanvasElement, sceneCamera?: Camera | null, showFrameRate?: boolean);
42
+ private backend;
43
+ constructor(idOrCanvasRef: string | HTMLCanvasElement, options?: SimulationOptions);
40
44
  private handleCanvasResize;
41
45
  on<K extends keyof HTMLElementEventMap>(event: K, cb: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
42
46
  onResize(cb: (width: number, height: number) => void): void;
47
+ getBackend(): SimJsBackend;
43
48
  getWidth(): number;
44
49
  getHeight(): number;
45
50
  add(el: SimulationElement3d, id?: string): void;
@@ -58,3 +63,4 @@ export declare class Simulation extends Settings {
58
63
  private renderScene;
59
64
  fitElement(): void;
60
65
  }
66
+ export {};
@@ -1,9 +1,10 @@
1
1
  import { vec3 } from 'wgpu-matrix';
2
- import { Color, matrix4, transitionValues, vector2, vector3 } from './utils.js';
3
- import { buildDepthTexture, buildMultisampleTexture, updateProjectionMatrix, getVertexAndIndexSize, updateOrthoProjectionMatrix, updateWorldProjectionMatrix, CachedArray, addToScene, removeSceneObj, removeSceneId } from './internalUtils.js';
2
+ import { matrix4, transitionValues, vector2, vector3, webGLAvailable } from './utils.js';
3
+ import { updateProjectionMatrix, updateOrthoProjectionMatrix, updateWorldProjectionMatrix, CachedArray, addToScene, removeSceneObj, removeSceneId } from './internalUtils.js';
4
4
  import { Settings } from './settings.js';
5
- import { MemoBuffer } from './buffers.js';
6
5
  import { globalInfo, logger } from './globals.js';
6
+ import { WebGLBackend } from './backends/webgl.js';
7
+ import { WebGPUBackend } from './backends/webgpu.js';
7
8
  const simjsFrameRateCss = `.simjs-frame-rate {
8
9
  position: absolute;
9
10
  top: 0;
@@ -142,9 +143,13 @@ export class Camera {
142
143
  }
143
144
  }
144
145
  export let camera = new Camera(vector3());
146
+ const defaultSimulationOptions = {
147
+ sceneCamera: null,
148
+ showFrameRate: false,
149
+ backendMode: 'webgpu'
150
+ };
145
151
  export class Simulation extends Settings {
146
152
  canvasRef = null;
147
- bgColor = new Color(255, 255, 255);
148
153
  scene = [];
149
154
  fittingElement = false;
150
155
  running = true;
@@ -152,9 +157,9 @@ export class Simulation extends Settings {
152
157
  resizeEvents;
153
158
  frameRateView;
154
159
  transparentElements;
155
- vertexBuffer;
156
- indexBuffer;
157
- constructor(idOrCanvasRef, sceneCamera = null, showFrameRate = false) {
160
+ backend;
161
+ constructor(idOrCanvasRef, options = {}) {
162
+ const { sceneCamera = defaultSimulationOptions.sceneCamera, showFrameRate = defaultSimulationOptions.showFrameRate, backendMode = defaultSimulationOptions.backendMode } = options;
158
163
  super();
159
164
  if (typeof idOrCanvasRef === 'string') {
160
165
  const ref = document.getElementById(idOrCanvasRef);
@@ -181,8 +186,15 @@ export class Simulation extends Settings {
181
186
  this.frameRateView = new FrameRateView(showFrameRate);
182
187
  this.frameRateView.updateFrameRate(1);
183
188
  this.transparentElements = new CachedArray();
184
- this.vertexBuffer = new MemoBuffer(GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, 0);
185
- this.indexBuffer = new MemoBuffer(GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, 0);
189
+ if (backendMode === 'webgpu' && 'gpu' in navigator) {
190
+ this.backend = new WebGPUBackend();
191
+ }
192
+ else if (webGLAvailable(this.canvasRef)) {
193
+ this.backend = new WebGLBackend();
194
+ }
195
+ else {
196
+ throw logger.error('WebGL and WebGPU not available');
197
+ }
186
198
  }
187
199
  handleCanvasResize(parent) {
188
200
  if (this.fittingElement) {
@@ -199,6 +211,9 @@ export class Simulation extends Settings {
199
211
  onResize(cb) {
200
212
  this.resizeEvents.push(cb);
201
213
  }
214
+ getBackend() {
215
+ return this.backend;
216
+ }
202
217
  getWidth() {
203
218
  return this.canvasRef?.width || 0;
204
219
  }
@@ -242,35 +257,23 @@ export class Simulation extends Settings {
242
257
  (async () => {
243
258
  if (this.canvasRef === null)
244
259
  return;
245
- this.initialized = true;
246
- this.running = true;
247
- const adapter = await navigator.gpu.requestAdapter();
248
- if (!adapter)
249
- throw logger.error('Adapter is null');
250
- const ctx = this.canvasRef.getContext('webgpu');
251
- if (!ctx)
252
- throw logger.error('Context is null');
253
- const device = await adapter.requestDevice();
254
- globalInfo.setDevice(device);
255
260
  const screenSize = vector2(this.canvasRef.width, this.canvasRef.height);
256
261
  camera.setScreenSize(screenSize);
257
262
  const canvas = this.canvasRef;
258
263
  canvas.width = canvas.clientWidth * devicePixelRatio;
259
264
  canvas.height = canvas.clientHeight * devicePixelRatio;
260
- const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
261
- ctx.configure({
262
- device,
263
- format: presentationFormat,
264
- alphaMode: 'opaque'
265
- });
266
- this.render(device, ctx, canvas);
265
+ this.initialized = true;
266
+ this.running = true;
267
+ await this.backend.init(this.canvasRef);
268
+ this.backend.initShaders(globalInfo.getToInitShaders());
269
+ this.render(canvas, this.backend);
267
270
  })();
268
271
  }
269
272
  stop() {
270
273
  this.running = false;
271
274
  }
272
275
  setBackground(color) {
273
- this.bgColor = color;
276
+ this.backend.setClearColor(color);
274
277
  }
275
278
  setDefaultColor(color) {
276
279
  globalInfo.setDefaultColor(color);
@@ -281,15 +284,7 @@ export class Simulation extends Settings {
281
284
  getScene() {
282
285
  return this.scene;
283
286
  }
284
- render(device, ctx, canvas) {
285
- const colorAttachment = {
286
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
287
- // @ts-ignore
288
- view: undefined, // Assigned later
289
- clearValue: this.bgColor.toObject(),
290
- loadOp: 'clear',
291
- storeOp: 'store'
292
- };
287
+ render(canvas, backend) {
293
288
  const newAspectRatio = canvas.width / canvas.height;
294
289
  if (newAspectRatio !== aspectRatio) {
295
290
  updateProjectionMatrix(projMat, newAspectRatio);
@@ -297,23 +292,11 @@ export class Simulation extends Settings {
297
292
  }
298
293
  updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
299
294
  updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
300
- let multisampleTexture = buildMultisampleTexture(device, ctx, canvas.width, canvas.height);
301
- let depthTexture = buildDepthTexture(device, canvas.width, canvas.height);
302
- const renderPassDescriptor = {
303
- colorAttachments: [colorAttachment],
304
- depthStencilAttachment: {
305
- view: depthTexture.createView(),
306
- depthClearValue: 1.0,
307
- depthLoadOp: 'clear',
308
- depthStoreOp: 'store'
309
- }
310
- };
295
+ backend.renderStart(canvas);
311
296
  // sub 10 to start with a reasonable gap between starting time and next frame time
312
297
  let prev = Date.now() - 10;
313
298
  let prevFps = 0;
314
299
  const frame = async () => {
315
- if (!canvas)
316
- return;
317
300
  requestAnimationFrame(frame);
318
301
  if (!this.running)
319
302
  return;
@@ -333,36 +316,23 @@ export class Simulation extends Settings {
333
316
  aspectRatio = camera.getAspectRatio();
334
317
  updateProjectionMatrix(projMat, aspectRatio);
335
318
  updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
336
- multisampleTexture = buildMultisampleTexture(device, ctx, screenSize[0], screenSize[1]);
337
- depthTexture = buildDepthTexture(device, screenSize[0], screenSize[1]);
338
- renderPassDescriptor.depthStencilAttachment.view = depthTexture.createView();
319
+ backend.updateTextures(screenSize);
339
320
  }
340
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
341
- // @ts-ignore
342
- renderPassDescriptor.colorAttachments[0].view = multisampleTexture.createView();
343
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
344
- // @ts-ignore
345
- renderPassDescriptor.colorAttachments[0].resolveTarget = ctx.getCurrentTexture().createView();
346
321
  if (camera.hasUpdated()) {
347
322
  updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
348
323
  updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
349
324
  }
350
- const commandEncoder = device.createCommandEncoder();
351
- const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
352
- const [totalVerticesSize, totalIndexSize] = getVertexAndIndexSize(this.scene);
353
- this.vertexBuffer.setSize(totalVerticesSize * 4);
354
- this.indexBuffer.setSize(totalIndexSize * 4);
325
+ backend.preRender(this.scene);
355
326
  this.transparentElements.reset();
356
- const [opaqueVertexOffset, opaqueIndexOffset] = this.renderScene(device, passEncoder, this.vertexBuffer.getBuffer(), this.indexBuffer.getBuffer(), 0, 0, this.scene, this.scene.length, diff, false);
357
- this.renderScene(device, passEncoder, this.vertexBuffer.getBuffer(), this.indexBuffer.getBuffer(), opaqueVertexOffset, opaqueIndexOffset, this.transparentElements.getArray(), this.transparentElements.length, diff, true);
327
+ const [opaqueVertexOffset, opaqueIndexOffset] = this.renderScene(backend, 0, 0, this.scene, this.scene.length, diff, false);
328
+ this.renderScene(backend, opaqueVertexOffset, opaqueIndexOffset, this.transparentElements.getArray(), this.transparentElements.length, diff, true);
358
329
  camera.updateConsumed();
359
- passEncoder.end();
360
- device.queue.submit([commandEncoder.finish()]);
330
+ backend.finishRender();
361
331
  };
362
332
  requestAnimationFrame(frame);
363
333
  }
364
- renderScene(device, passEncoder, vertexBuffer, indexBuffer, startVertexOffset, startIndexOffset, scene, numElements, diff, transparent) {
365
- let vertexOffset = startVertexOffset;
334
+ renderScene(backend, startVertexCallOffset, startIndexOffset, scene, numElements, diff, transparent) {
335
+ let vertexCallOffset = startVertexCallOffset;
366
336
  let indexOffset = startIndexOffset;
367
337
  for (let i = 0; i < numElements; i++) {
368
338
  const obj = scene[i];
@@ -372,30 +342,23 @@ export class Simulation extends Settings {
372
342
  }
373
343
  if (obj.hasChildren()) {
374
344
  const childObjects = obj.getChildrenInfos();
375
- const [vertexDiff, indexDiff] = this.renderScene(device, passEncoder, vertexBuffer, indexBuffer, vertexOffset, indexOffset, childObjects, childObjects.length, diff, transparent);
376
- vertexOffset += vertexDiff;
345
+ const [vertexDiff, indexDiff] = this.renderScene(backend, vertexCallOffset, indexOffset, childObjects, childObjects.length, diff, transparent);
346
+ vertexCallOffset += vertexDiff;
377
347
  indexOffset += indexDiff;
378
348
  }
379
349
  if (obj.isEmpty)
380
350
  continue;
381
- const vertices = obj.getVertexBuffer();
351
+ const vertexCallBuffer = obj.getVertexCallBuffer();
382
352
  const indices = obj.getIndexBuffer();
383
- device.queue.writeBuffer(vertexBuffer, vertexOffset, vertices.buffer, vertices.byteOffset, vertices.byteLength);
384
- device.queue.writeBuffer(indexBuffer, indexOffset, indices.buffer, indices.byteOffset, indices.byteLength);
385
- passEncoder.setVertexBuffer(0, vertexBuffer, vertexOffset, vertices.byteLength);
386
- passEncoder.setIndexBuffer(indexBuffer, 'uint32', indexOffset, indices.byteLength);
387
- passEncoder.setPipeline(obj.getPipeline());
388
- obj.writeBuffers();
389
- const instances = obj.isInstance ? obj.getNumInstances() : 1;
390
- const bindGroups = obj.getShader().getBindGroups(obj);
391
- for (let i = 0; i < bindGroups.length; i++) {
392
- passEncoder.setBindGroup(i, bindGroups[i]);
393
- }
394
- passEncoder.drawIndexed(indices.length, instances);
395
- vertexOffset += vertices.byteLength;
353
+ backend.draw(obj,
354
+ // vertex
355
+ vertexCallOffset, vertexCallBuffer,
356
+ // index
357
+ indexOffset, indices);
358
+ vertexCallOffset += vertexCallBuffer.byteLength;
396
359
  indexOffset += indices.byteLength;
397
360
  }
398
- return [vertexOffset - startVertexOffset, indexOffset - startIndexOffset];
361
+ return [vertexCallOffset - startVertexCallOffset, indexOffset - startIndexOffset];
399
362
  }
400
363
  fitElement() {
401
364
  if (this.canvasRef === null)