simulationjsv2 0.1.5 → 0.1.7

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,33 +1,6 @@
1
- import { Camera, Color } from './simulation.js';
2
- import type { Vector2, Vector3, LerpFunc, VertexColorMap, Vector4 } from './types.js';
3
- declare class VertexCache {
4
- private vertices;
5
- private hasUpdated;
6
- constructor();
7
- setCache(vertices: number[]): void;
8
- getCache(): number[];
9
- updated(): void;
10
- shouldUpdate(): boolean;
11
- getVertexCount(): number;
12
- }
13
- export declare class Vertex {
14
- private pos;
15
- private color;
16
- private is3d;
17
- private readonly uv;
18
- constructor(x?: number, y?: number, z?: number, color?: Color, is3dPoint?: boolean, uv?: Vector2);
19
- getPos(): Vector3;
20
- getColor(): Color | null;
21
- getUv(): Vector2;
22
- setColor(color: Color): void;
23
- setPos(pos: Vector3): void;
24
- setX(x: number): void;
25
- setY(y: number): void;
26
- setZ(z: number): void;
27
- setIs3d(is3d: boolean): void;
28
- clone(): Vertex;
29
- toBuffer(defaultColor: Color): number[];
30
- }
1
+ import { Camera } from './simulation.js';
2
+ import type { Vector2, Vector3, LerpFunc, VertexColorMap } from './types.js';
3
+ import { Vertex, VertexCache, Color } from './utils.js';
31
4
  export declare abstract class SimulationElement {
32
5
  private pos;
33
6
  private color;
@@ -85,17 +58,45 @@ export declare class Polygon extends SimulationElement {
85
58
  constructor(pos: Vector3, vertices: Vertex[], color?: Color);
86
59
  rotate(amount: number, t?: number, f?: LerpFunc): Promise<void>;
87
60
  rotateTo(num: number, t?: number, f?: LerpFunc): Promise<void>;
88
- setPoints(newVertices: Vertex[], t?: number, f?: LerpFunc): Promise<void>;
61
+ getVertices(): Vertex[];
62
+ setVertices(newVertices: Vertex[], t?: number, f?: LerpFunc): Promise<void>;
63
+ getBuffer(camera: Camera, force: boolean): number[];
64
+ }
65
+ export declare class BezierCurve2d {
66
+ private points;
67
+ constructor(points: Vector2[]);
68
+ interpolateSlope(t: number): readonly [Vector2, Vector2];
69
+ interpolate(t: number): Vector2;
70
+ getPoints(): Vector2[];
71
+ getLength(): number;
72
+ }
73
+ export declare class CubicBezierCurve2d extends BezierCurve2d {
74
+ private detail;
75
+ constructor(points: [Vector2, Vector2, Vector2, Vector2], detail?: number);
76
+ getDetail(): number | undefined;
77
+ }
78
+ export declare class SplinePoint2d {
79
+ private start;
80
+ private end;
81
+ private control1;
82
+ private control2;
83
+ private rawControls;
84
+ private detail;
85
+ constructor(start: Vertex | null, end: Vertex, control1: Vector2 | null, control2: Vector2, rawControls: [Vector2, Vector2], detail?: number);
86
+ getStart(): Vertex | null;
87
+ getEnd(): Vertex;
88
+ getControls(): readonly [Vector2 | null, Vector2];
89
+ getRawControls(): [Vector2, Vector2];
90
+ getDetail(): number | undefined;
91
+ getVectorArray(prevEnd: Vector2 | null, prevControl: Vector2 | null): readonly [Vector2, Vector2, Vector2, Vector2];
92
+ }
93
+ export declare class Spline2d extends SimulationElement {
94
+ private curves;
95
+ private width;
96
+ private detail;
97
+ private interpolateLimit;
98
+ private distance;
99
+ constructor(pos: Vector2, points: SplinePoint2d[], width?: number, color?: Color, detail?: number);
100
+ setInterpolateLimit(limit: number, t?: number, f?: LerpFunc): Promise<void>;
89
101
  getBuffer(camera: Camera, force: boolean): number[];
90
102
  }
91
- export declare function vector4(x?: number, y?: number, z?: number, w?: number): Vector4;
92
- export declare function vector3(x?: number, y?: number, z?: number): Vector3;
93
- export declare function vector2(x?: number, y?: number): Vector2;
94
- export declare function vec3fromVec2(vec: Vector2): Vector3;
95
- export declare function colorFromVec4(vec: Vector4): Color;
96
- export declare function randomInt(range: number, min?: number): number;
97
- export declare function randomColor(a?: number): Color;
98
- export declare function vertex(x?: number, y?: number, z?: number, color?: Color, is3dPoint?: boolean, uv?: Vector2): Vertex;
99
- export declare function color(r?: number, g?: number, b?: number, a?: number): Color;
100
- export declare function colorf(val: number, a?: number): Color;
101
- export {};
package/dist/graphics.js CHANGED
@@ -1,75 +1,5 @@
1
1
  import { vec3, quat, mat4, vec2, vec4 } from 'wgpu-matrix';
2
- import { Color, transitionValues } from './simulation.js';
3
- import { BUF_LEN } from './constants.js';
4
- class VertexCache {
5
- vertices = [];
6
- hasUpdated = true;
7
- constructor() { }
8
- setCache(vertices) {
9
- this.vertices = vertices;
10
- this.hasUpdated = false;
11
- }
12
- getCache() {
13
- return this.vertices;
14
- }
15
- updated() {
16
- this.hasUpdated = true;
17
- }
18
- shouldUpdate() {
19
- return this.hasUpdated;
20
- }
21
- getVertexCount() {
22
- return this.vertices.length / BUF_LEN;
23
- }
24
- }
25
- export class Vertex {
26
- pos;
27
- color;
28
- is3d;
29
- uv;
30
- constructor(x = 0, y = 0, z = 0, color, is3dPoint = true, uv = vector2()) {
31
- this.pos = vector3(x, y, z);
32
- this.color = color ? color : null;
33
- this.is3d = is3dPoint;
34
- this.uv = uv;
35
- }
36
- getPos() {
37
- return this.pos;
38
- }
39
- getColor() {
40
- return this.color;
41
- }
42
- getUv() {
43
- return this.uv;
44
- }
45
- setColor(color) {
46
- this.color = color;
47
- }
48
- setPos(pos) {
49
- this.pos = pos;
50
- }
51
- setX(x) {
52
- this.pos[0] = x;
53
- }
54
- setY(y) {
55
- this.pos[1] = y;
56
- }
57
- setZ(z) {
58
- this.pos[2] = z;
59
- }
60
- setIs3d(is3d) {
61
- this.is3d = is3d;
62
- }
63
- clone() {
64
- return new Vertex(this.pos[0], this.pos[1], this.pos[2], this.color?.clone(), this.is3d, cloneBuf(this.uv));
65
- }
66
- toBuffer(defaultColor) {
67
- if (this.is3d)
68
- return vertexBuffer3d(this.pos[0], this.pos[1], this.pos[2], this.color || defaultColor, this.uv);
69
- else
70
- return vertexBuffer2d(this.pos[0], this.pos[1], this.color || defaultColor, this.uv);
71
- }
72
- }
2
+ import { Vertex, VertexCache, cloneBuf, color, colorFromVector4, lossyTriangulate, vec3ToPixelRatio, vector3FromVector2, vector2, vector3, vertex, vertexBuffer2d, vertexBuffer3d, Color, transitionValues, logger, vector2FromVector3 } from './utils.js';
73
3
  export class SimulationElement {
74
4
  pos;
75
5
  color;
@@ -209,7 +139,7 @@ export class Square extends SimulationElement {
209
139
  * @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
210
140
  */
211
141
  constructor(pos, width, height, color, rotation, vertexColors) {
212
- super(vec3fromVec2(pos), color);
142
+ super(vector3FromVector2(pos), color);
213
143
  this.width = width * devicePixelRatio;
214
144
  this.height = height * devicePixelRatio;
215
145
  this.rotation = rotation || 0;
@@ -331,7 +261,7 @@ export class Circle extends SimulationElement {
331
261
  radius;
332
262
  detail = 100;
333
263
  constructor(pos, radius, color, detail = 50) {
334
- super(vec3fromVec2(pos), color);
264
+ super(vector3FromVector2(pos), color);
335
265
  this.radius = radius * devicePixelRatio;
336
266
  this.detail = detail;
337
267
  }
@@ -410,7 +340,10 @@ export class Polygon extends SimulationElement {
410
340
  this.rotation = num;
411
341
  }, t, f);
412
342
  }
413
- setPoints(newVertices, t = 0, f) {
343
+ getVertices() {
344
+ return this.vertices;
345
+ }
346
+ setVertices(newVertices, t = 0, f) {
414
347
  const vertices = newVertices.map((vert) => {
415
348
  const newVertex = vert.clone();
416
349
  newVertex.setZ(0);
@@ -461,7 +394,7 @@ export class Polygon extends SimulationElement {
461
394
  vec4.scale(colorChange, p, colorChange);
462
395
  vec4.add((vert.getColor() || this.getColor()).toVec4(), colorChange, colorChange);
463
396
  vert.setPos(posChange);
464
- vert.setColor(colorFromVec4(colorChange));
397
+ vert.setColor(colorFromVector4(colorChange));
465
398
  });
466
399
  this.vertexCache.updated();
467
400
  }, () => {
@@ -471,7 +404,7 @@ export class Polygon extends SimulationElement {
471
404
  vec3.add(initPos, posChanges[i], initPos);
472
405
  vec4.add(initColor, colorChanges[i], initColor);
473
406
  vert.setPos(initPos);
474
- vert.setColor(colorFromVec4(initColor));
407
+ vert.setColor(colorFromVector4(initColor));
475
408
  });
476
409
  this.vertices.splice(vertices.length, this.vertices.length);
477
410
  this.vertexCache.updated();
@@ -498,74 +431,194 @@ export class Polygon extends SimulationElement {
498
431
  return this.vertexCache.getCache();
499
432
  }
500
433
  }
501
- // optomized for speed, depending on orientation of vertices as input, shape may not be preserved
502
- function lossyTriangulate(vertices) {
503
- const res = [];
504
- let facingRight = true;
505
- let rightOffset = 0;
506
- let leftOffset = 0;
507
- while (rightOffset < vertices.length - leftOffset - 2) {
508
- if (facingRight) {
509
- const triangle = [
510
- vertices[rightOffset],
511
- vertices[rightOffset + 1],
512
- vertices[vertices.length - leftOffset - 1]
513
- ];
514
- res.push(triangle);
515
- rightOffset++;
516
- }
517
- else {
518
- const triangle = [
519
- vertices[rightOffset],
520
- vertices[vertices.length - leftOffset - 1],
521
- vertices[vertices.length - leftOffset - 2]
522
- ];
523
- res.push(triangle);
524
- leftOffset++;
434
+ export class BezierCurve2d {
435
+ points;
436
+ constructor(points) {
437
+ if (points.length === 0)
438
+ throw logger.error('Expected 1 or more points for BezierCurve2d');
439
+ this.points = points;
440
+ }
441
+ interpolateSlope(t) {
442
+ let vectors = this.points;
443
+ let slopeVector = vector2(1);
444
+ while (vectors.length > 2) {
445
+ let newVectors = [];
446
+ for (let i = 1; i < vectors.length - 1; i++) {
447
+ const from = vector2();
448
+ const to = vector2();
449
+ vec2.sub(vectors[i], vectors[i - 1], from);
450
+ vec2.scale(from, t, from);
451
+ vec2.add(from, vectors[i - 1], from);
452
+ vec2.sub(vectors[i + 1], vectors[i], to);
453
+ vec2.scale(to, t, to);
454
+ vec2.add(to, vectors[i], to);
455
+ if (i === 1) {
456
+ newVectors.push(from);
457
+ }
458
+ newVectors.push(to);
459
+ }
460
+ vectors = newVectors;
525
461
  }
526
- facingRight = !facingRight;
462
+ vec2.sub(vectors[1], vectors[0], slopeVector);
463
+ let resVector = vector2();
464
+ vec2.scale(slopeVector, t, resVector);
465
+ vec2.add(resVector, vectors[0], resVector);
466
+ return [resVector, slopeVector];
467
+ }
468
+ interpolate(t) {
469
+ const [vec] = this.interpolateSlope(t);
470
+ return vec;
471
+ }
472
+ getPoints() {
473
+ return this.points;
474
+ }
475
+ getLength() {
476
+ const start = this.points[0];
477
+ const end = this.points[this.points.length - 1];
478
+ return Math.sqrt(Math.pow(end[0] - start[0], 2) + Math.pow(end[1] - start[1], 2));
527
479
  }
528
- return res;
529
- }
530
- function vertexBuffer3d(x, y, z, color, uv = vector2()) {
531
- return [x, y, z, 1, ...color.toBuffer(), ...uv, 1];
532
- }
533
- function vertexBuffer2d(x, y, color, uv = vector2()) {
534
- return [x, y, 0, 1, ...color.toBuffer(), ...uv, 0];
535
- }
536
- function vec3ToPixelRatio(vec) {
537
- vec3.mul(vec, vector3(devicePixelRatio, devicePixelRatio, devicePixelRatio), vec);
538
- }
539
- function cloneBuf(buf) {
540
- return new Float32Array(buf);
541
- }
542
- export function vector4(x = 0, y = 0, z = 0, w = 0) {
543
- return vec4.fromValues(x, y, z, w);
544
- }
545
- export function vector3(x = 0, y = 0, z = 0) {
546
- return vec3.fromValues(x, y, z);
547
- }
548
- export function vector2(x = 0, y = 0) {
549
- return vec2.fromValues(x, y, 0);
550
- }
551
- export function vec3fromVec2(vec) {
552
- return vector3(vec[0], vec[1]);
553
- }
554
- export function colorFromVec4(vec) {
555
- return new Color(vec[0], vec[1], vec[2], vec[3]);
556
- }
557
- export function randomInt(range, min = 0) {
558
- return Math.floor(Math.random() * (range - min)) + min;
559
- }
560
- export function randomColor(a = 1) {
561
- return new Color(randomInt(255), randomInt(255), randomInt(255), a);
562
480
  }
563
- export function vertex(x, y, z, color, is3dPoint, uv) {
564
- return new Vertex(x, y, z, color, is3dPoint, uv);
481
+ export class CubicBezierCurve2d extends BezierCurve2d {
482
+ detail;
483
+ constructor(points, detail) {
484
+ super(points);
485
+ this.detail = detail;
486
+ }
487
+ getDetail() {
488
+ return this.detail;
489
+ }
565
490
  }
566
- export function color(r, g, b, a) {
567
- return new Color(r, g, b, a);
491
+ export class SplinePoint2d {
492
+ start;
493
+ end;
494
+ control1;
495
+ control2;
496
+ rawControls;
497
+ detail;
498
+ constructor(start, end, control1, control2, rawControls, detail) {
499
+ this.start = start;
500
+ this.end = end;
501
+ this.control1 = control1;
502
+ this.control2 = control2;
503
+ this.rawControls = rawControls;
504
+ this.detail = detail;
505
+ }
506
+ getStart() {
507
+ return this.start;
508
+ }
509
+ getEnd() {
510
+ return this.end;
511
+ }
512
+ getControls() {
513
+ return [this.control1, this.control2];
514
+ }
515
+ getRawControls() {
516
+ return this.rawControls;
517
+ }
518
+ getDetail() {
519
+ return this.detail;
520
+ }
521
+ getVectorArray(prevEnd, prevControl) {
522
+ const firstControl = cloneBuf(this.control1 || prevControl || vector2());
523
+ if (prevEnd) {
524
+ vec2.add(firstControl, prevEnd, firstControl);
525
+ }
526
+ else if (!this.start) {
527
+ prevEnd = vector2();
528
+ }
529
+ return [
530
+ this.start ? vector2FromVector3(this.start.getPos()) : prevEnd,
531
+ firstControl,
532
+ this.control2,
533
+ vector2FromVector3(this.end.getPos())
534
+ ];
535
+ }
568
536
  }
569
- export function colorf(val, a) {
570
- return color(val, val, val, a);
537
+ export class Spline2d extends SimulationElement {
538
+ curves;
539
+ width;
540
+ detail;
541
+ interpolateLimit;
542
+ distance;
543
+ constructor(pos, points, width = 2, color, detail = 40) {
544
+ super(vector3FromVector2(pos), color);
545
+ this.curves = [];
546
+ this.width = width * devicePixelRatio;
547
+ this.detail = detail;
548
+ this.interpolateLimit = 1;
549
+ this.distance = 0;
550
+ for (let i = 0; i < points.length; i++) {
551
+ let prevControl = null;
552
+ if (i > 0) {
553
+ prevControl = cloneBuf(points[i - 1].getRawControls()[1]);
554
+ vec2.negate(prevControl, prevControl);
555
+ console.log(prevControl);
556
+ }
557
+ const bezierPoints = points[i].getVectorArray(i > 0 ? vector2FromVector3(points[i - 1].getEnd().getPos()) : null, prevControl);
558
+ const curve = new CubicBezierCurve2d(bezierPoints, points[i].getDetail());
559
+ this.distance += curve.getLength();
560
+ this.curves.push(curve);
561
+ }
562
+ }
563
+ setInterpolateLimit(limit, t = 0, f) {
564
+ const diff = limit - this.interpolateLimit;
565
+ return transitionValues((p) => {
566
+ this.interpolateLimit += diff * p;
567
+ this.vertexCache.updated();
568
+ }, () => {
569
+ this.interpolateLimit = limit;
570
+ this.vertexCache.updated();
571
+ }, t, f);
572
+ }
573
+ getBuffer(camera, force) {
574
+ if (this.vertexCache.shouldUpdate() || force) {
575
+ const screenSize = camera.getScreenSize();
576
+ let verticesTop = [];
577
+ const verticesBottom = [];
578
+ let currentDistance = 0;
579
+ outer: for (let i = 0; i < this.curves.length; i++) {
580
+ const detail = this.curves[i].getDetail() || this.detail;
581
+ const step = 1 / detail;
582
+ const distanceRatio = currentDistance / this.distance;
583
+ if (distanceRatio > this.interpolateLimit)
584
+ break;
585
+ const curveLength = this.curves[i].getLength();
586
+ currentDistance += curveLength;
587
+ const sectionRatio = curveLength / this.distance;
588
+ for (let j = 0; j < detail + 1; j++) {
589
+ let currentInterpolation = step * j;
590
+ let atLimit = false;
591
+ if (step * j * sectionRatio + distanceRatio > this.interpolateLimit) {
592
+ atLimit = true;
593
+ currentInterpolation = (this.interpolateLimit - distanceRatio) / sectionRatio;
594
+ }
595
+ const [point, slope] = this.curves[i].interpolateSlope(currentInterpolation);
596
+ const pos = this.getPos();
597
+ point[0] += pos[0];
598
+ point[1] += screenSize[1] - pos[1];
599
+ const normal = vector2(-slope[1], slope[0]);
600
+ vec2.normalize(normal, normal);
601
+ vec2.scale(normal, this.width / 2, normal);
602
+ const vertTop = vertex(point[0] + normal[0], point[1] + normal[1]);
603
+ verticesTop.push(vertTop);
604
+ const vertBottom = vertex(point[0] - normal[0], point[1] - normal[1]);
605
+ verticesBottom.unshift(vertBottom);
606
+ if (atLimit) {
607
+ break outer;
608
+ }
609
+ }
610
+ }
611
+ verticesTop = verticesTop.concat(verticesBottom);
612
+ let resBuffer = [];
613
+ lossyTriangulate(verticesTop)
614
+ .flat()
615
+ .forEach((vert) => {
616
+ const pos = vert.getPos();
617
+ resBuffer = resBuffer.concat(vertexBuffer2d(pos[0], pos[1], vert.getColor() || this.getColor()));
618
+ });
619
+ this.vertexCache.setCache(resBuffer);
620
+ return resBuffer;
621
+ }
622
+ return this.vertexCache.getCache();
623
+ }
571
624
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './simulation.js';
2
2
  export * from './graphics.js';
3
3
  export * from './types.js';
4
+ export { Vertex, Color, cloneBuf, vector4, vector3, vector2, vector3FromVector2, colorFromVector4, randomInt, randomColor, vertex, color, colorf, transitionValues, lerp, smoothStep, linearStep, splinePoint2d, continuousSplinePoint2d } from './utils.js';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './simulation.js';
2
2
  export * from './graphics.js';
3
3
  export * from './types.js';
4
+ export { Vertex, Color, cloneBuf, vector4, vector3, vector2, vector3FromVector2, colorFromVector4, randomInt, randomColor, vertex, color, colorf, transitionValues, lerp, smoothStep, linearStep, splinePoint2d, continuousSplinePoint2d } from './utils.js';
@@ -1,6 +1,7 @@
1
1
  /// <reference types="dist" />
2
2
  import { SimulationElement } from './graphics.js';
3
3
  import type { Vector2, Vector3, LerpFunc } from './types.js';
4
+ import { Color } from './utils.js';
4
5
  export declare class Simulation {
5
6
  canvasRef: HTMLCanvasElement | null;
6
7
  private bgColor;
@@ -47,30 +48,3 @@ export declare class Camera {
47
48
  getPos(): Vector3;
48
49
  getAspectRatio(): number;
49
50
  }
50
- export declare class Color {
51
- r: number;
52
- g: number;
53
- b: number;
54
- a: number;
55
- constructor(r?: number, g?: number, b?: number, a?: number);
56
- clone(): Color;
57
- toBuffer(): readonly [number, number, number, number];
58
- toVec4(): import("./types.js").Vector4;
59
- toObject(): {
60
- r: number;
61
- g: number;
62
- b: number;
63
- a: number;
64
- };
65
- diff(color: Color): Color;
66
- }
67
- /**
68
- * @param callback1 - called every frame until the animation is finished
69
- * @param callback2 - called after animation is finished (called immediately when t = 0)
70
- * @param t - animation time (seconds)
71
- * @returns {Promise<void>}
72
- */
73
- export declare function transitionValues(callback1: (deltaT: number, t: number) => void, callback2: () => void, transitionLength: number, func?: (n: number) => number): Promise<void>;
74
- export declare function lerp(a: number, b: number, t: number): number;
75
- export declare function smoothStep(t: number): number;
76
- export declare function linearStep(n: number): number;
@@ -1,7 +1,7 @@
1
1
  import { vec3 } from 'wgpu-matrix';
2
- import { SimulationElement, vector2, vector3, vector4 } from './graphics.js';
2
+ import { SimulationElement } from './graphics.js';
3
3
  import { BUF_LEN } from './constants.js';
4
- import { applyElementToScene, buildDepthTexture, buildProjectionMatrix, getOrthoMatrix, getTransformationMatrix, logger } from './utils.js';
4
+ import { Color, applyElementToScene, buildDepthTexture, buildProjectionMatrix, getOrthoMatrix, getTransformationMatrix, logger, transitionValues, vector2, vector3 } from './utils.js';
5
5
  const vertexSize = 44; // 4 * 10 + 1
6
6
  const colorOffset = 16; // 4 * 4
7
7
  const uvOffset = 32; // 4 * 8
@@ -251,7 +251,7 @@ export class Simulation {
251
251
  });
252
252
  const colorAttachment = {
253
253
  // @ts-ignore
254
- view: undefined,
254
+ view: undefined, // Assigned later
255
255
  clearValue: this.bgColor.toObject(),
256
256
  loadOp: 'clear',
257
257
  storeOp: 'store'
@@ -469,83 +469,3 @@ export class Camera {
469
469
  return this.aspectRatio;
470
470
  }
471
471
  }
472
- export class Color {
473
- r; // 0 - 255
474
- g; // 0 - 255
475
- b; // 0 - 255
476
- a; // 0.0 - 1.0
477
- constructor(r = 0, g = 0, b = 0, a = 1) {
478
- this.r = r;
479
- this.g = g;
480
- this.b = b;
481
- this.a = a;
482
- }
483
- clone() {
484
- return new Color(this.r, this.g, this.b, this.a);
485
- }
486
- toBuffer() {
487
- return [this.r / 255, this.g / 255, this.b / 255, this.a];
488
- }
489
- toVec4() {
490
- return vector4(this.r, this.g, this.b, this.a);
491
- }
492
- toObject() {
493
- return {
494
- r: this.r / 255,
495
- g: this.g / 255,
496
- b: this.b / 255,
497
- a: this.a
498
- };
499
- }
500
- diff(color) {
501
- return new Color(this.r - color.r, this.g - color.g, this.b - color.b, this.a - color.a);
502
- }
503
- }
504
- /**
505
- * @param callback1 - called every frame until the animation is finished
506
- * @param callback2 - called after animation is finished (called immediately when t = 0)
507
- * @param t - animation time (seconds)
508
- * @returns {Promise<void>}
509
- */
510
- export function transitionValues(callback1, callback2, transitionLength, func) {
511
- return new Promise((resolve) => {
512
- if (transitionLength == 0) {
513
- callback2();
514
- resolve();
515
- }
516
- else {
517
- let prevPercent = 0;
518
- let prevTime = Date.now();
519
- const step = (t, f) => {
520
- const newT = f(t);
521
- callback1(newT - prevPercent, t);
522
- prevPercent = newT;
523
- const now = Date.now();
524
- let diff = now - prevTime;
525
- diff = diff === 0 ? 1 : diff;
526
- const fpsScale = 1 / diff;
527
- const inc = 1 / (1000 * fpsScale * transitionLength);
528
- prevTime = now;
529
- if (t < 1) {
530
- window.requestAnimationFrame(() => step(t + inc, f));
531
- }
532
- else {
533
- callback2();
534
- resolve();
535
- }
536
- };
537
- step(0, func ? func : linearStep);
538
- }
539
- });
540
- }
541
- export function lerp(a, b, t) {
542
- return a + (b - a) * t;
543
- }
544
- export function smoothStep(t) {
545
- const v1 = t * t;
546
- const v2 = 1 - (1 - t) * (1 - t);
547
- return lerp(v1, v2, t);
548
- }
549
- export function linearStep(n) {
550
- return n;
551
- }
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Color } from './simulation.js';
1
+ import { Color } from './utils.js';
2
2
  export type Vector4 = Float32Array & [number, number, number, number];
3
3
  export type Vector3 = Float32Array & [number, number, number];
4
4
  export type Vector2 = Float32Array & [number, number];
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,53 @@
1
1
  /// <reference types="dist" />
2
- import { SimulationElement } from './graphics.js';
3
- import { Vector3 } from './types.js';
2
+ import { SimulationElement, SplinePoint2d } from './graphics.js';
3
+ import { Vector2, Vector3, Vector4 } from './types.js';
4
4
  import { Camera } from './simulation.js';
5
+ export declare class Color {
6
+ r: number;
7
+ g: number;
8
+ b: number;
9
+ a: number;
10
+ constructor(r?: number, g?: number, b?: number, a?: number);
11
+ clone(): Color;
12
+ toBuffer(): readonly [number, number, number, number];
13
+ toVec4(): Vector4;
14
+ toObject(): {
15
+ r: number;
16
+ g: number;
17
+ b: number;
18
+ a: number;
19
+ };
20
+ diff(color: Color): Color;
21
+ }
22
+ export declare class VertexCache {
23
+ private vertices;
24
+ private hasUpdated;
25
+ constructor();
26
+ setCache(vertices: number[]): void;
27
+ getCache(): number[];
28
+ updated(): void;
29
+ shouldUpdate(): boolean;
30
+ getVertexCount(): number;
31
+ }
32
+ export declare class Vertex {
33
+ private pos;
34
+ private color;
35
+ private is3d;
36
+ private uv;
37
+ constructor(x?: number, y?: number, z?: number, color?: Color, is3dPoint?: boolean, uv?: Vector2);
38
+ getPos(): Vector3;
39
+ setPos(pos: Vector3): void;
40
+ getColor(): Color | null;
41
+ setColor(color: Color): void;
42
+ getUv(): Vector2;
43
+ setUv(uv: Vector2): void;
44
+ setX(x: number): void;
45
+ setY(y: number): void;
46
+ setZ(z: number): void;
47
+ setIs3d(is3d: boolean): void;
48
+ clone(): Vertex;
49
+ toBuffer(defaultColor: Color): number[];
50
+ }
5
51
  export declare const buildProjectionMatrix: (aspectRatio: number, zNear?: number, zFar?: number) => any;
6
52
  export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3, projectionMatrix: mat4) => Float32Array;
7
53
  export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
@@ -16,4 +62,32 @@ declare class Logger {
16
62
  log_error(msg: string): void;
17
63
  }
18
64
  export declare const logger: Logger;
65
+ export declare function lossyTriangulate(vertices: Vertex[]): (readonly [Vertex, Vertex, Vertex])[];
66
+ /**
67
+ * @param callback1 - called every frame until the animation is finished
68
+ * @param callback2 - called after animation is finished (called immediately when t = 0)
69
+ * @param t - animation time (seconds)
70
+ * @returns {Promise<void>}
71
+ */
72
+ export declare function transitionValues(callback1: (deltaT: number, t: number) => void, callback2: () => void, transitionLength: number, func?: (n: number) => number): Promise<void>;
73
+ export declare function lerp(a: number, b: number, t: number): number;
74
+ export declare function smoothStep(t: number): number;
75
+ export declare function linearStep(n: number): number;
76
+ export declare function vertexBuffer3d(x: number, y: number, z: number, color: Color, uv?: Vector2): number[];
77
+ export declare function vertexBuffer2d(x: number, y: number, color: Color, uv?: Vector2): number[];
78
+ export declare function vec3ToPixelRatio(vec: Vector3): void;
79
+ export declare function cloneBuf<T extends Float32Array>(buf: T): T;
80
+ export declare function vector4(x?: number, y?: number, z?: number, w?: number): Vector4;
81
+ export declare function vector3(x?: number, y?: number, z?: number): Vector3;
82
+ export declare function vector2(x?: number, y?: number): Vector2;
83
+ export declare function vector3FromVector2(vec: Vector2): Vector3;
84
+ export declare function vector2FromVector3(vec: Vector3): Vector2;
85
+ export declare function colorFromVector4(vec: Vector4): Color;
86
+ export declare function randomInt(range: number, min?: number): number;
87
+ export declare function randomColor(a?: number): Color;
88
+ export declare function vertex(x?: number, y?: number, z?: number, color?: Color, is3dPoint?: boolean, uv?: Vector2): Vertex;
89
+ export declare function color(r?: number, g?: number, b?: number, a?: number): Color;
90
+ export declare function colorf(val: number, a?: number): Color;
91
+ export declare function splinePoint2d(end: Vertex, control1: Vector2, control2: Vector2, detail?: number): SplinePoint2d;
92
+ export declare function continuousSplinePoint2d(end: Vertex, control: Vector2, detail?: number): SplinePoint2d;
19
93
  export {};
package/dist/utils.js CHANGED
@@ -1,5 +1,110 @@
1
- import { mat4, vec3 } from 'wgpu-matrix';
2
- import { SimulationElement, vector3 } from './graphics.js';
1
+ import { mat4, vec2, vec3, vec4 } from 'wgpu-matrix';
2
+ import { SimulationElement, SplinePoint2d } from './graphics.js';
3
+ import { BUF_LEN } from './constants.js';
4
+ export class Color {
5
+ r; // 0 - 255
6
+ g; // 0 - 255
7
+ b; // 0 - 255
8
+ a; // 0.0 - 1.0
9
+ constructor(r = 0, g = 0, b = 0, a = 1) {
10
+ this.r = r;
11
+ this.g = g;
12
+ this.b = b;
13
+ this.a = a;
14
+ }
15
+ clone() {
16
+ return new Color(this.r, this.g, this.b, this.a);
17
+ }
18
+ toBuffer() {
19
+ return [this.r / 255, this.g / 255, this.b / 255, this.a];
20
+ }
21
+ toVec4() {
22
+ return vector4(this.r, this.g, this.b, this.a);
23
+ }
24
+ toObject() {
25
+ return {
26
+ r: this.r / 255,
27
+ g: this.g / 255,
28
+ b: this.b / 255,
29
+ a: this.a
30
+ };
31
+ }
32
+ diff(color) {
33
+ return new Color(this.r - color.r, this.g - color.g, this.b - color.b, this.a - color.a);
34
+ }
35
+ }
36
+ export class VertexCache {
37
+ vertices = [];
38
+ hasUpdated = true;
39
+ constructor() { }
40
+ setCache(vertices) {
41
+ this.vertices = vertices;
42
+ this.hasUpdated = false;
43
+ }
44
+ getCache() {
45
+ return this.vertices;
46
+ }
47
+ updated() {
48
+ this.hasUpdated = true;
49
+ }
50
+ shouldUpdate() {
51
+ return this.hasUpdated;
52
+ }
53
+ getVertexCount() {
54
+ return this.vertices.length / BUF_LEN;
55
+ }
56
+ }
57
+ export class Vertex {
58
+ pos;
59
+ color;
60
+ is3d;
61
+ uv;
62
+ constructor(x = 0, y = 0, z = 0, color, is3dPoint = true, uv = vector2()) {
63
+ this.pos = vector3(x, y, z);
64
+ this.color = color ? color : null;
65
+ this.is3d = is3dPoint;
66
+ this.uv = uv;
67
+ }
68
+ getPos() {
69
+ return this.pos;
70
+ }
71
+ setPos(pos) {
72
+ this.pos = pos;
73
+ }
74
+ getColor() {
75
+ return this.color;
76
+ }
77
+ setColor(color) {
78
+ this.color = color;
79
+ }
80
+ getUv() {
81
+ return this.uv;
82
+ }
83
+ setUv(uv) {
84
+ this.uv = uv;
85
+ }
86
+ setX(x) {
87
+ this.pos[0] = x;
88
+ }
89
+ setY(y) {
90
+ this.pos[1] = y;
91
+ }
92
+ setZ(z) {
93
+ this.pos[2] = z;
94
+ }
95
+ setIs3d(is3d) {
96
+ this.is3d = is3d;
97
+ }
98
+ clone() {
99
+ return new Vertex(this.pos[0], this.pos[1], this.pos[2], this.color?.clone(), this.is3d, cloneBuf(this.uv));
100
+ }
101
+ toBuffer(defaultColor) {
102
+ if (this.is3d)
103
+ return vertexBuffer3d(this.pos[0], this.pos[1], this.pos[2], this.color || defaultColor, this.uv);
104
+ else
105
+ return vertexBuffer2d(this.pos[0], this.pos[1], this.color || defaultColor, this.uv);
106
+ }
107
+ }
3
108
  export const buildProjectionMatrix = (aspectRatio, zNear = 1, zFar = 500) => {
4
109
  const fov = (2 * Math.PI) / 5;
5
110
  return mat4.perspective(fov, aspectRatio, zNear, zFar);
@@ -57,3 +162,140 @@ class Logger {
57
162
  }
58
163
  }
59
164
  export const logger = new Logger();
165
+ // optomized for speed, depending on orientation of vertices as input, shape may not be preserved
166
+ export function lossyTriangulate(vertices) {
167
+ const res = [];
168
+ let facingRight = true;
169
+ let rightOffset = 0;
170
+ let leftOffset = 0;
171
+ while (rightOffset < vertices.length - leftOffset - 2) {
172
+ if (facingRight) {
173
+ const triangle = [
174
+ vertices[rightOffset],
175
+ vertices[rightOffset + 1],
176
+ vertices[vertices.length - leftOffset - 1]
177
+ ];
178
+ res.push(triangle);
179
+ rightOffset++;
180
+ }
181
+ else {
182
+ const triangle = [
183
+ vertices[rightOffset],
184
+ vertices[vertices.length - leftOffset - 1],
185
+ vertices[vertices.length - leftOffset - 2]
186
+ ];
187
+ res.push(triangle);
188
+ leftOffset++;
189
+ }
190
+ facingRight = !facingRight;
191
+ }
192
+ return res;
193
+ }
194
+ /**
195
+ * @param callback1 - called every frame until the animation is finished
196
+ * @param callback2 - called after animation is finished (called immediately when t = 0)
197
+ * @param t - animation time (seconds)
198
+ * @returns {Promise<void>}
199
+ */
200
+ export function transitionValues(callback1, callback2, transitionLength, func) {
201
+ return new Promise((resolve) => {
202
+ if (transitionLength == 0) {
203
+ callback2();
204
+ resolve();
205
+ }
206
+ else {
207
+ let prevPercent = 0;
208
+ let prevTime = Date.now();
209
+ const step = (t, f) => {
210
+ const newT = f(t);
211
+ callback1(newT - prevPercent, t);
212
+ prevPercent = newT;
213
+ const now = Date.now();
214
+ let diff = now - prevTime;
215
+ diff = diff === 0 ? 1 : diff;
216
+ const fpsScale = 1 / diff;
217
+ const inc = 1 / (1000 * fpsScale * transitionLength);
218
+ prevTime = now;
219
+ if (t < 1) {
220
+ window.requestAnimationFrame(() => step(t + inc, f));
221
+ }
222
+ else {
223
+ callback2();
224
+ resolve();
225
+ }
226
+ };
227
+ step(0, func ? func : linearStep);
228
+ }
229
+ });
230
+ }
231
+ export function lerp(a, b, t) {
232
+ return a + (b - a) * t;
233
+ }
234
+ export function smoothStep(t) {
235
+ const v1 = t * t;
236
+ const v2 = 1 - (1 - t) * (1 - t);
237
+ return lerp(v1, v2, t);
238
+ }
239
+ export function linearStep(n) {
240
+ return n;
241
+ }
242
+ export function vertexBuffer3d(x, y, z, color, uv = vector2()) {
243
+ return [x, y, z, 1, ...color.toBuffer(), ...uv, 1];
244
+ }
245
+ export function vertexBuffer2d(x, y, color, uv = vector2()) {
246
+ return [x, y, 0, 1, ...color.toBuffer(), ...uv, 0];
247
+ }
248
+ export function vec3ToPixelRatio(vec) {
249
+ vec3.mul(vec, vector3(devicePixelRatio, devicePixelRatio, devicePixelRatio), vec);
250
+ }
251
+ export function cloneBuf(buf) {
252
+ return new Float32Array(buf);
253
+ }
254
+ export function vector4(x = 0, y = 0, z = 0, w = 0) {
255
+ return vec4.fromValues(x, y, z, w);
256
+ }
257
+ export function vector3(x = 0, y = 0, z = 0) {
258
+ return vec3.fromValues(x, y, z);
259
+ }
260
+ export function vector2(x = 0, y = 0) {
261
+ return vec2.fromValues(x, y);
262
+ }
263
+ export function vector3FromVector2(vec) {
264
+ return vector3(vec[0], vec[1]);
265
+ }
266
+ export function vector2FromVector3(vec) {
267
+ return vector2(vec[0], vec[1]);
268
+ }
269
+ export function colorFromVector4(vec) {
270
+ return new Color(vec[0], vec[1], vec[2], vec[3]);
271
+ }
272
+ export function randomInt(range, min = 0) {
273
+ return Math.floor(Math.random() * (range - min)) + min;
274
+ }
275
+ export function randomColor(a = 1) {
276
+ return new Color(randomInt(255), randomInt(255), randomInt(255), a);
277
+ }
278
+ export function vertex(x, y, z, color, is3dPoint, uv) {
279
+ return new Vertex(x, y, z, color, is3dPoint, uv);
280
+ }
281
+ export function color(r, g, b, a) {
282
+ return new Color(r, g, b, a);
283
+ }
284
+ export function colorf(val, a) {
285
+ return color(val, val, val, a);
286
+ }
287
+ export function splinePoint2d(end, control1, control2, detail) {
288
+ vec2.scale(control1, devicePixelRatio, control1);
289
+ vec2.scale(control2, devicePixelRatio, control2);
290
+ vec2.scale(end.getPos(), devicePixelRatio, end.getPos());
291
+ const rawControls = [cloneBuf(control1), cloneBuf(control2)];
292
+ vec2.add(end.getPos(), control2, control2);
293
+ return new SplinePoint2d(null, end, control1, control2, rawControls, detail);
294
+ }
295
+ export function continuousSplinePoint2d(end, control, detail) {
296
+ vec2.scale(control, devicePixelRatio, control);
297
+ vec2.scale(end.getPos(), devicePixelRatio, end.getPos());
298
+ const rawControls = [vector2(), cloneBuf(control)];
299
+ vec2.add(end.getPos(), control, control);
300
+ return new SplinePoint2d(null, end, null, control, rawControls, detail);
301
+ }
package/package.json CHANGED
@@ -5,14 +5,13 @@
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Jackson Otto",
7
7
  "description": "A simple graphics library using WebGPU",
8
- "version": "0.1.5",
8
+ "version": "0.1.7",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": "./dist/index.js",
12
12
  "types": "./dist/index.d.ts"
13
13
  }
14
14
  },
15
- "type": "module",
16
15
  "scripts": {
17
16
  "dev": "npx nodemon --watch src -e ts --exec 'npx tsc || exit 1'",
18
17
  "test": "vite --port 3000",
@@ -1 +0,0 @@
1
- export declare const BUF_LEN = 11;
@@ -1,90 +0,0 @@
1
- import { Camera, Color } from './simulation.js';
2
- import type { Vector2, Vector3, LerpFunc, VertexColorMap } from './types.js';
3
- declare class VertexCache {
4
- private vertices;
5
- private hasUpdated;
6
- constructor();
7
- setCache(vertices: number[]): void;
8
- getCache(): number[];
9
- updated(): void;
10
- shouldUpdate(): boolean;
11
- getVertexCount(): number;
12
- }
13
- declare class Vertex {
14
- private readonly pos;
15
- private readonly color;
16
- private readonly is3d;
17
- private readonly uv;
18
- constructor(x?: number, y?: number, z?: number, color?: Color, is3dPoint?: boolean, uv?: Vector2);
19
- getPos(): Vector3;
20
- getColor(): Color | null;
21
- toBuffer(defaultColor: Color): number[];
22
- }
23
- export declare abstract class SimulationElement {
24
- private pos;
25
- private color;
26
- camera: Camera | null;
27
- vertexCache: VertexCache;
28
- constructor(pos: Vector3, color?: Color);
29
- setPos(pos: Vector3): void;
30
- getPos(): Vector3;
31
- setCamera(camera: Camera): void;
32
- fill(newColor: Color, t?: number, f?: LerpFunc): Promise<void>;
33
- getColor(): Color;
34
- move(amount: Vector3, t?: number, f?: LerpFunc): Promise<void>;
35
- moveTo(pos: Vector3, t?: number, f?: LerpFunc): Promise<void>;
36
- abstract getBuffer(camera: Camera, force: boolean): number[];
37
- }
38
- export declare class Plane extends SimulationElement {
39
- private points;
40
- private rotation;
41
- constructor(pos: Vector3, points: Vertex[], rotation?: Vector3, color?: Color);
42
- setPoints(newPoints: Vertex[]): void;
43
- rotate(amount: Vector3, t?: number, f?: LerpFunc): Promise<void>;
44
- rotateTo(angle: Vector3, t?: number, f?: LerpFunc): Promise<void>;
45
- getBuffer(_: Camera, force: boolean): number[];
46
- }
47
- export declare class Square extends SimulationElement {
48
- private width;
49
- private height;
50
- private rotation;
51
- private vertexColors;
52
- /**
53
- * @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
54
- */
55
- constructor(pos: Vector2, width: number, height: number, color?: Color, rotation?: number, vertexColors?: VertexColorMap);
56
- scaleWidth(amount: number, t?: number, f?: LerpFunc): Promise<void>;
57
- scaleHeight(amount: number, t?: number, f?: LerpFunc): Promise<void>;
58
- scale(amount: number, t?: number, f?: LerpFunc): Promise<void>;
59
- setWidth(num: number, t?: number, f?: LerpFunc): Promise<void>;
60
- setHeight(num: number, t?: number, f?: LerpFunc): Promise<void>;
61
- rotate(rotation: number, t?: number, f?: LerpFunc): Promise<void>;
62
- setRotation(newRotation: number, t?: number, f?: LerpFunc): Promise<void>;
63
- getBuffer(camera: Camera, force: boolean): number[];
64
- }
65
- export declare class Circle extends SimulationElement {
66
- private radius;
67
- private detail;
68
- constructor(pos: Vector2, radius: number, color?: Color, detail?: number);
69
- setRadius(num: number, t?: number, f?: LerpFunc): Promise<void>;
70
- scale(amount: number, t?: number, f?: LerpFunc): Promise<void>;
71
- getBuffer(camera: Camera, force: boolean): number[];
72
- }
73
- export declare class Polygon extends SimulationElement {
74
- private points;
75
- private rotation;
76
- constructor(pos: Vector3, points: Vector2[], color?: Color);
77
- rotate(amount: number, t?: number, f?: LerpFunc): Promise<void>;
78
- rotateTo(num: number, t?: number, f?: LerpFunc): Promise<void>;
79
- setPoints(newPoints: Vector3[], t?: number, f?: LerpFunc): Promise<void>;
80
- getBuffer(): never[];
81
- }
82
- export declare function vector3(x?: number, y?: number, z?: number): Vector3;
83
- export declare function vector2(x?: number, y?: number): Vector2;
84
- export declare function vec3fromVec2(vec: Vector2): Vector3;
85
- export declare function randomInt(range: number, min?: number): number;
86
- export declare function randomColor(a?: number): Color;
87
- export declare function vertex(x?: number, y?: number, z?: number, color?: Color): Vertex;
88
- export declare function color(r?: number, g?: number, b?: number, a?: number): Color;
89
- export declare function colorf(val: number, a?: number): Color;
90
- export {};
package/types/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './simulation.js';
2
- export * from './graphics.js';
3
- export * from './types.js';
package/types/types.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Color } from './simulation.js';
2
- export type Vector3 = Float32Array & [number, number, number];
3
- export type Vector2 = Float32Array & [number, number];
4
- export type LerpFunc = (n: number) => number;
5
- export type VertexColorMap = Record<0 | 1 | 2 | 3, Color>;
package/types/utils.d.ts DELETED
@@ -1,18 +0,0 @@
1
- import { SimulationElement } from './graphics.js';
2
- import { Vector3 } from './types.js';
3
- import { Camera } from './simulation.js';
4
- export declare const buildProjectionMatrix: (aspectRatio: number, zNear?: number, zFar?: number) => any;
5
- export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3, projectionMatrix: mat4) => Float32Array;
6
- export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
7
- export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => any;
8
- export declare const applyElementToScene: (scene: SimulationElement[], camera: Camera | null, el: SimulationElement) => void;
9
- declare class Logger {
10
- constructor();
11
- private fmt;
12
- log(msg: string): void;
13
- error(msg: string): Error;
14
- warn(msg: string): void;
15
- log_error(msg: string): void;
16
- }
17
- export declare const logger: Logger;
18
- export {};