simulationjsv2 0.1.0
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/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/graphics.d.ts +90 -0
- package/dist/graphics.js +505 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/simulation.d.ts +73 -0
- package/dist/simulation.js +541 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +59 -0
- package/package.json +30 -0
- package/types/constants.d.ts +1 -0
- package/types/graphics.d.ts +90 -0
- package/types/index.d.ts +3 -0
- package/types/types.d.ts +5 -0
- package/types/utils.d.ts +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Jackson Otto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# SimulationJS v2
|
|
2
|
+
|
|
3
|
+
SimulationJS is a graphics library with simple easy to use APIs. Version 2 hopes to boost performance by using webgpu under the hood.
|
|
4
|
+
|
|
5
|
+
The APIs for v2 will be different however semantically, using them should be nearly identical.
|
|
6
|
+
|
|
7
|
+
**Documentation coming soon**
|
|
8
|
+
|
|
9
|
+
By _Jackson Otto_
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BUF_LEN = 11;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BUF_LEN = 11;
|
|
@@ -0,0 +1,90 @@
|
|
|
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/dist/graphics.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import { vec3, quat, mat4, vec2 } 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
|
+
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
|
+
}
|
|
49
|
+
export class SimulationElement {
|
|
50
|
+
pos;
|
|
51
|
+
color;
|
|
52
|
+
camera;
|
|
53
|
+
vertexCache;
|
|
54
|
+
constructor(pos, color = new Color()) {
|
|
55
|
+
this.pos = pos;
|
|
56
|
+
vec3ToPixelRatio(this.pos);
|
|
57
|
+
this.color = color;
|
|
58
|
+
this.vertexCache = new VertexCache();
|
|
59
|
+
this.camera = null;
|
|
60
|
+
}
|
|
61
|
+
setPos(pos) {
|
|
62
|
+
this.pos = pos;
|
|
63
|
+
}
|
|
64
|
+
getPos() {
|
|
65
|
+
return this.pos;
|
|
66
|
+
}
|
|
67
|
+
setCamera(camera) {
|
|
68
|
+
this.camera = camera;
|
|
69
|
+
}
|
|
70
|
+
fill(newColor, t = 0, f) {
|
|
71
|
+
const diffR = newColor.r - this.color.r;
|
|
72
|
+
const diffG = newColor.g - this.color.g;
|
|
73
|
+
const diffB = newColor.b - this.color.b;
|
|
74
|
+
const diffA = newColor.a - this.color.a;
|
|
75
|
+
const finalColor = newColor.clone();
|
|
76
|
+
return transitionValues((p) => {
|
|
77
|
+
this.color.r += diffR * p;
|
|
78
|
+
this.color.g += diffG * p;
|
|
79
|
+
this.color.b += diffB * p;
|
|
80
|
+
this.color.a += diffA * p;
|
|
81
|
+
this.vertexCache.updated();
|
|
82
|
+
}, () => {
|
|
83
|
+
this.color = finalColor;
|
|
84
|
+
this.vertexCache.updated();
|
|
85
|
+
}, t, f);
|
|
86
|
+
}
|
|
87
|
+
getColor() {
|
|
88
|
+
return this.color;
|
|
89
|
+
}
|
|
90
|
+
move(amount, t = 0, f) {
|
|
91
|
+
const finalPos = vec3.create();
|
|
92
|
+
vec3.add(finalPos, this.pos, amount);
|
|
93
|
+
return transitionValues((p) => {
|
|
94
|
+
const x = amount[0] * p;
|
|
95
|
+
const y = amount[1] * p;
|
|
96
|
+
const z = amount[2] * p;
|
|
97
|
+
vec3.add(this.pos, this.pos, vector3(x, y, z));
|
|
98
|
+
this.vertexCache.updated();
|
|
99
|
+
}, () => {
|
|
100
|
+
this.pos = finalPos;
|
|
101
|
+
this.vertexCache.updated();
|
|
102
|
+
}, t, f);
|
|
103
|
+
}
|
|
104
|
+
moveTo(pos, t = 0, f) {
|
|
105
|
+
const diff = vec3.create();
|
|
106
|
+
vec3.sub(diff, pos, this.pos);
|
|
107
|
+
return transitionValues((p) => {
|
|
108
|
+
const x = diff[0] * p;
|
|
109
|
+
const y = diff[1] * p;
|
|
110
|
+
const z = diff[2] * p;
|
|
111
|
+
vec3.add(this.pos, this.pos, vector3(x, y, z));
|
|
112
|
+
this.vertexCache.updated();
|
|
113
|
+
}, () => {
|
|
114
|
+
this.pos = pos;
|
|
115
|
+
this.vertexCache.updated();
|
|
116
|
+
}, t, f);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export class Plane extends SimulationElement {
|
|
120
|
+
points;
|
|
121
|
+
rotation;
|
|
122
|
+
constructor(pos, points, rotation = vector3(), color) {
|
|
123
|
+
super(pos, color);
|
|
124
|
+
this.points = points;
|
|
125
|
+
this.rotation = rotation;
|
|
126
|
+
}
|
|
127
|
+
setPoints(newPoints) {
|
|
128
|
+
this.points = newPoints;
|
|
129
|
+
}
|
|
130
|
+
rotate(amount, t = 0, f) {
|
|
131
|
+
const initial = vec3.clone(this.rotation);
|
|
132
|
+
return transitionValues((p) => {
|
|
133
|
+
const step = vector3();
|
|
134
|
+
vec3.scale(amount, p, step);
|
|
135
|
+
vec3.add(this.rotation, step, this.rotation);
|
|
136
|
+
this.vertexCache.updated();
|
|
137
|
+
}, () => {
|
|
138
|
+
vec3.add(initial, amount, initial);
|
|
139
|
+
this.rotation = initial;
|
|
140
|
+
this.vertexCache.updated();
|
|
141
|
+
}, t, f);
|
|
142
|
+
}
|
|
143
|
+
rotateTo(angle, t = 0, f) {
|
|
144
|
+
const diff = vector3();
|
|
145
|
+
vec3.sub(angle, this.rotation, diff);
|
|
146
|
+
return transitionValues((p) => {
|
|
147
|
+
const toRotate = vector3();
|
|
148
|
+
vec3.scale(diff, p, toRotate);
|
|
149
|
+
vec3.add(this.rotation, toRotate, this.rotation);
|
|
150
|
+
this.vertexCache.updated();
|
|
151
|
+
}, () => {
|
|
152
|
+
this.rotation = angle;
|
|
153
|
+
this.vertexCache.updated();
|
|
154
|
+
}, t, f);
|
|
155
|
+
}
|
|
156
|
+
getBuffer(_, force) {
|
|
157
|
+
if (this.vertexCache.shouldUpdate() || force) {
|
|
158
|
+
const resBuffer = [];
|
|
159
|
+
const triangles = generateTriangles(this.points).flat();
|
|
160
|
+
triangles.forEach((verticy) => {
|
|
161
|
+
const rot = quat.create();
|
|
162
|
+
quat.fromEuler(...this.rotation, 'xyz', rot);
|
|
163
|
+
const mat = mat4.create();
|
|
164
|
+
mat4.fromQuat(rot, mat);
|
|
165
|
+
const out = vector3();
|
|
166
|
+
vec3.transformMat4(verticy.getPos(), mat, out);
|
|
167
|
+
vec3.add(out, this.getPos(), out);
|
|
168
|
+
let vertexColor = verticy.getColor();
|
|
169
|
+
vertexColor = vertexColor ? vertexColor : this.getColor();
|
|
170
|
+
resBuffer.push(...vertexBuffer3d(out, vertexColor));
|
|
171
|
+
});
|
|
172
|
+
this.vertexCache.setCache(resBuffer);
|
|
173
|
+
return resBuffer;
|
|
174
|
+
}
|
|
175
|
+
return this.vertexCache.getCache();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export class Square extends SimulationElement {
|
|
179
|
+
width;
|
|
180
|
+
height;
|
|
181
|
+
rotation;
|
|
182
|
+
vertexColors;
|
|
183
|
+
/**
|
|
184
|
+
* @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
|
|
185
|
+
*/
|
|
186
|
+
constructor(pos, width, height, color, rotation, vertexColors) {
|
|
187
|
+
super(vec3fromVec2(pos), color);
|
|
188
|
+
this.width = width * devicePixelRatio;
|
|
189
|
+
this.height = height * devicePixelRatio;
|
|
190
|
+
this.rotation = rotation || 0;
|
|
191
|
+
this.vertexColors = vertexColors || {};
|
|
192
|
+
}
|
|
193
|
+
scaleWidth(amount, t = 0, f) {
|
|
194
|
+
const finalWidth = this.width * amount;
|
|
195
|
+
const diffWidth = finalWidth - this.width;
|
|
196
|
+
return transitionValues((p) => {
|
|
197
|
+
this.width += diffWidth * p;
|
|
198
|
+
this.vertexCache.updated();
|
|
199
|
+
}, () => {
|
|
200
|
+
this.width = finalWidth;
|
|
201
|
+
this.vertexCache.updated();
|
|
202
|
+
}, t, f);
|
|
203
|
+
}
|
|
204
|
+
scaleHeight(amount, t = 0, f) {
|
|
205
|
+
const finalHeight = this.height * amount;
|
|
206
|
+
const diffHeight = finalHeight - this.height;
|
|
207
|
+
return transitionValues((p) => {
|
|
208
|
+
this.height += diffHeight * p;
|
|
209
|
+
this.vertexCache.updated();
|
|
210
|
+
}, () => {
|
|
211
|
+
this.height = finalHeight;
|
|
212
|
+
this.vertexCache.updated();
|
|
213
|
+
}, t, f);
|
|
214
|
+
}
|
|
215
|
+
scale(amount, t = 0, f) {
|
|
216
|
+
const finalWidth = this.width * amount;
|
|
217
|
+
const finalHeight = this.height * amount;
|
|
218
|
+
const diffWidth = finalWidth - this.width;
|
|
219
|
+
const diffHeight = finalHeight - this.height;
|
|
220
|
+
return transitionValues((p) => {
|
|
221
|
+
this.width += diffWidth * p;
|
|
222
|
+
this.height += diffHeight * p;
|
|
223
|
+
this.vertexCache.updated();
|
|
224
|
+
}, () => {
|
|
225
|
+
this.width = finalWidth;
|
|
226
|
+
this.height = finalHeight;
|
|
227
|
+
this.vertexCache.updated();
|
|
228
|
+
}, t, f);
|
|
229
|
+
}
|
|
230
|
+
setWidth(num, t = 0, f) {
|
|
231
|
+
num *= devicePixelRatio;
|
|
232
|
+
const diffWidth = num - this.width;
|
|
233
|
+
return transitionValues((p) => {
|
|
234
|
+
this.width += diffWidth * p;
|
|
235
|
+
this.vertexCache.updated();
|
|
236
|
+
}, () => {
|
|
237
|
+
this.width = num;
|
|
238
|
+
this.vertexCache.updated();
|
|
239
|
+
}, t, f);
|
|
240
|
+
}
|
|
241
|
+
setHeight(num, t = 0, f) {
|
|
242
|
+
num *= devicePixelRatio;
|
|
243
|
+
const diffHeight = num - this.height;
|
|
244
|
+
return transitionValues((p) => {
|
|
245
|
+
this.height += diffHeight * p;
|
|
246
|
+
this.vertexCache.updated();
|
|
247
|
+
}, () => {
|
|
248
|
+
this.height = num;
|
|
249
|
+
this.vertexCache.updated();
|
|
250
|
+
}, t, f);
|
|
251
|
+
}
|
|
252
|
+
rotate(rotation, t = 0, f) {
|
|
253
|
+
const finalRotation = this.rotation + rotation;
|
|
254
|
+
return transitionValues((p) => {
|
|
255
|
+
this.rotation += rotation * p;
|
|
256
|
+
this.vertexCache.updated();
|
|
257
|
+
}, () => {
|
|
258
|
+
this.rotation = finalRotation;
|
|
259
|
+
this.vertexCache.updated();
|
|
260
|
+
}, t, f);
|
|
261
|
+
}
|
|
262
|
+
setRotation(newRotation, t = 0, f) {
|
|
263
|
+
const diff = newRotation - this.rotation;
|
|
264
|
+
return transitionValues((p) => {
|
|
265
|
+
this.rotation += diff * p;
|
|
266
|
+
this.vertexCache.updated();
|
|
267
|
+
}, () => {
|
|
268
|
+
this.rotation = newRotation;
|
|
269
|
+
this.vertexCache.updated();
|
|
270
|
+
}, t, f);
|
|
271
|
+
}
|
|
272
|
+
getBuffer(camera, force) {
|
|
273
|
+
const resBuffer = [];
|
|
274
|
+
if (this.vertexCache.shouldUpdate() || force) {
|
|
275
|
+
const points = [
|
|
276
|
+
vector2(this.width / 2, this.height / 2),
|
|
277
|
+
vector2(-this.width / 2, this.height / 2),
|
|
278
|
+
vector2(-this.width / 2, -this.height / 2),
|
|
279
|
+
vector2(this.width / 2, -this.height / 2)
|
|
280
|
+
].map((vec) => {
|
|
281
|
+
const mat = mat4.identity();
|
|
282
|
+
mat4.rotateZ(mat, this.rotation, mat);
|
|
283
|
+
vec2.transformMat4(vec, mat, vec);
|
|
284
|
+
const pos = vector2();
|
|
285
|
+
vec2.clone(this.getPos(), pos);
|
|
286
|
+
pos[1] = camera.getScreenSize()[1] - pos[1];
|
|
287
|
+
vec2.add(pos, vector2(this.width / 2, -this.height / 2), pos);
|
|
288
|
+
vec2.add(vec, pos, vec);
|
|
289
|
+
return vec;
|
|
290
|
+
});
|
|
291
|
+
const vertexOrder = [0, 1, 2, 0, 2, 3];
|
|
292
|
+
vertexOrder.forEach((vertex) => {
|
|
293
|
+
let vertexColor = this.vertexColors[vertex];
|
|
294
|
+
vertexColor = vertexColor ? vertexColor : this.getColor();
|
|
295
|
+
resBuffer.push(...vertexBuffer2d(vec3fromVec2(points[vertex]), vertexColor));
|
|
296
|
+
});
|
|
297
|
+
this.vertexCache.setCache(resBuffer);
|
|
298
|
+
return resBuffer;
|
|
299
|
+
}
|
|
300
|
+
return this.vertexCache.getCache();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
export class Circle extends SimulationElement {
|
|
304
|
+
radius;
|
|
305
|
+
detail = 100;
|
|
306
|
+
constructor(pos, radius, color, detail = 50) {
|
|
307
|
+
super(vec3fromVec2(pos), color);
|
|
308
|
+
this.radius = radius * devicePixelRatio;
|
|
309
|
+
this.detail = detail;
|
|
310
|
+
}
|
|
311
|
+
setRadius(num, t = 0, f) {
|
|
312
|
+
num *= devicePixelRatio;
|
|
313
|
+
const diff = num - this.radius;
|
|
314
|
+
return transitionValues((p) => {
|
|
315
|
+
this.radius += diff * p;
|
|
316
|
+
this.vertexCache.updated();
|
|
317
|
+
}, () => {
|
|
318
|
+
this.radius = num;
|
|
319
|
+
this.vertexCache.updated();
|
|
320
|
+
}, t, f);
|
|
321
|
+
}
|
|
322
|
+
scale(amount, t = 0, f) {
|
|
323
|
+
const finalRadius = this.radius * amount;
|
|
324
|
+
const diff = finalRadius - this.radius;
|
|
325
|
+
return transitionValues((p) => {
|
|
326
|
+
this.radius += diff * p;
|
|
327
|
+
this.vertexCache.updated();
|
|
328
|
+
}, () => {
|
|
329
|
+
this.radius = finalRadius;
|
|
330
|
+
this.vertexCache.updated();
|
|
331
|
+
}, t, f);
|
|
332
|
+
}
|
|
333
|
+
getBuffer(camera, force) {
|
|
334
|
+
if (this.vertexCache.shouldUpdate() || force) {
|
|
335
|
+
const points = [];
|
|
336
|
+
const rotationInc = (Math.PI * 2) / this.detail;
|
|
337
|
+
for (let i = 0; i < this.detail; i++) {
|
|
338
|
+
const mat = mat4.identity();
|
|
339
|
+
mat4.rotateZ(mat, rotationInc * i, mat);
|
|
340
|
+
const vec = vector3(this.radius);
|
|
341
|
+
vec3.transformMat4(vec, mat, vec);
|
|
342
|
+
vec3.add(vec, this.getPos(), vec);
|
|
343
|
+
const screenSize = camera.getScreenSize();
|
|
344
|
+
points.push(new Vertex(vec[0], screenSize[1] - vec[1], vec[2], this.getColor(), false));
|
|
345
|
+
}
|
|
346
|
+
const vertices = generateTriangles(points).reduce((acc, curr) => {
|
|
347
|
+
curr.forEach((vertex) => acc.push(...vertex.toBuffer(this.getColor())));
|
|
348
|
+
return acc;
|
|
349
|
+
}, []);
|
|
350
|
+
this.vertexCache.setCache(vertices);
|
|
351
|
+
return vertices;
|
|
352
|
+
}
|
|
353
|
+
return this.vertexCache.getCache();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
export class Polygon extends SimulationElement {
|
|
357
|
+
points;
|
|
358
|
+
rotation = 0;
|
|
359
|
+
/*
|
|
360
|
+
* points adjusted for device pixel ratio
|
|
361
|
+
*/
|
|
362
|
+
constructor(pos, points, color) {
|
|
363
|
+
super(pos, color);
|
|
364
|
+
this.points = points.map((point) => {
|
|
365
|
+
return new Vertex(point[0], point[1], 0, this.getColor(), false);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
rotate(amount, t = 0, f) {
|
|
369
|
+
const finalRotation = this.rotation + amount;
|
|
370
|
+
return transitionValues((p) => {
|
|
371
|
+
this.rotation += amount * p;
|
|
372
|
+
this.vertexCache.updated();
|
|
373
|
+
}, () => {
|
|
374
|
+
this.rotation = finalRotation;
|
|
375
|
+
}, t, f);
|
|
376
|
+
}
|
|
377
|
+
rotateTo(num, t = 0, f) {
|
|
378
|
+
const diff = num - this.rotation;
|
|
379
|
+
return transitionValues((p) => {
|
|
380
|
+
this.rotation += diff * p;
|
|
381
|
+
this.vertexCache.updated();
|
|
382
|
+
}, () => {
|
|
383
|
+
this.rotation = num;
|
|
384
|
+
}, t, f);
|
|
385
|
+
}
|
|
386
|
+
setPoints(newPoints, t = 0, f) {
|
|
387
|
+
const points = newPoints.map((point) => {
|
|
388
|
+
const vec = vector3(...point);
|
|
389
|
+
return vec;
|
|
390
|
+
});
|
|
391
|
+
const lastPoint = this.points.length > 0 ? this.points[this.points.length - 1] : vec3.create();
|
|
392
|
+
if (points.length > this.points.length) {
|
|
393
|
+
while (points.length > this.points.length) {
|
|
394
|
+
this.points.push(new Vertex(lastPoint[0], lastPoint[1], 0, this.getColor(), false));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const initial = this.points.map((p) => vector3(...p.getPos()));
|
|
398
|
+
const changes = [
|
|
399
|
+
...points.map((p, i) => {
|
|
400
|
+
const vec = vec3.create();
|
|
401
|
+
vec3.sub(vec, p, this.points[i]);
|
|
402
|
+
return vec;
|
|
403
|
+
}),
|
|
404
|
+
...this.points.slice(points.length, this.points.length).map((point) => {
|
|
405
|
+
const vec = vector3(...points[points.length - 1]) || vec3.create();
|
|
406
|
+
vec3.sub(vec, vec, point);
|
|
407
|
+
return vec;
|
|
408
|
+
})
|
|
409
|
+
];
|
|
410
|
+
return transitionValues((p) => {
|
|
411
|
+
this.points = this.points.map((point, i) => {
|
|
412
|
+
const change = vector3(...changes[i]);
|
|
413
|
+
vec3.scale(change, change, p);
|
|
414
|
+
vec3.add(point, point, change);
|
|
415
|
+
return point;
|
|
416
|
+
});
|
|
417
|
+
this.vertexCache.updated();
|
|
418
|
+
}, () => {
|
|
419
|
+
this.points = initial.map((p, i) => {
|
|
420
|
+
const vec = vec3.create();
|
|
421
|
+
vec3.add(vec, p, changes[i]);
|
|
422
|
+
return vec;
|
|
423
|
+
});
|
|
424
|
+
this.points.splice(points.length, this.points.length);
|
|
425
|
+
this.vertexCache.updated();
|
|
426
|
+
}, t, f);
|
|
427
|
+
}
|
|
428
|
+
getBuffer() {
|
|
429
|
+
// let triangles: Triangles = [];
|
|
430
|
+
// if (this.triangleCache.shouldUpdate()) {
|
|
431
|
+
// let newPoints: vec3[] = this.points.map((vec) => {
|
|
432
|
+
// const newPoint = vec3.create();
|
|
433
|
+
// vec3.add(newPoint, vec, this.getPos());
|
|
434
|
+
// return newPoint;
|
|
435
|
+
// });
|
|
436
|
+
// triangles = generateTriangles(newPoints);
|
|
437
|
+
// this.triangleCache.setCache(triangles);
|
|
438
|
+
// } else {
|
|
439
|
+
// triangles = this.triangleCache.getCache();
|
|
440
|
+
// }
|
|
441
|
+
// return trianglesAndColorToBuffer(triangles, this.getColor());
|
|
442
|
+
return [];
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function generateTriangles(vertices) {
|
|
446
|
+
const res = [];
|
|
447
|
+
let facingRight = true;
|
|
448
|
+
let rightOffset = 0;
|
|
449
|
+
let leftOffset = 0;
|
|
450
|
+
while (rightOffset < vertices.length - leftOffset - 2) {
|
|
451
|
+
if (facingRight) {
|
|
452
|
+
const triangle = [
|
|
453
|
+
vertices[rightOffset],
|
|
454
|
+
vertices[rightOffset + 1],
|
|
455
|
+
vertices[vertices.length - leftOffset - 1]
|
|
456
|
+
];
|
|
457
|
+
res.push(triangle);
|
|
458
|
+
rightOffset++;
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
const triangle = [
|
|
462
|
+
vertices[rightOffset],
|
|
463
|
+
vertices[vertices.length - leftOffset - 1],
|
|
464
|
+
vertices[vertices.length - leftOffset - 2]
|
|
465
|
+
];
|
|
466
|
+
res.push(triangle);
|
|
467
|
+
leftOffset++;
|
|
468
|
+
}
|
|
469
|
+
facingRight = !facingRight;
|
|
470
|
+
}
|
|
471
|
+
return res;
|
|
472
|
+
}
|
|
473
|
+
function vertexBuffer3d(point, color, uv = vector2()) {
|
|
474
|
+
return [...point, 1, ...color.toBuffer(), ...uv, 1];
|
|
475
|
+
}
|
|
476
|
+
function vertexBuffer2d(point, color, uv = vector2()) {
|
|
477
|
+
return [...point, 1, ...color.toBuffer(), ...uv, 0];
|
|
478
|
+
}
|
|
479
|
+
export function vector3(x = 0, y = 0, z = 0) {
|
|
480
|
+
return vec3.fromValues(x, y, z);
|
|
481
|
+
}
|
|
482
|
+
export function vector2(x = 0, y = 0) {
|
|
483
|
+
return vec2.fromValues(x, y, 0);
|
|
484
|
+
}
|
|
485
|
+
function vec3ToPixelRatio(vec) {
|
|
486
|
+
vec3.mul(vec, vector3(devicePixelRatio, devicePixelRatio, devicePixelRatio), vec);
|
|
487
|
+
}
|
|
488
|
+
export function vec3fromVec2(vec) {
|
|
489
|
+
return vector3(vec[0], vec[1]);
|
|
490
|
+
}
|
|
491
|
+
export function randomInt(range, min = 0) {
|
|
492
|
+
return Math.floor(Math.random() * (range - min)) + min;
|
|
493
|
+
}
|
|
494
|
+
export function randomColor(a = 1) {
|
|
495
|
+
return new Color(randomInt(255), randomInt(255), randomInt(255), a);
|
|
496
|
+
}
|
|
497
|
+
export function vertex(x, y, z, color) {
|
|
498
|
+
return new Vertex(x, y, z, color);
|
|
499
|
+
}
|
|
500
|
+
export function color(r, g, b, a) {
|
|
501
|
+
return new Color(r, g, b, a);
|
|
502
|
+
}
|
|
503
|
+
export function colorf(val, a) {
|
|
504
|
+
return color(val, val, val, a);
|
|
505
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED