simulationjsv2 0.2.4 → 0.2.5

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.
@@ -1,7 +1,8 @@
1
1
  /// <reference types="dist" />
2
- import { SimulationElement } from './graphics.js';
2
+ import { SimulationElement, SimulationElement3d } from './graphics.js';
3
3
  import type { Vector2, Vector3, LerpFunc } from './types.js';
4
4
  import { Color } from './utils.js';
5
+ import { BlankGeometry } from './geometry.js';
5
6
  export declare class Simulation {
6
7
  canvasRef: HTMLCanvasElement | null;
7
8
  private bgColor;
@@ -20,14 +21,18 @@ export declare class Simulation {
20
21
  fitElement(): void;
21
22
  private assertHasCanvas;
22
23
  }
23
- export declare class SceneCollection extends SimulationElement {
24
+ export declare class SceneCollection extends SimulationElement3d {
25
+ protected geometry: BlankGeometry;
24
26
  private name;
25
27
  private scene;
26
28
  constructor(name: string);
27
29
  getName(): string;
28
30
  add(el: SimulationElement<any>): void;
29
31
  empty(): void;
30
- getBuffer(camera: Camera, force: boolean): number[];
32
+ getSceneBuffer(camera: Camera): number[];
33
+ getWireframe(camera: Camera): number[];
34
+ getTriangles(camera: Camera): number[];
35
+ protected updateMatrix(camera: Camera): void;
31
36
  }
32
37
  export declare class Camera {
33
38
  private pos;
@@ -1,10 +1,8 @@
1
1
  import { vec3 } from 'wgpu-matrix';
2
- import { SimulationElement, SimulationElement3d } from './graphics.js';
2
+ import { SimulationElement3d } from './graphics.js';
3
3
  import { BUF_LEN } from './constants.js';
4
- import { Color, applyElementToScene, buildDepthTexture, buildMultisampleTexture, buildProjectionMatrix, getOrthoMatrix, getTransformationMatrix, logger, transitionValues, vector2, vector3 } from './utils.js';
5
- const vertexSize = 40; // 4 * 10
6
- const colorOffset = 16; // 4 * 4
7
- const uvOffset = 32; // 4 * 8
4
+ import { Color, applyElementToScene, buildDepthTexture, buildMultisampleTexture, buildProjectionMatrix, createPipeline, getOrthoMatrix, getTransformationMatrix, logger, transitionValues, vector2, vector3 } from './utils.js';
5
+ import { BlankGeometry } from './geometry.js';
8
6
  const shader = `
9
7
  struct Uniforms {
10
8
  modelViewProjectionMatrix : mat4x4<f32>,
@@ -140,7 +138,7 @@ export class Simulation {
140
138
  this.frameRateView.updateFrameRate(1);
141
139
  }
142
140
  add(el) {
143
- applyElementToScene(this.scene, this.camera, el);
141
+ applyElementToScene(this.scene, el);
144
142
  }
145
143
  setCanvasSize(width, height) {
146
144
  this.assertHasCanvas();
@@ -187,169 +185,19 @@ export class Simulation {
187
185
  format: presentationFormat,
188
186
  alphaMode: 'premultiplied'
189
187
  });
190
- const pipeline2d = device.createRenderPipeline({
191
- layout: 'auto',
192
- vertex: {
193
- module: shaderModule,
194
- entryPoint: 'vertex_main_2d',
195
- buffers: [
196
- {
197
- arrayStride: vertexSize,
198
- attributes: [
199
- {
200
- // position
201
- shaderLocation: 0,
202
- offset: 0,
203
- format: 'float32x4'
204
- },
205
- {
206
- // color
207
- shaderLocation: 1,
208
- offset: colorOffset,
209
- format: 'float32x4'
210
- },
211
- {
212
- // size
213
- shaderLocation: 2,
214
- offset: uvOffset,
215
- format: 'float32x2'
216
- }
217
- ]
218
- }
219
- ]
220
- },
221
- fragment: {
222
- module: shaderModule,
223
- entryPoint: 'fragment_main',
224
- targets: [
225
- {
226
- format: presentationFormat
227
- }
228
- ]
229
- },
230
- primitive: {
231
- topology: 'triangle-list'
232
- },
233
- multisample: {
234
- count: 4
235
- },
236
- depthStencil: {
237
- depthWriteEnabled: true,
238
- depthCompare: 'less',
239
- format: 'depth24plus'
240
- }
241
- });
242
- const pipeline3d = device.createRenderPipeline({
243
- layout: 'auto',
244
- vertex: {
245
- module: shaderModule,
246
- entryPoint: 'vertex_main_3d',
247
- buffers: [
248
- {
249
- arrayStride: vertexSize,
250
- attributes: [
251
- {
252
- // position
253
- shaderLocation: 0,
254
- offset: 0,
255
- format: 'float32x4'
256
- },
257
- {
258
- // color
259
- shaderLocation: 1,
260
- offset: colorOffset,
261
- format: 'float32x4'
262
- },
263
- {
264
- // size
265
- shaderLocation: 2,
266
- offset: uvOffset,
267
- format: 'float32x2'
268
- }
269
- ]
270
- }
271
- ]
272
- },
273
- fragment: {
274
- module: shaderModule,
275
- entryPoint: 'fragment_main',
276
- targets: [
277
- {
278
- format: presentationFormat
279
- }
280
- ]
281
- },
282
- primitive: {
283
- topology: 'triangle-list'
284
- },
285
- multisample: {
286
- count: 4
287
- },
288
- depthStencil: {
289
- depthWriteEnabled: true,
290
- depthCompare: 'less',
291
- format: 'depth24plus'
292
- }
293
- });
294
- const wireframePipeline = device.createRenderPipeline({
295
- layout: 'auto',
296
- vertex: {
297
- module: shaderModule,
298
- entryPoint: 'vertex_main_3d',
299
- buffers: [
300
- {
301
- arrayStride: vertexSize,
302
- attributes: [
303
- {
304
- // position
305
- shaderLocation: 0,
306
- offset: 0,
307
- format: 'float32x4'
308
- },
309
- {
310
- // color
311
- shaderLocation: 1,
312
- offset: colorOffset,
313
- format: 'float32x4'
314
- },
315
- {
316
- // size
317
- shaderLocation: 2,
318
- offset: uvOffset,
319
- format: 'float32x2'
320
- }
321
- ]
322
- }
323
- ]
324
- },
325
- fragment: {
326
- module: shaderModule,
327
- entryPoint: 'fragment_main',
328
- targets: [
329
- {
330
- format: presentationFormat
331
- }
332
- ]
333
- },
334
- primitive: {
335
- topology: 'line-strip'
336
- },
337
- multisample: {
338
- count: 4
339
- },
340
- depthStencil: {
341
- depthWriteEnabled: true,
342
- depthCompare: 'less',
343
- format: 'depth24plus'
344
- }
345
- });
188
+ const pipeline2dTriangleList = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_2d', 'triangle-list');
189
+ const pipeline2dTriangleStrip = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_2d', 'triangle-strip');
190
+ const pipeline2dLineStrip = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_2d', 'line-strip');
191
+ const pipeline3dTriangleList = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_3d', 'triangle-list');
192
+ const pipeline3dTriangleStrip = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_3d', 'triangle-strip');
193
+ const pipeline3dLineStrip = createPipeline(device, shaderModule, presentationFormat, 'vertex_main_3d', 'line-strip');
346
194
  const uniformBufferSize = 4 * 16 + 4 * 16 + 4 * 2 + 8; // 4x4 matrix + 4x4 matrix + vec2<f32> + 8 bc 144 is cool
347
195
  const uniformBuffer = device.createBuffer({
348
196
  size: uniformBufferSize,
349
197
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
350
198
  });
351
199
  const uniformBindGroup = device.createBindGroup({
352
- layout: pipeline3d.getBindGroupLayout(0),
200
+ layout: pipeline3dTriangleList.getBindGroupLayout(0),
353
201
  entries: [
354
202
  {
355
203
  binding: 0,
@@ -433,10 +281,10 @@ export class Simulation {
433
281
  screenSize.buffer, screenSize.byteOffset, screenSize.byteLength);
434
282
  const commandEncoder = device.createCommandEncoder();
435
283
  const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
436
- passEncoder.setPipeline(pipeline3d);
284
+ passEncoder.setPipeline(pipeline3dTriangleList);
437
285
  passEncoder.setBindGroup(0, uniformBindGroup);
438
286
  for (let i = 0; i < this.scene.length; i++) {
439
- const buffer = this.scene[i].getBuffer(this.camera, this.camera.hasUpdated());
287
+ const buffer = this.scene[i].getBuffer(this.camera);
440
288
  const vertexF32Array = new Float32Array(buffer);
441
289
  const vertexBuffer = device.createBuffer({
442
290
  size: vertexF32Array.byteLength,
@@ -446,20 +294,37 @@ export class Simulation {
446
294
  new Float32Array(vertexBuffer.getMappedRange()).set(vertexF32Array);
447
295
  vertexBuffer.unmap();
448
296
  const vertexCount = vertexF32Array.length / BUF_LEN;
449
- if (this.scene[i] instanceof SimulationElement3d) {
450
- if (this.scene[i].isWireframe()) {
451
- passEncoder.setPipeline(wireframePipeline);
297
+ if (this.scene[i].isWireframe()) {
298
+ if (this.scene[i].is3d) {
299
+ passEncoder.setPipeline(pipeline3dLineStrip);
452
300
  }
453
301
  else {
454
- passEncoder.setPipeline(pipeline3d);
302
+ passEncoder.setPipeline(pipeline2dLineStrip);
455
303
  }
456
304
  }
457
305
  else {
458
- passEncoder.setPipeline(pipeline2d);
306
+ const type = this.scene[i].getGeometryType();
307
+ if (type === 'strip') {
308
+ if (this.scene[i].is3d) {
309
+ passEncoder.setPipeline(pipeline3dTriangleStrip);
310
+ }
311
+ else {
312
+ passEncoder.setPipeline(pipeline2dTriangleStrip);
313
+ }
314
+ }
315
+ else if (type === 'list') {
316
+ if (this.scene[i].is3d) {
317
+ passEncoder.setPipeline(pipeline3dTriangleList);
318
+ }
319
+ else {
320
+ passEncoder.setPipeline(pipeline2dTriangleList);
321
+ }
322
+ }
459
323
  }
460
324
  passEncoder.setVertexBuffer(0, vertexBuffer);
461
325
  passEncoder.draw(vertexCount);
462
326
  }
327
+ this.camera.updateConsumed();
463
328
  passEncoder.end();
464
329
  device.queue.submit([commandEncoder.finish()]);
465
330
  };
@@ -481,27 +346,36 @@ export class Simulation {
481
346
  }
482
347
  }
483
348
  }
484
- export class SceneCollection extends SimulationElement {
349
+ export class SceneCollection extends SimulationElement3d {
350
+ geometry;
485
351
  name;
486
352
  scene;
487
353
  constructor(name) {
488
354
  super(vector3());
489
355
  this.name = name;
490
356
  this.scene = [];
357
+ this.geometry = new BlankGeometry();
491
358
  }
492
359
  getName() {
493
360
  return this.name;
494
361
  }
495
362
  add(el) {
496
- applyElementToScene(this.scene, this.camera, el);
363
+ applyElementToScene(this.scene, el);
497
364
  }
498
365
  empty() {
499
366
  this.scene = [];
500
367
  }
501
- getBuffer(camera, force) {
502
- const res = [];
503
- this.scene.forEach((item) => res.push(...item.getBuffer(camera, force)));
504
- return res;
368
+ getSceneBuffer(camera) {
369
+ return this.scene.map((item) => item.getBuffer(camera)).flat();
370
+ }
371
+ getWireframe(camera) {
372
+ return this.getSceneBuffer(camera);
373
+ }
374
+ getTriangles(camera) {
375
+ return this.getSceneBuffer(camera);
376
+ }
377
+ updateMatrix(camera) {
378
+ this.defaultUpdateMatrix(camera);
505
379
  }
506
380
  }
507
381
  export class Camera {
package/dist/types.d.ts CHANGED
@@ -1,6 +1,61 @@
1
- import { Color } from './utils.js';
1
+ import { CubicBezierCurve2d, SplinePoint2d } from './graphics.js';
2
+ import { Color, Vertex } from './utils.js';
2
3
  export type Vector4 = Float32Array & [number, number, number, number];
3
4
  export type Vector3 = Float32Array & [number, number, number];
4
5
  export type Vector2 = Float32Array & [number, number];
6
+ export type Mat4 = Float32Array & [
7
+ number,
8
+ number,
9
+ number,
10
+ number,
11
+ number,
12
+ number,
13
+ number,
14
+ number,
15
+ number,
16
+ number,
17
+ number,
18
+ number,
19
+ number,
20
+ number,
21
+ number,
22
+ number
23
+ ];
5
24
  export type LerpFunc = (n: number) => number;
6
- export type VertexColorMap = Record<0 | 1 | 2 | 3, Color>;
25
+ export type VertexColorMap = Record<number, Color>;
26
+ export type ElementRotation<T extends Vector2 | Vector3> = T extends Vector2 ? number : T;
27
+ export type CubeGeometryParams = {
28
+ width: number;
29
+ height: number;
30
+ depth: number;
31
+ };
32
+ export type SquareGeometryParams = {
33
+ width: number;
34
+ height: number;
35
+ colorMap: VertexColorMap;
36
+ };
37
+ export type CircleGeometryParams = {
38
+ radius: number;
39
+ detail: number;
40
+ };
41
+ export type SplineGeometryParams = {
42
+ points: SplinePoint2d[];
43
+ curves: CubicBezierCurve2d[];
44
+ distance: number;
45
+ detail: number;
46
+ interpolateStart: number;
47
+ interpolateLimit: number;
48
+ thickness: number;
49
+ color: Color;
50
+ vertexColors: Color[];
51
+ };
52
+ export type LineGeometryParams<T extends Vector2 | Vector3> = {
53
+ pos: T;
54
+ to: T;
55
+ thickness: number;
56
+ };
57
+ export type Line2dGeometryParams = LineGeometryParams<Vector2>;
58
+ export type Line3dGeometryParams = LineGeometryParams<Vector3>;
59
+ export type PolygonGeometryParams = {
60
+ points: Vertex[];
61
+ };
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /// <reference types="dist" />
2
2
  import { SimulationElement, SplinePoint2d } from './graphics.js';
3
- import { Vector2, Vector3, Vector4 } from './types.js';
4
- import { Camera } from './simulation.js';
3
+ import { Mat4, Vector2, Vector3, Vector4 } from './types.js';
5
4
  export declare class Color {
6
5
  r: number;
7
6
  g: number;
@@ -53,7 +52,7 @@ export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3,
53
52
  export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
54
53
  export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => GPUTexture;
55
54
  export declare const buildMultisampleTexture: (device: GPUDevice, ctx: GPUCanvasContext, width: number, height: number) => GPUTexture;
56
- export declare const applyElementToScene: (scene: SimulationElement[], camera: Camera | null, el: SimulationElement) => void;
55
+ export declare const applyElementToScene: (scene: SimulationElement[], el: SimulationElement) => void;
57
56
  declare class Logger {
58
57
  constructor();
59
58
  private fmt;
@@ -63,7 +62,7 @@ declare class Logger {
63
62
  log_error(msg: string): void;
64
63
  }
65
64
  export declare const logger: Logger;
66
- export declare function lossyTriangulate(vertices: Vertex[]): (readonly [Vertex, Vertex, Vertex])[];
65
+ export declare function lossyTriangulate<T>(vertices: T[]): (readonly [T, T, T])[];
67
66
  /**
68
67
  * @param callback1 - called every frame until the animation is finished
69
68
  * @param callback2 - called after animation is finished (called immediately when t = 0)
@@ -78,11 +77,13 @@ export declare function easeInOutExpo(t: number): number;
78
77
  export declare function easeInOutQuart(t: number): number;
79
78
  export declare function easeInOutQuad(t: number): number;
80
79
  export declare function vertexBuffer(x: number, y: number, z: number, color: Color, uv?: Vector2): number[];
81
- export declare function vec3ToPixelRatio(vec: Vector3): void;
80
+ export declare function vector3ToPixelRatio(vec: Vector3): void;
81
+ export declare function vector2ToPixelRatio(vec: Vector2): void;
82
82
  export declare function cloneBuf<T extends Float32Array>(buf: T): T;
83
83
  export declare function vector4(x?: number, y?: number, z?: number, w?: number): Vector4;
84
84
  export declare function vector3(x?: number, y?: number, z?: number): Vector3;
85
85
  export declare function vector2(x?: number, y?: number): Vector2;
86
+ export declare function matrix4(): Mat4;
86
87
  export declare function vector3FromVector2(vec: Vector2): Vector3;
87
88
  export declare function vector2FromVector3(vec: Vector3): Vector2;
88
89
  export declare function colorFromVector4(vec: Vector4): Color;
@@ -98,4 +99,8 @@ export declare function interpolateColors(colors: Color[], t: number): Color;
98
99
  * @param t - seconds
99
100
  */
100
101
  export declare function waitFor(t: number): Promise<unknown>;
102
+ export declare function matrixFromRotation(rotation: Vector3): Mat4;
103
+ export declare function rotateMat4(mat: Mat4, rotation: Vector3): void;
104
+ export declare function createPipeline(device: GPUDevice, module: GPUShaderModule, presentationFormat: GPUTextureFormat, entryPoint: string, topology: GPUPrimitiveTopology): GPURenderPipeline;
105
+ export declare function triangulateWireFrameOrder(len: number): number[];
101
106
  export {};
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { mat4, vec2, vec3, vec4 } from 'wgpu-matrix';
2
2
  import { SimulationElement, SplinePoint2d } from './graphics.js';
3
- import { BUF_LEN } from './constants.js';
3
+ import { BUF_LEN, colorOffset, uvOffset, vertexSize } from './constants.js';
4
4
  export class Color {
5
5
  r; // 0 - 255
6
6
  g; // 0 - 255
@@ -141,11 +141,8 @@ export const buildMultisampleTexture = (device, ctx, width, height) => {
141
141
  sampleCount: 4
142
142
  });
143
143
  };
144
- export const applyElementToScene = (scene, camera, el) => {
145
- if (!camera)
146
- throw logger.error('Camera is not initialized in element');
144
+ export const applyElementToScene = (scene, el) => {
147
145
  if (el instanceof SimulationElement) {
148
- el.setCamera(camera);
149
146
  scene.push(el);
150
147
  }
151
148
  else {
@@ -266,8 +263,14 @@ export function easeInOutQuad(t) {
266
263
  export function vertexBuffer(x, y, z, color, uv = vector2()) {
267
264
  return [x, y, z, 1, ...color.toBuffer(), ...uv];
268
265
  }
269
- export function vec3ToPixelRatio(vec) {
270
- vec3.mul(vec, vector3(devicePixelRatio, devicePixelRatio, devicePixelRatio), vec);
266
+ export function vector3ToPixelRatio(vec) {
267
+ vec[0] *= devicePixelRatio;
268
+ vec[1] *= devicePixelRatio;
269
+ vec[2] *= devicePixelRatio;
270
+ }
271
+ export function vector2ToPixelRatio(vec) {
272
+ vec[0] *= devicePixelRatio;
273
+ vec[1] *= devicePixelRatio;
271
274
  }
272
275
  export function cloneBuf(buf) {
273
276
  return new Float32Array(buf);
@@ -281,6 +284,9 @@ export function vector3(x = 0, y = 0, z = 0) {
281
284
  export function vector2(x = 0, y = 0) {
282
285
  return vec2.fromValues(x, y);
283
286
  }
287
+ export function matrix4() {
288
+ return mat4.identity();
289
+ }
284
290
  export function vector3FromVector2(vec) {
285
291
  return vector3(vec[0], vec[1]);
286
292
  }
@@ -353,3 +359,82 @@ export function waitFor(t) {
353
359
  setTimeout(resolve, t * 1000);
354
360
  });
355
361
  }
362
+ export function matrixFromRotation(rotation) {
363
+ let rotMatrix = mat4.identity();
364
+ mat4.rotateZ(rotMatrix, rotation[2], rotMatrix);
365
+ mat4.rotateY(rotMatrix, rotation[1], rotMatrix);
366
+ mat4.rotateX(rotMatrix, rotation[0], rotMatrix);
367
+ return rotMatrix;
368
+ }
369
+ export function rotateMat4(mat, rotation) {
370
+ mat4.rotateZ(mat, rotation[2], mat);
371
+ mat4.rotateY(mat, rotation[1], mat);
372
+ mat4.rotateX(mat, rotation[0], mat);
373
+ }
374
+ export function createPipeline(device, module, presentationFormat, entryPoint, topology) {
375
+ return device.createRenderPipeline({
376
+ layout: 'auto',
377
+ vertex: {
378
+ module,
379
+ entryPoint,
380
+ buffers: [
381
+ {
382
+ arrayStride: vertexSize,
383
+ attributes: [
384
+ {
385
+ // position
386
+ shaderLocation: 0,
387
+ offset: 0,
388
+ format: 'float32x4'
389
+ },
390
+ {
391
+ // color
392
+ shaderLocation: 1,
393
+ offset: colorOffset,
394
+ format: 'float32x4'
395
+ },
396
+ {
397
+ // size
398
+ shaderLocation: 2,
399
+ offset: uvOffset,
400
+ format: 'float32x2'
401
+ }
402
+ ]
403
+ }
404
+ ]
405
+ },
406
+ fragment: {
407
+ module,
408
+ entryPoint: 'fragment_main',
409
+ targets: [
410
+ {
411
+ format: presentationFormat
412
+ }
413
+ ]
414
+ },
415
+ primitive: {
416
+ topology
417
+ },
418
+ multisample: {
419
+ count: 4
420
+ },
421
+ depthStencil: {
422
+ depthWriteEnabled: true,
423
+ depthCompare: 'less',
424
+ format: 'depth24plus'
425
+ }
426
+ });
427
+ }
428
+ export function triangulateWireFrameOrder(len) {
429
+ const order = Array(len)
430
+ .fill(0)
431
+ .map((_, index) => index);
432
+ let front = 0;
433
+ let back = len - 1;
434
+ while (front < back) {
435
+ order.push(front, back);
436
+ front++;
437
+ back--;
438
+ }
439
+ return order;
440
+ }
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.2.4",
8
+ "version": "0.2.5",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": "./dist/index.js",