simulationjsv2 0.11.1 → 0.11.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # SimulationJS v2
2
2
 
3
- SimulationJS is a graphics library with simple easy to use APIs. Version 2 hopes to improve 3d graphics and boost performance by using webgpu under the hood.
3
+ SimulationJS is a graphics library with simple easy to use APIs. Version 2 hopes to improve 2d/3d graphics and boost performance by using webgpu or webgl2 under the hood.
4
4
 
5
5
  Watch a quick demo
6
6
 
@@ -1,12 +1,14 @@
1
1
  import { SimulationElement3d } from '../graphics.js';
2
2
  import { SimJSShader } from '../shaders/shader.js';
3
+ import { Simulation } from '../simulation.js';
3
4
  import { BackendType, GPUBuffers, SpecificBackendType, Vector2 } from '../types.js';
4
5
  import { Color } from '../utils.js';
5
6
  export declare abstract class SimJsBackend {
6
- private type;
7
+ protected sim: Simulation;
8
+ protected type: BackendType;
7
9
  protected abstract buffers: GPUBuffers<unknown> | null;
8
10
  protected clearColor: Color;
9
- constructor(type: BackendType);
11
+ constructor(sim: Simulation, type: BackendType);
10
12
  getBackendType(): BackendType;
11
13
  abstract init(canvas: HTMLCanvasElement): Promise<void>;
12
14
  abstract renderStart(canvas: HTMLCanvasElement): void;
@@ -14,7 +16,7 @@ export declare abstract class SimJsBackend {
14
16
  abstract preRender(scene: SimulationElement3d[]): void;
15
17
  abstract finishRender(): void;
16
18
  abstract draw(obj: SimulationElement3d, vertexCallOffset: number, vertexCallBuffer: Float32Array, indexOffset: number, indices: Uint32Array): void;
17
- abstract initShaders(shaders: SimJSShader[]): void;
19
+ abstract initShader(shaders: SimJSShader): void;
18
20
  abstract destroy(): void;
19
21
  abstract onClearColorChange(): void;
20
22
  setClearColor(color: Color): void;
@@ -1,9 +1,11 @@
1
1
  import { logger } from '../globals.js';
2
2
  import { color } from '../utils.js';
3
3
  export class SimJsBackend {
4
+ sim;
4
5
  type;
5
6
  clearColor = color();
6
- constructor(type) {
7
+ constructor(sim, type) {
8
+ this.sim = sim;
7
9
  this.type = type;
8
10
  }
9
11
  getBackendType() {
@@ -2,17 +2,18 @@ import { SimulationElement3d } from '../graphics.js';
2
2
  import { SimJsBackend } from './backend.js';
3
3
  import { SimJSShader } from '../shaders/shader.js';
4
4
  import { GPUBuffers, Vector2 } from '../types.js';
5
+ import { Simulation } from '../simulation.js';
5
6
  export declare class WebGLBackend extends SimJsBackend {
6
7
  private gl;
7
8
  protected buffers: GPUBuffers<'webgl'> | null;
8
- constructor();
9
+ constructor(sim: Simulation);
9
10
  init(canvas: HTMLCanvasElement): Promise<void>;
10
11
  getContextOrError(): WebGL2RenderingContext;
11
12
  renderStart(_canvas: HTMLCanvasElement): void;
12
13
  updateTextures(screenSize: Vector2): void;
13
14
  preRender(): void;
14
15
  finishRender(): void;
15
- initShaders(shaders: SimJSShader[]): void;
16
+ initShader(shader: SimJSShader): void;
16
17
  draw(obj: SimulationElement3d, vertexCallOffset: number, vertexCallBuffer: Float32Array, indexOffset: number, indices: Uint32Array): void;
17
18
  destroy(): void;
18
19
  onClearColorChange(): void;
@@ -1,12 +1,12 @@
1
1
  import { logger } from '../globals.js';
2
2
  import { SimJsBackend } from './backend.js';
3
3
  import { WebGLMemoBuffer } from '../buffers/webgl.js';
4
+ import { defaultWebGLShader, defaultWebGLVertexColorShader } from '../shaders/webgl.js';
4
5
  export class WebGLBackend extends SimJsBackend {
5
6
  gl = null;
6
7
  buffers = null;
7
- constructor() {
8
- super('webgl');
9
- console.log('new webgl backend');
8
+ constructor(sim) {
9
+ super(sim, 'webgl');
10
10
  }
11
11
  async init(canvas) {
12
12
  this.gl = canvas.getContext('webgl2');
@@ -21,6 +21,8 @@ export class WebGLBackend extends SimJsBackend {
21
21
  const clearColor = this.clearColor.toObject();
22
22
  this.gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
23
23
  this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
24
+ this.initShader(defaultWebGLShader);
25
+ this.initShader(defaultWebGLVertexColorShader);
24
26
  }
25
27
  getContextOrError() {
26
28
  if (!this.gl)
@@ -58,21 +60,17 @@ export class WebGLBackend extends SimJsBackend {
58
60
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
59
61
  }
60
62
  finishRender() { }
61
- initShaders(shaders) {
63
+ initShader(shader) {
62
64
  if (!this.gl)
63
65
  throw logger.error('WebGL context is null');
64
- for (let i = 0; i < shaders.length; i++) {
65
- const shader = shaders[i];
66
- if (shader.compatableWith('webgl')) {
67
- shader.as('webgl').init(this.gl);
68
- }
69
- }
66
+ const webglShader = shader.as('webgl');
67
+ webglShader.init(this.gl);
70
68
  }
71
69
  draw(obj, vertexCallOffset, vertexCallBuffer, indexOffset, indices) {
72
70
  if (!this.gl || !this.buffers)
73
71
  throw logger.error('Invalid draw state');
74
72
  const gl = this.gl;
75
- const shader = obj.getShader().as('webgl');
73
+ const shader = obj.getShaderOrError().as('webgl');
76
74
  const shaderProgram = shader.getShaderProgram();
77
75
  if (!shaderProgram)
78
76
  throw logger.error('Null shader program');
@@ -1,5 +1,7 @@
1
1
  import { SimulationElement3d } from '../graphics.js';
2
2
  import { SimJSShader } from '../shaders/shader.js';
3
+ import { SimJSWebGPUShader } from '../shaders/webgpu.js';
4
+ import { Simulation } from '../simulation.js';
3
5
  import { GPUBuffers, Vector2 } from '../types.js';
4
6
  import { SimJsBackend } from './backend.js';
5
7
  export declare class WebGPUBackend extends SimJsBackend {
@@ -11,7 +13,7 @@ export declare class WebGPUBackend extends SimJsBackend {
11
13
  private passEncoder;
12
14
  private commandEncoder;
13
15
  protected buffers: GPUBuffers<'webgpu'> | null;
14
- constructor();
16
+ constructor(sim: Simulation);
15
17
  getDeviceOrError(): GPUDevice;
16
18
  init(canvas: HTMLCanvasElement): Promise<void>;
17
19
  renderStart(canvas: HTMLCanvasElement): void;
@@ -20,6 +22,13 @@ export declare class WebGPUBackend extends SimJsBackend {
20
22
  preRender(scene: SimulationElement3d[]): void;
21
23
  finishRender(): void;
22
24
  draw(obj: SimulationElement3d, vertexCallOffset: number, vertexCallBuffer: Float32Array, indexOffset: number, indices: Uint32Array): void;
23
- initShaders(shaders: SimJSShader[]): void;
25
+ initShader(shader: SimJSShader): void;
24
26
  onClearColorChange(): void;
27
+ private getPipeline;
28
+ }
29
+ export declare class PipelineCache {
30
+ private pipelines;
31
+ constructor();
32
+ getPipeline(sim: Simulation, device: GPUDevice, info: string, shader: SimJSWebGPUShader): GPURenderPipeline;
25
33
  }
34
+ export declare const pipelineCache: PipelineCache;
@@ -1,6 +1,7 @@
1
1
  import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
2
2
  import { logger } from '../globals.js';
3
3
  import { buildDepthTexture, buildMultisampleTexture, getVertexAndIndexSize } from '../internalUtils.js';
4
+ import { defaultWebGPUShader, defaultWebGPUVertexColorShader } from '../shaders/webgpu.js';
4
5
  import { SimJsBackend } from './backend.js';
5
6
  export class WebGPUBackend extends SimJsBackend {
6
7
  device = null;
@@ -11,8 +12,8 @@ export class WebGPUBackend extends SimJsBackend {
11
12
  passEncoder = null;
12
13
  commandEncoder = null;
13
14
  buffers = null;
14
- constructor() {
15
- super('webgpu');
15
+ constructor(sim) {
16
+ super(sim, 'webgpu');
16
17
  }
17
18
  getDeviceOrError() {
18
19
  if (!this.device)
@@ -37,6 +38,8 @@ export class WebGPUBackend extends SimJsBackend {
37
38
  gpuVertexCallBuffer: new WebGPUMemoBuffer(this.device, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, 0),
38
39
  gpuIndexBuffer: new WebGPUMemoBuffer(this.device, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, 0)
39
40
  };
41
+ this.initShader(defaultWebGPUShader);
42
+ this.initShader(defaultWebGPUVertexColorShader);
40
43
  }
41
44
  renderStart(canvas) {
42
45
  if (!this.device || !this.ctx)
@@ -102,10 +105,10 @@ export class WebGPUBackend extends SimJsBackend {
102
105
  this.device.queue.writeBuffer(this.buffers.gpuIndexBuffer.getBuffer(), indexOffset, indices.buffer, indices.byteOffset, indices.byteLength);
103
106
  this.passEncoder.setVertexBuffer(0, this.buffers.gpuVertexCallBuffer.getBuffer(), vertexCallOffset, vertexCallBuffer.byteLength);
104
107
  this.passEncoder.setIndexBuffer(this.buffers.gpuIndexBuffer.getBuffer(), 'uint32', indexOffset, indices.byteLength);
105
- this.passEncoder.setPipeline(obj.getPipeline());
106
- const shader = obj.getShader().as('webgpu');
108
+ this.passEncoder.setPipeline(this.getPipeline(obj));
109
+ const shader = obj.getShaderOrError().as('webgpu');
107
110
  shader.writeUniformBuffers(obj);
108
- const bindGroups = shader.getBindGroups(this.device, obj);
111
+ const bindGroups = shader.getBindGroups(this.sim, this.device, obj);
109
112
  for (let i = 0; i < bindGroups.length; i++) {
110
113
  this.passEncoder.setBindGroup(i, bindGroups[i]);
111
114
  }
@@ -114,15 +117,11 @@ export class WebGPUBackend extends SimJsBackend {
114
117
  : 1;
115
118
  this.passEncoder.drawIndexed(indices.length, instances);
116
119
  }
117
- initShaders(shaders) {
120
+ initShader(shader) {
118
121
  if (!this.device)
119
122
  throw logger.error('WebGPU device is null');
120
- for (let i = 0; i < shaders.length; i++) {
121
- const shader = shaders[i];
122
- if (shader.compatableWith('webgpu')) {
123
- shader.as('webgpu').init(this.device);
124
- }
125
- }
123
+ const webGPUShader = shader.as('webgpu');
124
+ webGPUShader.init(this.device);
126
125
  }
127
126
  onClearColorChange() {
128
127
  if (!this.renderPassDescriptor)
@@ -131,4 +130,72 @@ export class WebGPUBackend extends SimJsBackend {
131
130
  .colorAttachments;
132
131
  colorAttachments[0].clearValue = this.clearColor.toObject();
133
132
  }
133
+ getPipeline(obj) {
134
+ if (!this.device)
135
+ throw logger.error('Backend not initialized');
136
+ const objInfo = obj.getObjectInfo();
137
+ return pipelineCache.getPipeline(this.sim, this.device, objInfo, obj.getShaderOrError().as('webgpu'));
138
+ }
139
+ }
140
+ export class PipelineCache {
141
+ pipelines;
142
+ constructor() {
143
+ this.pipelines = new Map();
144
+ }
145
+ getPipeline(sim, device, info, shader) {
146
+ const res = this.pipelines.get(info);
147
+ if (res)
148
+ return res;
149
+ const pipeline = createPipeline(sim, device, info, shader);
150
+ this.pipelines.set(info, pipeline);
151
+ return pipeline;
152
+ }
153
+ }
154
+ export const pipelineCache = new PipelineCache();
155
+ function createPipeline(sim, device, info, shader) {
156
+ const shaderModule = shader.getModule();
157
+ const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
158
+ const infoObj = JSON.parse(info);
159
+ return device.createRenderPipeline({
160
+ layout: device.createPipelineLayout({
161
+ bindGroupLayouts: shader.getBindGroupLayouts(sim)
162
+ }),
163
+ vertex: {
164
+ module: shaderModule,
165
+ entryPoint: shader.getVertexMain(),
166
+ buffers: [shader.getVertexBuffers()]
167
+ },
168
+ fragment: {
169
+ module: shaderModule,
170
+ entryPoint: 'fragment_main',
171
+ targets: [
172
+ {
173
+ format: presentationFormat,
174
+ blend: {
175
+ color: {
176
+ srcFactor: 'src-alpha',
177
+ dstFactor: 'one-minus-src-alpha'
178
+ },
179
+ alpha: {
180
+ srcFactor: 'src-alpha',
181
+ dstFactor: 'one-minus-src-alpha'
182
+ }
183
+ }
184
+ }
185
+ ]
186
+ },
187
+ primitive: {
188
+ topology: infoObj.topology,
189
+ stripIndexFormat: infoObj.topology.endsWith('strip') ? 'uint32' : undefined,
190
+ cullMode: infoObj.cullMode
191
+ },
192
+ multisample: {
193
+ count: 4
194
+ },
195
+ depthStencil: {
196
+ depthWriteEnabled: !infoObj.transparent,
197
+ depthCompare: 'less',
198
+ format: 'depth24plus'
199
+ }
200
+ });
134
201
  }
@@ -13,7 +13,7 @@ export declare abstract class Geometry<T extends EmptyParams> {
13
13
  protected vertices: Vector3[];
14
14
  protected topology: 'list' | 'strip';
15
15
  constructor(geometryType?: 'list' | 'strip');
16
- getTopology(): "strip" | "list";
16
+ getTopology(): "list" | "strip";
17
17
  computeVertices(): void;
18
18
  compute(): void;
19
19
  triangulate(): void;
package/dist/globals.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- import { SimJSShader } from './shaders/shader.js';
2
- import { SimJSWebGPUShader } from './shaders/webgpu.js';
3
- import { Simulation } from './simulation.js';
4
1
  import { Color } from './utils.js';
5
2
  declare class Logger {
6
3
  constructor();
@@ -12,23 +9,10 @@ declare class Logger {
12
9
  }
13
10
  export declare const logger: Logger;
14
11
  export declare class GlobalInfo {
15
- private canvas;
16
12
  private defaultColor;
17
- private toInitShaders;
18
13
  constructor();
19
14
  setDefaultColor(color: Color): void;
20
15
  getDefaultColor(): Color;
21
- setCanvas(canvas: Simulation): void;
22
- errorGetCanvas(): Simulation;
23
- getCanvas(): Simulation | null;
24
- addToInitShader(shader: SimJSShader): void;
25
- getToInitShaders(): SimJSShader[];
26
16
  }
27
17
  export declare const globalInfo: GlobalInfo;
28
- export declare class PipelineCache {
29
- private pipelines;
30
- constructor();
31
- getPipeline(device: GPUDevice, info: string, shader: SimJSWebGPUShader): GPURenderPipeline;
32
- }
33
- export declare const pipelineCache: PipelineCache;
34
18
  export {};
package/dist/globals.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createPipeline } from './internalUtils.js';
2
1
  import { color } from './utils.js';
3
2
  class Logger {
4
3
  constructor() { }
@@ -20,13 +19,9 @@ class Logger {
20
19
  }
21
20
  export const logger = new Logger();
22
21
  export class GlobalInfo {
23
- canvas;
24
22
  defaultColor;
25
- toInitShaders;
26
23
  constructor() {
27
- this.canvas = null;
28
24
  this.defaultColor = null;
29
- this.toInitShaders = [];
30
25
  }
31
26
  setDefaultColor(color) {
32
27
  this.defaultColor = color;
@@ -34,35 +29,5 @@ export class GlobalInfo {
34
29
  getDefaultColor() {
35
30
  return this.defaultColor?.clone() ?? color();
36
31
  }
37
- setCanvas(canvas) {
38
- this.canvas = canvas;
39
- }
40
- errorGetCanvas() {
41
- if (!this.canvas)
42
- throw logger.error('Canvas is null');
43
- return this.canvas;
44
- }
45
- getCanvas() {
46
- return this.canvas;
47
- }
48
- addToInitShader(shader) {
49
- this.toInitShaders.push(shader);
50
- }
51
- getToInitShaders() {
52
- return this.toInitShaders;
53
- }
54
32
  }
55
33
  export const globalInfo = new GlobalInfo();
56
- export class PipelineCache {
57
- pipelines;
58
- constructor() {
59
- this.pipelines = new Map();
60
- }
61
- getPipeline(device, info, shader) {
62
- const res = this.pipelines.get(info);
63
- if (!res)
64
- return createPipeline(device, info, shader);
65
- return res;
66
- }
67
- }
68
- export const pipelineCache = new PipelineCache();
@@ -1,16 +1,16 @@
1
- import type { Vector2, Vector3, LerpFunc, Mat4 } from './types.js';
1
+ import type { Vector2, Vector3, LerpFunc, Mat4, BackendType } from './types.js';
2
2
  import { Vertex, Color } from './utils.js';
3
3
  import { BlankGeometry, CircleGeometry, CubeGeometry, Geometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry, TraceLinesGeometry as TraceLinesGeometry } from './geometry.js';
4
4
  import { Float32ArrayCache } from './internalUtils.js';
5
5
  import { SimJSShader } from './shaders/shader.js';
6
6
  import { Material } from './materials.js';
7
7
  import { MemoBuffer } from './buffers/buffer.js';
8
+ import { Simulation } from './simulation.js';
8
9
  export declare abstract class SimulationElement3d {
10
+ protected sim: Simulation | null;
9
11
  private children;
10
- private prevInfo;
11
- private pipeline;
12
12
  protected id: string | null;
13
- protected shader: SimJSShader;
13
+ protected shader: SimJSShader | null;
14
14
  protected material: Material;
15
15
  protected cullMode: GPUCullMode;
16
16
  protected parent: SimulationElement3d | null;
@@ -27,6 +27,10 @@ export declare abstract class SimulationElement3d {
27
27
  is3d: boolean;
28
28
  isEmpty: boolean;
29
29
  constructor(pos: Vector3, rotation: Vector3, color?: Color);
30
+ onAddToScene(sim: Simulation, backendSpecificShaderFetchFn?: (type: BackendType) => SimJSShader): void;
31
+ getParentSim(): Simulation | null;
32
+ getParentSimOrError(): Simulation;
33
+ isOnCanvas(): boolean;
30
34
  delete(): void;
31
35
  setUniformBuffer(buffer: MemoBuffer): void;
32
36
  getUniformBuffer(): MemoBuffer | null;
@@ -52,18 +56,18 @@ export declare abstract class SimulationElement3d {
52
56
  setSubdivisionVertexLimit(limit: number): void;
53
57
  clearSubdivisionVertexLimit(): void;
54
58
  setCenterOffset(offset: Vector3): void;
55
- getShader(): SimJSShader;
59
+ getShader(): SimJSShader | null;
60
+ getShaderOrError(): SimJSShader;
56
61
  setShader(shader: SimJSShader): void;
57
62
  resetCenterOffset(): void;
58
63
  getModelMatrix(): Mat4;
59
64
  isTransparent(): boolean;
60
65
  getObjectInfo(): string;
61
- getPipeline(): GPURenderPipeline;
62
66
  protected mirrorParentTransforms3d(mat: Mat4): void;
63
67
  protected updateModelMatrix3d(): void;
64
68
  protected mirrorParentTransforms2d(mat: Mat4): void;
65
69
  protected updateModelMatrix2d(): void;
66
- getGeometryTopology(): "strip" | "list";
70
+ getGeometryTopology(): "list" | "strip";
67
71
  setWireframe(wireframe: boolean): void;
68
72
  isWireframe(): boolean;
69
73
  getMaterial(): Material;
@@ -136,6 +140,7 @@ export declare class OutlineCircle extends Circle {
136
140
  export declare class Polygon extends SimulationElement2d {
137
141
  protected geometry: PolygonGeometry;
138
142
  constructor(pos: Vector2, vertices: Vertex[], color?: Color, rotation?: number);
143
+ onAddToScene(sim: Simulation): void;
139
144
  getVertices(): Vector3[];
140
145
  setVertices(vertices: Vertex[], t?: number, f?: LerpFunc): Promise<void>;
141
146
  }
@@ -208,6 +213,7 @@ export declare class Spline2d extends SimulationElement2d {
208
213
  private interpolateLimit;
209
214
  private length;
210
215
  constructor(pos: Vertex, points: SplinePoint2d[], thickness?: number, detail?: number);
216
+ onAddToScene(sim: Simulation): void;
211
217
  protected setVertexColors(): void;
212
218
  getVertexCallBuffer(): Float32Array<ArrayBufferLike>;
213
219
  isTransparent(): boolean;
@@ -237,7 +243,7 @@ export declare class Instance<T extends SimulationElement3d> extends SimulationE
237
243
  getInstanceBuffer(): Float32Array<ArrayBufferLike>;
238
244
  getTreeVertexCount(): number;
239
245
  getIndexCount(): number;
240
- getGeometryTopology(): "strip" | "list";
246
+ getGeometryTopology(): "list" | "strip";
241
247
  getVertexCallBuffer(): Float32Array<ArrayBufferLike>;
242
248
  getIndexBuffer(): Uint32Array<ArrayBuffer>;
243
249
  getModelMatrix(): Mat4;
package/dist/graphics.js CHANGED
@@ -3,15 +3,15 @@ import { cloneBuf, vector2, vector3, vector2FromVector3, matrix4, vector3FromVec
3
3
  import { BlankGeometry, CircleGeometry, CubeGeometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry, TraceLinesGeometry as TraceLinesGeometry } from './geometry.js';
4
4
  import { Float32ArrayCache, internalTransitionValues, posTo2dScreen } from './internalUtils.js';
5
5
  import { mat4ByteLength } from './constants.js';
6
- import { globalInfo, logger, pipelineCache } from './globals.js';
6
+ import { globalInfo, logger } from './globals.js';
7
7
  import { BasicMaterial, VertexColorMaterial } from './materials.js';
8
8
  import { getDefaultShaderForBackend, getDefaultVertexColorShaderForBackend } from './shaders/utils.js';
9
+ const SIM_ELEMENT_3D_NOT_INIT_ERROR = 'SimulationElement3d is not initialized';
9
10
  export class SimulationElement3d {
11
+ sim = null;
10
12
  children;
11
- prevInfo;
12
- pipeline;
13
13
  id;
14
- shader;
14
+ shader = null;
15
15
  material;
16
16
  cullMode;
17
17
  parent;
@@ -35,19 +35,37 @@ export class SimulationElement3d {
35
35
  this.children = [];
36
36
  this.modelMatrix = matrix4();
37
37
  this.parent = null;
38
- this.pipeline = null;
39
- this.prevInfo = null;
40
38
  this.material = new BasicMaterial(color);
41
39
  this.cullMode = 'none';
42
40
  this.id = null;
43
- const canvas = globalInfo.getCanvas();
44
- if (!canvas)
45
- throw logger.error('Canvas is null');
46
- const backendType = canvas.getBackend().getBackendType();
47
- this.shader = getDefaultShaderForBackend(backendType);
41
+ }
42
+ onAddToScene(sim, backendSpecificShaderFetchFn = getDefaultShaderForBackend) {
43
+ this.sim = sim;
44
+ const backend = sim.getBackend().getBackendType();
45
+ this.shader = backendSpecificShaderFetchFn(backend);
46
+ for (let i = 0; i < this.children.length; i++) {
47
+ if (this.children[i].getParentSim() !== sim) {
48
+ this.children[i].onAddToScene(sim, backendSpecificShaderFetchFn);
49
+ }
50
+ }
51
+ }
52
+ getParentSim() {
53
+ return this.sim;
54
+ }
55
+ getParentSimOrError() {
56
+ if (!this.sim)
57
+ throw logger.error(SIM_ELEMENT_3D_NOT_INIT_ERROR);
58
+ return this.sim;
59
+ }
60
+ isOnCanvas() {
61
+ return this.sim !== null;
48
62
  }
49
63
  delete() {
50
64
  this.uniformBuffer?.destroy();
65
+ this.sim = null;
66
+ for (let i = 0; i < this.children.length; i++) {
67
+ this.children[i].delete();
68
+ }
51
69
  }
52
70
  setUniformBuffer(buffer) {
53
71
  this.uniformBuffer = buffer;
@@ -78,6 +96,9 @@ export class SimulationElement3d {
78
96
  if (id)
79
97
  el.setId(id);
80
98
  this.children.push(el);
99
+ if (this.sim && el.getParentSim() !== this.sim) {
100
+ el.onAddToScene(this.sim);
101
+ }
81
102
  }
82
103
  remove(el) {
83
104
  for (let i = 0; i < this.children.length; i++) {
@@ -153,6 +174,11 @@ export class SimulationElement3d {
153
174
  getShader() {
154
175
  return this.shader;
155
176
  }
177
+ getShaderOrError() {
178
+ if (!this.shader)
179
+ throw logger.error(SIM_ELEMENT_3D_NOT_INIT_ERROR);
180
+ return this.shader;
181
+ }
156
182
  setShader(shader) {
157
183
  this.shader = shader;
158
184
  }
@@ -174,18 +200,6 @@ export class SimulationElement3d {
174
200
  : 'triangle-' + this.getGeometryTopology();
175
201
  return `{ "topology": "${topologyString}", "transparent": ${this.isTransparent()}, "cullMode": "${this.cullMode}" }`;
176
202
  }
177
- getPipeline() {
178
- // TODO - probably change
179
- const backend = globalInfo.errorGetCanvas().getBackend();
180
- const device = backend.as('webgpu').getDeviceOrError();
181
- const objInfo = this.getObjectInfo();
182
- if (!this.pipeline || !this.prevInfo || this.prevInfo !== objInfo) {
183
- // @ts-ignore
184
- this.pipeline = pipelineCache.getPipeline(device, objInfo, this.shader);
185
- this.prevInfo = objInfo;
186
- }
187
- return this.pipeline;
188
- }
189
203
  mirrorParentTransforms3d(mat) {
190
204
  if (!this.parent)
191
205
  return;
@@ -210,8 +224,10 @@ export class SimulationElement3d {
210
224
  mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
211
225
  }
212
226
  mirrorParentTransforms2d(mat) {
227
+ if (!this.sim)
228
+ throw logger.error(SIM_ELEMENT_3D_NOT_INIT_ERROR);
213
229
  if (!this.parent) {
214
- const parentPos = posTo2dScreen(this.pos);
230
+ const parentPos = posTo2dScreen(this.sim.getCamera(), this.pos);
215
231
  mat4.translate(mat, parentPos, mat);
216
232
  return;
217
233
  }
@@ -222,8 +238,10 @@ export class SimulationElement3d {
222
238
  mat4.translate(mat, pos, mat);
223
239
  }
224
240
  updateModelMatrix2d() {
241
+ if (!this.sim)
242
+ throw logger.error(SIM_ELEMENT_3D_NOT_INIT_ERROR);
225
243
  mat4.identity(this.modelMatrix);
226
- const pos = posTo2dScreen(this.pos);
244
+ const pos = posTo2dScreen(this.sim.getCamera(), this.pos);
227
245
  vec3.add(pos, this.centerOffset, pos);
228
246
  if (this.parent) {
229
247
  this.mirrorParentTransforms2d(this.modelMatrix);
@@ -412,6 +430,8 @@ export class SimulationElement3d {
412
430
  return indexCount;
413
431
  }
414
432
  getVertexCallBuffer() {
433
+ if (!this.shader)
434
+ throw logger.error(SIM_ELEMENT_3D_NOT_INIT_ERROR);
415
435
  if (this.vertexCache.shouldUpdate() || this.geometry.hasUpdated()) {
416
436
  this.geometry.compute();
417
437
  const vertices = this.geometry.getVertices();
@@ -617,6 +637,9 @@ export class Polygon extends SimulationElement2d {
617
637
  const colors = vertices.map((vert) => vert.getColor() ?? this.material.getColor());
618
638
  this.material.setVertexColors(colors);
619
639
  }
640
+ onAddToScene(sim) {
641
+ super.onAddToScene(sim, getDefaultVertexColorShaderForBackend);
642
+ }
620
643
  getVertices() {
621
644
  return this.geometry.getVertices();
622
645
  }
@@ -975,11 +998,12 @@ export class Spline2d extends SimulationElement2d {
975
998
  this.geometry = new Spline2dGeometry(points, this.thickness, this.detail);
976
999
  this.material = new VertexColorMaterial([]);
977
1000
  this.material.setColor(pos.getColor() ?? globalInfo.getDefaultColor());
978
- const backend = globalInfo.getCanvas()?.getBackend().getBackendType();
979
- this.shader = getDefaultVertexColorShaderForBackend(backend);
980
1001
  this.setVertexColors();
981
1002
  this.estimateLength();
982
1003
  }
1004
+ onAddToScene(sim) {
1005
+ super.onAddToScene(sim, getDefaultVertexColorShaderForBackend);
1006
+ }
983
1007
  setVertexColors() {
984
1008
  const numVertices = this.geometry.getVertices().length;
985
1009
  const curves = this.geometry.getCurves();
@@ -1208,8 +1232,6 @@ export class TraceLines2d extends SimulationElement2d {
1208
1232
  this.material = new VertexColorMaterial([]);
1209
1233
  if (color)
1210
1234
  this.material.setColor(color);
1211
- const backend = globalInfo.getCanvas()?.getBackend().getBackendType();
1212
- this.shader = getDefaultShaderForBackend(backend);
1213
1235
  }
1214
1236
  addPoint(vert, color) {
1215
1237
  const newVert = vert.length < 3 ? vector3(vert[0] ?? 0, vert[1] ?? 0, 0) : vert;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,6 @@ export * from './simulation.js';
2
2
  export * from './graphics.js';
3
3
  export * from './utils.js';
4
4
  export * from './types.js';
5
- export * as webGPUShaderUtils from './shaders/webgpu.js';
6
5
  export * from './materials.js';
7
6
  export * from './constants.js';
8
7
  export * from './backends/backend.js';
package/dist/index.js CHANGED
@@ -2,7 +2,6 @@ export * from './simulation.js';
2
2
  export * from './graphics.js';
3
3
  export * from './utils.js';
4
4
  export * from './types.js';
5
- export * as webGPUShaderUtils from './shaders/webgpu.js';
6
5
  export * from './materials.js';
7
6
  export * from './constants.js';
8
7
  export * from './backends/backend.js';
@@ -1,5 +1,5 @@
1
1
  import { Mat4, Vector3 } from './types.js';
2
- import { SimJSWebGPUShader } from './shaders/webgpu.js';
2
+ import { Camera, Simulation } from './simulation.js';
3
3
  import { SimulationElement3d } from './graphics.js';
4
4
  export declare class Float32ArrayCache {
5
5
  private vertices;
@@ -21,7 +21,7 @@ export declare class CachedArray<T> {
21
21
  getArray(): T[];
22
22
  }
23
23
  export declare const updateProjectionMatrix: (mat: Mat4, aspectRatio: number, zNear?: number, zFar?: number) => any;
24
- export declare const updateWorldProjectionMatrix: (worldProjMat: Mat4, projMat: Mat4) => void;
24
+ export declare const updateWorldProjectionMatrix: (camera: Camera, worldProjMat: Mat4, projMat: Mat4) => void;
25
25
  export declare const updateOrthoProjectionMatrix: (mat: Mat4, screenSize: [number, number]) => Float32Array;
26
26
  export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => GPUTexture;
27
27
  export declare const buildMultisampleTexture: (device: GPUDevice, ctx: GPUCanvasContext, width: number, height: number) => GPUTexture;
@@ -31,8 +31,7 @@ export declare function createIndexArray(length: number): number[];
31
31
  export declare function triangulateWireFrameOrder(len: number): number[];
32
32
  export declare function getVertexAndIndexSize(scene: SimulationElement3d[]): readonly [number, number];
33
33
  export declare function internalTransitionValues(onFrame: (deltaT: number, t: number, total: number) => void, adjustment: () => void, transitionLength: number, func?: (n: number) => number): Promise<void>;
34
- export declare function posTo2dScreen(pos: Vector3): Vector3;
35
- export declare function createPipeline(device: GPUDevice, info: string, shader: SimJSWebGPUShader): GPURenderPipeline;
36
- export declare function addToScene(scene: SimulationElement3d[], el: SimulationElement3d, id?: string): void;
34
+ export declare function posTo2dScreen(camera: Camera, pos: Vector3): Vector3;
35
+ export declare function addToScene(sim: Simulation, el: SimulationElement3d, id?: string): void;
37
36
  export declare function removeSceneObj(scene: SimulationElement3d[], el: SimulationElement3d): void;
38
37
  export declare function removeSceneId(scene: SimulationElement3d[], id: string): void;
@@ -1,6 +1,5 @@
1
1
  import { mat4, vec3 } from 'wgpu-matrix';
2
2
  import { cloneBuf, transitionValues } from './utils.js';
3
- import { camera } from './simulation.js';
4
3
  import { settings } from './settings.js';
5
4
  import { SimulationElement3d } from './graphics.js';
6
5
  import { logger } from './globals.js';
@@ -58,7 +57,7 @@ export const updateProjectionMatrix = (mat, aspectRatio, zNear = 1, zFar = 500)
58
57
  const fov = Math.PI / 4;
59
58
  return mat4.perspective(fov, aspectRatio, zNear, zFar, mat);
60
59
  };
61
- export const updateWorldProjectionMatrix = (worldProjMat, projMat) => {
60
+ export const updateWorldProjectionMatrix = (camera, worldProjMat, projMat) => {
62
61
  mat4.identity(worldProjMat);
63
62
  const camPos = cloneBuf(camera.getPos());
64
63
  const rotation = camera.getRotation();
@@ -159,7 +158,7 @@ export function getVertexAndIndexSize(scene) {
159
158
  let indexSize = 0;
160
159
  for (let i = 0; i < scene.length; i++) {
161
160
  const obj = scene[i];
162
- vertexSize += obj.getTreeVertexCount() * obj.getShader().getBufferLength();
161
+ vertexSize += obj.getTreeVertexCount() * obj.getShaderOrError().getBufferLength();
163
162
  indexSize += obj.getIndexCount();
164
163
  }
165
164
  return [vertexSize, indexSize];
@@ -171,63 +170,18 @@ export function internalTransitionValues(onFrame, adjustment, transitionLength,
171
170
  };
172
171
  return transitionValues(onFrame, newAdjustment, transitionLength, func);
173
172
  }
174
- export function posTo2dScreen(pos) {
173
+ export function posTo2dScreen(camera, pos) {
175
174
  const newPos = cloneBuf(pos);
176
175
  newPos[1] = camera.getScreenSize()[1] + newPos[1];
177
176
  return newPos;
178
177
  }
179
- export function createPipeline(device, info, shader) {
180
- const shaderModule = shader.getModule();
181
- const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
182
- const infoObj = JSON.parse(info);
183
- return device.createRenderPipeline({
184
- layout: device.createPipelineLayout({
185
- bindGroupLayouts: shader.getBindGroupLayouts()
186
- }),
187
- vertex: {
188
- module: shaderModule,
189
- entryPoint: shader.getVertexMain(),
190
- buffers: [shader.getVertexBuffers()]
191
- },
192
- fragment: {
193
- module: shaderModule,
194
- entryPoint: 'fragment_main',
195
- targets: [
196
- {
197
- format: presentationFormat,
198
- blend: {
199
- color: {
200
- srcFactor: 'src-alpha',
201
- dstFactor: 'one-minus-src-alpha'
202
- },
203
- alpha: {
204
- srcFactor: 'src-alpha',
205
- dstFactor: 'one-minus-src-alpha'
206
- }
207
- }
208
- }
209
- ]
210
- },
211
- primitive: {
212
- topology: infoObj.topology,
213
- stripIndexFormat: infoObj.topology.endsWith('strip') ? 'uint32' : undefined,
214
- cullMode: infoObj.cullMode
215
- },
216
- multisample: {
217
- count: 4
218
- },
219
- depthStencil: {
220
- depthWriteEnabled: !infoObj.transparent,
221
- depthCompare: 'less',
222
- format: 'depth24plus'
223
- }
224
- });
225
- }
226
- export function addToScene(scene, el, id) {
178
+ export function addToScene(sim, el, id) {
179
+ const scene = sim.getScene();
227
180
  if (el instanceof SimulationElement3d) {
228
181
  if (id)
229
182
  el.setId(id);
230
183
  scene.unshift(el);
184
+ el.onAddToScene(sim);
231
185
  }
232
186
  else {
233
187
  throw logger.error('Cannot add invalid SimulationElement');
@@ -6,8 +6,10 @@ export declare abstract class SimJSShader {
6
6
  protected vertexBufferWriter: VertexBufferWriter;
7
7
  protected compatableBackend: BackendType;
8
8
  protected bufferLength: number;
9
+ protected initialized: boolean;
9
10
  constructor(conpatableBackend: BackendType, vertexBufferWriter: VertexBufferWriter);
10
11
  abstract writeUniformBuffers(obj: SimulationElement3d): void;
12
+ getIsInitialized(): boolean;
11
13
  setVertexInfo(element: SimulationElement3d, buffer: Float32Array, vertex: Vector3, vertexIndex: number, offset: number): void;
12
14
  getCompatableBackend(): BackendType;
13
15
  compatableWith(backendType: BackendType): boolean;
@@ -3,11 +3,15 @@ export class SimJSShader {
3
3
  vertexBufferWriter;
4
4
  compatableBackend;
5
5
  bufferLength;
6
+ initialized = false;
6
7
  constructor(conpatableBackend, vertexBufferWriter) {
7
8
  this.bufferLength = 0;
8
9
  this.vertexBufferWriter = vertexBufferWriter;
9
10
  this.compatableBackend = conpatableBackend;
10
11
  }
12
+ getIsInitialized() {
13
+ return this.initialized;
14
+ }
11
15
  setVertexInfo(element, buffer, vertex, vertexIndex, offset) {
12
16
  this.vertexBufferWriter(element, buffer, vertex, vertexIndex, offset);
13
17
  }
@@ -1,6 +1,6 @@
1
1
  import { WebGLMemoBuffer } from '../buffers/webgl.js';
2
2
  import { FLOAT_SIZE, mat4ByteLength } from '../constants.js';
3
- import { globalInfo, logger } from '../globals.js';
3
+ import { logger } from '../globals.js';
4
4
  import { orthogonalMatrix, worldProjectionMatrix } from '../simulation.js';
5
5
  import { defaultVertexBufferWriter, defaultVertexColorBufferWriter, SimJSShader } from './shader.js';
6
6
  export class SimJSWebGLShader extends SimJSShader {
@@ -22,13 +22,6 @@ export class SimJSWebGLShader extends SimJSShader {
22
22
  this.uniformBufferWriter = uniformBufferWriter;
23
23
  this.getShaderProgramInfoFn = getShaderProgramInfoFn;
24
24
  this.bufferDeclerations = bufferDeclerations;
25
- const canvas = globalInfo.getCanvas();
26
- if (!canvas) {
27
- globalInfo.addToInitShader(this);
28
- return;
29
- }
30
- const backend = canvas.getBackend().as('webgl');
31
- this.init(backend.getContextOrError());
32
25
  }
33
26
  init(gl) {
34
27
  this.gl = gl;
@@ -1,10 +1,11 @@
1
1
  import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
2
2
  import { SimulationElement3d } from '../graphics.js';
3
3
  import { WebGPUBufferDecleration, Vector3, VertexBufferWriter, VertexParamInfo } from '../types.js';
4
+ import { Simulation } from '../simulation.js';
4
5
  import { SimJSShader } from './shader.js';
5
6
  export declare const WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE: number;
6
7
  type WebGPUUniformBufferWriter = (device: GPUDevice, element: SimulationElement3d, buffers: WebGPUMemoBuffer[]) => void;
7
- type WebGPUBindGroupGenerator = (device: GPUDevice, element: SimulationElement3d, buffers: WebGPUMemoBuffer[]) => GPUBindGroup[];
8
+ type WebGPUBindGroupGenerator = (sim: Simulation, device: GPUDevice, element: SimulationElement3d, buffers: WebGPUMemoBuffer[]) => GPUBindGroup[];
8
9
  export declare class SimJSWebGPUShader extends SimJSShader {
9
10
  protected buffers: WebGPUMemoBuffer[];
10
11
  private bindGroupLayoutDescriptors;
@@ -22,7 +23,7 @@ export declare class SimJSWebGPUShader extends SimJSShader {
22
23
  init(device: GPUDevice): void;
23
24
  getCode(): string;
24
25
  getVertexBuffers(): GPUVertexBufferLayout;
25
- getBindGroupLayouts(): GPUBindGroupLayout[];
26
+ getBindGroupLayouts(sim: Simulation): GPUBindGroupLayout[];
26
27
  getBindGroupLayoutDescriptors(): GPUBindGroupLayoutDescriptor[];
27
28
  getBufferInfo(): WebGPUBufferDecleration[];
28
29
  getUniformBufferWriter(): WebGPUUniformBufferWriter;
@@ -33,7 +34,7 @@ export declare class SimJSWebGPUShader extends SimJSShader {
33
34
  getFragmentMain(): string;
34
35
  setVertexInfo(element: SimulationElement3d, buffer: Float32Array, vertex: Vector3, vertexIndex: number, offset: number): void;
35
36
  writeUniformBuffers(el: SimulationElement3d): void;
36
- getBindGroups(device: GPUDevice, el: SimulationElement3d): GPUBindGroup[];
37
+ getBindGroups(sim: Simulation, device: GPUDevice, el: SimulationElement3d): GPUBindGroup[];
37
38
  }
38
39
  export declare const defaultWebGPUShader: SimJSWebGPUShader;
39
40
  export declare const defaultWebGPUVertexColorShader: SimJSWebGPUShader;
@@ -1,11 +1,11 @@
1
1
  import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
2
2
  import { mat4ByteLength, modelProjMatOffset } from '../constants.js';
3
- import { globalInfo, logger } from '../globals.js';
4
- import { createBindGroup } from '../utils.js';
3
+ import { logger } from '../globals.js';
5
4
  import { orthogonalMatrix, worldProjectionMatrix } from '../simulation.js';
6
5
  import { worldProjMatOffset } from '../constants.js';
7
6
  import { defaultVertexColorBufferWriter, SimJSShader } from './shader.js';
8
7
  export const WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE = mat4ByteLength * 2 + 4 * 2 + 8; // 4x4 matrix * 2 + vec2<f32> + 8 bc 144 is cool
8
+ const SHADER_NOT_INIT_ERROR = 'Shader not initialized';
9
9
  const defaultInfos = [
10
10
  {
11
11
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
@@ -26,16 +26,13 @@ const defaultWebGPUUniformBufferWriter = (device, el, buffers) => {
26
26
  buffers[0].write(el.getInstanceBuffer());
27
27
  }
28
28
  };
29
- const defaultBindGroupGenerator = (_device, el, buffers) => {
30
- // TODO - why is this here?
31
- const shader = el.getShader();
32
- if (!shader.compatableWith('webgpu'))
33
- throw logger.error('Wrong shader type for backend or something idk');
29
+ const defaultBindGroupGenerator = (sim, device, el, buffers) => {
30
+ const shader = el.getShaderOrError().as('webgpu');
34
31
  const gpuBuffers = [
35
32
  el.getUniformBuffer().getBuffer(),
36
33
  buffers[0].getBuffer()
37
34
  ];
38
- return [createBindGroup(shader, 0, gpuBuffers)];
35
+ return [createBindGroup(sim, device, shader, 0, gpuBuffers)];
39
36
  };
40
37
  export class SimJSWebGPUShader extends SimJSShader {
41
38
  buffers;
@@ -78,13 +75,6 @@ export class SimJSWebGPUShader extends SimJSShader {
78
75
  arrayStride: stride,
79
76
  attributes
80
77
  };
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
78
  }
89
79
  init(device) {
90
80
  this.device = device;
@@ -98,9 +88,8 @@ export class SimJSWebGPUShader extends SimJSShader {
98
88
  getVertexBuffers() {
99
89
  return this.vertexBuffers;
100
90
  }
101
- getBindGroupLayouts() {
102
- // TODO - probably change
103
- const backend = globalInfo.errorGetCanvas().getBackend();
91
+ getBindGroupLayouts(sim) {
92
+ const backend = sim.getBackend().as('webgpu');
104
93
  const device = backend.getDeviceOrError();
105
94
  if (!this.bindGroupLayouts) {
106
95
  this.bindGroupLayouts = this.bindGroupLayoutDescriptors.map((descriptor) => device.createBindGroupLayout(descriptor));
@@ -123,11 +112,10 @@ export class SimJSWebGPUShader extends SimJSShader {
123
112
  return this.bindGroupGenerator;
124
113
  }
125
114
  getModule() {
126
- // TODO - probably change
127
- const backend = globalInfo.errorGetCanvas().getBackend();
128
- const device = backend.getDeviceOrError();
115
+ if (!this.device)
116
+ throw logger.error(SHADER_NOT_INIT_ERROR);
129
117
  if (!this.module) {
130
- this.module = device.createShaderModule({ code: this.code });
118
+ this.module = this.device.createShaderModule({ code: this.code });
131
119
  }
132
120
  return this.module;
133
121
  }
@@ -142,11 +130,11 @@ export class SimJSWebGPUShader extends SimJSShader {
142
130
  }
143
131
  writeUniformBuffers(el) {
144
132
  if (!this.device)
145
- throw logger.error('Shader not initialized');
133
+ throw logger.error(SHADER_NOT_INIT_ERROR);
146
134
  this.uniformBufferWriter(this.device, el, this.buffers);
147
135
  }
148
- getBindGroups(device, el) {
149
- return this.bindGroupGenerator(device, el, this.buffers);
136
+ getBindGroups(sim, device, el) {
137
+ return this.bindGroupGenerator(sim, device, el, this.buffers);
150
138
  }
151
139
  }
152
140
  const positionSize = 4 * 3;
@@ -288,3 +276,15 @@ export const defaultWebGPUVertexColorShader = new SimJSWebGPUShader(defaultWebGP
288
276
  format: 'float32'
289
277
  }
290
278
  ], defaultInfos, defaultWebGPUUniformBufferWriter, defaultBindGroupGenerator, defaultVertexColorBufferWriter);
279
+ function createBindGroup(sim, device, shader, bindGroupIndex, buffers) {
280
+ const layout = shader.getBindGroupLayouts(sim)[bindGroupIndex];
281
+ return device.createBindGroup({
282
+ layout: layout,
283
+ entries: buffers.map((buffer, index) => ({
284
+ binding: index,
285
+ resource: {
286
+ buffer
287
+ }
288
+ }))
289
+ });
290
+ }
@@ -3,6 +3,7 @@ import type { Vector2, Vector3, LerpFunc, BackendType } from './types.js';
3
3
  import { Color } from './utils.js';
4
4
  import { Settings } from './settings.js';
5
5
  import { SimJsBackend } from './backends/backend.js';
6
+ import { SimJSShader } from './shaders/shader.js';
6
7
  export declare const worldProjectionMatrix: import("./types.js").Mat4;
7
8
  export declare const orthogonalMatrix: import("./types.js").Mat4;
8
9
  export declare class Camera {
@@ -24,11 +25,10 @@ export declare class Camera {
24
25
  getPos(): Vector3;
25
26
  getAspectRatio(): number;
26
27
  }
27
- export declare let camera: Camera;
28
28
  type SimulationOptions = {
29
- sceneCamera?: Camera | null;
29
+ camera?: Camera | null;
30
30
  showFrameRate?: boolean;
31
- backendMode?: BackendType;
31
+ backend?: BackendType;
32
32
  };
33
33
  export declare class Simulation extends Settings {
34
34
  canvasRef: HTMLCanvasElement | null;
@@ -40,6 +40,7 @@ export declare class Simulation extends Settings {
40
40
  private frameRateView;
41
41
  private transparentElements;
42
42
  private backend;
43
+ private camera;
43
44
  constructor(idOrCanvasRef: string | HTMLCanvasElement, options?: SimulationOptions);
44
45
  private handleCanvasResize;
45
46
  on<K extends keyof HTMLElementEventMap>(event: K, cb: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
@@ -53,6 +54,8 @@ export declare class Simulation extends Settings {
53
54
  empty(): void;
54
55
  private applyCanvasSize;
55
56
  setCanvasSize(width: number, height: number): void;
57
+ preInitShader(shader: SimJSShader): void;
58
+ getCamera(): Camera;
56
59
  start(): void;
57
60
  stop(): void;
58
61
  setBackground(color: Color): void;
@@ -142,11 +142,10 @@ export class Camera {
142
142
  return this.aspectRatio;
143
143
  }
144
144
  }
145
- export let camera = new Camera(vector3());
146
145
  const defaultSimulationOptions = {
147
- sceneCamera: null,
146
+ camera: null,
148
147
  showFrameRate: false,
149
- backendMode: 'webgpu'
148
+ backend: 'webgpu'
150
149
  };
151
150
  export class Simulation extends Settings {
152
151
  canvasRef = null;
@@ -158,8 +157,9 @@ export class Simulation extends Settings {
158
157
  frameRateView;
159
158
  transparentElements;
160
159
  backend;
160
+ camera;
161
161
  constructor(idOrCanvasRef, options = {}) {
162
- const { sceneCamera = defaultSimulationOptions.sceneCamera, showFrameRate = defaultSimulationOptions.showFrameRate, backendMode = defaultSimulationOptions.backendMode } = options;
162
+ const { camera = defaultSimulationOptions.camera, showFrameRate = defaultSimulationOptions.showFrameRate, backend = defaultSimulationOptions.backend } = options;
163
163
  super();
164
164
  if (typeof idOrCanvasRef === 'string') {
165
165
  const ref = document.getElementById(idOrCanvasRef);
@@ -172,9 +172,11 @@ export class Simulation extends Settings {
172
172
  }
173
173
  else
174
174
  throw logger.error(`Canvas ref/id provided is invalid`);
175
- globalInfo.setCanvas(this);
176
- if (sceneCamera) {
177
- camera = sceneCamera;
175
+ if (camera) {
176
+ this.camera = camera;
177
+ }
178
+ else {
179
+ this.camera = new Camera(vector3());
178
180
  }
179
181
  const parent = this.canvasRef.parentElement;
180
182
  if (parent === null)
@@ -186,11 +188,11 @@ export class Simulation extends Settings {
186
188
  this.frameRateView = new FrameRateView(showFrameRate);
187
189
  this.frameRateView.updateFrameRate(1);
188
190
  this.transparentElements = new CachedArray();
189
- if (backendMode === 'webgpu' && 'gpu' in navigator) {
190
- this.backend = new WebGPUBackend();
191
+ if (backend === 'webgpu' && 'gpu' in navigator) {
192
+ this.backend = new WebGPUBackend(this);
191
193
  }
192
194
  else if (webGLAvailable(this.canvasRef)) {
193
- this.backend = new WebGLBackend();
195
+ this.backend = new WebGLBackend(this);
194
196
  }
195
197
  else {
196
198
  throw logger.error('WebGL and WebGPU not available');
@@ -221,7 +223,7 @@ export class Simulation extends Settings {
221
223
  return this.canvasRef?.height || 0;
222
224
  }
223
225
  add(el, id) {
224
- addToScene(this.scene, el, id);
226
+ addToScene(this, el, id);
225
227
  }
226
228
  remove(el) {
227
229
  removeSceneObj(this.scene, el);
@@ -249,6 +251,17 @@ export class Simulation extends Settings {
249
251
  this.resizeEvents[i](width, height);
250
252
  }
251
253
  }
254
+ preInitShader(shader) {
255
+ const backendType = this.backend.getBackendType();
256
+ if (!shader.compatableWith(backendType)) {
257
+ logger.warn('Not initializing shader, not compatible with backend');
258
+ return;
259
+ }
260
+ this.backend.initShader(shader);
261
+ }
262
+ getCamera() {
263
+ return this.camera;
264
+ }
252
265
  start() {
253
266
  if (this.initialized) {
254
267
  this.running = true;
@@ -258,14 +271,13 @@ export class Simulation extends Settings {
258
271
  if (this.canvasRef === null)
259
272
  return;
260
273
  const screenSize = vector2(this.canvasRef.width, this.canvasRef.height);
261
- camera.setScreenSize(screenSize);
274
+ this.camera.setScreenSize(screenSize);
262
275
  const canvas = this.canvasRef;
263
276
  canvas.width = canvas.clientWidth * devicePixelRatio;
264
277
  canvas.height = canvas.clientHeight * devicePixelRatio;
265
278
  this.initialized = true;
266
279
  this.running = true;
267
280
  await this.backend.init(this.canvasRef);
268
- this.backend.initShaders(globalInfo.getToInitShaders());
269
281
  this.render(canvas, this.backend);
270
282
  })();
271
283
  }
@@ -290,8 +302,8 @@ export class Simulation extends Settings {
290
302
  updateProjectionMatrix(projMat, newAspectRatio);
291
303
  aspectRatio = newAspectRatio;
292
304
  }
293
- updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
294
- updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
305
+ updateWorldProjectionMatrix(this.camera, worldProjectionMatrix, projMat);
306
+ updateOrthoProjectionMatrix(orthogonalMatrix, this.camera.getScreenSize());
295
307
  backend.renderStart(canvas);
296
308
  // sub 10 to start with a reasonable gap between starting time and next frame time
297
309
  let prev = Date.now() - 10;
@@ -308,25 +320,25 @@ export class Simulation extends Settings {
308
320
  this.frameRateView.updateFrameRate(fps);
309
321
  }
310
322
  prevFps = fps;
311
- const screenSize = camera.getScreenSize();
323
+ const screenSize = this.camera.getScreenSize();
312
324
  if (screenSize[0] !== canvas.width || screenSize[1] !== canvas.height) {
313
- camera.setScreenSize(vector2(canvas.width, canvas.height));
325
+ this.camera.setScreenSize(vector2(canvas.width, canvas.height));
314
326
  screenSize[0] = canvas.width;
315
327
  screenSize[1] = canvas.height;
316
- aspectRatio = camera.getAspectRatio();
328
+ aspectRatio = this.camera.getAspectRatio();
317
329
  updateProjectionMatrix(projMat, aspectRatio);
318
- updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
330
+ updateWorldProjectionMatrix(this.camera, worldProjectionMatrix, projMat);
319
331
  backend.updateTextures(screenSize);
320
332
  }
321
- if (camera.hasUpdated()) {
322
- updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
323
- updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
333
+ if (this.camera.hasUpdated()) {
334
+ updateOrthoProjectionMatrix(orthogonalMatrix, this.camera.getScreenSize());
335
+ updateWorldProjectionMatrix(this.camera, worldProjectionMatrix, projMat);
324
336
  }
325
337
  backend.preRender(this.scene);
326
338
  this.transparentElements.reset();
327
339
  const [opaqueVertexOffset, opaqueIndexOffset] = this.renderScene(backend, 0, 0, this.scene, this.scene.length, diff, false);
328
340
  this.renderScene(backend, opaqueVertexOffset, opaqueIndexOffset, this.transparentElements.getArray(), this.transparentElements.length, diff, true);
329
- camera.updateConsumed();
341
+ this.camera.updateConsumed();
330
342
  backend.finishRender();
331
343
  };
332
344
  requestAnimationFrame(frame);
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { SimulationElement3d, SplinePoint2d } from './graphics.js';
2
2
  import { FloatArray, LerpFunc, Mat4, Vector2, Vector2m, Vector3, Vector3m, Vector4 } from './types.js';
3
- import { SimJSWebGPUShader } from './shaders/webgpu.js';
4
3
  export declare class Color {
5
4
  r: number;
6
5
  g: number;
@@ -82,7 +81,6 @@ export declare function distance3d(vector1: Vector3m, vector2: Vector3m): number
82
81
  export declare function interpolateColors(colors: Color[], t: number): Color;
83
82
  export declare function vectorsToVertex(vectors: Vector3[]): Vertex[];
84
83
  export declare function cloneVectors(vectors: Vector3[]): Vector3[];
85
- export declare function createBindGroup(shader: SimJSWebGPUShader, bindGroupIndex: number, buffers: GPUBuffer[]): GPUBindGroup;
86
84
  export declare function transform(from: SimulationElement3d, to: SimulationElement3d, t: number, f?: LerpFunc): Promise<void>;
87
85
  export declare function defaultColor(): Color;
88
86
  export declare function webGLAvailable(canvas: HTMLCanvasElement): boolean;
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { mat4, vec2, vec3, vec4 } from 'wgpu-matrix';
2
2
  import { SplinePoint2d } from './graphics.js';
3
- import { globalInfo } from './globals.js';
3
+ import { globalInfo, logger } from './globals.js';
4
4
  export class Color {
5
5
  r; // 0 - 255
6
6
  g; // 0 - 255
@@ -285,24 +285,11 @@ export function vectorsToVertex(vectors) {
285
285
  export function cloneVectors(vectors) {
286
286
  return vectors.map((vec) => cloneBuf(vec));
287
287
  }
288
- export function createBindGroup(shader, bindGroupIndex, buffers) {
289
- // TODO - probably change
290
- const backend = globalInfo.errorGetCanvas().getBackend();
291
- const device = backend.getDeviceOrError();
292
- const layout = shader.getBindGroupLayouts()[bindGroupIndex];
293
- return device.createBindGroup({
294
- layout: layout,
295
- entries: buffers.map((buffer, index) => ({
296
- binding: index,
297
- resource: {
298
- buffer
299
- }
300
- }))
301
- });
302
- }
303
288
  /// may have unexpected position behavior for nested elements, or elements with a geometry with a set triangle order
304
289
  export function transform(from, to, t, f) {
305
- const canvas = globalInfo.errorGetCanvas();
290
+ const canvas = from.getParentSimOrError();
291
+ if (to.isOnCanvas())
292
+ throw logger.error('Cannot transform to an element on a canvas');
306
293
  const fromVertCount = from.getVertexCount();
307
294
  const toVertCount = to.getVertexCount();
308
295
  if (fromVertCount < toVertCount) {
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Jackson Otto",
7
7
  "description": "A simple graphics library using WebGPU",
8
- "version": "0.11.1",
8
+ "version": "0.11.2",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": "./dist/index.js",