simulationjsv2 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/geometry.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { mat4, vec2, vec3 } from 'wgpu-matrix';
2
- import { cloneBuf, interpolateColors, lossyTriangulate, matrix4, triangulateWireFrameOrder, vector2, vector2FromVector3, vector3, vector3FromVector2, vertex, bufferGenerator } from './utils.js';
2
+ import { cloneBuf, matrix4, vector2, vector2FromVector3, vector3, vector3FromVector2, vertex } from './utils.js';
3
3
  import { CubicBezierCurve2d } from './graphics.js';
4
4
  import { BUF_LEN } from './constants.js';
5
+ import { bufferGenerator, interpolateColors, lossyTriangulate, triangulateWireFrameOrder } from './internalUtils.js';
5
6
  export class Geometry {
6
7
  vertices;
7
8
  matrix;
@@ -1,8 +1,9 @@
1
1
  /// <reference types="dist" />
2
2
  import { Camera } from './simulation.js';
3
3
  import type { Vector2, Vector3, LerpFunc, VertexColorMap, ElementRotation, Mat4 } from './types.js';
4
- import { Vertex, VertexCache, Color } from './utils.js';
4
+ import { Vertex, Color } from './utils.js';
5
5
  import { BlankGeometry, CircleGeometry, CubeGeometry, Geometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry } from './geometry.js';
6
+ import { VertexCache } from './internalUtils.js';
6
7
  export declare abstract class SimulationElement<T extends Vector2 | Vector3 = Vector3> {
7
8
  protected abstract pos: T;
8
9
  protected abstract geometry: Geometry;
@@ -125,10 +126,12 @@ export declare class Cube extends SimulationElement3d {
125
126
  }
126
127
  export declare class BezierCurve2d {
127
128
  private points;
129
+ private length;
128
130
  constructor(points: Vector2[]);
129
131
  interpolateSlope(t: number): readonly [Vector2, Vector2];
130
132
  interpolate(t: number): Vector2;
131
133
  getPoints(): Vector2[];
134
+ estimateLength(detail: number): number;
132
135
  getLength(): number;
133
136
  }
134
137
  export declare class CubicBezierCurve2d extends BezierCurve2d {
@@ -160,7 +163,10 @@ export declare class Spline2d extends SimulationElement2d {
160
163
  private detail;
161
164
  private interpolateStart;
162
165
  private interpolateLimit;
166
+ private length;
163
167
  constructor(pos: Vertex, points: SplinePoint2d[], thickness?: number, detail?: number);
168
+ private estimateLength;
169
+ getLength(): number;
164
170
  setInterpolateStart(start: number, t?: number, f?: LerpFunc): Promise<void>;
165
171
  setInterpolateLimit(limit: number, t?: number, f?: LerpFunc): Promise<void>;
166
172
  setThickness(thickness: number, t?: number, f?: LerpFunc): Promise<void>;
package/dist/graphics.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { vec3, mat4, vec2, vec4 } from 'wgpu-matrix';
2
- import { Vertex, VertexCache, cloneBuf, color, colorFromVector4, vector3ToPixelRatio, vector2, vector3, vertex, Color, transitionValues, logger, vector2FromVector3, matrix4, rotateMat4, vector3FromVector2, vector2ToPixelRatio, bufferGenerator } from './utils.js';
2
+ import { Vertex, cloneBuf, color, colorFromVector4, vector2, vector3, vertex, Color, transitionValues, vector2FromVector3, matrix4, vector3FromVector2, distance2d } from './utils.js';
3
3
  import { BlankGeometry, CircleGeometry, CubeGeometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry } from './geometry.js';
4
+ import { VertexCache, bufferGenerator, logger, rotateMat4, vector2ToPixelRatio, vector3ToPixelRatio } from './internalUtils.js';
4
5
  export class SimulationElement {
5
6
  color;
6
7
  wireframe;
@@ -62,7 +63,7 @@ export class SimulationElement {
62
63
  const matrix = matrix4();
63
64
  if (typeof this.rotation === 'number') {
64
65
  const pos = vector3FromVector2(this.pos);
65
- pos[1] = camera.getScreenSize()[1] - pos[1];
66
+ pos[1] = camera.getScreenSize()[1] + pos[1];
66
67
  mat4.translate(matrix, pos, matrix);
67
68
  mat4.rotateZ(matrix, this.rotation, matrix);
68
69
  }
@@ -359,7 +360,7 @@ export class Square extends SimulationElement2d {
359
360
  }
360
361
  updateMatrix(camera) {
361
362
  const pos = cloneBuf(this.pos);
362
- pos[1] = camera.getScreenSize()[1] - pos[1];
363
+ pos[1] = camera.getScreenSize()[1] + pos[1];
363
364
  const matrix = matrix4();
364
365
  mat4.translate(matrix, vector3FromVector2(pos), matrix);
365
366
  mat4.rotateZ(matrix, this.rotation, matrix);
@@ -637,10 +638,13 @@ export class Cube extends SimulationElement3d {
637
638
  }
638
639
  export class BezierCurve2d {
639
640
  points;
641
+ length;
640
642
  constructor(points) {
641
643
  if (points.length === 0)
642
644
  throw logger.error('Expected 1 or more points for BezierCurve2d');
643
645
  this.points = points;
646
+ const dist = distance2d(points[0], points[points.length - 1]);
647
+ this.length = this.estimateLength(dist);
644
648
  }
645
649
  interpolateSlope(t) {
646
650
  t = Math.max(0, Math.min(1, t));
@@ -677,10 +681,20 @@ export class BezierCurve2d {
677
681
  getPoints() {
678
682
  return this.points;
679
683
  }
684
+ estimateLength(detail) {
685
+ let totalDist = 0;
686
+ for (let i = 0; i < detail - 1; i++) {
687
+ const t1 = i / detail;
688
+ const t2 = (i + 1) / detail;
689
+ const p1 = this.interpolate(t1);
690
+ const p2 = this.interpolate(t2);
691
+ const dist = distance2d(p1, p2);
692
+ totalDist += dist;
693
+ }
694
+ return totalDist;
695
+ }
680
696
  getLength() {
681
- const start = this.points[0];
682
- const end = this.points[this.points.length - 1];
683
- return Math.sqrt(Math.pow(end[0] - start[0], 2) + Math.pow(end[1] - start[1], 2));
697
+ return this.length;
684
698
  }
685
699
  }
686
700
  export class CubicBezierCurve2d extends BezierCurve2d {
@@ -766,6 +780,7 @@ export class Spline2d extends SimulationElement2d {
766
780
  detail;
767
781
  interpolateStart;
768
782
  interpolateLimit;
783
+ length;
769
784
  constructor(pos, points, thickness = devicePixelRatio, detail = 40) {
770
785
  const tempPos = vector2FromVector3(pos.getPos());
771
786
  vector2ToPixelRatio(tempPos);
@@ -774,7 +789,18 @@ export class Spline2d extends SimulationElement2d {
774
789
  this.detail = detail;
775
790
  this.interpolateStart = 0;
776
791
  this.interpolateLimit = 1;
792
+ this.length = 0;
777
793
  this.geometry = new Spline2dGeometry(points, this.getColor(), this.thickness, this.detail);
794
+ this.estimateLength();
795
+ }
796
+ estimateLength() {
797
+ const curves = this.geometry.getCurves();
798
+ for (let i = 0; i < curves.length; i++) {
799
+ this.length += curves[i].getLength();
800
+ }
801
+ }
802
+ getLength() {
803
+ return this.length;
778
804
  }
779
805
  setInterpolateStart(start, t = 0, f) {
780
806
  const diff = start - this.interpolateStart;
@@ -815,11 +841,20 @@ export class Spline2d extends SimulationElement2d {
815
841
  }
816
842
  interpolateSlope(t) {
817
843
  const curves = this.geometry.getCurves();
818
- const curveInterval = 1 / curves.length;
819
- let index = Math.floor(t / curveInterval);
820
- if (index === curves.length)
821
- index--;
822
- const diff = (t - curveInterval * index) * 2;
844
+ const totalLength = this.length;
845
+ let currentLength = 0;
846
+ let index = 0;
847
+ let diff = 0;
848
+ for (let i = 0; i < curves.length; i++) {
849
+ if ((currentLength + curves[i].getLength()) / totalLength >= t) {
850
+ let dist = totalLength * t;
851
+ dist -= currentLength;
852
+ diff = dist / curves[i].getLength();
853
+ index = i;
854
+ break;
855
+ }
856
+ currentLength += curves[i].getLength();
857
+ }
823
858
  return curves[index].interpolateSlope(diff);
824
859
  }
825
860
  interpolate(t) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './simulation.js';
2
2
  export * from './graphics.js';
3
+ export * from './utils.js';
3
4
  export * from './types.js';
4
5
  export { vec2, vec3, vec4, mat3, mat4 } from 'wgpu-matrix';
5
- export { Vertex, Color, cloneBuf, vector4, vector3, vector2, vector3FromVector2, colorFromVector4, randomInt, randomColor, vertex, color, colorf, transitionValues, lerp, smoothStep, linearStep, splinePoint2d, continuousSplinePoint2d, easeInOutQuad, easeInOutExpo, easeInOutQuart, waitFor, matrix4 } from './utils.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './simulation.js';
2
2
  export * from './graphics.js';
3
+ export * from './utils.js';
3
4
  export * from './types.js';
4
5
  export { vec2, vec3, vec4, mat3, mat4 } from 'wgpu-matrix';
5
- export { Vertex, Color, cloneBuf, vector4, vector3, vector2, vector3FromVector2, colorFromVector4, randomInt, randomColor, vertex, color, colorf, transitionValues, lerp, smoothStep, linearStep, splinePoint2d, continuousSplinePoint2d, easeInOutQuad, easeInOutExpo, easeInOutQuart, waitFor, matrix4 } from './utils.js';
@@ -0,0 +1,46 @@
1
+ /// <reference types="dist" />
2
+ import { Mat4, Vector2, Vector3 } from './types.js';
3
+ import { Color } from './utils.js';
4
+ import { SimulationElement } from './graphics.js';
5
+ export declare class VertexCache {
6
+ private vertices;
7
+ private hasUpdated;
8
+ constructor();
9
+ setCache(vertices: number[]): void;
10
+ getCache(): number[];
11
+ updated(): void;
12
+ shouldUpdate(): boolean;
13
+ getVertexCount(): number;
14
+ }
15
+ export declare const buildProjectionMatrix: (aspectRatio: number, zNear?: number, zFar?: number) => any;
16
+ export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3, projectionMatrix: mat4) => Float32Array;
17
+ export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
18
+ export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => GPUTexture;
19
+ export declare const buildMultisampleTexture: (device: GPUDevice, ctx: GPUCanvasContext, width: number, height: number) => GPUTexture;
20
+ export declare const applyElementToScene: (scene: SimulationElement[], el: SimulationElement) => void;
21
+ declare class Logger {
22
+ constructor();
23
+ private fmt;
24
+ log(msg: string): void;
25
+ error(msg: string): Error;
26
+ warn(msg: string): void;
27
+ log_error(msg: string): void;
28
+ }
29
+ export declare const logger: Logger;
30
+ export declare function lossyTriangulate<T>(vertices: T[]): (readonly [T, T, T])[];
31
+ declare class BufferGenerator {
32
+ private instancing;
33
+ constructor();
34
+ setInstancing(state: boolean): void;
35
+ generate(x: number, y: number, z: number, color: Color, uv?: Vector2): number[];
36
+ }
37
+ export declare const bufferGenerator: BufferGenerator;
38
+ export declare function vector3ToPixelRatio(vec: Vector3): void;
39
+ export declare function vector2ToPixelRatio(vec: Vector2): void;
40
+ export declare function interpolateColors(colors: Color[], t: number): Color;
41
+ export declare function matrixFromRotation(rotation: Vector3): Mat4;
42
+ export declare function rotateMat4(mat: Mat4, rotation: Vector3): void;
43
+ export declare function createPipeline(device: GPUDevice, module: GPUShaderModule, bindGroupLayout: GPUBindGroupLayout, presentationFormat: GPUTextureFormat, entryPoint: string, topology: GPUPrimitiveTopology): GPURenderPipeline;
44
+ export declare function triangulateWireFrameOrder(len: number): number[];
45
+ export declare function getTotalVertices(scene: SimulationElement[]): number;
46
+ export {};
@@ -0,0 +1,258 @@
1
+ import { mat4, vec3 } from 'wgpu-matrix';
2
+ import { BUF_LEN, colorOffset, drawingInstancesOffset, uvOffset, vertexSize } from './constants.js';
3
+ import { color, vector2, vector3 } from './utils.js';
4
+ import { SimulationElement } from './graphics.js';
5
+ export class VertexCache {
6
+ vertices = [];
7
+ hasUpdated = true;
8
+ constructor() { }
9
+ setCache(vertices) {
10
+ this.vertices = vertices;
11
+ this.hasUpdated = false;
12
+ }
13
+ getCache() {
14
+ return this.vertices;
15
+ }
16
+ updated() {
17
+ this.hasUpdated = true;
18
+ }
19
+ shouldUpdate() {
20
+ return this.hasUpdated;
21
+ }
22
+ getVertexCount() {
23
+ return this.vertices.length / BUF_LEN;
24
+ }
25
+ }
26
+ export const buildProjectionMatrix = (aspectRatio, zNear = 1, zFar = 500) => {
27
+ const fov = (2 * Math.PI) / 5;
28
+ return mat4.perspective(fov, aspectRatio, zNear, zFar);
29
+ };
30
+ export const getTransformationMatrix = (pos, rotation, projectionMatrix) => {
31
+ const modelViewProjectionMatrix = mat4.create();
32
+ const viewMatrix = mat4.identity();
33
+ const camPos = vector3();
34
+ vec3.clone(pos, camPos);
35
+ vec3.scale(camPos, -1, camPos);
36
+ mat4.rotateZ(viewMatrix, rotation[2], viewMatrix);
37
+ mat4.rotateY(viewMatrix, rotation[1], viewMatrix);
38
+ mat4.rotateX(viewMatrix, rotation[0], viewMatrix);
39
+ mat4.translate(viewMatrix, camPos, viewMatrix);
40
+ mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);
41
+ return modelViewProjectionMatrix;
42
+ };
43
+ export const getOrthoMatrix = (screenSize) => {
44
+ return mat4.ortho(0, screenSize[0], 0, screenSize[1], 0, 100);
45
+ };
46
+ export const buildDepthTexture = (device, width, height) => {
47
+ return device.createTexture({
48
+ size: [width, height],
49
+ format: 'depth24plus',
50
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
51
+ sampleCount: 4
52
+ });
53
+ };
54
+ export const buildMultisampleTexture = (device, ctx, width, height) => {
55
+ return device.createTexture({
56
+ size: [width, height],
57
+ format: ctx.getCurrentTexture().format,
58
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
59
+ sampleCount: 4
60
+ });
61
+ };
62
+ export const applyElementToScene = (scene, el) => {
63
+ if (el instanceof SimulationElement) {
64
+ scene.unshift(el);
65
+ }
66
+ else {
67
+ throw logger.error('Cannot add invalid SimulationElement');
68
+ }
69
+ };
70
+ class Logger {
71
+ constructor() { }
72
+ fmt(msg) {
73
+ return `SimJS: ${msg}`;
74
+ }
75
+ log(msg) {
76
+ console.log(this.fmt(msg));
77
+ }
78
+ error(msg) {
79
+ return new Error(this.fmt(msg));
80
+ }
81
+ warn(msg) {
82
+ console.warn(this.fmt(msg));
83
+ }
84
+ log_error(msg) {
85
+ console.error(this.fmt(msg));
86
+ }
87
+ }
88
+ export const logger = new Logger();
89
+ // optomized for speed, depending on orientation of vertices as input, shape may not be preserved
90
+ export function lossyTriangulate(vertices) {
91
+ const res = [];
92
+ let facingRight = true;
93
+ let rightOffset = 0;
94
+ let leftOffset = 0;
95
+ while (rightOffset < vertices.length - leftOffset - 2) {
96
+ if (facingRight) {
97
+ const triangle = [
98
+ vertices[rightOffset],
99
+ vertices[rightOffset + 1],
100
+ vertices[vertices.length - leftOffset - 1]
101
+ ];
102
+ res.push(triangle);
103
+ rightOffset++;
104
+ }
105
+ else {
106
+ const triangle = [
107
+ vertices[rightOffset],
108
+ vertices[vertices.length - leftOffset - 1],
109
+ vertices[vertices.length - leftOffset - 2]
110
+ ];
111
+ res.push(triangle);
112
+ leftOffset++;
113
+ }
114
+ facingRight = !facingRight;
115
+ }
116
+ return res;
117
+ }
118
+ class BufferGenerator {
119
+ instancing = false;
120
+ constructor() { }
121
+ setInstancing(state) {
122
+ this.instancing = state;
123
+ }
124
+ generate(x, y, z, color, uv = vector2()) {
125
+ return [x, y, z, 1, ...color.toBuffer(), ...uv, this.instancing ? 1 : 0];
126
+ }
127
+ }
128
+ export const bufferGenerator = new BufferGenerator();
129
+ export function vector3ToPixelRatio(vec) {
130
+ vec[0] *= devicePixelRatio;
131
+ vec[1] *= devicePixelRatio;
132
+ vec[2] *= devicePixelRatio;
133
+ }
134
+ export function vector2ToPixelRatio(vec) {
135
+ vec[0] *= devicePixelRatio;
136
+ vec[1] *= devicePixelRatio;
137
+ }
138
+ export function interpolateColors(colors, t) {
139
+ t = Math.min(1, Math.max(0, t));
140
+ if (colors.length === 0)
141
+ return color();
142
+ if (colors.length === 1)
143
+ return colors[0];
144
+ const colorInterval = 1 / colors.length;
145
+ let index = Math.floor(t / colorInterval);
146
+ if (index >= colors.length)
147
+ index = colors.length - 1;
148
+ const from = index === colors.length - 1 ? colors[index - 1] : colors[index];
149
+ const to = index === colors.length - 1 ? colors[index] : colors[index + 1];
150
+ const diff = to.diff(from);
151
+ const scale = t / (colorInterval * colors.length);
152
+ diff.r *= scale;
153
+ diff.g *= scale;
154
+ diff.b *= scale;
155
+ diff.a *= scale;
156
+ const res = from.clone();
157
+ res.r += diff.r;
158
+ res.g += diff.g;
159
+ res.b += diff.b;
160
+ res.a += diff.a;
161
+ return res;
162
+ }
163
+ export function matrixFromRotation(rotation) {
164
+ let rotMatrix = mat4.identity();
165
+ mat4.rotateZ(rotMatrix, rotation[2], rotMatrix);
166
+ mat4.rotateY(rotMatrix, rotation[1], rotMatrix);
167
+ mat4.rotateX(rotMatrix, rotation[0], rotMatrix);
168
+ return rotMatrix;
169
+ }
170
+ export function rotateMat4(mat, rotation) {
171
+ mat4.rotateZ(mat, rotation[2], mat);
172
+ mat4.rotateY(mat, rotation[1], mat);
173
+ mat4.rotateX(mat, rotation[0], mat);
174
+ }
175
+ export function createPipeline(device, module, bindGroupLayout, presentationFormat, entryPoint, topology) {
176
+ return device.createRenderPipeline({
177
+ layout: device.createPipelineLayout({
178
+ bindGroupLayouts: [bindGroupLayout]
179
+ }),
180
+ vertex: {
181
+ module,
182
+ entryPoint,
183
+ buffers: [
184
+ {
185
+ arrayStride: vertexSize,
186
+ attributes: [
187
+ {
188
+ // position
189
+ shaderLocation: 0,
190
+ offset: 0,
191
+ format: 'float32x4'
192
+ },
193
+ {
194
+ // color
195
+ shaderLocation: 1,
196
+ offset: colorOffset,
197
+ format: 'float32x4'
198
+ },
199
+ {
200
+ // size
201
+ shaderLocation: 2,
202
+ offset: uvOffset,
203
+ format: 'float32x2'
204
+ },
205
+ {
206
+ // drawing instances
207
+ shaderLocation: 3,
208
+ offset: drawingInstancesOffset,
209
+ format: 'float32'
210
+ }
211
+ ]
212
+ }
213
+ ]
214
+ },
215
+ fragment: {
216
+ module,
217
+ entryPoint: 'fragment_main',
218
+ targets: [
219
+ {
220
+ format: presentationFormat
221
+ }
222
+ ]
223
+ },
224
+ primitive: {
225
+ topology
226
+ },
227
+ multisample: {
228
+ count: 4
229
+ },
230
+ depthStencil: {
231
+ depthWriteEnabled: true,
232
+ depthCompare: 'less',
233
+ format: 'depth24plus'
234
+ }
235
+ });
236
+ }
237
+ export function triangulateWireFrameOrder(len) {
238
+ const order = Array(len)
239
+ .fill(0)
240
+ .map((_, index) => index);
241
+ let front = 0;
242
+ let back = len - 1;
243
+ while (front < back) {
244
+ order.push(front, back);
245
+ front++;
246
+ back--;
247
+ }
248
+ return order;
249
+ }
250
+ export function getTotalVertices(scene) {
251
+ let total = 0;
252
+ for (let i = 0; i < scene.length; i++) {
253
+ if (scene[i].isCollection)
254
+ continue;
255
+ total += scene[i].getVertexCount();
256
+ }
257
+ return total;
258
+ }
@@ -1,8 +1,9 @@
1
1
  import { vec3 } from 'wgpu-matrix';
2
2
  import { SimulationElement3d } from './graphics.js';
3
3
  import { BUF_LEN } from './constants.js';
4
- import { Color, applyElementToScene, buildDepthTexture, buildMultisampleTexture, buildProjectionMatrix, createPipeline, getOrthoMatrix, getTotalVertices, getTransformationMatrix, logger, transitionValues, vector2, vector3 } from './utils.js';
4
+ import { Color, transitionValues, vector2, vector3 } from './utils.js';
5
5
  import { BlankGeometry } from './geometry.js';
6
+ import { applyElementToScene, buildDepthTexture, buildMultisampleTexture, buildProjectionMatrix, createPipeline, getOrthoMatrix, getTotalVertices, getTransformationMatrix, logger } from './internalUtils.js';
6
7
  const shader = `
7
8
  struct Uniforms {
8
9
  modelViewProjectionMatrix : mat4x4<f32>,
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /// <reference types="dist" />
2
2
  import { CubicBezierCurve2d, SplinePoint2d } from './graphics.js';
3
3
  import { Color, Vertex } from './utils.js';
4
+ export type Shift<T extends any[]> = ((...args: T) => any) extends (arg1: any, ...rest: infer R) => any ? R : never;
4
5
  export type FloatArray = Float32Array | Float64Array;
5
6
  export type Vector4 = FloatArray & [number, number, number, number];
6
7
  export type Vector3 = FloatArray & [number, number, number];
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- /// <reference types="dist" />
2
- import { SimulationElement, SplinePoint2d } from './graphics.js';
3
- import { FloatArray, Mat4, Vector2, Vector3, Vector4 } from './types.js';
1
+ import { SplinePoint2d } from './graphics.js';
2
+ import { FloatArray, Mat4, Shift, Vector2, Vector3, Vector4 } from './types.js';
4
3
  export declare class Color {
5
4
  r: number;
6
5
  g: number;
@@ -18,16 +17,6 @@ export declare class Color {
18
17
  };
19
18
  diff(color: Color): Color;
20
19
  }
21
- export declare class VertexCache {
22
- private vertices;
23
- private hasUpdated;
24
- constructor();
25
- setCache(vertices: number[]): void;
26
- getCache(): number[];
27
- updated(): void;
28
- shouldUpdate(): boolean;
29
- getVertexCount(): number;
30
- }
31
20
  export declare class Vertex {
32
21
  private pos;
33
22
  private color;
@@ -47,22 +36,6 @@ export declare class Vertex {
47
36
  clone(): Vertex;
48
37
  toBuffer(defaultColor: Color): number[];
49
38
  }
50
- export declare const buildProjectionMatrix: (aspectRatio: number, zNear?: number, zFar?: number) => any;
51
- export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3, projectionMatrix: mat4) => Float32Array;
52
- export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
53
- export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => GPUTexture;
54
- export declare const buildMultisampleTexture: (device: GPUDevice, ctx: GPUCanvasContext, width: number, height: number) => GPUTexture;
55
- export declare const applyElementToScene: (scene: SimulationElement[], el: SimulationElement) => void;
56
- declare class Logger {
57
- constructor();
58
- private fmt;
59
- log(msg: string): void;
60
- error(msg: string): Error;
61
- warn(msg: string): void;
62
- log_error(msg: string): void;
63
- }
64
- export declare const logger: Logger;
65
- export declare function lossyTriangulate<T>(vertices: T[]): (readonly [T, T, T])[];
66
39
  /**
67
40
  * @param callback1 - called every frame until the animation is finished
68
41
  * @param callback2 - called after animation is finished (called immediately when t = 0)
@@ -70,21 +43,13 @@ export declare function lossyTriangulate<T>(vertices: T[]): (readonly [T, T, T])
70
43
  * @returns {Promise<void>}
71
44
  */
72
45
  export declare function transitionValues(callback1: (deltaT: number, t: number) => void, callback2: () => void, transitionLength: number, func?: (n: number) => number): Promise<void>;
46
+ export declare function frameLoop<T extends (...args: any[]) => any>(cb: T): (...params: Shift<Parameters<T>>) => void;
73
47
  export declare function lerp(a: number, b: number, t: number): number;
74
48
  export declare function smoothStep(t: number): number;
75
49
  export declare function linearStep(t: number): number;
76
50
  export declare function easeInOutExpo(t: number): number;
77
51
  export declare function easeInOutQuart(t: number): number;
78
52
  export declare function easeInOutQuad(t: number): number;
79
- declare class BufferGenerator {
80
- private instancing;
81
- constructor();
82
- setInstancing(state: boolean): void;
83
- generate(x: number, y: number, z: number, color: Color, uv?: Vector2): number[];
84
- }
85
- export declare const bufferGenerator: BufferGenerator;
86
- export declare function vector3ToPixelRatio(vec: Vector3): void;
87
- export declare function vector2ToPixelRatio(vec: Vector2): void;
88
53
  export declare function cloneBuf<T extends FloatArray>(buf: T): T;
89
54
  export declare function vector4(x?: number, y?: number, z?: number, w?: number): Vector4;
90
55
  export declare function vector3(x?: number, y?: number, z?: number): Vector3;
@@ -100,14 +65,9 @@ export declare function color(r?: number, g?: number, b?: number, a?: number): C
100
65
  export declare function colorf(val: number, a?: number): Color;
101
66
  export declare function splinePoint2d(end: Vertex, control1: Vector2, control2: Vector2, detail?: number): SplinePoint2d;
102
67
  export declare function continuousSplinePoint2d(end: Vertex, control: Vector2, detail?: number): SplinePoint2d;
103
- export declare function interpolateColors(colors: Color[], t: number): Color;
104
68
  /**
105
69
  * @param t - seconds
106
70
  */
107
71
  export declare function waitFor(t: number): Promise<unknown>;
108
- export declare function matrixFromRotation(rotation: Vector3): Mat4;
109
- export declare function rotateMat4(mat: Mat4, rotation: Vector3): void;
110
- export declare function createPipeline(device: GPUDevice, module: GPUShaderModule, bindGroupLayout: GPUBindGroupLayout, presentationFormat: GPUTextureFormat, entryPoint: string, topology: GPUPrimitiveTopology): GPURenderPipeline;
111
- export declare function triangulateWireFrameOrder(len: number): number[];
112
- export declare function getTotalVertices(scene: SimulationElement[]): number;
113
- export {};
72
+ export declare function distance2d(vector1: Vector2, vector2: Vector2): number;
73
+ export declare function distance3d(vector1: Vector3, vector2: Vector3): number;
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { mat4, vec2, vec3, vec4 } from 'wgpu-matrix';
2
- import { SimulationElement, SplinePoint2d } from './graphics.js';
3
- import { BUF_LEN, colorOffset, drawingInstancesOffset, uvOffset, vertexSize } from './constants.js';
2
+ import { SplinePoint2d } from './graphics.js';
3
+ import { bufferGenerator } from './internalUtils.js';
4
4
  export class Color {
5
5
  r; // 0 - 255
6
6
  g; // 0 - 255
@@ -33,27 +33,6 @@ export class Color {
33
33
  return new Color(this.r - color.r, this.g - color.g, this.b - color.b, this.a - color.a);
34
34
  }
35
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
36
  export class Vertex {
58
37
  pos;
59
38
  color;
@@ -105,98 +84,6 @@ export class Vertex {
105
84
  return bufferGenerator.generate(this.pos[0], this.pos[1], 0, this.color || defaultColor, this.uv);
106
85
  }
107
86
  }
108
- export const buildProjectionMatrix = (aspectRatio, zNear = 1, zFar = 500) => {
109
- const fov = (2 * Math.PI) / 5;
110
- return mat4.perspective(fov, aspectRatio, zNear, zFar);
111
- };
112
- export const getTransformationMatrix = (pos, rotation, projectionMatrix) => {
113
- const modelViewProjectionMatrix = mat4.create();
114
- const viewMatrix = mat4.identity();
115
- const camPos = vector3();
116
- vec3.clone(pos, camPos);
117
- vec3.scale(camPos, -1, camPos);
118
- mat4.rotateZ(viewMatrix, rotation[2], viewMatrix);
119
- mat4.rotateY(viewMatrix, rotation[1], viewMatrix);
120
- mat4.rotateX(viewMatrix, rotation[0], viewMatrix);
121
- mat4.translate(viewMatrix, camPos, viewMatrix);
122
- mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);
123
- return modelViewProjectionMatrix;
124
- };
125
- export const getOrthoMatrix = (screenSize) => {
126
- return mat4.ortho(0, screenSize[0], 0, screenSize[1], 0, 100);
127
- };
128
- export const buildDepthTexture = (device, width, height) => {
129
- return device.createTexture({
130
- size: [width, height],
131
- format: 'depth24plus',
132
- usage: GPUTextureUsage.RENDER_ATTACHMENT,
133
- sampleCount: 4
134
- });
135
- };
136
- export const buildMultisampleTexture = (device, ctx, width, height) => {
137
- return device.createTexture({
138
- size: [width, height],
139
- format: ctx.getCurrentTexture().format,
140
- usage: GPUTextureUsage.RENDER_ATTACHMENT,
141
- sampleCount: 4
142
- });
143
- };
144
- export const applyElementToScene = (scene, el) => {
145
- if (el instanceof SimulationElement) {
146
- scene.unshift(el);
147
- }
148
- else {
149
- throw logger.error('Cannot add invalid SimulationElement');
150
- }
151
- };
152
- class Logger {
153
- constructor() { }
154
- fmt(msg) {
155
- return `SimJS: ${msg}`;
156
- }
157
- log(msg) {
158
- console.log(this.fmt(msg));
159
- }
160
- error(msg) {
161
- return new Error(this.fmt(msg));
162
- }
163
- warn(msg) {
164
- console.warn(this.fmt(msg));
165
- }
166
- log_error(msg) {
167
- console.error(this.fmt(msg));
168
- }
169
- }
170
- export const logger = new Logger();
171
- // optomized for speed, depending on orientation of vertices as input, shape may not be preserved
172
- export function lossyTriangulate(vertices) {
173
- const res = [];
174
- let facingRight = true;
175
- let rightOffset = 0;
176
- let leftOffset = 0;
177
- while (rightOffset < vertices.length - leftOffset - 2) {
178
- if (facingRight) {
179
- const triangle = [
180
- vertices[rightOffset],
181
- vertices[rightOffset + 1],
182
- vertices[vertices.length - leftOffset - 1]
183
- ];
184
- res.push(triangle);
185
- rightOffset++;
186
- }
187
- else {
188
- const triangle = [
189
- vertices[rightOffset],
190
- vertices[vertices.length - leftOffset - 1],
191
- vertices[vertices.length - leftOffset - 2]
192
- ];
193
- res.push(triangle);
194
- leftOffset++;
195
- }
196
- facingRight = !facingRight;
197
- }
198
- return res;
199
- }
200
87
  /**
201
88
  * @param callback1 - called every frame until the animation is finished
202
89
  * @param callback2 - called after animation is finished (called immediately when t = 0)
@@ -234,6 +121,27 @@ export function transitionValues(callback1, callback2, transitionLength, func) {
234
121
  }
235
122
  });
236
123
  }
124
+ export function frameLoop(cb) {
125
+ let prevFrame = 0;
126
+ let prevTime = 0;
127
+ function start(dt, ...args) {
128
+ let res = cb(dt, ...args);
129
+ if (res === false) {
130
+ window.cancelAnimationFrame(prevFrame);
131
+ return;
132
+ }
133
+ if (!Array.isArray(res))
134
+ res = args;
135
+ const now = Date.now();
136
+ const diff = now - prevTime;
137
+ prevTime = now;
138
+ prevFrame = window.requestAnimationFrame(() => start(diff, ...res));
139
+ }
140
+ return (...p) => {
141
+ prevTime = Date.now();
142
+ start(0, ...p);
143
+ };
144
+ }
237
145
  export function lerp(a, b, t) {
238
146
  return a + (b - a) * t;
239
147
  }
@@ -260,26 +168,6 @@ export function easeInOutQuart(t) {
260
168
  export function easeInOutQuad(t) {
261
169
  return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
262
170
  }
263
- class BufferGenerator {
264
- instancing = false;
265
- constructor() { }
266
- setInstancing(state) {
267
- this.instancing = state;
268
- }
269
- generate(x, y, z, color, uv = vector2()) {
270
- return [x, y, z, 1, ...color.toBuffer(), ...uv, this.instancing ? 1 : 0];
271
- }
272
- }
273
- export const bufferGenerator = new BufferGenerator();
274
- export function vector3ToPixelRatio(vec) {
275
- vec[0] *= devicePixelRatio;
276
- vec[1] *= devicePixelRatio;
277
- vec[2] *= devicePixelRatio;
278
- }
279
- export function vector2ToPixelRatio(vec) {
280
- vec[0] *= devicePixelRatio;
281
- vec[1] *= devicePixelRatio;
282
- }
283
171
  export function cloneBuf(buf) {
284
172
  return new Float32Array(buf);
285
173
  }
@@ -334,31 +222,6 @@ export function continuousSplinePoint2d(end, control, detail) {
334
222
  vec2.add(end.getPos(), control, control);
335
223
  return new SplinePoint2d(null, end, null, control, rawControls, detail);
336
224
  }
337
- export function interpolateColors(colors, t) {
338
- t = Math.min(1, Math.max(0, t));
339
- if (colors.length === 0)
340
- return color();
341
- if (colors.length === 1)
342
- return colors[0];
343
- const colorInterval = 1 / colors.length;
344
- let index = Math.floor(t / colorInterval);
345
- if (index >= colors.length)
346
- index = colors.length - 1;
347
- const from = index === colors.length - 1 ? colors[index - 1] : colors[index];
348
- const to = index === colors.length - 1 ? colors[index] : colors[index + 1];
349
- const diff = to.diff(from);
350
- const scale = t / (colorInterval * colors.length);
351
- diff.r *= scale;
352
- diff.g *= scale;
353
- diff.b *= scale;
354
- diff.a *= scale;
355
- const res = from.clone();
356
- res.r += diff.r;
357
- res.g += diff.g;
358
- res.b += diff.b;
359
- res.a += diff.a;
360
- return res;
361
- }
362
225
  /**
363
226
  * @param t - seconds
364
227
  */
@@ -367,99 +230,9 @@ export function waitFor(t) {
367
230
  setTimeout(resolve, t * 1000);
368
231
  });
369
232
  }
370
- export function matrixFromRotation(rotation) {
371
- let rotMatrix = mat4.identity();
372
- mat4.rotateZ(rotMatrix, rotation[2], rotMatrix);
373
- mat4.rotateY(rotMatrix, rotation[1], rotMatrix);
374
- mat4.rotateX(rotMatrix, rotation[0], rotMatrix);
375
- return rotMatrix;
233
+ export function distance2d(vector1, vector2) {
234
+ return vec2.distance(vector1, vector2);
376
235
  }
377
- export function rotateMat4(mat, rotation) {
378
- mat4.rotateZ(mat, rotation[2], mat);
379
- mat4.rotateY(mat, rotation[1], mat);
380
- mat4.rotateX(mat, rotation[0], mat);
381
- }
382
- export function createPipeline(device, module, bindGroupLayout, presentationFormat, entryPoint, topology) {
383
- return device.createRenderPipeline({
384
- layout: device.createPipelineLayout({
385
- bindGroupLayouts: [bindGroupLayout]
386
- }),
387
- vertex: {
388
- module,
389
- entryPoint,
390
- buffers: [
391
- {
392
- arrayStride: vertexSize,
393
- attributes: [
394
- {
395
- // position
396
- shaderLocation: 0,
397
- offset: 0,
398
- format: 'float32x4'
399
- },
400
- {
401
- // color
402
- shaderLocation: 1,
403
- offset: colorOffset,
404
- format: 'float32x4'
405
- },
406
- {
407
- // size
408
- shaderLocation: 2,
409
- offset: uvOffset,
410
- format: 'float32x2'
411
- },
412
- {
413
- // drawing instances
414
- shaderLocation: 3,
415
- offset: drawingInstancesOffset,
416
- format: 'float32'
417
- }
418
- ]
419
- }
420
- ]
421
- },
422
- fragment: {
423
- module,
424
- entryPoint: 'fragment_main',
425
- targets: [
426
- {
427
- format: presentationFormat
428
- }
429
- ]
430
- },
431
- primitive: {
432
- topology
433
- },
434
- multisample: {
435
- count: 4
436
- },
437
- depthStencil: {
438
- depthWriteEnabled: true,
439
- depthCompare: 'less',
440
- format: 'depth24plus'
441
- }
442
- });
443
- }
444
- export function triangulateWireFrameOrder(len) {
445
- const order = Array(len)
446
- .fill(0)
447
- .map((_, index) => index);
448
- let front = 0;
449
- let back = len - 1;
450
- while (front < back) {
451
- order.push(front, back);
452
- front++;
453
- back--;
454
- }
455
- return order;
456
- }
457
- export function getTotalVertices(scene) {
458
- let total = 0;
459
- for (let i = 0; i < scene.length; i++) {
460
- if (scene[i].isCollection)
461
- continue;
462
- total += scene[i].getVertexCount();
463
- }
464
- return total;
236
+ export function distance3d(vector1, vector2) {
237
+ return vec3.distance(vector1, vector2);
465
238
  }
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.3.0",
8
+ "version": "0.3.1",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": "./dist/index.js",
@@ -24,6 +24,6 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@webgpu/types": "^0.1.34",
27
- "wgpu-matrix": "^2.5.1"
27
+ "wgpu-matrix": "^2.8.0"
28
28
  }
29
29
  }