simulationjsv2 0.1.4 → 0.1.6
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/graphics.d.ts +34 -35
- package/dist/graphics.js +221 -168
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/simulation.d.ts +1 -25
- package/dist/simulation.js +3 -77
- package/dist/types.d.ts +2 -1
- package/dist/utils.d.ts +75 -2
- package/dist/utils.js +236 -2
- package/package.json +1 -2
- package/types/constants.d.ts +0 -1
- package/types/graphics.d.ts +0 -90
- package/types/index.d.ts +0 -3
- package/types/types.d.ts +0 -5
- package/types/utils.d.ts +0 -18
package/dist/graphics.d.ts
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
import { Camera
|
|
1
|
+
import { Camera } from './simulation.js';
|
|
2
2
|
import type { Vector2, Vector3, LerpFunc, VertexColorMap } from './types.js';
|
|
3
|
-
|
|
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
|
-
}
|
|
3
|
+
import { Vertex, VertexCache, Color } from './utils.js';
|
|
23
4
|
export declare abstract class SimulationElement {
|
|
24
5
|
private pos;
|
|
25
6
|
private color;
|
|
@@ -38,7 +19,7 @@ export declare abstract class SimulationElement {
|
|
|
38
19
|
export declare class Plane extends SimulationElement {
|
|
39
20
|
private points;
|
|
40
21
|
private rotation;
|
|
41
|
-
constructor(pos: Vector3, points: Vertex[],
|
|
22
|
+
constructor(pos: Vector3, points: Vertex[], color?: Color, rotation?: Vector3);
|
|
42
23
|
setPoints(newPoints: Vertex[]): void;
|
|
43
24
|
rotate(amount: Vector3, t?: number, f?: LerpFunc): Promise<void>;
|
|
44
25
|
rotateTo(angle: Vector3, t?: number, f?: LerpFunc): Promise<void>;
|
|
@@ -72,20 +53,38 @@ export declare class Circle extends SimulationElement {
|
|
|
72
53
|
getBuffer(camera: Camera, force: boolean): number[];
|
|
73
54
|
}
|
|
74
55
|
export declare class Polygon extends SimulationElement {
|
|
75
|
-
private
|
|
56
|
+
private vertices;
|
|
76
57
|
private rotation;
|
|
77
|
-
constructor(pos: Vector3,
|
|
58
|
+
constructor(pos: Vector3, vertices: Vertex[], color?: Color);
|
|
78
59
|
rotate(amount: number, t?: number, f?: LerpFunc): Promise<void>;
|
|
79
60
|
rotateTo(num: number, t?: number, f?: LerpFunc): Promise<void>;
|
|
80
|
-
|
|
81
|
-
|
|
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
|
+
}
|
|
72
|
+
export declare class CubicBezierCurve2d extends BezierCurve2d {
|
|
73
|
+
constructor(points: [Vector2, Vector2, Vector2, Vector2]);
|
|
74
|
+
}
|
|
75
|
+
export declare class SplinePoint2d {
|
|
76
|
+
private start;
|
|
77
|
+
private end;
|
|
78
|
+
private controls;
|
|
79
|
+
constructor(start: Vertex | null, end: Vertex, controls: [Vector2, Vector2]);
|
|
80
|
+
getStart(): Vertex | null;
|
|
81
|
+
getEnd(): Vertex;
|
|
82
|
+
getVectorArray(prevEnd?: Vector2 | null): readonly [Vector2, Vector2, Vector2, Vector2];
|
|
83
|
+
}
|
|
84
|
+
export declare class Spline2d extends SimulationElement {
|
|
85
|
+
private curves;
|
|
86
|
+
private width;
|
|
87
|
+
private detail;
|
|
88
|
+
constructor(pos: Vector2, points: SplinePoint2d[], width?: number, color?: Color, detail?: number);
|
|
89
|
+
getBuffer(camera: Camera, force: boolean): number[];
|
|
82
90
|
}
|
|
83
|
-
export declare function vector3(x?: number, y?: number, z?: number): Vector3;
|
|
84
|
-
export declare function vector2(x?: number, y?: number): Vector2;
|
|
85
|
-
export declare function vec3fromVec2(vec: Vector2): Vector3;
|
|
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): 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 {};
|
package/dist/graphics.js
CHANGED
|
@@ -1,51 +1,5 @@
|
|
|
1
|
-
import { vec3, quat, mat4, vec2 } from 'wgpu-matrix';
|
|
2
|
-
import { Color, transitionValues } from './
|
|
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
|
-
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
|
-
toBuffer(defaultColor) {
|
|
43
|
-
if (this.is3d)
|
|
44
|
-
return vertexBuffer3d(this.pos, this.color || defaultColor, this.uv);
|
|
45
|
-
else
|
|
46
|
-
return vertexBuffer2d(this.pos, this.color || defaultColor, this.uv);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
1
|
+
import { vec3, quat, mat4, vec2, vec4 } from 'wgpu-matrix';
|
|
2
|
+
import { Vertex, VertexCache, cloneBuf, color, colorFromVector4, lossyTriangulate, vec3ToPixelRatio, vector3FromVector2, vector2, vector3, vertex, vertexBuffer2d, vertexBuffer3d, Color, transitionValues, logger, vector2FromVector3 } from './utils.js';
|
|
49
3
|
export class SimulationElement {
|
|
50
4
|
pos;
|
|
51
5
|
color;
|
|
@@ -119,7 +73,7 @@ export class SimulationElement {
|
|
|
119
73
|
export class Plane extends SimulationElement {
|
|
120
74
|
points;
|
|
121
75
|
rotation;
|
|
122
|
-
constructor(pos, points, rotation = vector3()
|
|
76
|
+
constructor(pos, points, color, rotation = vector3()) {
|
|
123
77
|
super(pos, color);
|
|
124
78
|
this.points = points;
|
|
125
79
|
this.rotation = rotation;
|
|
@@ -155,8 +109,8 @@ export class Plane extends SimulationElement {
|
|
|
155
109
|
}
|
|
156
110
|
getBuffer(_, force) {
|
|
157
111
|
if (this.vertexCache.shouldUpdate() || force) {
|
|
158
|
-
|
|
159
|
-
const triangles =
|
|
112
|
+
let resBuffer = [];
|
|
113
|
+
const triangles = lossyTriangulate(this.points).flat();
|
|
160
114
|
triangles.forEach((verticy) => {
|
|
161
115
|
const rot = quat.create();
|
|
162
116
|
quat.fromEuler(...this.rotation, 'xyz', rot);
|
|
@@ -167,7 +121,7 @@ export class Plane extends SimulationElement {
|
|
|
167
121
|
vec3.add(out, this.getPos(), out);
|
|
168
122
|
let vertexColor = verticy.getColor();
|
|
169
123
|
vertexColor = vertexColor ? vertexColor : this.getColor();
|
|
170
|
-
resBuffer.
|
|
124
|
+
resBuffer = resBuffer.concat(vertexBuffer3d(out[0], out[1], out[2], vertexColor));
|
|
171
125
|
});
|
|
172
126
|
this.vertexCache.setCache(resBuffer);
|
|
173
127
|
return resBuffer;
|
|
@@ -185,7 +139,7 @@ export class Square extends SimulationElement {
|
|
|
185
139
|
* @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
|
|
186
140
|
*/
|
|
187
141
|
constructor(pos, width, height, color, rotation, vertexColors) {
|
|
188
|
-
super(
|
|
142
|
+
super(vector3FromVector2(pos), color);
|
|
189
143
|
this.width = width * devicePixelRatio;
|
|
190
144
|
this.height = height * devicePixelRatio;
|
|
191
145
|
this.rotation = rotation || 0;
|
|
@@ -277,25 +231,25 @@ export class Square extends SimulationElement {
|
|
|
277
231
|
}, t, f);
|
|
278
232
|
}
|
|
279
233
|
getBuffer(camera, force) {
|
|
280
|
-
const resBuffer = [];
|
|
281
|
-
const vertexOrder = [0, 1, 2, 0, 2, 3];
|
|
282
234
|
if (this.vertexCache.shouldUpdate() || force) {
|
|
235
|
+
let resBuffer = [];
|
|
236
|
+
const vertexOrder = [0, 1, 2, 0, 2, 3];
|
|
283
237
|
const rotationMat = mat4.identity();
|
|
284
238
|
mat4.rotateZ(rotationMat, this.rotation, rotationMat);
|
|
285
239
|
const points = this.points.map((vec) => {
|
|
286
|
-
vec2.transformMat4(vec, rotationMat, vec);
|
|
287
240
|
const pos = vector2();
|
|
288
|
-
vec2.
|
|
241
|
+
vec2.add(vec, pos, pos);
|
|
242
|
+
vec2.transformMat4(vec, rotationMat, pos);
|
|
243
|
+
vec2.add(vec, this.getPos(), pos);
|
|
289
244
|
pos[1] = camera.getScreenSize()[1] - pos[1];
|
|
290
245
|
pos[0] += this.width / 2;
|
|
291
246
|
pos[1] -= this.height / 2;
|
|
292
|
-
|
|
293
|
-
return vec;
|
|
247
|
+
return pos;
|
|
294
248
|
});
|
|
295
249
|
vertexOrder.forEach((vertex) => {
|
|
296
250
|
let vertexColor = this.vertexColors[vertex];
|
|
297
251
|
vertexColor = vertexColor ? vertexColor : this.getColor();
|
|
298
|
-
resBuffer.
|
|
252
|
+
resBuffer = resBuffer.concat(vertexBuffer2d(points[vertex][0], points[vertex][1], vertexColor));
|
|
299
253
|
});
|
|
300
254
|
this.vertexCache.setCache(resBuffer);
|
|
301
255
|
return resBuffer;
|
|
@@ -307,7 +261,7 @@ export class Circle extends SimulationElement {
|
|
|
307
261
|
radius;
|
|
308
262
|
detail = 100;
|
|
309
263
|
constructor(pos, radius, color, detail = 50) {
|
|
310
|
-
super(
|
|
264
|
+
super(vector3FromVector2(pos), color);
|
|
311
265
|
this.radius = radius * devicePixelRatio;
|
|
312
266
|
this.detail = detail;
|
|
313
267
|
}
|
|
@@ -346,7 +300,7 @@ export class Circle extends SimulationElement {
|
|
|
346
300
|
const screenSize = camera.getScreenSize();
|
|
347
301
|
points.push(new Vertex(vec[0], screenSize[1] - vec[1], vec[2], this.getColor(), false));
|
|
348
302
|
}
|
|
349
|
-
const vertices =
|
|
303
|
+
const vertices = lossyTriangulate(points).reduce((acc, curr) => {
|
|
350
304
|
curr.forEach((vertex) => acc.push(...vertex.toBuffer(this.getColor())));
|
|
351
305
|
return acc;
|
|
352
306
|
}, []);
|
|
@@ -357,15 +311,15 @@ export class Circle extends SimulationElement {
|
|
|
357
311
|
}
|
|
358
312
|
}
|
|
359
313
|
export class Polygon extends SimulationElement {
|
|
360
|
-
|
|
314
|
+
vertices;
|
|
361
315
|
rotation = 0;
|
|
362
|
-
|
|
363
|
-
* points adjusted for device pixel ratio
|
|
364
|
-
*/
|
|
365
|
-
constructor(pos, points, color) {
|
|
316
|
+
constructor(pos, vertices, color) {
|
|
366
317
|
super(pos, color);
|
|
367
|
-
this.
|
|
368
|
-
|
|
318
|
+
this.vertices = vertices.map((vertex) => {
|
|
319
|
+
const newVertex = vertex.clone();
|
|
320
|
+
newVertex.setZ(0);
|
|
321
|
+
newVertex.setIs3d(false);
|
|
322
|
+
return vertex;
|
|
369
323
|
});
|
|
370
324
|
}
|
|
371
325
|
rotate(amount, t = 0, f) {
|
|
@@ -386,123 +340,222 @@ export class Polygon extends SimulationElement {
|
|
|
386
340
|
this.rotation = num;
|
|
387
341
|
}, t, f);
|
|
388
342
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
343
|
+
getVertices() {
|
|
344
|
+
return this.vertices;
|
|
345
|
+
}
|
|
346
|
+
setVertices(newVertices, t = 0, f) {
|
|
347
|
+
const vertices = newVertices.map((vert) => {
|
|
348
|
+
const newVertex = vert.clone();
|
|
349
|
+
newVertex.setZ(0);
|
|
350
|
+
newVertex.setIs3d(false);
|
|
351
|
+
return newVertex;
|
|
393
352
|
});
|
|
394
|
-
const
|
|
395
|
-
if (
|
|
396
|
-
while (
|
|
397
|
-
|
|
353
|
+
const lastVert = this.vertices.length > 0 ? this.vertices[this.vertices.length - 1] : vertex(0, 0, 0, color(), false);
|
|
354
|
+
if (vertices.length > this.vertices.length) {
|
|
355
|
+
while (vertices.length > this.vertices.length) {
|
|
356
|
+
const lastPos = lastVert.getPos();
|
|
357
|
+
this.vertices.push(new Vertex(lastPos[0], lastPos[1], 0, lastVert.getColor() || this.getColor(), false));
|
|
398
358
|
}
|
|
399
359
|
}
|
|
400
|
-
const
|
|
401
|
-
const
|
|
402
|
-
...
|
|
403
|
-
const vec =
|
|
404
|
-
vec3.sub(
|
|
405
|
-
return vec;
|
|
360
|
+
const initialPositions = this.vertices.map((p) => cloneBuf(p.getPos()));
|
|
361
|
+
const posChanges = [
|
|
362
|
+
...vertices.map((vert, i) => {
|
|
363
|
+
const vec = vector3();
|
|
364
|
+
vec3.sub(vert.getPos(), this.vertices[i].getPos(), vec);
|
|
365
|
+
return cloneBuf(vec);
|
|
406
366
|
}),
|
|
407
|
-
...this.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
367
|
+
...(this.vertices.length > vertices.length
|
|
368
|
+
? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
|
|
369
|
+
const vec = cloneBuf(vertices[vertices.length - 1].getPos());
|
|
370
|
+
vec3.sub(vec, vert.getPos(), vec);
|
|
371
|
+
return vec;
|
|
372
|
+
})
|
|
373
|
+
: [])
|
|
374
|
+
];
|
|
375
|
+
const initialColors = this.vertices.map((vert) => (vert.getColor() || this.getColor()).toVec4());
|
|
376
|
+
const colorChanges = [
|
|
377
|
+
...vertices.map((vert, i) => {
|
|
378
|
+
const diff = (vert.getColor() || this.getColor()).diff(this.vertices[i].getColor() || this.getColor());
|
|
379
|
+
return diff.toVec4();
|
|
380
|
+
}),
|
|
381
|
+
...(this.vertices.length > vertices.length
|
|
382
|
+
? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
|
|
383
|
+
const toColor = vertices[vertices.length - 1].getColor();
|
|
384
|
+
return (toColor || this.getColor()).diff(vert.getColor() || this.getColor()).toVec4();
|
|
385
|
+
})
|
|
386
|
+
: [])
|
|
412
387
|
];
|
|
413
388
|
return transitionValues((p) => {
|
|
414
|
-
this.
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
vec3.
|
|
418
|
-
|
|
389
|
+
this.vertices.forEach((vert, i) => {
|
|
390
|
+
const posChange = cloneBuf(posChanges[i]);
|
|
391
|
+
const colorChange = cloneBuf(colorChanges[i]);
|
|
392
|
+
vec3.scale(posChange, p, posChange);
|
|
393
|
+
vec3.add(vert.getPos(), posChange, posChange);
|
|
394
|
+
vec4.scale(colorChange, p, colorChange);
|
|
395
|
+
vec4.add((vert.getColor() || this.getColor()).toVec4(), colorChange, colorChange);
|
|
396
|
+
vert.setPos(posChange);
|
|
397
|
+
vert.setColor(colorFromVector4(colorChange));
|
|
419
398
|
});
|
|
420
399
|
this.vertexCache.updated();
|
|
421
400
|
}, () => {
|
|
422
|
-
this.
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
401
|
+
this.vertices.forEach((vert, i) => {
|
|
402
|
+
const initPos = initialPositions[i];
|
|
403
|
+
const initColor = initialColors[i];
|
|
404
|
+
vec3.add(initPos, posChanges[i], initPos);
|
|
405
|
+
vec4.add(initColor, colorChanges[i], initColor);
|
|
406
|
+
vert.setPos(initPos);
|
|
407
|
+
vert.setColor(colorFromVector4(initColor));
|
|
426
408
|
});
|
|
427
|
-
this.
|
|
409
|
+
this.vertices.splice(vertices.length, this.vertices.length);
|
|
428
410
|
this.vertexCache.updated();
|
|
429
411
|
}, t, f);
|
|
430
412
|
}
|
|
431
|
-
getBuffer() {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
413
|
+
getBuffer(camera, force) {
|
|
414
|
+
if (this.vertexCache.shouldUpdate() || force) {
|
|
415
|
+
let resBuffer = [];
|
|
416
|
+
const rotationMat = mat4.identity();
|
|
417
|
+
mat4.rotateZ(rotationMat, this.rotation, rotationMat);
|
|
418
|
+
lossyTriangulate(this.vertices)
|
|
419
|
+
.flat()
|
|
420
|
+
.forEach((vert) => {
|
|
421
|
+
const pos = vector3();
|
|
422
|
+
vec3.add(vert.getPos(), pos, pos);
|
|
423
|
+
vec3.transformMat4(pos, rotationMat, pos);
|
|
424
|
+
vec3.add(this.getPos(), pos, pos);
|
|
425
|
+
pos[1] = camera.getScreenSize()[1] - pos[1];
|
|
426
|
+
resBuffer = resBuffer.concat(vertexBuffer2d(pos[0], pos[1], vert.getColor() || this.getColor()));
|
|
427
|
+
});
|
|
428
|
+
this.vertexCache.setCache(resBuffer);
|
|
429
|
+
return resBuffer;
|
|
430
|
+
}
|
|
431
|
+
return this.vertexCache.getCache();
|
|
446
432
|
}
|
|
447
433
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
];
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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;
|
|
471
461
|
}
|
|
472
|
-
|
|
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;
|
|
473
474
|
}
|
|
474
|
-
return res;
|
|
475
|
-
}
|
|
476
|
-
function vertexBuffer3d(point, color, uv = vector2()) {
|
|
477
|
-
return [...point, 1, ...color.toBuffer(), ...uv, 1];
|
|
478
|
-
}
|
|
479
|
-
function vertexBuffer2d(point, color, uv = vector2()) {
|
|
480
|
-
return [...point, 1, ...color.toBuffer(), ...uv, 0];
|
|
481
|
-
}
|
|
482
|
-
export function vector3(x = 0, y = 0, z = 0) {
|
|
483
|
-
return vec3.fromValues(x, y, z);
|
|
484
|
-
}
|
|
485
|
-
export function vector2(x = 0, y = 0) {
|
|
486
|
-
return vec2.fromValues(x, y, 0);
|
|
487
|
-
}
|
|
488
|
-
function vec3ToPixelRatio(vec) {
|
|
489
|
-
vec3.mul(vec, vector3(devicePixelRatio, devicePixelRatio, devicePixelRatio), vec);
|
|
490
|
-
}
|
|
491
|
-
export function vec3fromVec2(vec) {
|
|
492
|
-
return vector3(vec[0], vec[1]);
|
|
493
|
-
}
|
|
494
|
-
export function randomInt(range, min = 0) {
|
|
495
|
-
return Math.floor(Math.random() * (range - min)) + min;
|
|
496
|
-
}
|
|
497
|
-
export function randomColor(a = 1) {
|
|
498
|
-
return new Color(randomInt(255), randomInt(255), randomInt(255), a);
|
|
499
475
|
}
|
|
500
|
-
export
|
|
501
|
-
|
|
476
|
+
export class CubicBezierCurve2d extends BezierCurve2d {
|
|
477
|
+
constructor(points) {
|
|
478
|
+
super(points);
|
|
479
|
+
}
|
|
502
480
|
}
|
|
503
|
-
export
|
|
504
|
-
|
|
481
|
+
export class SplinePoint2d {
|
|
482
|
+
start;
|
|
483
|
+
end;
|
|
484
|
+
controls;
|
|
485
|
+
constructor(start, end, controls) {
|
|
486
|
+
this.start = start;
|
|
487
|
+
this.end = end;
|
|
488
|
+
this.controls = controls;
|
|
489
|
+
}
|
|
490
|
+
getStart() {
|
|
491
|
+
return this.start;
|
|
492
|
+
}
|
|
493
|
+
getEnd() {
|
|
494
|
+
return this.end;
|
|
495
|
+
}
|
|
496
|
+
getVectorArray(prevEnd) {
|
|
497
|
+
const firstControl = cloneBuf(this.controls[0]);
|
|
498
|
+
if (prevEnd) {
|
|
499
|
+
vec2.add(firstControl, prevEnd, firstControl);
|
|
500
|
+
}
|
|
501
|
+
else if (!this.start) {
|
|
502
|
+
prevEnd = vector2();
|
|
503
|
+
}
|
|
504
|
+
return [
|
|
505
|
+
this.start ? vector2FromVector3(this.start.getPos()) : prevEnd,
|
|
506
|
+
firstControl,
|
|
507
|
+
this.controls[1],
|
|
508
|
+
vector2FromVector3(this.end.getPos())
|
|
509
|
+
];
|
|
510
|
+
}
|
|
505
511
|
}
|
|
506
|
-
export
|
|
507
|
-
|
|
512
|
+
export class Spline2d extends SimulationElement {
|
|
513
|
+
curves;
|
|
514
|
+
width;
|
|
515
|
+
detail;
|
|
516
|
+
constructor(pos, points, width = 2, color, detail = 40) {
|
|
517
|
+
super(vector3FromVector2(pos), color);
|
|
518
|
+
this.curves = [];
|
|
519
|
+
this.width = width * devicePixelRatio;
|
|
520
|
+
this.detail = detail;
|
|
521
|
+
for (let i = 0; i < points.length; i++) {
|
|
522
|
+
const bezierPoints = points[i].getVectorArray(i > 0 ? vector2FromVector3(points[i - 1].getEnd().getPos()) : null);
|
|
523
|
+
const curve = new CubicBezierCurve2d(bezierPoints);
|
|
524
|
+
this.curves.push(curve);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
getBuffer(camera, force) {
|
|
528
|
+
if (this.vertexCache.shouldUpdate() || force) {
|
|
529
|
+
const screenSize = camera.getScreenSize();
|
|
530
|
+
const step = 1 / this.detail;
|
|
531
|
+
let verticesTop = [];
|
|
532
|
+
const verticesBottom = [];
|
|
533
|
+
for (let i = 0; i < this.curves.length; i++) {
|
|
534
|
+
for (let j = 0; j < this.detail + 1; j++) {
|
|
535
|
+
const [point, slope] = this.curves[i].interpolateSlope(step * j);
|
|
536
|
+
const pos = this.getPos();
|
|
537
|
+
point[0] += pos[0];
|
|
538
|
+
point[1] += screenSize[1] - pos[1];
|
|
539
|
+
const normal = vector2(-slope[1], slope[0]);
|
|
540
|
+
vec2.normalize(normal, normal);
|
|
541
|
+
vec2.scale(normal, this.width / 2, normal);
|
|
542
|
+
const vertTop = vertex(point[0] + normal[0], point[1] + normal[1]);
|
|
543
|
+
verticesTop.push(vertTop);
|
|
544
|
+
const vertBottom = vertex(point[0] - normal[0], point[1] - normal[1]);
|
|
545
|
+
verticesBottom.unshift(vertBottom);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
verticesTop = verticesTop.concat(verticesBottom);
|
|
549
|
+
let resBuffer = [];
|
|
550
|
+
lossyTriangulate(verticesTop)
|
|
551
|
+
.flat()
|
|
552
|
+
.forEach((vert) => {
|
|
553
|
+
const pos = vert.getPos();
|
|
554
|
+
resBuffer = resBuffer.concat(vertexBuffer2d(pos[0], pos[1], vert.getColor() || this.getColor()));
|
|
555
|
+
});
|
|
556
|
+
this.vertexCache.setCache(resBuffer);
|
|
557
|
+
return resBuffer;
|
|
558
|
+
}
|
|
559
|
+
return this.vertexCache.getCache();
|
|
560
|
+
}
|
|
508
561
|
}
|
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 } 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 } from './utils.js';
|
package/dist/simulation.d.ts
CHANGED
|
@@ -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,28 +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
|
-
toObject(): {
|
|
59
|
-
r: number;
|
|
60
|
-
g: number;
|
|
61
|
-
b: number;
|
|
62
|
-
a: number;
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* @param callback1 - called every frame until the animation is finished
|
|
67
|
-
* @param callback2 - called after animation is finished (called immediately when t = 0)
|
|
68
|
-
* @param t - animation time (seconds)
|
|
69
|
-
* @returns {Promise<void>}
|
|
70
|
-
*/
|
|
71
|
-
export declare function transitionValues(callback1: (deltaT: number, t: number) => void, callback2: () => void, transitionLength: number, func?: (n: number) => number): Promise<void>;
|
|
72
|
-
export declare function lerp(a: number, b: number, t: number): number;
|
|
73
|
-
export declare function smoothStep(t: number): number;
|
|
74
|
-
export declare function linearStep(n: number): number;
|
package/dist/simulation.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { vec3 } from 'wgpu-matrix';
|
|
2
|
-
import { SimulationElement
|
|
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,77 +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
|
-
toObject() {
|
|
490
|
-
return {
|
|
491
|
-
r: this.r / 255,
|
|
492
|
-
g: this.g / 255,
|
|
493
|
-
b: this.b / 255,
|
|
494
|
-
a: this.a
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* @param callback1 - called every frame until the animation is finished
|
|
500
|
-
* @param callback2 - called after animation is finished (called immediately when t = 0)
|
|
501
|
-
* @param t - animation time (seconds)
|
|
502
|
-
* @returns {Promise<void>}
|
|
503
|
-
*/
|
|
504
|
-
export function transitionValues(callback1, callback2, transitionLength, func) {
|
|
505
|
-
return new Promise((resolve) => {
|
|
506
|
-
if (transitionLength == 0) {
|
|
507
|
-
callback2();
|
|
508
|
-
resolve();
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
let prevPercent = 0;
|
|
512
|
-
let prevTime = Date.now();
|
|
513
|
-
const step = (t, f) => {
|
|
514
|
-
const newT = f(t);
|
|
515
|
-
callback1(newT - prevPercent, t);
|
|
516
|
-
prevPercent = newT;
|
|
517
|
-
const now = Date.now();
|
|
518
|
-
let diff = now - prevTime;
|
|
519
|
-
diff = diff === 0 ? 1 : diff;
|
|
520
|
-
const fpsScale = 1 / diff;
|
|
521
|
-
const inc = 1 / (1000 * fpsScale * transitionLength);
|
|
522
|
-
prevTime = now;
|
|
523
|
-
if (t < 1) {
|
|
524
|
-
window.requestAnimationFrame(() => step(t + inc, f));
|
|
525
|
-
}
|
|
526
|
-
else {
|
|
527
|
-
callback2();
|
|
528
|
-
resolve();
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
step(0, func ? func : linearStep);
|
|
532
|
-
}
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
export function lerp(a, b, t) {
|
|
536
|
-
return a + (b - a) * t;
|
|
537
|
-
}
|
|
538
|
-
export function smoothStep(t) {
|
|
539
|
-
const v1 = t * t;
|
|
540
|
-
const v2 = 1 - (1 - t) * (1 - t);
|
|
541
|
-
return lerp(v1, v2, t);
|
|
542
|
-
}
|
|
543
|
-
export function linearStep(n) {
|
|
544
|
-
return n;
|
|
545
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Color } from './
|
|
1
|
+
import { Color } from './utils.js';
|
|
2
|
+
export type Vector4 = Float32Array & [number, number, number, number];
|
|
2
3
|
export type Vector3 = Float32Array & [number, number, number];
|
|
3
4
|
export type Vector2 = Float32Array & [number, number];
|
|
4
5
|
export type LerpFunc = (n: 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,31 @@ 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): SplinePoint2d;
|
|
19
92
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,110 @@
|
|
|
1
|
-
import { mat4, vec3 } from 'wgpu-matrix';
|
|
2
|
-
import { SimulationElement,
|
|
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,132 @@ 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) {
|
|
288
|
+
vec2.scale(control1, devicePixelRatio, control1);
|
|
289
|
+
vec2.scale(control2, devicePixelRatio, control2);
|
|
290
|
+
vec2.scale(end.getPos(), devicePixelRatio, end.getPos());
|
|
291
|
+
vec2.add(end.getPos(), control2, control2);
|
|
292
|
+
return new SplinePoint2d(null, end, [control1, control2]);
|
|
293
|
+
}
|
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.
|
|
8
|
+
"version": "0.1.6",
|
|
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",
|
package/types/constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const BUF_LEN = 11;
|
package/types/graphics.d.ts
DELETED
|
@@ -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
package/types/types.d.ts
DELETED
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 {};
|